<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: brk</title>
    <description>The latest articles on Forem by brk (@atomictangerline).</description>
    <link>https://forem.com/atomictangerline</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2883243%2F5cfa0c9a-7dc3-4d65-9f5c-8047d681adce.JPG</url>
      <title>Forem: brk</title>
      <link>https://forem.com/atomictangerline</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/atomictangerline"/>
    <language>en</language>
    <item>
      <title>Oh, the water, the water!</title>
      <dc:creator>brk</dc:creator>
      <pubDate>Mon, 03 Mar 2025 17:26:59 +0000</pubDate>
      <link>https://forem.com/atomictangerline/oh-the-water-the-water-18jo</link>
      <guid>https://forem.com/atomictangerline/oh-the-water-the-water-18jo</guid>
      <description>&lt;h2&gt;
  
  
  The data is out, the challenge has started..
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Hackaton rule number 1&lt;/strong&gt;: Allow yourself a headstart by carefully lurking for any signs. Will you crack the enigma of the flyer's cryptic clues?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5vmq22d3pskiqsi6iqzl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5vmq22d3pskiqsi6iqzl.png" title="A flyer for the Hackaviz dataviz challenge. It represents a photomontage of a boat floating ont he Garonne in a fictive Toulouse" alt="Hackaviz flyer" width="575" height="844"&gt;&lt;/a&gt;&lt;em&gt;Source: Toulouse DataViz&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Well now, the good folks over at Toulouse Dataviz, they've really gone and done it this time. They've put together a whole mess of datasets to commemorate that doozy of a flood back in (&lt;em&gt;eighteen&lt;/em&gt;)&lt;a href="https://fr.wikipedia.org/wiki/Crue_de_la_Garonne_en_1875" rel="noopener noreferrer"&gt;'75&lt;/a&gt; the one that just about tore the heart right out of this town. 200 souls lost, 25,000 left without a roof over their heads. To them, it was the end of times, I tell you.&lt;/p&gt;

&lt;p&gt;But the previous generations had the wisdom to set up a system for monitoring the waterways and rainfall. For more than a century, thousands of little hands have recorded this data, day after day, come what may. Rain, wind or snow, they spared no effort to keep a record of nature's caprices.&lt;/p&gt;

&lt;p&gt;This data is now available &lt;a href="https://github.com/Toulouse-Dataviz/hackaviz-2025/tree/main/data" rel="noopener noreferrer"&gt;here&lt;/a&gt; in various formats, so that everyone can dive into this story of water and resilience - it's all there to remind us that this river has always been a force that is both beneficent and destructive.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hydrometric stations:
    * Historical records of 132 hydrometric stations, including details like station name, river, opening/closing dates, coordinates, and more.
    Time series data on water levels during 9 major flood events from 1857 to 2022.
    * Time series data on water discharge during 5 major flood events from 1905 to 2022.
    * A long-term, high-resolution (hourly, 30-minute, 15-minute, 5-minute) water level series for the Toulouse Pont-Neuf station dating back 160 years.

Precipitation:
    * Rainfall data from meteorological stations, collected around the time of each major flood event.

Terrain Elevation:
    * High-resolution elevation data for a 100-meter buffer around the Garonne River basin.
    * Detailed elevation data focused specifically on the Saint-Cyprien neighborhood of Toulouse.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Make no mistake, friend, that river, she's a wild one. A force of nature that can give life one moment and take it away the next. But with all this information at our fingertips, maybe, just maybe, we can start to tame her a little. Learn her ways, predict her moods, and keep the heartbreak at bay when she decides to flex her muscles again.&lt;/p&gt;

&lt;p&gt;It's a tall order, I know. But hey, if those folks back in the day could do it, with nothing but pens and papers, then by golly, we've got a fighting chance. So let's roll up our sleeves and get to work, shall we? The Garonne's got a story to tell, and it's high time we listened.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://github.com/Toulouse-Dataviz/hackaviz-2025/tree/main" rel="noopener noreferrer"&gt;Hackaviz 2025 github repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Datasets are available &lt;a href="https://github.com/Toulouse-Dataviz/hackaviz-2025/tree/main/data" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Rules and presentation of the challenge are available &lt;a href="https://toulouse-dataviz.fr/hackaviz/reglement/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In short&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can use any tools&lt;/li&gt;
&lt;li&gt;No obligation to use all the available data.&lt;/li&gt;
&lt;li&gt;Aside from external map tile layers, candidates are not authorized to use any other data than the provided one but it's authorized to perform any type of calculation on the provided datasets.&lt;/li&gt;
&lt;li&gt;The submission format for static visuals is PDF. In the case of an interactive data visualization, the submission will contain the URL and the deliverable must not exceed the equivalent of 2 A4 pages or the equivalent of 3 screenshots.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;(Cover picture: Pont d'Empalot, Inondations de 1875 by Eugène Trutat)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>dataviz</category>
      <category>hackathon</category>
      <category>datavisualization</category>
      <category>dataset</category>
    </item>
    <item>
      <title>The Curious Case of the Visualization State Machine</title>
      <dc:creator>brk</dc:creator>
      <pubDate>Sun, 02 Mar 2025 23:39:56 +0000</pubDate>
      <link>https://forem.com/atomictangerline/the-curious-case-of-the-visualization-state-machine-b8p</link>
      <guid>https://forem.com/atomictangerline/the-curious-case-of-the-visualization-state-machine-b8p</guid>
      <description>&lt;p&gt;It was a curious thing indeed, this &lt;em&gt;state machine&lt;/em&gt;. I stumbled upon the concept quite by accident, you see, while tinkering with some coding challenge. At first, it seemed like a jumble of gears and levers, a confusing mess of switch-statements and method calls. But the more I studied it, the more I began to see the beauty of its design.&lt;/p&gt;

&lt;p&gt;Now, a state machine - what is it, you ask? See it like a well-oiled machine. It breaks down a great, swirling mass of computation into neat, tidy little states, each with its own set of rules and transitions.&lt;/p&gt;

&lt;p&gt;You see, this machine is no ordinary automaton. It has states, like when you have different rooms in a grand old house, each with its own unique character and purpose. It also has transitions, just like the pathways of that house that are allowing you to move from one room to the next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq2s7kw5to7xf85x1394r.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq2s7kw5to7xf85x1394r.gif" alt="An animated image depicting the different states of a data visualization using state machines" width="1190" height="446"&gt;&lt;/a&gt;&lt;em&gt;The state machine in action&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Some more &lt;strong&gt;&lt;a href="https://kentcdodds.com/blog/implementing-a-simple-state-machine-library-in-javascript" rel="noopener noreferrer"&gt;findings&lt;/a&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;One state is defined as the initial state. When a machine starts to execute, it automatically enters this state.&lt;/li&gt;
&lt;li&gt;Each state can define actions that occur when a machine enters or exits that state. Actions will typically have side effects.&lt;/li&gt;
&lt;li&gt;Each state can define events that trigger a transition.&lt;/li&gt;
&lt;li&gt;A transition defines how a machine would react to the event, by exiting one state and entering another state.&lt;/li&gt;
&lt;li&gt;A transition can define actions that occur when the transition happens.&lt;/li&gt;
&lt;li&gt;Actions will typically have side effects.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;And what some of us might call a &lt;a href="https://en.wikipedia.org/wiki/Finite-state_machine" rel="noopener noreferrer"&gt;finite-state machine&lt;/a&gt; (FSM), are the foundation of all computation. They are the building blocks of everything from digital circuits to software programs. By breaking down a problem into a set of defined states and transitions, we can &lt;em&gt;create&lt;/em&gt; systems that are more &lt;strong&gt;predictable&lt;/strong&gt;, &lt;strong&gt;maintainable&lt;/strong&gt;, and therefore &lt;strong&gt;scalable&lt;/strong&gt;. It's like taking a great, tangled ball of yarn and carefully, methodically, winding it into a neat, tidy skein.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Now that you've had a look at the big picture, watch a &lt;a href="https://brooks-code.github.io/silver-broccoli/test.html" rel="noopener noreferrer"&gt;live demo&lt;/a&gt; of a (basic) state machine tailored to our data visualization use case and then, we'll dig further.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A never-ending mechanic
&lt;/h2&gt;

&lt;p&gt;Take, the &lt;code&gt;updateVisualization()&lt;/code&gt; method. This is the heart of the state machine, the conductor that orchestrates the entire performance. It is a simple enough method, really, just a switch statement that calls the appropriate state-specific method based on the current step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * This is the State machine.
 *
 * Updates the visualization based on the current step.
 * @param {number} step - The current step of the visualization.
 */&lt;/span&gt;
&lt;span class="nf"&gt;updateVisualization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;step&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;visualizationSteps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showInitialState&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showIntroState&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showZoneState&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="c1"&gt;// ... and so on&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;visualizationSteps&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;step&lt;/span&gt;&lt;span class="p"&gt;]?.();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The line of code below simply means that the first state of the visualization will be handled by &lt;code&gt;showInitialState()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showInitialState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Within each of those state-specific methods, the real magic happens. Take the &lt;code&gt;showZoneState()&lt;/code&gt; method, for instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="nf"&gt;showZoneState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setupVisualizationState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;hideText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#intro-text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#presentation-text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;styleType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;zone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tooltipType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;zone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The state machine is calling the &lt;code&gt;setupVisualizationState()&lt;/code&gt; method, which is responsible for configuring the various aspects of the visualization –like hiding and showing text, updating the styles and tool-tips, and so on. This way, each step is building upon the last, creating therefore a seamless and engaging user experience.&lt;/p&gt;

&lt;p&gt;And as I delved deeper into the concept, I couldn't help but marvel at the elegance of it all. The way it handled the complex interplay of user interactions, map layers, and visualization settings – it was like watching a master puppeteer, pulling the strings with effortless grace.&lt;/p&gt;

&lt;p&gt;But what really struck me was the way the state machine anticipated the user's every move. It was as if it could peer into the future, anticipating the next button click or menu selection, and adjust its course accordingly. Have a peek at the &lt;code&gt;handleStepChange()&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Handles Next/Previous buttons change.
 *
 * Handles the step change when the "Next" or "Previous" button is clicked.
 * @param {number} direction - The direction of the step change (1 for next, -1 for previous).
 */&lt;/span&gt;
&lt;span class="nf"&gt;handleStepChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newStep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentStep&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newStep&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;newStep&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentStep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newStep&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateVisualization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newStep&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateButtonState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the method is carefully monitoring the user's button clicks, adjusting the current step, updating the visualization to the corresponding step, and of course updating the state of the buttons themselves. We wouldn't like to get lost along the way, right?&lt;/p&gt;

&lt;p&gt;So when the user makes a move, the state machine springs into action, smoothly transitioning from one state to the next, updating the visualization with precision and finesse.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;And by watching in motion this humble piece of code, I saw the embodiment of a fundamental truth: the most &lt;em&gt;complex&lt;/em&gt; systems can be tamed, if only we have the patience and the vision to understand them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Enhancing the visualization
&lt;/h2&gt;

&lt;p&gt;Now, this visualization tool we've been tinkering with - since we aim to elevate the viewer's experience and make it a veritable dance of data and pixels, we'll need to furnish it with neat little goodies. Let's review some:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Adds circle markers to the map representing the population percentage of each GeoJSON feature.
 */&lt;/span&gt;
&lt;span class="nf"&gt;addPopulationDots&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geoJsonLayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eachLayer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;feature&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pop_percentage&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;L&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;circleMarker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBounds&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getCenter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COLORS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEFAULT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OPACITY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEFAULT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;fillOpacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OPACITY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LOWER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;fillColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COLORS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEFAULT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;zIndexOffset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;bindTooltip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nom_complet&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;br&amp;gt;Part de la pop. rég. &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pop_percentage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;%`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;permanent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;custom-tooltip&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;dot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Take, for instance, the way it handles the population visualization in the snippet provided above. The &lt;code&gt;addPopulationDots()&lt;/code&gt; method adds those little dots to the map, each one a representation of the humanity in a visual symphony of our fellow citizens. And wait.. with a flick of the wrist, the whole thing can be cleared away leaving the canvas clean and pristine, ready for the next movement.&lt;/p&gt;

&lt;p&gt;But it doesn't stop there, oh no! This state machine, it's got tricks up its sleeve. Look below at the way it manages the styles and tool-tips, seamlessly transitioning from one map mode to the next. Each one is a unique expression of the data, and therefore a different glimpse through a lens which to view the world.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Generates a style for the GeoJSON layer .
 *
 * Returns a style object based on the specified feature, type and option.
 * @param {object} feature - The feature to generate the style for.
 * @param {string} type - The type of style to generate. (e.g., "default", "zone", "consumption", "production", "ratioEnr").
 * @param {object} options - Optional options for the style.
 * @returns {object} The generated style object.
 */&lt;/span&gt;
&lt;span class="nf"&gt;generateStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;styleMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... various style generation functions&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;styleMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;styleMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now look at the way it handles the transitions between states. Like a skilled dancer, the state machine glides effortlessly from one step to the next, each move carefully choreographed to create a seamless and captivating performance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Updates the visualization based on the specified category and type.
 * @param {string} category - The category of the visualization (e.g., "consumption", "production", "final").
 * @param {string|Object} type - The type of visualization within the category.
 */&lt;/span&gt;
&lt;span class="nf"&gt;updateVisualizationByType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="c1"&gt;// ... set up options based on category and type&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateGeoJsonStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;final&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateTooltips&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;category&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;final&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And when the user wants to explore different aspects of the data within an interactive menu, the state machine is there to guide them, offering up a display of options that integrate with the overall visualization.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * Shows a radio button menu on the map with the specified types and name.
 * @param {Array} types - An array of objects representing the menu options, each with an id and label.
 * @param {string} name - The name of the menu.
 */&lt;/span&gt;
&lt;span class="nf"&gt;showMenu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hideMenu&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SELECTORS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MAP&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createMenu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`input[name="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-type"]`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateVisualizationByType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all folks, we did it, and I can tell that the visualization in motion you see, is a delicate &lt;em&gt;pas de deux&lt;/em&gt; between a human and a machine, each one responding to the other's every move. In the end, what do we have? A visualization that doesn't just display data, but rather, one that makes it sing by telling a story, just like a telltale that captivates and inspires people.&lt;/p&gt;

&lt;p&gt;The complete source code is available on this &lt;a href="https://github.com/brooks-code/silver-broccoli" rel="noopener noreferrer"&gt;github repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Cover picture: Modern Times, 1936).&lt;/em&gt;&lt;/p&gt;

</description>
      <category>statemachine</category>
      <category>programming</category>
      <category>javascript</category>
      <category>dataviz</category>
    </item>
    <item>
      <title>Basic Selenium – Bonus</title>
      <dc:creator>brk</dc:creator>
      <pubDate>Thu, 20 Feb 2025 15:36:06 +0000</pubDate>
      <link>https://forem.com/atomictangerline/basic-selenium-bonus-41dp</link>
      <guid>https://forem.com/atomictangerline/basic-selenium-bonus-41dp</guid>
      <description>&lt;h2&gt;
  
  
  The tome of wise practices
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Some tips on improving code readability.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The Code header
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Where the purpose, the author, and the date of creation are inscribed&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The header, ahh.. the header. That little snippet of code at the top of the script is like a preamble, a clearing of the throat before the real business begins. What purpose does it serve? Well, the header is a kind of introduction, letting the reader know what's to come with some basic information.&lt;/p&gt;

&lt;h3&gt;
  
  
  A main() function
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Let the Code be governed by a singular, mighty function&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ah, the main() function - now there's a topic! It's like the heart and soul of your code, the place where everything comes together. See, when you're working on a code project, it's like you're building a big machine, right? And the main() function, well, that's the control panel, the place where you pull all the levers and push all the buttons to make the whole thing rock. In order to use that machine, you gotta follow a certain set of steps right? Turn the key, check the fuel, prime the pump.. Well, that's what the main() function is all about - it's the sequence of events that gets your code up and running.&lt;/p&gt;

&lt;h3&gt;
  
  
  The parameters, guardians of function
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Each one a gatekeeper, ensuring the proper flow of information.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Parameters are those little vessels that carry the lifeblood of our functions.&lt;br&gt;
&lt;strong&gt;Classes or variables?&lt;/strong&gt;&lt;br&gt;
Now, I know what you're thinkin' - "But George, how do I know which one to use?" Well, my friend, it all comes down to the task at hand.&lt;br&gt;
If you're dealing with a relatively simple setup like here, them variables-as-parameters might be just the ticket you need. But if you're working on somethin' a little more complex, with all sorts of moving parts and interdependencies, well, them classes, they're the way to go. Classes, are the real MVPs of the bunch, and they will help keeping everything organized and running smooth as silk.&lt;/p&gt;

&lt;h3&gt;
  
  
  The docstrings, the illuminating scrolls
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Where the function's purpose, its workings, and its returns are documented.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Alright, people, let me tell you about these things called docstrings. Now, I know what you're thinking - "Docstrings? What in the Sam Hill are those?" Let me break it down for you.&lt;br&gt;
These docstrings, they're like little notes, little snippets of information that you tack on to your code, just to give folks a heads up on what's going on. It's like when you're doing some work around the house, and you leave a little note for the neighbour, just to let ‘em know what you're up to.&lt;br&gt;
Now, these docstrings, they come in all shapes and sizes. But the way I see it, these docstrings, they're not just about the code, no sir. They're about the people too. So, when you write one of these things, you're not just explaining what the code does, you're telling a story. You're givin' people a little glimpse into your mind and your thought process. And this makes &lt;em&gt;t-h-e&lt;/em&gt; difference because on bigger projects, we all know you will never code alone.&lt;/p&gt;

&lt;h3&gt;
  
  
  Type hints as vigilant sentinels
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Ensuring the integrity of the data.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Listen up, I'm about to let you in on a little secret when it comes to this Python business. It's all about them type hints, they're guardrails that keep you from taking a wrong turn by telling your fellow programmers, "hey, this is what I'm expecting here, so don't go messing it up, y'hear?"&lt;br&gt;
See, these type hints, they're some kind of guardians of your program, keeping a watchful eye to make sure you don't go trying to mix apples and oranges, so to speak. When you're dealing with a language as flexible as Python, that's a darn good thing to have in your corner. The more you use ‘em, the more you'll see just how powerful they can be.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you skipped the project introduction, feel free to check &lt;a href="https://dev.to/atomictangerline/basic-selenium-the-easy-peasy-introduction-chapter-1-of-3-4fe3"&gt;the first chapter (setup)&lt;/a&gt;, the &lt;a href="https://dev.to/atomictangerline/basic-selenium-the-easy-peasy-introduction-chapter-2-of-3-1oad"&gt;Code overview&lt;/a&gt;, or just dive deep into the source code in the &lt;a href="https://dev.to/atomictangerline/basic-selenium-the-easy-peasy-introduction-chapter-3-of-3-3bb7"&gt;previous chapter&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;The code is available on &lt;a href="https://github.com/brooks-code/special-octo-telegram" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(Cover picture: &lt;em&gt;unknown&lt;/em&gt;).&lt;/p&gt;

</description>
      <category>programming</category>
      <category>bestpractices</category>
      <category>python</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Basic Selenium – The Easy Peasy Introduction, Chapter 3 of 3</title>
      <dc:creator>brk</dc:creator>
      <pubDate>Thu, 20 Feb 2025 15:28:52 +0000</pubDate>
      <link>https://forem.com/atomictangerline/basic-selenium-the-easy-peasy-introduction-chapter-3-of-3-3bb7</link>
      <guid>https://forem.com/atomictangerline/basic-selenium-the-easy-peasy-introduction-chapter-3-of-3-3bb7</guid>
      <description>&lt;p&gt;&lt;strong&gt;Automating web-based tasks with Selenium? Efficiently. That's the name of the game here, so.. Take the reins and make technology work for you.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A coding story in three chapters (with a bonus).&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
The Odyssey of the Code

&lt;ul&gt;
&lt;li&gt;I. In the realm of the browser, a puppet is forged&lt;/li&gt;
&lt;li&gt;II. The opening of the file&lt;/li&gt;
&lt;li&gt;III. Sentence splitting action unleashed&lt;/li&gt;
&lt;li&gt;IV. The forging of the chunks&lt;/li&gt;
&lt;li&gt;V. Print statements illuminate the path&lt;/li&gt;
&lt;li&gt;VI. The sorcery of the selectors&lt;/li&gt;
&lt;li&gt;VII. The bridge of translation is crossed&lt;/li&gt;
&lt;li&gt;VIII. The file is written&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Conclusion&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Odyssey of the Code
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Taming of the Firefox&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  I. In the realm of the browser, a puppet is forged
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Where the mighty browser is bound to our will, as if by sorcery.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize_browser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Remote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="n"&gt;driver_service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GECKODRIVER_PATH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;log_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;geckodriver.log&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FirefoxOptions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;binary_location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FIREFOX_PATH&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;HEADLESS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-headless&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Firefox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;driver_service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First up, we've got this &lt;code&gt;driver_service&lt;/code&gt; business. Now, I know what you're thinking - "George, what in the world is a driver service?" Well, let me tell you, it's the piece of code that's gonna make this whole Selenium thing work. It's like a bridge between our script and the middleman, I name the &lt;em&gt;geckodriver&lt;/em&gt;! And after that service is up, the gecko’s gonna turn our Firefox into a nice &lt;strong&gt;marionette&lt;/strong&gt;.&lt;br&gt;
And where do we get this driver service, you ask? From the &lt;code&gt;GECKODRIVER_PATH&lt;/code&gt;, of course! That's the path to the executable that's gonna make Firefox dance to our tune. Do you know what else it's gonna do? It's gonna log everything that's happening, right into the &lt;code&gt;geckodriver.log&lt;/code&gt; file. That way, if anything goes sideways, we can take a peek under the hood and see why’s that.&lt;br&gt;
Now, the options. See, we're creating a shiny new set of &lt;code&gt;FirefoxOptions&lt;/code&gt;, and we're gonna deck them out with some goodies. First up, we're pointing it to the &lt;code&gt;FIREFOX_PATH&lt;/code&gt;, making sure we've got the right browser to work with.&lt;br&gt;
And then, if that &lt;code&gt;HEADLESS&lt;/code&gt; variable is set to True, we're gonna add a little &lt;code&gt;-headless&lt;/code&gt; argument to the mix. That means the browser's gonna run without a visible window, stealthier than your average ninja. No need for all the bells and whistles (and windows), we're just here to get the job done, right?&lt;br&gt;
And finally, we're wrapping it all up by returning a brand-spankin' new instance of the &lt;em&gt;Firefox webdriver&lt;/em&gt;, complete with our custom service and options. This one's like a well-oiled machine, and we're the ones behind the wheel.&lt;br&gt;
Just remember: if you ever find yourself scratching your head, wondering what in the world is going on, just take a peek at that &lt;em&gt;geckodriver.log&lt;/em&gt; file. It's like a crystal ball, and it might tell you everything you need to know.&lt;/p&gt;
&lt;h3&gt;
  
  
  II. The opening of the file
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Like an ancient tome unveiling its secrets.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_input_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;FileNotFoundError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;File &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;file_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; not found. Please check, and try again.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alright, folks, gather 'round, because we're about to dive into some more of this code. Now, this right here, this is the kind of stuff that separates the wheat from the chaff.&lt;br&gt;
First up, we've got this &lt;code&gt;try&lt;/code&gt; block. Now, I know what you're thinking: "George, what in the world is a &lt;em&gt;'try'&lt;/em&gt; block?" Well, let me tell you, it's the statement that’s gonna keep us from running headfirst into a brick wall every time something goes wrong. And trust me, in the universe of programming, something's always going wrong.&lt;br&gt;
See, what we're doing here is we're trying to open a file, right? And we're using this fancy-schmancy &lt;code&gt;open()&lt;/code&gt; function to do it. And that's where the &lt;code&gt;try&lt;/code&gt; block comes in.&lt;br&gt;
If everything goes according to plan, and the file is there, waiting for us with open arms, we're gonna read the contents and hand 'em back, no problem.  "But George, what could possibly go wrong?" Well, my friends, the world is a cruel and unpredictable place (&lt;em&gt;especially&lt;/em&gt; when you’re learning software development), and sometimes, those files, they just up and disappear. But don't you worry, we've got a plan and that's where the &lt;code&gt;except&lt;/code&gt; block comes in.&lt;br&gt;
If that &lt;code&gt;'FileNotFoundError'&lt;/code&gt; rears its ugly head, we're gonna print out a nice, friendly message, letting the user know that the file they were looking for is.. not there..&lt;br&gt;
It's like a safety net, a way to keep the wheels from falling off even when the road gets a little bumpy. And you know what they say, "the more you plan for the unexpected, the less unexpected it becomes." Or something like that.. I don't know, I'm just making it up as I go along.&lt;/p&gt;

&lt;p&gt;Anyway, the point is when life hands you lemons, you make lemonade. And when life hands you &lt;em&gt;FileNotFoundError's&lt;/em&gt;, you just smile ;)&lt;/p&gt;
&lt;h3&gt;
  
  
  III. Sentence splitting action unleashed
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;The fellowship of words is broken.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;split_text_into_sentences&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(?&amp;lt;=[\.?!])&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, listen up, because we're about to dive into some serious sentence-splitting action.&lt;br&gt;
Now, you might be looking at this line of code and thinking: "what in the world is going on here?" Well, let me tell you, it's a thing of beauty: we're taking this text that we've been handed, and we're gonna break it down into its individual sentences.&lt;br&gt;
And how are we doing it, you ask? With the power of regular expressions (&lt;em&gt;regex&lt;/em&gt;) and its &lt;code&gt;re.split()&lt;/code&gt; implementation, that's how. "But George, what's a regular expression?" Well, my friends, it's a language all its own, a way of describing patterns in ways that would make your head spin. You can tinker with it &lt;a href="https://regex101.com/r/rsVgaP/1" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
But don't worry, we're not gonna get too deep into the weeds here. All you need to know is that this little regular expression is the key to our success. It's gonna look for those periods, question marks, and exclamation marks, and it's gonna use them as the boundaries to split our text into individual sentences. But careful, this regex has its limits, see, every language is like a delicate little dance, with each word and phrase movin' in perfect harmony. Some Pros, they’re like aware of that more than us so they built up nice little tools using carefully crafted and more accurate natural language processing (NLP)  formulas (for example you can experiment with the &lt;a href="https://www.nltk.org/" rel="noopener noreferrer"&gt;nltk&lt;/a&gt; library). For the sake of simplicity, let’s stick to the basics with the regex way.&lt;/p&gt;

&lt;p&gt;The next time you find yourself staring at a wall of text, wondering how in the world you're gonna make sense of it all, just remember this little line of code and no more trying to figure out where one sentence ends and the next one begins. And who knows, maybe one day, you'll be the one writing the regular expressions turning chaos of strings into order.&lt;/p&gt;
&lt;h3&gt;
  
  
  IV. The forging of the chunks
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;The awakening of mighty blocks of text.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_chunks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;char_limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CHAR_LIMIT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Generator&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;

    &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;deque&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;chunk_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;sentence&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;sentence_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sentence&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;  &lt;span class="c1"&gt;# Add 1 for the space character
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;chunk_length&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;sentence_length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;char_limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sentence&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;chunk_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sentence_length&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sentence&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;chunk_length&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;sentence_length&lt;/span&gt;

    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hmm, we're about to dive into some serious text-chunking action now. You see, we've got this text that we need to translate, but we can't just send the whole thing off to the translation service all at once. Nah, that would be way too easy. Instead, we've gotta break it down into manageable chunks, little bite-sized pieces that the service can handle without breaking a sweat. That's where this &lt;code&gt;generate_chunks()&lt;/code&gt; function comes in handy. It's like a master chef, carefully slicing and dicing the text, making sure each piece is the perfect size.&lt;br&gt;
First, we set up a little &lt;em&gt;deque&lt;/em&gt;, a fancy data structure that's gonna help us keeping track of the current chunk.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A &lt;strong&gt;deque&lt;/strong&gt;, that's just a &lt;em&gt;chic&lt;/em&gt; way of saying double-ended queue, obviously we deal with small amounts of data here but I wanted to give a try to this exotic thing. Your less sophisticated arrays would work fine there too. Just remember that usual &lt;em&gt;pop&lt;/em&gt; and &lt;em&gt;append&lt;/em&gt; methods don’t perform fast on items on the opposite side of the line. So Python’s &lt;code&gt;collections&lt;/code&gt; module provides that class called deque that’s specially designed to provide fast and memory-efficient ways to append and pop item from both ends.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And then, we start looping through the sentences of the "text" block  (we provided it as an argument when we called the function), and for each sentence, we're gonna figure out its length, -including the space character at the end.&lt;br&gt;
Now, you might be wondering, "but George, how do you know when to start a new chunk?" Well, my friends, it's all about that &lt;code&gt;char_limit&lt;/code&gt; variable and the one called &lt;code&gt;chunk_length&lt;/code&gt; that we use as a counter to keep a running tally of the length of the current chunk. If the current sentence is gonna fit within the chunk size character limit, well, we're just gonna add it on and update the chunk length accordingly. That’s the normal way to go. Got it?&lt;br&gt;
Now, if the length of the current sentence, plus the length of the chunk we've got so far, pushes us &lt;em&gt;over&lt;/em&gt; the character limit we've set, well, we're gonna do a few things. First, we're gonna take all the sentences in the chunk and join 'em up with spaces, and then we're gonna yield that beasty. That just means we're gonna spit it out and move on to a new chunk.&lt;br&gt;
Moving on to the next chunk means we're gonna clear out the chunk variable and start fresh, adding the current sentence to it and resetting the chunk length to just the length of that sentence, and then, just like before, we’ll keep rolling until we hit the limit again.&lt;br&gt;
Finally, after we've gone through all the sentences, we're gonna yield the last chunk, if there is one.&lt;/p&gt;

&lt;p&gt;That’s it for our symphony of text-chunking perfection. And who knows.. maybe you'll even find yourself singing the praises of them deques and character limits soon.&lt;/p&gt;
&lt;h3&gt;
  
  
  V. Print statements illuminate the path
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;The chronicles of progress are Written.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;print_preprocess_infos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;------------------&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Delete extra spaces gathered during generate_chunks
&lt;/span&gt;    &lt;span class="n"&gt;input_text_with_spaces&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input_text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;? &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;! &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Input text contains &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_text_with_spaces&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; characters.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;------------------&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Found &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; chunks!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sizes: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; characters each.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;------------------&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alright, but George, why do we need all these print statements? Isn't the script just supposed to, you know, just work?"&lt;br&gt;
Well see, we've got this script that's doing all sorts of stuff, translating text and whatnot. But how are we supposed to know if it's working, huh? That's where these print statements come in, my friends, they're like the canaries in the coal mine. They're the early warning system that's gonna deal us some intel to let us know something's gone awry.&lt;br&gt;
We're gonna print out the length of the input text. Because let's be real, how are we supposed to know if this thing is working if we don't know how much text we're dealing with, am I right? It's like trying to bake a cake without knowing how much flour you've got. There's more.. We're also gonna print out the number of chunks that the script has generated. And to top it all off, we're gonna print out the length of each of those chunks. Because, honestly, who doesn't love a good old-fashioned character count? It's like a little treasure hunt, but instead of finding gold, we're finding out how many letters are in each sentence.&lt;br&gt;
A little &lt;em&gt;apparté&lt;/em&gt; for when you will be contributing to bigger projects: there is that other breed of statements called &lt;strong&gt;loggers&lt;/strong&gt;. They're the quiet ones, they slip in the back door and get the job done without all the fanfare of the print. Just keep in mind they're the ones that keep a careful &lt;em&gt;record&lt;/em&gt; when things start to get a little hairy.&lt;/p&gt;
&lt;h3&gt;
  
  
  VI. The sorcery of the selectors
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Their spell cast the way.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_input_textarea_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Remote&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;WebElement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;WebDriverWait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TIMEOUT&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;until&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;element_to_be_clickable&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CSS_SELECTOR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;INPUT_AREA&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it’s time to jump into some serious Selenium wizardry.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F582dkzvjknbphi4nxa9m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F582dkzvjknbphi4nxa9m.png" title="A screenshot showing the input field of deepL's website." alt="DeepL website's input field" width="800" height="336"&gt;&lt;/a&gt;&lt;em&gt;The input field our marionette will search for.&lt;/em&gt;&lt;br&gt;
You see, we've got this input field that we need to find on the web page, and we can't just go barging in there, hoping it'll be there. Instead, we've gotta harness the power of Selenium, which is gonna help us navigate this digital bytescape.&lt;br&gt;
To understand this whole pasta here, We need to know more about’em selectors. See, when you're coding a website, just like a building, you got all sorts of elements fitting together - your headings, your paragraphs, buttons, an' the like. Each one of those elements, it's got its own little personality, just like a set of traits and characteristics. And to identify them, you can use all sorts of different selectors:  element selectors, class selectors, ID selectors, and many more other lads. Find out more &lt;a href="https://www.w3schools.com/cssref/trysel.php" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That's where this &lt;code&gt;get_input_textarea_element()&lt;/code&gt; function comes in. It's like a secret agent, carefully scanning the page, looking for that elusive &lt;em&gt;input field&lt;/em&gt; where you insert the text you want to translate.&lt;br&gt;
But there’s a challenge to it: what's the point of finding the input field if it's not even ready for us to use? So first, we create a &lt;code&gt;WebDriverWait&lt;/code&gt; object, and we instruct it to wait for up to &lt;code&gt;TIMEOUT&lt;/code&gt; seconds (we've set it at the beginning as a parameter, by the way) for the element to be loaded and clickable thanks to this intriguing &lt;code&gt;EC.element_to_be_clickable()&lt;/code&gt; thing that tells Selenium exactly what we're looking for. In this case, we're saying, "Hey, Selenium, find me an element that's clickable, and it's gotta match this &lt;code&gt;CSS_SELECTOR&lt;/code&gt;. But.. how did I found that damn selector we've got here? Well, invoke the inspector by hitting &lt;em&gt;F12&lt;/em&gt; in Firefox. Then try the &lt;em&gt;ctrl+shift+C&lt;/em&gt; combo, point &amp;amp; clic your target and in the inspector you'll be able to right clic the highlighted piece of code and extract its info.&lt;/p&gt;

&lt;p&gt;Concretely we’re looking to mimic human behavior just like when you paste your first chunk of text. Let’s break it down again:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You select the input field by clicking on it (it’s selected).&lt;/li&gt;
&lt;li&gt;Depending of your laziness level, either you start typing or you just paste some text into that area.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Well, our driver should be instructed to do the same.&lt;br&gt;
Now, I know what you're thinking, "but George, what if the element never becomes clickable? What then?" Well, friends, that's where the &lt;code&gt;WebDriverWait&lt;/code&gt; comes to the rescue. If the element doesn't become clickable within the &lt;code&gt;TIMEOUT&lt;/code&gt; period, the whole thing is gonna throw an exception, and we'll know that something's gone wrong. Maybe the website has been updated and our old CSS selector pal is no more, or a networking problem occured somewhere. Whatever.&lt;br&gt;
If everything goes according to plan, and Selenium manages to find that input field and confirm that it's ready for us to use, well, that's when the wonder happens. We're gonna return that element, and the rest of the script is gonna be able to work its magic.&lt;/p&gt;
&lt;h3&gt;
  
  
  VII. The bridge of translation is crossed
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Meaning is conveyed across the void.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;translate_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Remote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input_field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;WebElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="n"&gt;translation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Translating chunk &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; of &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;------------------&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;input_field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Fetching translation...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SLEEP_TIME&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;translated_chunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CSS_SELECTOR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OUTPUT_AREA&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;

        &lt;span class="n"&gt;translation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;translated_chunk&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;input_field&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;translation&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alright, friends, gather 'round, because we're about to witness the main event, the grand finale and the moment you've all been waiting for - the translation process! Now, I know what you're thinking, "but George, how in the world is this script gonna take all those chunks of text and turn them into a beautiful translation?" Well, my friends, watch out.&lt;/p&gt;

&lt;p&gt;First, we're gonna set up an empty list called &lt;code&gt;translation&lt;/code&gt;. Our little treasure trove of linguistic gold. This is where we're gonna store all the translated chunks.&lt;br&gt;
And then, we're gonna start looping through those chunks, one by one. Now, I know what you're thinking, "but George, how are we gonna keep track of which chunk we're on?" Well, that's where the &lt;code&gt;enumerate()&lt;/code&gt; function comes in, my friends. It's gonna give us the &lt;em&gt;index&lt;/em&gt; of each chunk, so we can keep tabs on our progress.&lt;br&gt;
As we loop through each chunk, we're gonna print out a little separator, just to let the user know that we're hard at work. And then, we're gonna send that chunk of text to the input field, using the &lt;code&gt;send_keys()&lt;/code&gt; method. It's like we're typing the text over to the translation service, saying, "Here, take a look at this! A new text chunk for you to translate."&lt;br&gt;
But we can't just sit back and wait, oh no, that would be way too easy. Instead, we're gonna print out a little message, letting the user know that we're fetching the translation. And then, we're gonna hit the &lt;code&gt;time.sleep()&lt;/code&gt; function, giving the translation service some time to achieve its task.&lt;br&gt;
When the time is up, we're gonna use Selenium again to find the output area on the web page, and we're gonna grab the text that's been translated by now. We're talking about pure algorithmic alchemy, folks, turning one language into another with the click of a button. The thing there is just that we’re not behind the wheels anymore.&lt;br&gt;
So once we've put our hands on that translated chunk, we're gonna append it to our translation list. And then, just to be on the safe side, we're gonna clear out the input field, making sure we're ready for the next chunk.&lt;br&gt;
When we've gone through all the chunks, and collected all those translated gems, we're gonna return the whole &lt;em&gt;(translation)&lt;/em&gt; list  which is the result of all the translations we’ve collected.&lt;/p&gt;
&lt;h3&gt;
  
  
  VIII. The file is written
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;The chronicle of the realm is inscribed.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;write_output_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;translation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writelines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;translation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last step starts by calling &lt;code&gt;write_output_file()&lt;/code&gt;, and let me tell you, it's one of the unsung hero of this whole operation. Because, let's be honest, what's the point of all this translation process if we can't actually, you know, save the results somewhere?&lt;br&gt;
So, here's how it works. First, we're gonna open up a file, using that &lt;code&gt;with&lt;/code&gt; statement. And let me tell you, that &lt;em&gt;with statement&lt;/em&gt;, it's like a handshake that tells Python, "Hey, I'm about to do some serious file-handling business, so don't you dare interrupt me!" And what are we gonna do with this file, you ask? Well, my friends, we're gonna write some text to it. But not just any text, oh no, we're talking about the fruits of our labor, the translated chunks that we've been slaving over for who knows how long.&lt;br&gt;
Now, I know what you're thinking, "but George, how are we gonna get all those chunks into the file?" Well, that's where the &lt;code&gt;f.writelines()&lt;/code&gt; function comes in. It's like a magic wand, taking our list of translated chunks and turning them into a cohesive piece of writing. When that file finally gets saved, it's gonna be all those chunks of text, neatly packaged up into a tangible reality: a file!&lt;br&gt;
But you know, it's not just about the end result, folks. It's about the journey, the process of getting there. And this &lt;code&gt;write_output_file()&lt;/code&gt; function, was the final step in that journey. A cherry on top, mic drop moment that says, "We did it, folks, we translated the heck out of that text!"&lt;br&gt;
&lt;strong&gt;kudos&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We’ve been:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Taming that Selenium machine (&lt;a href="https://dev.to/atomictangerline/basic-selenium-the-easy-peasy-introduction-chapter-1-of-3-4fe3"&gt;installation and configuration&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Managing files (&lt;em&gt;loading a source file and writing results into another one&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;Witnessing that the true sorcery of this tutorial lies in the automated process of translating a text by &lt;em&gt;splitting it into sentences&lt;/em&gt;, stacking them into &lt;em&gt;piles of chunks&lt;/em&gt; sent one by one to the &lt;em&gt;online translation service&lt;/em&gt;, through Selenium, without ever exceeding a &lt;strong&gt;character limit!&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;And the &lt;a href="https://dev.to/atomictangerline/basic-selenium-bonus-41dp"&gt;goodies&lt;/a&gt;: raise a glass to the coder's toolkit, by implementing some good practices &lt;em&gt;(using a header, organizing the code using functions, parameters and a main(), use docstrings and type hints)&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's just the beginning, isn't it? This Selenium business, it's got so much more to offer. The possibilities, they're practically endless, my friends. &lt;strong&gt;So I want you to take this code, tinker with it, experiment, see what else you can make it do&lt;/strong&gt;. You’re ready to go.&lt;br&gt;
Try it out on different translation services, see how it handles the variations. Heck, see if you can make it do your taxes while you're at it (okay, maybe not that, but you get the idea). The point is, this is tip of the iceberg. So, what are you waiting for? Good luck!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The code is available on &lt;a href="https://github.com/brooks-code/special-octo-telegram" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(Cover picture: &lt;em&gt;Cat People, 1942&lt;/em&gt;).&lt;/p&gt;

</description>
      <category>seleniumautomation</category>
      <category>python</category>
      <category>automationscripting</category>
      <category>webdriver</category>
    </item>
    <item>
      <title>Basic Selenium – The Easy Peasy Introduction, Chapter 2 of 3</title>
      <dc:creator>brk</dc:creator>
      <pubDate>Thu, 20 Feb 2025 15:17:29 +0000</pubDate>
      <link>https://forem.com/atomictangerline/basic-selenium-the-easy-peasy-introduction-chapter-2-of-3-1oad</link>
      <guid>https://forem.com/atomictangerline/basic-selenium-the-easy-peasy-introduction-chapter-2-of-3-1oad</guid>
      <description>&lt;p&gt;&lt;strong&gt;Automating web-based tasks with Selenium? Efficiently. That's the name of the game here, so.. Take the reins and make technology work for you.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A coding story in three chapters (with a bonus).&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fellowship of the Functions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A Functional Overview&lt;/strong&gt;:&lt;br&gt;
 There's a whole lot going on under the hood, and you're gonna want to know what makes this thing tick.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For the newcomers out there, on using functions:&lt;br&gt;
Sometimes you got bits of code that you need to use over and over again, right? Well, functions, they make your code a whole lot easier to read and understand. I mean, think about it: instead of trying to decipher a tangled web of spaghetti code, you got these nice, neat little packages that do one thing and do it well. And when you need to make a change, well, you just gotta tweak the function, and b-a-m, problem solved. No muss, no fuss.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Word of advice:&lt;/strong&gt; Embrace 'em, you love 'em. Trust me, your future self is gonna thank you for it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First, let's have a look at this &lt;em&gt;simplified&lt;/em&gt; version of the main function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Main Code
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;

    &lt;span class="c1"&gt;# Initiate an instance of the web browser
&lt;/span&gt;    &lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;initialize_browser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LINK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Wait a bit
&lt;/span&gt;    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SLEEP_TIME&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Parse the text
&lt;/span&gt;    &lt;span class="n"&gt;input_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load_input_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;INPUT_FILE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sentences&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;split_text_into_sentences&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;generate_chunks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sentences&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="c1"&gt;# Eventually print some more details 
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;PRINT_DETAILS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print_preprocess_infos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Find the input field
&lt;/span&gt;    &lt;span class="n"&gt;input_field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_input_textarea_element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Translate the text
&lt;/span&gt;    &lt;span class="n"&gt;translation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;translate_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input_field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Save to output file
&lt;/span&gt;    &lt;span class="nf"&gt;write_output_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OUTPUT_FILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;translation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Shut down the browser instance
&lt;/span&gt;    &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Initialization of the Browser
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;In which the Selenium-forged steed is summoned, and the journey begins.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First, we've got the &lt;code&gt;initialize_browser()&lt;/code&gt; function. This is where the magic starts - it's setting up a brand new instance of the Firefox browser, all decked out with our custom options. &lt;em&gt;Headless&lt;/em&gt; mode is on by default! No need for a window to appear, we're going full stealth mode here.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Parsing of the Text
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Where the words are divided into manageable chunks, as if by the wisdom of the regex.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next, we've got &lt;code&gt;load_input_file()&lt;/code&gt;. This one's pretty straightforward - it's just reading the contents of a file and handing us back the text.&lt;br&gt;
Then there's &lt;code&gt;split_text_into_sentences()&lt;/code&gt;. This is where the script takes that input text and breaks it down into individual sentences. Gotta make sure we're not overwhelming the translation service, you know? Bite-sized chunks are the way to go.&lt;br&gt;
And speaking of those chunks, that's where &lt;code&gt;generate_chunks()&lt;/code&gt; comes in. It's taking those sentences and slicing them, making sure each sentence-block is small enough to play nice with the translation service. No more hitting character limits.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Gathering of the Fields
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;In which the input field is sought and found.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, the real showstoppers: &lt;code&gt;get_input_textarea_element()&lt;/code&gt;. This is the function that use Selenium to find the right spot on the web page to do our work. I mean the input field, where we're gonna pour in our text. Without it, no circus troupe at your fingertips, ready to leap through hoops an' do backflips at your every whim.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Fetching of the Results
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The final step, where the fruits of the labors are harvested and the story ends.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Finally, we've got &lt;code&gt;translate_text()&lt;/code&gt; and &lt;code&gt;write_output_file()&lt;/code&gt;. These are the heavy hitters. &lt;code&gt;translate_text()&lt;/code&gt; is where the rubber meets the road, sending those sentence chunks off to be translated and bringing back the long awaited goods. &lt;code&gt;write_output_file()&lt;/code&gt; is the grand finale, putting the whole shebang down on paper (or, you know, in a file).&lt;br&gt;
Whew, that's a lot to take in, I know. But well, once you've got this thing up and running, you’ll see, it's gonna be smooth sailing. Just sit back, let the wind.. Hmm.. the script do its thing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you skipped the project introduction, feel free to check &lt;a href="https://dev.to/atomictangerline/basic-selenium-the-easy-peasy-introduction-chapter-1-of-3-4fe3"&gt;the first chapter&lt;/a&gt; or just dive deep into the source code in the &lt;a href="https://dev.to/atomictangerline/basic-selenium-the-easy-peasy-introduction-chapter-3-of-3-3bb7"&gt;next chapter&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;The code is available on &lt;a href="https://github.com/brooks-code/special-octo-telegram" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(Cover picture: &lt;em&gt;Laura, 1944&lt;/em&gt;).&lt;/p&gt;

</description>
      <category>python</category>
      <category>selenium</category>
      <category>webautomation</category>
      <category>codingtutorial</category>
    </item>
    <item>
      <title>Basic Selenium – The Easy Peasy Introduction, Chapter 1 of 3</title>
      <dc:creator>brk</dc:creator>
      <pubDate>Thu, 20 Feb 2025 15:08:34 +0000</pubDate>
      <link>https://forem.com/atomictangerline/basic-selenium-the-easy-peasy-introduction-chapter-1-of-3-4fe3</link>
      <guid>https://forem.com/atomictangerline/basic-selenium-the-easy-peasy-introduction-chapter-1-of-3-4fe3</guid>
      <description>&lt;p&gt;&lt;strong&gt;Automating web-based tasks with Selenium? Efficiently. That's the name of the game here, so.. Take the reins and make technology work for you.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A coding story in three chapters (with a bonus).&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About the Project
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F786orcqfkk1it54rsg7q.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F786orcqfkk1it54rsg7q.jpg" title="Néo-noir picture of a man waiting in the dark. Comics. Author unknown" alt="A cover image depicting a conflicted man in a Polar environment" width="564" height="237"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There I was, sitting on a chair, having to gather all these newspaper translations, from who knows where, in who knows what languages. Let me tell you, it was a real slog. The &lt;em&gt;c h a r a c t e r&lt;/em&gt;   &lt;em&gt;l i m i t&lt;/em&gt;, just wouldn't let me get the full show. Nothing but snippets, snippets, snippets...&lt;/p&gt;

&lt;p&gt;Then, the idea struck. This script, see, it's gonna let you bypass all that. No more copying and pasting. Just grab a coffee, make it strong, black and wait for the whole enchilada - right there in front of you. A real time-saver, I'm telling you.&lt;/p&gt;

&lt;p&gt;The best part? Turns out, it wasn't just about solving an immediate problem: it was about deepening my know-how, getting my hands dirty with some real-world programming. A win-win, if you ask me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation and Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Alright, let's crack open this code. Step by step, we're gonna peel back the layers of that machine where each piece is fitting in like a puzzle. By the time we're done, you're gonna have a whole new appreciation for Selenium automation and what it can do.&lt;/p&gt;

&lt;p&gt;And beware, you're not just gonna be learning for learning's sake. Nah, this is about equipping you with the tools to tackle your own challenges. Whatever got you tied up in knots, this is your chance to untangle it and make it sing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;"Time to get this thing installed and ready to rock."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First things first - you're gonna need to clone or download the source code. The repository is online &lt;a href="https://github.com/brooks-code/special-octo-telegram" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Don't worry, I'll wait.&lt;/p&gt;

&lt;p&gt;If you don't already have Firefox on your system, you're gonna need to get that taken care of. For  Ubuntu and other Debianistas folks out there, it's a simple enough fix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;firefox
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;It’s also possible to use Chrome instead of Firefox.. It’s not covered here so if you really want it that way, it’s this way &lt;a href="https://developer.chrome.com/docs/chromedriver/get-started" rel="noopener noreferrer"&gt;there&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next, we've got some packages to install. Nothing too crazy, but we gotta make sure we've got all the tools ready to roll. So fire up that trusty old pip and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boom. Done and done.&lt;br&gt;
Now, the real kicker - &lt;em&gt;the GeckoDriver&lt;/em&gt;. This is the secret sauce that sits behind the scenes, translating your commands into a language web browsers can understand.&lt;br&gt;
You're gonna want to head over to the Mozilla repository, grab the latest version, and get it all set up. I'm talking extraction, permissions, symbolic links - the whole nine yards. And you know the magic? There’s a bash spell ready out there for that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget https://github.com/mozilla/geckodriver/releases/download/v0.35.0/geckodriver-v0.35.0-linux64.tar.gz &lt;span class="nt"&gt;-O&lt;/span&gt; /tmp/geckodriver.tar.gz &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo tar&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; /opt &lt;span class="nt"&gt;-xzf&lt;/span&gt; /tmp/geckodriver.tar.gz &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo chmod &lt;/span&gt;755 /opt/geckodriver &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo ln&lt;/span&gt; &lt;span class="nt"&gt;-fs&lt;/span&gt; /opt/geckodriver /usr/bin/geckodriver &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo ln&lt;/span&gt; &lt;span class="nt"&gt;-fs&lt;/span&gt; /opt/geckodriver /usr/local/bin/geckodriver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a mouthful, I know. But trust me, it's worth it. Once you've got all that squared away, you're gonna be almost ready to start automating like never before.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;Alright, folks, time to dive into the nitty-gritty of this configuration stuff. Because let me tell you, if you don't get this part right, the whole thing's gonna be about as useful as.. a lawn mower in the middle of the Mojave.&lt;br&gt;
First up, we've got those &lt;code&gt;FIREFOX_PATH&lt;/code&gt; and &lt;code&gt;GECKODRIVER_PATH&lt;/code&gt; variables. Now, I know what you're thinking - "But how in the world am I supposed to know where these things are hiding on my system?" Well, fellas, depending on the one you’re looking for, there's a little bash command you can run to ferret that out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;which firefox
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;About the Gecko.. Remember that installation process we went through earlier? Well, the path you set up there is the one you'll want to use here. Not sure about it? No problem, same sauce, Just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;which geckodriver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And Zap! Paste that info into the right place. Easy, right?&lt;br&gt;
Now, the &lt;code&gt;HEADLESS&lt;/code&gt; parameter - this one's a bit of a wild card. See, you can run this whole thing in headless mode, which means the browser will run and do its job but won't actually show up on your screen. Kinda like a ninja, you know? But if you want to see what's going on, and watch your Firefox acting like possessed by a spirit you can set it to &lt;em&gt;False&lt;/em&gt; and watch the magic unfold – try and see.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk43vuyw1rbry1gi6r0hl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk43vuyw1rbry1gi6r0hl.gif" title="A screenshot showing the firefox browser running as a marionette." alt="A screenshot of Firefox with Geckodriver as a WebDriver." width="800" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As for the &lt;code&gt;SOURCE_LANG&lt;/code&gt; and &lt;code&gt;OUTPUT_LANG&lt;/code&gt;, well, pretty self-explanatory. Just pick the languages you want to translate to (source) and from (output), and the script will handle the rest. If you're looking to learn a little more about the available languages, take a glance at that readme file in the repository &lt;a href="https://github.com/brooks-code/special-octo-telegram/blob/main/README.md" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
Last but not least, we've got the &lt;code&gt;CHAR_LIMIT&lt;/code&gt;, &lt;code&gt;TIMEOUT&lt;/code&gt;, and &lt;code&gt;SLEEP_TIME&lt;/code&gt;. These are all about fine-tuning the performance. &lt;code&gt;TIMEOUT&lt;/code&gt;, and &lt;code&gt;SLEEP_TIME&lt;/code&gt; depend mostly on the speed of your network connection. It’s about how long we oughta wait for the website to be fully loaded so we can proceed with the translation. &lt;code&gt;CHAR_LIMIT&lt;/code&gt; is linked to deepL’s restrictions (currently 1500 characters). Tinker with them as needed, but be careful - you don't want to break the whole machine.&lt;br&gt;
The &lt;code&gt;INPUT_FILE&lt;/code&gt; and &lt;code&gt;OUTPUT_FILE&lt;/code&gt; - those are the ones you'll want to point to your own input and output files. Simple enough, right? Just make sure you're pointing the input to something that actually contains text, because that's what this script is built to handle.&lt;br&gt;
Now, a quick word of warning – the script is not perfect - if the output file doesn't exist yet, the script's gonna go ahead and create it for you. But if it does exist, well, buckle up, because the script's gonna overwrite it every time you run it. So, you know, maybe keep an eye on that (and specify a different output each time) if you don’t want to see your previous achievements disappear..&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Wait.. I almost forgot.. You're a &lt;strong&gt;WSL&lt;/strong&gt; User? WSL now supports running Linux GUI applications in a fully &lt;a href="https://learn.microsoft.com/en-us/windows/wsl/tutorials/gui-apps" rel="noopener noreferrer"&gt;integrated experience&lt;/a&gt;. On older configurations, you might need &lt;a href="https://aalonso.dev/blog/2021/how-to-use-gui-apps-in-wsl2-forwarding-x-server-cdj" rel="noopener noreferrer"&gt;this&lt;/a&gt; if you intend to run Firefox as a marionette with its GUI.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;

&lt;p&gt;Once you've got those parameters all squared away, fire up the terminal, go to the script's folder and just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python translate.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ka-boom, the show’s hit the road. The script's gonna take that input file, work its translation-y wonders, and spit out the results into your output file. Fear not, my friend just keep an eye on that output file, and you'll be able to see the fruits of that labor, plain as day.&lt;br&gt;
What are you waiting for? Get out there, update those parameters, and let's see what kind of translation magic you can work!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you're curious about the code you can get a quick overview &lt;a href="https://dev.to/atomictangerline/basic-selenium-the-easy-peasy-introduction-chapter-2-of-3-1oad"&gt;in the second chapter&lt;/a&gt; or just dive deep into it &lt;a href="https://dev.to/atomictangerline/basic-selenium-the-easy-peasy-introduction-chapter-3-of-3-3bb7"&gt;(third chapter)&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;The code is available on &lt;a href="https://github.com/brooks-code/special-octo-telegram" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(Cover picture: &lt;em&gt;Double Indemnity, 1944&lt;/em&gt;).&lt;/p&gt;

</description>
      <category>python</category>
      <category>tutorial</category>
      <category>selenium</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
