From 3f4154005adeaf3ff46d07da3bab870a0c8c967f Mon Sep 17 00:00:00 2001 From: Yigit Colakoglu Date: Wed, 26 May 2021 12:32:21 +0300 Subject: [PATCH] Added cover --- ...-your-bash-scripts-with-multiprocessing.md | 27 +- public/about/index.html | 21 +- public/awards/index.html | 21 +- public/index.html | 43 +- public/index.xml | 334 ++++++++++- public/posts/index.html | 16 +- public/posts/index.xml | 335 ++++++++++- .../index.html | 542 ++++++++++++++++++ public/projects/index.html | 21 +- public/sitemap.xml | 25 +- public/tags/bash/index.html | 216 +++++++ public/tags/bash/index.xml | 343 +++++++++++ public/tags/bash/page/1/index.html | 1 + public/tags/index.html | 24 + public/tags/index.xml | 33 +- public/tags/programming/index.html | 216 +++++++ public/tags/programming/index.xml | 343 +++++++++++ public/tags/programming/page/1/index.html | 1 + public/tags/scripting/index.html | 216 +++++++ public/tags/scripting/index.xml | 343 +++++++++++ public/tags/scripting/page/1/index.html | 1 + static/images/glasses.png | Bin 0 -> 30136 bytes ...your-bash-scripts-with-multiprocessing.png | Bin 0 -> 9296 bytes 23 files changed, 3086 insertions(+), 36 deletions(-) create mode 100644 public/posts/supercharge-your-bash-scripts-with-multiprocessing/index.html create mode 100644 public/tags/bash/index.html create mode 100644 public/tags/bash/index.xml create mode 100644 public/tags/bash/page/1/index.html create mode 100644 public/tags/programming/index.html create mode 100644 public/tags/programming/index.xml create mode 100644 public/tags/programming/page/1/index.html create mode 100644 public/tags/scripting/index.html create mode 100644 public/tags/scripting/index.xml create mode 100644 public/tags/scripting/page/1/index.html create mode 100644 static/images/glasses.png create mode 100644 static/images/supercharge-your-bash-scripts-with-multiprocessing.png diff --git a/content/posts/supercharge-your-bash-scripts-with-multiprocessing.md b/content/posts/supercharge-your-bash-scripts-with-multiprocessing.md index 43e1a8c..dcb4b51 100644 --- a/content/posts/supercharge-your-bash-scripts-with-multiprocessing.md +++ b/content/posts/supercharge-your-bash-scripts-with-multiprocessing.md @@ -3,7 +3,7 @@ title = "Supercharge Your Bash Scripts with Multiprocessing" date = "2021-05-05T17:08:12+03:00" author = "Yigit Colakoglu" authorTwitter = "theFr1nge" -cover = "" +cover = "images/supercharge-your-bash-scripts-with-multiprocessing.png" tags = ["bash", "scripting", "programming"] keywords = ["bash", "scripting"] description = "Bash is a great tool for automating tasks and improving you work flow. However, it is ***SLOW***. Adding multiprocessing to the scripts you write can improve the performance greatly." @@ -35,7 +35,7 @@ process you ran the command on, if you change a variable that the command in the background uses while it runs, it will not be affected. Here is a simple example: -```bash +{{< code language="bash" id="1" expand="Show" collapse="Hide" isCollapsed="false" >}} foo="yeet" function run_in_background(){ @@ -47,7 +47,7 @@ run_in_background & # Spawn the function run_in_background in the background foo="YEET" echo "The value of foo changed to $foo." wait # wait for the background process to finish -``` +{{< /code >}} This should output: @@ -67,14 +67,14 @@ efficient route first before moving on to the big boy implementation. Let's open First of all, let's write a very simple function that allows us to easily test our implementation: -```bash +{{< code language="bash" id="1" expand="Show" collapse="Hide" isCollapsed="false" >}} function tester(){ # A function that takes an int as a parameter and sleeps echo "$1" sleep "$1" echo "ENDED $1" } -``` +{{< /code >}} Now that we have something to run in our processes, we now need to spawn several of them in controlled manner. Controlled being the keyword here. That's because @@ -82,7 +82,7 @@ each system has a maximum number of processes that can be spawned (You can find that out with the command `ulimit -u`). In our case, we want to limit the processes being ran to the variable `num_processes`. Here is the implementation: -```bash +{{< code language="bash" id="1" expand="Show" collapse="Hide" isCollapsed="false" >}} num_processes=$1 pcount=0 for i in {1..10}; do @@ -90,7 +90,7 @@ for i in {1..10}; do ((pcount++==0)) && wait tester $i & done -``` +{{< /code >}} What this loop does is that it takes the number of processes you would like to spawn as an argument and runs `tester` in that many processes. Go ahead and test it out! @@ -113,7 +113,8 @@ continuously pick up jobs from the job pool not waiting for any other process to Here is the implementation that uses job pools. Brace yourselves, because it is kind of complicated. -```bash + +{{< code language="bash" id="1" expand="Show" collapse="Hide" isCollapsed="false" >}} job_pool_end_of_jobs="NO_JOB_LEFT" job_pool_job_queue=/tmp/job_pool_job_queue_$$ job_pool_progress=/tmp/job_pool_progress_$$ @@ -203,7 +204,7 @@ function job_pool_wait() job_pool_stop_workers job_pool_start_workers ${job_pool_job_queue} } -``` +{{< /code >}} Ok... But that the actual fuck is going in here??? @@ -219,7 +220,6 @@ their purposes, shall we? fifo's man page tells us that: ``` - NAME fifo - first-in first-out special file, named pipe @@ -233,7 +233,7 @@ DESCRIPTION that processes can access the pipe using a name in the filesystem. ``` -So put in **very** simple terms, a fifo is a named pipe that can allows +So put in **very** simple terms, a fifo is a named pipe that allows communication between processes. Using a fifo allows us to loop through the jobs in the pool without having to delete them manually, because once we read them with `read cmd args < ${job_queue}`, the job is out of the pipe and the next @@ -285,7 +285,8 @@ inside an existing bash script. Whatever tickles your fancy. I have also provided an example that replicates our first implementation. Just paste the below code under our "chad" job pool script. -```bash + +{{< code language="bash" id="1" expand="Show" collapse="Hide" isCollapsed="false" >}} function tester(){ # A function that takes an int as a parameter and sleeps echo "$1" @@ -302,7 +303,7 @@ done job_pool_wait job_pool_shutdown -``` +{{< /code >}} Hopefully this article was(or will be) helpful to you. From now on, you don't ever have to write single threaded bash scripts like normies :) diff --git a/public/about/index.html b/public/about/index.html index 0a06d29..caeda71 100644 --- a/public/about/index.html +++ b/public/about/index.html @@ -176,7 +176,26 @@ hit me up through social media, I am open to chat :)

- +
+ + +comments powered by Disqus diff --git a/public/awards/index.html b/public/awards/index.html index 03363a5..84bb172 100644 --- a/public/awards/index.html +++ b/public/awards/index.html @@ -165,7 +165,26 @@ - +
+ + +comments powered by Disqus diff --git a/public/index.html b/public/index.html index 8d3c7e6..741f9a7 100644 --- a/public/index.html +++ b/public/index.html @@ -1,7 +1,7 @@ - + Fr1nge's Personal Blog @@ -146,6 +146,47 @@ +
+

+ Supercharge Your Bash Scripts with Multiprocessing +

+ + + + + + + + +
+ + Bash is a great tool for automating tasks and improving you work flow. However, it is SLOW. Adding multiprocessing to the scripts you write can improve the performance greatly. + +
+ + +
+ Read more → +
+ +
+ diff --git a/public/tags/index.xml b/public/tags/index.xml index db88d6d..0ffdec4 100644 --- a/public/tags/index.xml +++ b/public/tags/index.xml @@ -6,6 +6,37 @@ Recent content in Tags on Fr1nge's Personal Blog Hugo -- gohugo.io en-us - Yigit Colakoglu + Yigit Colakoglu + Wed, 05 May 2021 17:08:12 +0300 + + bash + http://fr1nge.xyz/tags/bash/ + Wed, 05 May 2021 17:08:12 +0300 + + http://fr1nge.xyz/tags/bash/ + + + + + + programming + http://fr1nge.xyz/tags/programming/ + Wed, 05 May 2021 17:08:12 +0300 + + http://fr1nge.xyz/tags/programming/ + + + + + + scripting + http://fr1nge.xyz/tags/scripting/ + Wed, 05 May 2021 17:08:12 +0300 + + http://fr1nge.xyz/tags/scripting/ + + + + diff --git a/public/tags/programming/index.html b/public/tags/programming/index.html new file mode 100644 index 0000000..74569e7 --- /dev/null +++ b/public/tags/programming/index.html @@ -0,0 +1,216 @@ + + + + + programming :: Fr1nge's Personal Blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + +
+ + + + +
+ + +
+ + +
+ +
+

+ Supercharge Your Bash Scripts with Multiprocessing +

+ + + + + + + + +
+ + Bash is a great tool for automating tasks and improving you work flow. However, it is SLOW. Adding multiprocessing to the scripts you write can improve the performance greatly. + +
+ + + + +
+ + + +
+ +
+ + +
+ +
+ + + + + + + + + + + +
+ + + diff --git a/public/tags/programming/index.xml b/public/tags/programming/index.xml new file mode 100644 index 0000000..265d536 --- /dev/null +++ b/public/tags/programming/index.xml @@ -0,0 +1,343 @@ + + + + programming on Fr1nge's Personal Blog + http://fr1nge.xyz/tags/programming/ + Recent content in programming on Fr1nge's Personal Blog + Hugo -- gohugo.io + en-us + Yigit Colakoglu + Wed, 05 May 2021 17:08:12 +0300 + + Supercharge Your Bash Scripts with Multiprocessing + http://fr1nge.xyz/posts/supercharge-your-bash-scripts-with-multiprocessing/ + Wed, 05 May 2021 17:08:12 +0300 + + http://fr1nge.xyz/posts/supercharge-your-bash-scripts-with-multiprocessing/ + Bash is a great tool for automating tasks and improving you work flow. However, it is SLOW. Adding multiprocessing to the scripts you write can improve the performance greatly. +What is multiprocessing? In the simplest terms, multiprocessing is the principle of splitting the computations or jobs that a script has to do and running them on different processes. In even simpler terms however, multiprocessing is the computer science equivalent of hiring more than one worker when you are constructing a building. + <p>Bash is a great tool for automating tasks and improving you work flow. However, +it is <em><strong>SLOW</strong></em>. Adding multiprocessing to the scripts you write can improve +the performance greatly.</p> +<h2 id="what-is-multiprocessing">What is multiprocessing?</h2> +<p>In the simplest terms, multiprocessing is the principle of splitting the +computations or jobs that a script has to do and running them on different +processes. In even simpler terms however, multiprocessing is the computer +science equivalent of hiring more than one +worker when you are constructing a building.</p> +<h3 id="introducing-">Introducing &ldquo;&amp;&rdquo;</h3> +<p>While implementing multiprocessing the sign <code>&amp;</code> is going to be our greatest +friend. It is an essential sign if you are writing bash scripts and a very +useful tool in general when you are in the terminal. What <code>&amp;</code> does is that it +makes the command you added it to the end of run in the background and allows +the rest of the script to continue running as the command runs in the +background. One thing to keep in mind is that since it creates a fork of the +process you ran the command on, if you change a variable that the command in the +background uses while it runs, it will not be affected. Here is a simple +example:</p> + + + + <div class="collapsable-code"> + <input id="1" type="checkbox" /> + <label for="1"> + <span class="collapsable-code__language">bash</span> + + <span class="collapsable-code__toggle" data-label-expand="Show" data-label-collapse="Hide"></span> + </label> + <pre class="language-bash" ><code> +foo=&#34;yeet&#34; + +function run_in_background(){ + sleep 0.5 + echo &#34;The value of foo in the function run_in_background is $foo&#34; +} + +run_in_background &amp; # Spawn the function run_in_background in the background +foo=&#34;YEET&#34; +echo &#34;The value of foo changed to $foo.&#34; +wait # wait for the background process to finish +</code></pre> + </div> + + +<p>This should output:</p> +<pre><code>The value of foo changed to YEET. +The value of foo in here is yeet +</code></pre><p>As you can see, the value of <code>foo</code> did not change in the background process even though +we changed it in the main function.</p> +<h2 id="baby-steps">Baby steps&hellip;</h2> +<p>Just like anything related to computer science, there is more than one way of +achieving our goal. We are going to take the easier, less intimidating but less +efficient route first before moving on to the big boy implementation. Let&rsquo;s open up vim and get to scripting! +First of all, let&rsquo;s write a very simple function that allows us to easily test +our implementation:</p> + + + + <div class="collapsable-code"> + <input id="1" type="checkbox" /> + <label for="1"> + <span class="collapsable-code__language">bash</span> + + <span class="collapsable-code__toggle" data-label-expand="Show" data-label-collapse="Hide"></span> + </label> + <pre class="language-bash" ><code> +function tester(){ + # A function that takes an int as a parameter and sleeps + echo &#34;$1&#34; + sleep &#34;$1&#34; + echo &#34;ENDED $1&#34; +} +</code></pre> + </div> + + +<p>Now that we have something to run in our processes, we now need to spawn several +of them in controlled manner. Controlled being the keyword here. That&rsquo;s because +each system has a maximum number of processes that can be spawned (You can find +that out with the command <code>ulimit -u</code>). In our case, we want to limit the +processes being ran to the variable <code>num_processes</code>. Here is the implementation:</p> + + + + <div class="collapsable-code"> + <input id="1" type="checkbox" /> + <label for="1"> + <span class="collapsable-code__language">bash</span> + + <span class="collapsable-code__toggle" data-label-expand="Show" data-label-collapse="Hide"></span> + </label> + <pre class="language-bash" ><code> +num_processes=$1 +pcount=0 +for i in {1..10}; do + ((pcount=pcount%num_processes)); + ((pcount&#43;&#43;==0)) &amp;&amp; wait + tester $i &amp; +done +</code></pre> + </div> + + +<p>What this loop does is that it takes the number of processes you would like to +spawn as an argument and runs <code>tester</code> in that many processes. Go ahead and test it out! +You might notice however that the processes are run int batches. And the size of +batches is the <code>num_processes</code> variable. The reason this happens is because +every time we spawn <code>num_processes</code> processes, we <code>wait</code> for all the processes +to end. This implementation is not a problem in itself, there are many cases +where you can use this implementation and it works perfectly fine. However, if +you don&rsquo;t want this to happen, we have to dump this naive approach all together +and improve our tool belt.</p> +<h2 id="real-chads-use-job-pools">Real Chads use Job Pools</h2> +<p>The solution to the bottleneck that was introduced in our previous approach lies +in using job pools. Job pools are where jobs created by a main process get sent +and wait to get executed. This approach solves our problems because instead of +spawning a new process for every copy and waiting for all the processes to +finish we instead only create a set number of processes(workers) which +continuously pick up jobs from the job pool not waiting for any other process to finish. +Here is the implementation that uses job pools. Brace yourselves, because it is +kind of complicated.</p> + + + + <div class="collapsable-code"> + <input id="1" type="checkbox" /> + <label for="1"> + <span class="collapsable-code__language">bash</span> + + <span class="collapsable-code__toggle" data-label-expand="Show" data-label-collapse="Hide"></span> + </label> + <pre class="language-bash" ><code> +job_pool_end_of_jobs=&#34;NO_JOB_LEFT&#34; +job_pool_job_queue=/tmp/job_pool_job_queue_$$ +job_pool_progress=/tmp/job_pool_progress_$$ +job_pool_pool_size=-1 +job_pool_nerrors=0 + +function job_pool_cleanup() +{ + rm -f ${job_pool_job_queue} + rm -f ${job_pool_progress} +} + +function job_pool_exit_handler() +{ + job_pool_stop_workers + job_pool_cleanup +} + +function job_pool_worker() +{ + local id=$1 + local job_queue=$2 + local cmd= + local args= + + exec 7&lt;&gt; ${job_queue} + while [[ &#34;${cmd}&#34; != &#34;${job_pool_end_of_jobs}&#34; &amp;&amp; -e &#34;${job_queue}&#34; ]]; do + flock --exclusive 7 + IFS=$&#39;\v&#39; + read cmd args &lt;${job_queue} + set -- ${args} + unset IFS + flock --unlock 7 + if [[ &#34;${cmd}&#34; == &#34;${job_pool_end_of_jobs}&#34; ]]; then + echo &#34;${cmd}&#34; &gt;&amp;7 + else + { ${cmd} &#34;$@&#34; ; } + fi + + done + exec 7&gt;&amp;- +} + +function job_pool_stop_workers() +{ + echo ${job_pool_end_of_jobs} &gt;&gt; ${job_pool_job_queue} + wait +} + +function job_pool_start_workers() +{ + local job_queue=$1 + for ((i=0; i&lt;${job_pool_pool_size}; i&#43;&#43;)); do + job_pool_worker ${i} ${job_queue} &amp; + done +} + +function job_pool_init() +{ + local pool_size=$1 + job_pool_pool_size=${pool_size:=1} + rm -rf ${job_pool_job_queue} + rm -rf ${job_pool_progress} + touch ${job_pool_progress} + mkfifo ${job_pool_job_queue} + echo 0 &gt;${job_pool_progress} &amp; + job_pool_start_workers ${job_pool_job_queue} +} + +function job_pool_shutdown() +{ + job_pool_stop_workers + job_pool_cleanup +} + +function job_pool_run() +{ + if [[ &#34;${job_pool_pool_size}&#34; == &#34;-1&#34; ]]; then + job_pool_init + fi + printf &#34;%s\v&#34; &#34;$@&#34; &gt;&gt; ${job_pool_job_queue} + echo &gt;&gt; ${job_pool_job_queue} +} + +function job_pool_wait() +{ + job_pool_stop_workers + job_pool_start_workers ${job_pool_job_queue} +} +</code></pre> + </div> + + +<p>Ok&hellip; But that the actual fuck is going in here???</p> +<h3 id="fifo-and-flock">fifo and flock</h3> +<p>In order to understand what this code is doing, you first need to understand two +key commands that we are using, <code>fifo</code> and <code>flock</code>. Despite their complicated +names, they are actually quite simple. Let&rsquo;s check their man pages to figure out +their purposes, shall we?</p> +<h4 id="man-fifo">man fifo</h4> +<p>fifo&rsquo;s man page tells us that:</p> +<pre><code>NAME + fifo - first-in first-out special file, named pipe + +DESCRIPTION + A FIFO special file (a named pipe) is similar to a pipe, except that + it is accessed as part of the filesystem. It can be opened by multiple + processes for reading or writing. When processes are exchanging data + via the FIFO, the kernel passes all data internally without writing it + to the filesystem. Thus, the FIFO special file has no contents on the + filesystem; the filesystem entry merely serves as a reference point so + that processes can access the pipe using a name in the filesystem. +</code></pre><p>So put in <strong>very</strong> simple terms, a fifo is a named pipe that can allows +communication between processes. Using a fifo allows us to loop through the jobs +in the pool without having to delete them manually, because once we read them +with <code>read cmd args &lt; ${job_queue}</code>, the job is out of the pipe and the next +read outputs the next job in the pool. However the fact that we have multiple +processes introduces one caveat, what if two processes access the pipe at the +same time? They would run the same command and we don&rsquo;t want that. So we resort +to using <code>flock</code>.</p> +<h4 id="man-flock">man flock</h4> +<p>flock&rsquo;s man page defines it as:</p> +<pre><code> SYNOPSIS + flock [options] file|directory command [arguments] + flock [options] file|directory -c command + flock [options] number + + DESCRIPTION + This utility manages flock(2) locks from within shell scripts or from + the command line. + + The first and second of the above forms wrap the lock around the + execution of a command, in a manner similar to su(1) or newgrp(1). + They lock a specified file or directory, which is created (assuming + appropriate permissions) if it does not already exist. By default, if + the lock cannot be immediately acquired, flock waits until the lock is + available. + + The third form uses an open file by its file descriptor number. See + the examples below for how that can be used. +</code></pre><p>Cool, translated to modern English that us regular folks use, <code>flock</code> is a thin +wrapper around the C standard function <code>flock</code> (see <code>man 2 flock</code> if you are +interested). It is used to manage locks and has several forms. The one we are +interested in is the third one. According to the man page, it uses and open file +by its <strong>file descriptor number</strong>. Aha! so that was the purpose of the <code>exec 7&lt;&gt; ${job_queue}</code> calls in the <code>job_pool_worker</code> function. It would essentially +assign the file descriptor 7 to the fifo <code>job_queue</code> and afterwards lock it with +<code>flock --exclusive 7</code>. Cool. This way only one process at a time can read from +the fifo <code>job_queue</code></p> +<h2 id="great-but-how-do-i-use-this">Great! But how do I use this?</h2> +<p>It depends on your preference, you can either save this in a file(e.g. +job_pool.sh) and source it in your bash script. Or you can simply paste it +inside an existing bash script. Whatever tickles your fancy. I have also +provided an example that replicates our first implementation. Just paste the +below code under our &ldquo;chad&rdquo; job pool script.</p> + + + + <div class="collapsable-code"> + <input id="1" type="checkbox" /> + <label for="1"> + <span class="collapsable-code__language">bash</span> + + <span class="collapsable-code__toggle" data-label-expand="Show" data-label-collapse="Hide"></span> + </label> + <pre class="language-bash" ><code> +function tester(){ + # A function that takes an int as a parameter and sleeps + echo &#34;$1&#34; + sleep &#34;$1&#34; + echo &#34;ENDED $1&#34; +} + +num_workers=$1 +job_pool_init $num_workers +pcount=0 +for i in {1..10}; do + job_pool_run tester &#34;$i&#34; +done + +job_pool_wait +job_pool_shutdown +</code></pre> + </div> + + +<p>Hopefully this article was(or will be) helpful to you. From now on, you don&rsquo;t +ever have to write single threaded bash scripts like normies :)</p> + + + + + diff --git a/public/tags/programming/page/1/index.html b/public/tags/programming/page/1/index.html new file mode 100644 index 0000000..3d52525 --- /dev/null +++ b/public/tags/programming/page/1/index.html @@ -0,0 +1 @@ +http://fr1nge.xyz/tags/programming/ \ No newline at end of file diff --git a/public/tags/scripting/index.html b/public/tags/scripting/index.html new file mode 100644 index 0000000..39b7892 --- /dev/null +++ b/public/tags/scripting/index.html @@ -0,0 +1,216 @@ + + + + + scripting :: Fr1nge's Personal Blog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + +
+ + + + +
+ + +
+ + +
+ +
+

+ Supercharge Your Bash Scripts with Multiprocessing +

+ + + + + + + + +
+ + Bash is a great tool for automating tasks and improving you work flow. However, it is SLOW. Adding multiprocessing to the scripts you write can improve the performance greatly. + +
+ + + + +
+ + + +
+ +
+ + +
+ +
+ + + + + + + + + + + +
+ + + diff --git a/public/tags/scripting/index.xml b/public/tags/scripting/index.xml new file mode 100644 index 0000000..a018f23 --- /dev/null +++ b/public/tags/scripting/index.xml @@ -0,0 +1,343 @@ + + + + scripting on Fr1nge's Personal Blog + http://fr1nge.xyz/tags/scripting/ + Recent content in scripting on Fr1nge's Personal Blog + Hugo -- gohugo.io + en-us + Yigit Colakoglu + Wed, 05 May 2021 17:08:12 +0300 + + Supercharge Your Bash Scripts with Multiprocessing + http://fr1nge.xyz/posts/supercharge-your-bash-scripts-with-multiprocessing/ + Wed, 05 May 2021 17:08:12 +0300 + + http://fr1nge.xyz/posts/supercharge-your-bash-scripts-with-multiprocessing/ + Bash is a great tool for automating tasks and improving you work flow. However, it is SLOW. Adding multiprocessing to the scripts you write can improve the performance greatly. +What is multiprocessing? In the simplest terms, multiprocessing is the principle of splitting the computations or jobs that a script has to do and running them on different processes. In even simpler terms however, multiprocessing is the computer science equivalent of hiring more than one worker when you are constructing a building. + <p>Bash is a great tool for automating tasks and improving you work flow. However, +it is <em><strong>SLOW</strong></em>. Adding multiprocessing to the scripts you write can improve +the performance greatly.</p> +<h2 id="what-is-multiprocessing">What is multiprocessing?</h2> +<p>In the simplest terms, multiprocessing is the principle of splitting the +computations or jobs that a script has to do and running them on different +processes. In even simpler terms however, multiprocessing is the computer +science equivalent of hiring more than one +worker when you are constructing a building.</p> +<h3 id="introducing-">Introducing &ldquo;&amp;&rdquo;</h3> +<p>While implementing multiprocessing the sign <code>&amp;</code> is going to be our greatest +friend. It is an essential sign if you are writing bash scripts and a very +useful tool in general when you are in the terminal. What <code>&amp;</code> does is that it +makes the command you added it to the end of run in the background and allows +the rest of the script to continue running as the command runs in the +background. One thing to keep in mind is that since it creates a fork of the +process you ran the command on, if you change a variable that the command in the +background uses while it runs, it will not be affected. Here is a simple +example:</p> + + + + <div class="collapsable-code"> + <input id="1" type="checkbox" /> + <label for="1"> + <span class="collapsable-code__language">bash</span> + + <span class="collapsable-code__toggle" data-label-expand="Show" data-label-collapse="Hide"></span> + </label> + <pre class="language-bash" ><code> +foo=&#34;yeet&#34; + +function run_in_background(){ + sleep 0.5 + echo &#34;The value of foo in the function run_in_background is $foo&#34; +} + +run_in_background &amp; # Spawn the function run_in_background in the background +foo=&#34;YEET&#34; +echo &#34;The value of foo changed to $foo.&#34; +wait # wait for the background process to finish +</code></pre> + </div> + + +<p>This should output:</p> +<pre><code>The value of foo changed to YEET. +The value of foo in here is yeet +</code></pre><p>As you can see, the value of <code>foo</code> did not change in the background process even though +we changed it in the main function.</p> +<h2 id="baby-steps">Baby steps&hellip;</h2> +<p>Just like anything related to computer science, there is more than one way of +achieving our goal. We are going to take the easier, less intimidating but less +efficient route first before moving on to the big boy implementation. Let&rsquo;s open up vim and get to scripting! +First of all, let&rsquo;s write a very simple function that allows us to easily test +our implementation:</p> + + + + <div class="collapsable-code"> + <input id="1" type="checkbox" /> + <label for="1"> + <span class="collapsable-code__language">bash</span> + + <span class="collapsable-code__toggle" data-label-expand="Show" data-label-collapse="Hide"></span> + </label> + <pre class="language-bash" ><code> +function tester(){ + # A function that takes an int as a parameter and sleeps + echo &#34;$1&#34; + sleep &#34;$1&#34; + echo &#34;ENDED $1&#34; +} +</code></pre> + </div> + + +<p>Now that we have something to run in our processes, we now need to spawn several +of them in controlled manner. Controlled being the keyword here. That&rsquo;s because +each system has a maximum number of processes that can be spawned (You can find +that out with the command <code>ulimit -u</code>). In our case, we want to limit the +processes being ran to the variable <code>num_processes</code>. Here is the implementation:</p> + + + + <div class="collapsable-code"> + <input id="1" type="checkbox" /> + <label for="1"> + <span class="collapsable-code__language">bash</span> + + <span class="collapsable-code__toggle" data-label-expand="Show" data-label-collapse="Hide"></span> + </label> + <pre class="language-bash" ><code> +num_processes=$1 +pcount=0 +for i in {1..10}; do + ((pcount=pcount%num_processes)); + ((pcount&#43;&#43;==0)) &amp;&amp; wait + tester $i &amp; +done +</code></pre> + </div> + + +<p>What this loop does is that it takes the number of processes you would like to +spawn as an argument and runs <code>tester</code> in that many processes. Go ahead and test it out! +You might notice however that the processes are run int batches. And the size of +batches is the <code>num_processes</code> variable. The reason this happens is because +every time we spawn <code>num_processes</code> processes, we <code>wait</code> for all the processes +to end. This implementation is not a problem in itself, there are many cases +where you can use this implementation and it works perfectly fine. However, if +you don&rsquo;t want this to happen, we have to dump this naive approach all together +and improve our tool belt.</p> +<h2 id="real-chads-use-job-pools">Real Chads use Job Pools</h2> +<p>The solution to the bottleneck that was introduced in our previous approach lies +in using job pools. Job pools are where jobs created by a main process get sent +and wait to get executed. This approach solves our problems because instead of +spawning a new process for every copy and waiting for all the processes to +finish we instead only create a set number of processes(workers) which +continuously pick up jobs from the job pool not waiting for any other process to finish. +Here is the implementation that uses job pools. Brace yourselves, because it is +kind of complicated.</p> + + + + <div class="collapsable-code"> + <input id="1" type="checkbox" /> + <label for="1"> + <span class="collapsable-code__language">bash</span> + + <span class="collapsable-code__toggle" data-label-expand="Show" data-label-collapse="Hide"></span> + </label> + <pre class="language-bash" ><code> +job_pool_end_of_jobs=&#34;NO_JOB_LEFT&#34; +job_pool_job_queue=/tmp/job_pool_job_queue_$$ +job_pool_progress=/tmp/job_pool_progress_$$ +job_pool_pool_size=-1 +job_pool_nerrors=0 + +function job_pool_cleanup() +{ + rm -f ${job_pool_job_queue} + rm -f ${job_pool_progress} +} + +function job_pool_exit_handler() +{ + job_pool_stop_workers + job_pool_cleanup +} + +function job_pool_worker() +{ + local id=$1 + local job_queue=$2 + local cmd= + local args= + + exec 7&lt;&gt; ${job_queue} + while [[ &#34;${cmd}&#34; != &#34;${job_pool_end_of_jobs}&#34; &amp;&amp; -e &#34;${job_queue}&#34; ]]; do + flock --exclusive 7 + IFS=$&#39;\v&#39; + read cmd args &lt;${job_queue} + set -- ${args} + unset IFS + flock --unlock 7 + if [[ &#34;${cmd}&#34; == &#34;${job_pool_end_of_jobs}&#34; ]]; then + echo &#34;${cmd}&#34; &gt;&amp;7 + else + { ${cmd} &#34;$@&#34; ; } + fi + + done + exec 7&gt;&amp;- +} + +function job_pool_stop_workers() +{ + echo ${job_pool_end_of_jobs} &gt;&gt; ${job_pool_job_queue} + wait +} + +function job_pool_start_workers() +{ + local job_queue=$1 + for ((i=0; i&lt;${job_pool_pool_size}; i&#43;&#43;)); do + job_pool_worker ${i} ${job_queue} &amp; + done +} + +function job_pool_init() +{ + local pool_size=$1 + job_pool_pool_size=${pool_size:=1} + rm -rf ${job_pool_job_queue} + rm -rf ${job_pool_progress} + touch ${job_pool_progress} + mkfifo ${job_pool_job_queue} + echo 0 &gt;${job_pool_progress} &amp; + job_pool_start_workers ${job_pool_job_queue} +} + +function job_pool_shutdown() +{ + job_pool_stop_workers + job_pool_cleanup +} + +function job_pool_run() +{ + if [[ &#34;${job_pool_pool_size}&#34; == &#34;-1&#34; ]]; then + job_pool_init + fi + printf &#34;%s\v&#34; &#34;$@&#34; &gt;&gt; ${job_pool_job_queue} + echo &gt;&gt; ${job_pool_job_queue} +} + +function job_pool_wait() +{ + job_pool_stop_workers + job_pool_start_workers ${job_pool_job_queue} +} +</code></pre> + </div> + + +<p>Ok&hellip; But that the actual fuck is going in here???</p> +<h3 id="fifo-and-flock">fifo and flock</h3> +<p>In order to understand what this code is doing, you first need to understand two +key commands that we are using, <code>fifo</code> and <code>flock</code>. Despite their complicated +names, they are actually quite simple. Let&rsquo;s check their man pages to figure out +their purposes, shall we?</p> +<h4 id="man-fifo">man fifo</h4> +<p>fifo&rsquo;s man page tells us that:</p> +<pre><code>NAME + fifo - first-in first-out special file, named pipe + +DESCRIPTION + A FIFO special file (a named pipe) is similar to a pipe, except that + it is accessed as part of the filesystem. It can be opened by multiple + processes for reading or writing. When processes are exchanging data + via the FIFO, the kernel passes all data internally without writing it + to the filesystem. Thus, the FIFO special file has no contents on the + filesystem; the filesystem entry merely serves as a reference point so + that processes can access the pipe using a name in the filesystem. +</code></pre><p>So put in <strong>very</strong> simple terms, a fifo is a named pipe that can allows +communication between processes. Using a fifo allows us to loop through the jobs +in the pool without having to delete them manually, because once we read them +with <code>read cmd args &lt; ${job_queue}</code>, the job is out of the pipe and the next +read outputs the next job in the pool. However the fact that we have multiple +processes introduces one caveat, what if two processes access the pipe at the +same time? They would run the same command and we don&rsquo;t want that. So we resort +to using <code>flock</code>.</p> +<h4 id="man-flock">man flock</h4> +<p>flock&rsquo;s man page defines it as:</p> +<pre><code> SYNOPSIS + flock [options] file|directory command [arguments] + flock [options] file|directory -c command + flock [options] number + + DESCRIPTION + This utility manages flock(2) locks from within shell scripts or from + the command line. + + The first and second of the above forms wrap the lock around the + execution of a command, in a manner similar to su(1) or newgrp(1). + They lock a specified file or directory, which is created (assuming + appropriate permissions) if it does not already exist. By default, if + the lock cannot be immediately acquired, flock waits until the lock is + available. + + The third form uses an open file by its file descriptor number. See + the examples below for how that can be used. +</code></pre><p>Cool, translated to modern English that us regular folks use, <code>flock</code> is a thin +wrapper around the C standard function <code>flock</code> (see <code>man 2 flock</code> if you are +interested). It is used to manage locks and has several forms. The one we are +interested in is the third one. According to the man page, it uses and open file +by its <strong>file descriptor number</strong>. Aha! so that was the purpose of the <code>exec 7&lt;&gt; ${job_queue}</code> calls in the <code>job_pool_worker</code> function. It would essentially +assign the file descriptor 7 to the fifo <code>job_queue</code> and afterwards lock it with +<code>flock --exclusive 7</code>. Cool. This way only one process at a time can read from +the fifo <code>job_queue</code></p> +<h2 id="great-but-how-do-i-use-this">Great! But how do I use this?</h2> +<p>It depends on your preference, you can either save this in a file(e.g. +job_pool.sh) and source it in your bash script. Or you can simply paste it +inside an existing bash script. Whatever tickles your fancy. I have also +provided an example that replicates our first implementation. Just paste the +below code under our &ldquo;chad&rdquo; job pool script.</p> + + + + <div class="collapsable-code"> + <input id="1" type="checkbox" /> + <label for="1"> + <span class="collapsable-code__language">bash</span> + + <span class="collapsable-code__toggle" data-label-expand="Show" data-label-collapse="Hide"></span> + </label> + <pre class="language-bash" ><code> +function tester(){ + # A function that takes an int as a parameter and sleeps + echo &#34;$1&#34; + sleep &#34;$1&#34; + echo &#34;ENDED $1&#34; +} + +num_workers=$1 +job_pool_init $num_workers +pcount=0 +for i in {1..10}; do + job_pool_run tester &#34;$i&#34; +done + +job_pool_wait +job_pool_shutdown +</code></pre> + </div> + + +<p>Hopefully this article was(or will be) helpful to you. From now on, you don&rsquo;t +ever have to write single threaded bash scripts like normies :)</p> + + + + + diff --git a/public/tags/scripting/page/1/index.html b/public/tags/scripting/page/1/index.html new file mode 100644 index 0000000..77c620c --- /dev/null +++ b/public/tags/scripting/page/1/index.html @@ -0,0 +1 @@ +http://fr1nge.xyz/tags/scripting/ \ No newline at end of file diff --git a/static/images/glasses.png b/static/images/glasses.png new file mode 100644 index 0000000000000000000000000000000000000000..56eee603eb1928ce87fbb18da9bb04899a88c7fe GIT binary patch literal 30136 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'h8&+IKFJf3f1Gs*TIVXKu;uV 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 literal 0 HcmV?d00001 diff --git a/static/images/supercharge-your-bash-scripts-with-multiprocessing.png b/static/images/supercharge-your-bash-scripts-with-multiprocessing.png new file mode 100644 index 0000000000000000000000000000000000000000..55cc3381b14fa7f1dd4bcbc914fc1259f367f588 GIT binary patch literal 9296 zcmd^lXHb({yLN;q*(eeOR6wO|l#W6o0#X79N|h3NQ;Kx9(yK^Sq=_`C(k1j>q^cC@ zy*KF)nn36wXT^8B=lk9{|ISzD%$Z?^%*wj^bzf^e_mek|m1HT%>B%7w2*sm^(y9;$ zi4O#F<{a!CSotZmD+7TrK^{q?)LjzRCzZ_^ERqO6vjh-rm(C#-Bs@o#FAZ@+YkJN< zW%}4~$zfpXf)u6Lk@=S!U}>ejSvIiBJZHQXX)`3gFzn(Lw^!hM{iXjZgftcO3G%182^=h3p-DS>2*D1Y0>s1msC62b(7UPaxW08!P*z@a3; zOjm6|1O}`yk~1>!3xYsH0Z{`hEPw$8_a27%NO)60zXGuapp>Zr=JNxH%>YYqBWUAa zKx~WtzmNJFn9st(8M^js*PK+dkEuB~*2K%p-@Pje=4U8d9M*`5;1y?7dwMf3C8I`T zUrD3{BWK0h*6}B8MR13SB&l-?qC#I}D|Xkx<7HP7mcSMkR(Fw}u1r{(n zQBuA$-Y0PJg6+`UWZ#?BzpdMpvLfD_svB~Fjy-a3@ z$*Dd#)MgdkEV!1Ra=4^YiVa!c6G%k=JD2!%j!0+4;@)qjhm3Wxi{B4 zIYcZXJsu0+f9-@VtM>j4J-6#nF02JzyZK*vEGr0LCYPd3>kYM+r3SjH8Y8#FGrax> z1wt%CO)(?m3>{bYkFp5P&uDb{Hht1vegWM0=-_h@)~*i9*cpo@U$txYKrohdL^NX zfC|gLBzp!YT#t&ap>KuIh93`C%C7HTo;f}C3Yp08p3PEZaq#T)7aVv zAtN%Gh4qV@xdnqEXrJFKF@#0>Br4s2=5QutYD=p++DkubXTK|e`Lfp-i{`0-c4z?9 zC=E(Yg?gH^wzjI*Ql;w_I2Idr)Bfg@vs|ztbpuArX|cu1iU5Z3vW`V{v2?1mpB$4C z7G>-Gl{$_S7Ta3v*_p-7o28rn?2iT&pRF5NX7n`;3yb{5HFlcGrGp|P%+;z=qdp@( zma*T(;-sO~M*UB;dL?5_(NlWvP_7Cyt_nnYuC{!Y;11GqHdpNjmC+C*dA@ z7T3Ov+w`>A11E-e7V%^O#|Z0$FKBQs;@J`u|6tO?q2$@zaFZd|o~uGL{}GmOfK93^ zpPt(!Oiv5?j!vIW*AI&GoT_yje6G~qJx-?g4hKi?z3AzaeY@R~Zm*lhbof>Aml-hy zhDV|qNxCl8AKMSx0iRBUVoT~h7WX3|GYWvLLU*@u^2D8NKwzyTc}0+bXQW#MBC(|FyOzvweO3OgapjYw%a8Kf1S@fL}WLy8m*^UCwjv z2PLKBLJk*L_UGeW-rKgRbvy}{PFfYkX<-26+QWpGTl$&%?d#N zFqI=+H_2MO7iX6b%r52H6JxC%asL44Iu#t4M3)Yp7k z!CBO2K_L;K)+W6)eY)L-V#BRpUQd-wS=mbC9hS0zWANud_Nh+1Bv|dQ_u4P;Qsz*d z2+elSsqj)hPrPisf~{DSA9^0{gKr|73^!K|Pfz&V2s`^A4LOE}gL6w^_@v9;FaQK9 zl-fgr_NhgctHR{r_nm6oBu}l|P8+DiYdE;FoI&{S7IYb}=6g8$hkQD-djVWsgyJN9 zQgE@=%`yYm)X09_a?;Jo|40IP?A8?5oCp;R%LXu-0U7eU3idOD{p%}T{fl=TH?=n{ zOrA)CsP;h#BwsVZ{4OXm|LAp7m;^b%Jmx(RWrHwF!J(3Vnc-V2_cM7#l1*7HA^OB6 zpUm*TtVA>Oi>Q#01dw{zy*SC#uj{eZ{{oyhxPpNznc71{*$p*kP|fOE4_&*dx}U%j z39tmEQDp8N0%6M5A3tmt=Q$STft&$)NnU5d5v4cO_D`2KvG2uSevuh~gc5Ikz_aB6 zSB2{gDx~*#K`!73{~3Lquxu-9Y5dboe^7~@7EmWh4~@^<>ix`(zFoG-S16AhN`wV6oG=mNAUYA+YEfzy#a96DRqXMqbN+{>gS~=5Q81>5{jYBpiCAZp)Ts zpPUE;p8-dShRp#jdM++tW9YT7rf@*@oi~r&s}Y{rHms`^Zdj1v0}$CRRh;BZ*%f!b zvC!<#M>w>o*Xal-;MN}~_%b!Z|6>erT14E{prY<`hNhhX(G5{>Cp`k#-I7|m9A=q%?tTt4;ZCz35}G{NI|sa>LcyUPl4`J{@9`COL}Lig zH^!^pFyN%vM-C{y4HRREFPWIx8_X~gQ5mpR9~fX%^86%OMFfNkxSZ_56`5fXSt80& ziQRVvQ@gsJ;r<2eo(E9WM_F@n)MMJVv-sJH`tYLQStq?@{DQ#U)N_(POfVPVnjebj za(!Lf9Y+ZmAPdS~8lS@FBAFYVn z{$vy%(y(a<+W!KQT|`M@UjFI$vmZ%O@Ox}=lHSf(fTSbA;nCOh%dAk;jGsCA8KwNk zyvtv+DT!+WU=0d-|I~83fcVwSVf&Iz%K))dy9bBHfLf%%VR0|BD>Hnvyl%%`PJ)Tp z4qn?eMDi?{s@Znek@yo(gfYm#a{j+s`vK)km*xFZ?^aN>O$jyFOd^28KvY3~>%UQ+ zcPq$UAW<>|0IBS{nzO~xB>)UjfL^^G8j@WD>>bCDkWWIH7q>10^bvJ2Rv536FZh7A zkbKJoDzKse3@Ri zf~HuuO9VZGKjH)y^(Eob>Af^0P}zSh-ed4#VtJbhXL12#sC#NL3Y5MASBpQ1+jPOU z&6lTjVuw4o#yo35>v%UX!&qJbgI`j1VynTKr}K-myd}UgKXEx5aNK_GKBD+GpoE4y zR8Xov5dM%Ke|Kh!6kK{4XqJ`*g&aN1Ew|JK=v&r>qWtI;nI(1|K-Pb@zl}3U-UAso zWP!1i0;Q>Wz!r8|Zx}#>xE&nheqC6>0t@mpJp+IR|2_->+*e^fuqZ|=@m0pUL$WwY zNGV{$P(Z=pAv*=72J?2d_(g@d9Kix`+RlL3C0}L2AuYI*1^W>0;AK&)C|&zIP^zmSh09R@c7Hc^?VxUb);R}2=bmA}j2DP<1Dw~me_`2y0<4FCb-a)00nGE&WKqx1it^pp(KRK2*?D*E7eR-cC}(EU@?Sdfk)_ARf?~(^XWCPGUK$?UrF?uxp`UCx=}OIBj>W ztJkq0WSB1qxp-$(DlA*RI}>?iRN5i{y~qMfeHQTcYbVJlXcX_;#MozJt{`j0JZGMV z=x7}k&41;7e#G4*5{;et+so#)XI z6kL?Q=zcG^M~E^3R0wWnhbsrPeBMy6XMJJ(s34DEnG?7dx4y4V^@OO|nBwDM1%CF* z@%_w#WRLaz0Z4-yXfwRxsoj{*4A~wTBD6seigE!Qw05O7n#r6y?Pbk=SfK4KQpl6- z1%k)QHMM;^GHlAYEx80A9QvaQ#LRQ@;ibq`7{PXNb9bC@m^ZC<7Sc`Ac2@r=Onx0# zXj)jobRq%w%aRk1z8D}8LvpoZ4rErFihDJ8Ys$u*v(d3~?C6IU z%ctSZr-;SliL15Ob4hJv6N87Y@?Ny6yqDWC8Qez@&ujdEVk0Q4zRCXfis|4L{tPnW z`TTNuK3OA}9wjZW27>WXYo3uzX~2~xuGUZQgGs-dt|NSZ+^y~``87yNile&_P@h)B zySkVbKgo-H<+MZP7}02yV2xO{sBpauwG*ozUC%lPza4^88Sr%)cm%mM_$h0WI1-}s z`6#mbr}uks3xi$z|MFQz%hgq)nV&2$QGNB)FG%D#EYHRSocJ9wd52|#8R_laEs?R0 ztjswI21N^A`u-=w9V_>a*|tK}{^xY<>|&yyI(%!|^6baCatb4R8`P}{`+SR~mE%7x zyKf>8@6|i_gA^$^bvZF(+xW4e*OzQJvydMr$^-4Bpj6OFm0RwCN7};~M;wpJ)_s~6 z)#wXDf@w8hIH@06DuUDG_Ll_7%bJ;y?`zH44N9VP>4ul_s3vY!0ntoVJmu*Y__F+P zM@TVJ28qz+`^#AdJs~>Z^qHR!sg__Si>Ql^slA^&kp8ZygmdkoD!R$vFPOI9=(*mW zn?V&B9eB(=@IcWDg?)$*6J&g^+s#!GiSFa)7ogV3tJkpk`yQU5T5b2sDP;AkYLet zAzVsQ!Dxv_0=;Yp3$HT+O;Iub>8* znQj{C@>n%bI3IlQcx)LjWh$B$8#S=3p*Z%PYtY4`-8f-d{KtJ6+6A-Vj)A}ApX6IS zXJ$60xcia-DhW)pq;%UuQO*P3r&7F}O1w0Xf{Y^YBg?@*OgAoAnw0F6NI6i0Bwyq+ zIj#_T&$bk|VdAe4!P(YL|KWSEpr*Zu5QUBmDc8bYfgt(BT0&A}KbUWQ?G~0>u|;vT zn}1Y~F1MlRHbayTp2jw3xwGmbErx4HvR7$32izX0D%v|6^E;27=c+-$9b^;NuCG3; za>v=*DUE*jO`)zu!GjCa$hA#Hd5q~O@`VH;N(QazZDSwRE(o80q^XY1&&Tu~u8i;b zom+j7RV|dRCGcrI$0mgH2^|C=?- zxVE@TW0Oq&wu$V5sG?b3E88B5e-csTH6-q-P(X`ts;D#T4dPI_s*-fHBIIM_C*;qa zUG$6=?X+s_j(&?Z?$UYpy>#u!XQ`j2c+5=WPCI*TZ@l=t&Y*@9#&n7}!Vw{e))ise zlpf^7Q+FA2v)Vi7=Y2M#;5nSQus9ke6ARS?Wy%sC-o|v&o)<@+_;Pxe+~(*Uk%y_6Dh@Z z^7Fsv2(eu={KHMPb+zK$#YA7^r-{(xu<}t|^bge7%1D_&+{jq{cCO75lAqejwX2d} zey&ZSTCaB_3hkz${=`OM)MBYTxYo0S=~K|<_OqSn@d7ui?$wId(Hj06%&_V-rM-)| z5_eq5&y_TedA(t7Rq@&f@Zj57;cSRf)t-rFJ$sspHjL8*|Gmk)kbzTSDna+I^*4i3 zvWE?OB#D@KU`{CcTL$B`x&=v_tX$Q({V^W)$(juJ*GD`N^L?v#>?jzY7No!9U{zzU z*>P_C`I`quYmc<^3~vkCW^58d-_jRlCxd~z%!rDWo^WDKI2yh6qNpU@(q7(2g;sC) zox1uMH>R||C?dm)fki(bqjRHgCeeE5vQqz40+?i+oTgfC>a5jhymON0w2dCyACB1b zomso)pZoTobU(#U6j9n3q=yrVxhf%wW^a>rjbdeOxcJ>UYwl#_r*Q35Z=bdg~8CJ z=XFUsE0ujsAK-rz9SD#k3h9;Qx%uD`#`bPf^3e(#0G(r2c;XYO0fC7z^W0kbj<7Pj zDLuxjqoahu1r!+M&YV`hu%f1~#af5Q*v_iIgryHIkEgY8T~`_8oashg8{ml+)ZlwN|DT}btz@rP=t?>xBA^3 zoB&6nJ%{XhnPxdlmr>ipBfaEn78?Ce@9+vBXGf_}A*9{!<#W~zr(blHA)-|*YioPd z+lfQ`t=z!aeNNa0ucdW!D;zrh3rUo+_%#=Q_;B}jvAv(czrO-WhT^>>;TLkuc?pAIpzR>fRE@PYT)f-7?l`qp0eL@CTC z@mG7aJiuSD!2`Z3v@tQescw7t!p2GgjIe)x{8Q|TwJgx@OjBH2yck_fpAa-`=lU%w z;rcs$o0C6sEv?7ctJM2e#|qD_$DWIB$8Dm~+@{ETwC{^%>0_^>Q*<7W@yk_Qi!-ng zlAchw8OaH*3tW#(6(=m}7y6FuC)HHyj7)9{#97sm;f9mSkeb2m;1$8dIAQAGI;#M( z?-B;XnMc9pd28cZfEYlZB=*&2V2v`be{M|@dIHo)$NF;j*XcCYB;5$7#YnCYs~SY+ z4-sf182*8ia4yv=pxkR?9$`*LksCSwa#BVjAyH)9W*yD~J2#}_pPLEFV%!wP3+Cds zTovjB^BPzGl@qEaGgY|}(l#2|D0hu0^}z`|xJsy5K9St3&ii>x8l-r0j9k@~EicwI zvQh*yp<_^$ksA^Hu1WyYB${1bg8Aa1*L*`YMMq^Y4X$QzBOD~dRf8{5#Hpk~T`-WQ zVwT?4!%nau(v&7XImeJ{sPuq|!Xj@^{y~?@ec0XMfZ!WSh}k!W zHeUQ4k=&EKWOP(c4#uJG**G=*3^hs<+SnkB36CX_PklPC@DODRQ^*`DX z1_Zqlwz^?F?I!Pf$tiyUTj8N=9&OoQFo{qX`g*Fx}4p#~7xL!{o@cM;S{5brw+0JowUQt1 ziO-gyhP$eozs&B+D3(2A4br`1dRJJic8tryq>cTqq568If9`7T_&vuf(^IMaKQvl% zFma2E#{B)pFQUaYqmq&Q{c}2KP6{POZlS>?UtU z9Xzj3dpBc_yX|ZCm&2EArQia z?IorBqlXShbBjxUlKOWX`i?D~6lEcYwLMlft5-sFY9ZHDJjlsOsmUv;x2tX3%2Hgt3$-zqK<{c8^5 zz#A#7eBW#O-r^p1(RBm7KoNv~VDR>XK%nOzf!_lBjp?CVm&cB@C$DLmwShP@80U}E z8EV9-prqK>k{X0ovAZIfUoQss0re2qU>i;IWZ z+1#twY^&neXHfYP#4%pYr{SsJI#Zn2VdDPIeV=yy6#eX%Ti=gt-fzd1tEz^{zqu1ZM9-Ei@hAxY=pfJt2P8QnO&+?0oui#2JtZ^k?$0Oi{S*F>I^QhZ} zp_QqV`G&ohWg@w*lvTbPKER)8x|JCAJ#bk5m@$VD#!S1gWNhhFo41gVoM^f3mSa(d zV9(OER;RYYCb(%|E>k*1sGmQ8fR8Zx&zYFR41C!h}*7Q}J zP1H@%2|)$zwJk_R$B4#Sb_dWn>r#>&coVm-2&~=$zbAsZi0Gsd|}3t z1HTR|PZ_*41jweOe(_LfrXSd9OSqie`Q6~fo|_!a+iRV^brQt1>@wh}8>QgiQ0_Tx zeCbi8iAdU?E0F=wS2&(7GyEbCF$uhM0~r58FA}d4ml_^{vG4!!&u4jI2Jy9-VA#-R zberXVey0KJR^>+}{;R?7LuEwQ?{@nz`8FCM&Y=pg|9a|oa?ssRrUE~Ic?GU9|8IW& e^6yqwU!HjZtGy9WZ3i5HKps6%lFpYj^7#*w#}>Q* literal 0 HcmV?d00001