<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Tech news and tutorials for and by DevOps | Kopax]]></title><description><![CDATA[Tech news and tutorials for and by DevOps ]]></description><link>https://blog.kop.ax/</link><image><url>https://blog.kop.ax/favicon.png</url><title>Tech news and tutorials for and by DevOps | Kopax</title><link>https://blog.kop.ax/</link></image><generator>Ghost 3.41</generator><lastBuildDate>Mon, 23 Mar 2026 16:25:13 GMT</lastBuildDate><atom:link href="https://blog.kop.ax/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[How to use React.Children.toArray to design re-usable components with a simple API]]></title><description><![CDATA[In this demo, I will show how to interface two or more components to assemble reusable components (fixed functionality defined) with your API interfaced on props.children]]></description><link>https://blog.kop.ax/how-to-use-react-children-to-array-to-create-re-usable-components-with-a-simple-api/</link><guid isPermaLink="false">602bfd188fc4d40001309c3f</guid><category><![CDATA[ReactNative]]></category><category><![CDATA[ReactJS]]></category><category><![CDATA[Design Pattern]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Dimitri Kopriwa]]></dc:creator><pubDate>Tue, 16 Feb 2021 17:33:08 GMT</pubDate><media:content url="https://blog.kop.ax/content/images/2021/02/tuto.png" medium="image"/><content:encoded><![CDATA[<blockquote>In this demo, I will present a commentary to interface a couple of two or more components to assemble reusable components (fixed functionality defined) with your API interfaced via props.children</blockquote><img src="https://blog.kop.ax/content/images/2021/02/tuto.png" alt="How to use React.Children.toArray to design re-usable components with a simple API"><p>The magic of using props.children as an API with a controller component is quite simple and boils down to two steps:</p><ol><li>Configure <code>props.children</code></li><li>Pass from component <code>controller</code> required<code>props</code> for your features</li></ol><h2 id="configure-props-children">Configure <code>props.children</code></h2><p>The first is to define if your component accepts, one (and / or) of the react element in children, to accept both:</p><pre><code class="language-jsx">const children = React.Childen.toArray(props.children)
</code></pre><p><code>React.Children.toArray</code> transforms the variable into an array so that the children.map method is always available. (Which is not the case if you only have one react element in children of your controller component)</p><ul><li>Use <code>React.Children.toArray</code> is only of interest if you want to support 1 or more children in your controller. If you still only have one child, in this case you can skip its use.</li></ul><h3 id="inject-props-from-your-controller-to-children-react-elements-with-cloneelement">Inject <code>props</code> from your controller to children react elements with <code>cloneElement</code></h3><p><code>React.cloneElement</code> Allows you to clone an already rendered JSX element (Unlike React.createElement which can render a ReactComponent into a JSX element). The 2nd parameter of the function allows to override the props, we can therefore write: :</p><pre><code class="language-jsx">cloneElement(child, { mine: true })
</code></pre><p>Done, you know how to use the <code>props.children</code> as an API interface of your reusable components. il ne vous manque plus qu'à écrire un composant controller pour provisionner des <code>props</code> à vos children.</p><p><strong>Yes but why ?</strong></p><p>Let's take the example of a <code>&lt;Carousel /&gt;</code>, if you want to add the following props to each <code>&lt;Slide /&gt;:</code></p><p><code>props.carouselRef</code> : created within carousel automatically</p><p><code>props.activeIndex</code> : available using the carousel reference</p><p>In bonus, we also want to automatically set the <code>index</code> on each slide, so we don't need to manually update it on each slide.</p><ul><li><code>props.index</code> can go up to slides.length - 1</li></ul><p>If we want to create a reusable component without exploiting l'API <code>props.children</code>, we should use another props and should write for example:</p><pre><code class="language-jsx">function App() {
  return (
    &lt;Carousel
      slides={[Slide1, Slide3, Slide3]}
    /&gt;
  );
}
// ou 
function App() {
  return (
    &lt;Carousel
      slides={[&lt;Slide1 /&gt;, &lt;Slide3 /&gt;, &lt;Slide3 /&gt;]}
    /&gt;
  );
}
</code></pre><p>It works very well and for each case we can inject props to each children :</p><ul><li>In the 1st using JSX or more precisely with <code>createElement</code></li><li>In the 2nd with <code>cloneElement</code>.</li></ul><p>So why should you use <code>props.children</code> ? Simply because the interface is more user land friendly (user-land i.e. in your user's code, aka your developer colleague who reuses your component):</p><pre><code class="language-jsx">&lt;Carousel&gt;
  &lt;Slide1 /&gt;
  &lt;Slide2 /&gt;
  &lt;Slide3 /&gt;
&lt;/Carousel&gt;
// et 
&lt;Carousel&gt;
  &lt;Slide1 /&gt; {/* &lt;= in this case, use React.Children.toArray */}
&lt;/Carousel&gt;
</code></pre><p>Finally, your controller should look like this :</p><pre><code class="language-jsx">function Carousel(props) {
  const carouselRef = useRef&lt;Carousel&gt;();
  return (
    &lt;ReactCarousel ref={carouselRef}&gt;
      {React.Children.toArray(props.children).map((child, index) =&gt; cloneElement({
        key: child.name
        carouselRef,
        activeIndex: carouselRef.current.getActiveIndex(),
        index,
      }))}
    &lt;/ReactCarousel&gt;
  )
}
</code></pre><p>Some example of feature that can be added :</p><ul><li>A "skip all" button (if many children) ou "skip" (if one child)</li><li>Add analytics on each slide to trigge <code>pageView</code> using automatique name that use the index</li><li>Event on skip action using the slide name and it's index</li></ul><h2 id="when-not-to-use-the-props-children-api">When not to use the <code>props.children</code> API?</h2><p></p><ul><li>When it is not for API purposes, i.e. your component is not reusable</li><li>When your API is not documented or you do not know how to write or maintain documentation properly so that no one gets it wrong (or when we will have automatic documentation for our components)</li><li>When your API is too complex, ie your component solves too many problems or problems that will probably change, as this may add complexity for those who are not familiar with your components.</li></ul><h3 id="other-examples-of-uses-cases">Other examples of uses cases</h3><h3 id="usercontroller"><code>&lt;UserController&gt;</code></h3><pre><code class="language-jsx">&lt;UserController perPage={25} filters={{ sort: { order: 'ASC', id: 'id' } }}&gt;
  &lt;SimpleUserList /&gt;
&lt;/UserController&gt;</code></pre><p>You can now re-use your controller for many kind of <code>UserList</code></p><ul><li>It is convenient to use a loading indicator when fetching, you will also do it in the controller to normalize its injection through various controllers, for example ...</li></ul><p>You can use <code>&lt;UserController /&gt;</code> with <code>&lt;SimpleUserList /&gt;</code> refactored in 2 componants:</p><ul><li>One as a layout controller</li><li>Many for each field that must be shown in the layout</li></ul><p>This will give you a lot more of layout re-usability without writing much code, always with an easy to learn interface :</p><pre><code class="language-jsx">&lt;UserController id={15}&gt;
  &lt;SimpleForm&gt;
    &lt;TextInput source="id" /&gt;
    &lt;TextInput source="firstName" /&gt;
  &lt;/SimpleForm&gt;
&lt;/UserController&gt;</code></pre><h3 id="usergrid"><code>&lt;UserGrid&gt;</code></h3><p>This example illustrates the simplicity offered by this new interface, to offer more grains for example for the display of columns according to the access rights of each: :</p><pre><code class="language-jsx">&lt;UserController perPage={25} filters={{ sort: { order: 'ASC', id: 'id' } }}&gt;
  &lt;UserGrid&gt;
    &lt;TextField source="id" /&gt;
    &lt;TextField source="firstname" /&gt;
    {isAdmin &amp;&amp; (&lt;TextField source="apiKey" /&gt;)}
  &lt;/UserGrid&gt;
&lt;/UserController&gt;
</code></pre>]]></content:encoded></item><item><title><![CDATA[How I made a home made free and unlimited SMS server with Docker and Gammu for 5 dollars]]></title><description><![CDATA[While working on an integration to send SMS messages to their users for a customer, I started to think my own solution so this could be done without paying any external service, learn how I did a 5 USD a free and unlimited SMS server with Docker and Gammu.]]></description><link>https://blog.kop.ax/how-i-made-a-home-made-free-and-unlimited-sms-server-with-docker-and-gammu-for-5-dollars/</link><guid isPermaLink="false">5f9386021dd6530001939e48</guid><category><![CDATA[gammu]]></category><category><![CDATA[docker]]></category><dc:creator><![CDATA[Dimitri Kopriwa]]></dc:creator><pubDate>Sat, 24 Oct 2020 01:40:23 GMT</pubDate><media:content url="https://blog.kop.ax/content/images/2020/11/dockerandgammu.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.kop.ax/content/images/2020/11/dockerandgammu.png" alt="How I made a home made free and unlimited SMS server with Docker and Gammu for 5 dollars"><p>Nowadays, SMS are widely used across web services. They are not aiming to replace bulk mail and they are generally used to identify a user more securely.</p><p>This list is just a few cases that come to my mind where you might want to send a text message to your users :</p><ul><li>Password recovery</li><li>Two factor authentication</li><li>Confirmation of an action with increased security</li><li>Alert: it is known that a SMS will have a higher rate of lecture than an email</li></ul><p>They are plenty of SMS provider online that can be used for sending SMS. They usually expose an HTTP API so you can send SMS over HTTP.</p><p>These provider are generally not free, despite the low pricing, for some developer this will still be to high for there need and it will be considered as not mandatory. This generally result in a weaker security strategy for your web service.</p><p>Hopefully, it's possible to build your home made SMS server with a minimal cost of 5 usd (not including the electricity).</p><p>For this, you will need the following:</p><ul><li>A Linux compatible USB 3G Modem</li><li>A valid SIM card that support SMS sending</li></ul><p>I bought the cheapest USB stick I could find on the internet from China, and prayed that it was supported by Linux, and it was.</p><figure class="kg-card kg-bookmark-card kg-card-hascaption"><a class="kg-bookmark-container" href="https://www.aliexpress.com/item/32848151009.html"><div class="kg-bookmark-content"><div class="kg-bookmark-title">US $7.0 29% OFF|HSDPA USB STICK SIM Modem 7.2Mbps 3G Wireless Network Adapter with TF SIM Card|3g modem|sim card stickhsdpa usb - AliExpress</div><div class="kg-bookmark-description">Smarter Shopping, Better Living! Aliexpress.com</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://ae01.alicdn.com/images/eng/wholesale/icon/aliexpress.ico" alt="How I made a home made free and unlimited SMS server with Docker and Gammu for 5 dollars"><span class="kg-bookmark-publisher">aliexpress.com</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://ae01.alicdn.com/kf/HTB1Ti4gcPgy_uJjSZKbq6xXkXXa8/HSDPA-USB-STICK-SIM-Modem-7-2Mbps-3G-Wireless-Network-Adapter-with-TF-SIM-Card.jpg" alt="How I made a home made free and unlimited SMS server with Docker and Gammu for 5 dollars"></div></a><figcaption>This is the cheapest 3G modem USB stick I could find online and it work perfectly on Linux</figcaption></figure><p>It cost 7$. As a new Aliexpress customer, I also had a 2$ voucher, overall I had to pay 5$ and waited one month to receive it.</p><p>Regarding the SIM card, you must choose the right plan depending on the country where you will host your SMS server, but also the location of your users.</p><p>In my case, the server will be hosted in Paris (France), and since my ISP is offering to their customers a SIM card with free and unlimited SMS to french numbers, I started with this one.</p><blockquote>If you are going to use an unlimited SMS plan, you should read carefully the general condition of it, sometimes broadband provider add limit such as the number of total recipients per month.</blockquote><p>If you have both the SIM card and a modem, you should now set the pin to something easy, or disable the PIN code so it will be less configuration.</p><h2 id="prerequisites">Prerequisites</h2><p>Either you are using Docker or standalone installation, your GSM modem must be visible in the system. When you put a USB stick to your system, you have to see a new USB device:</p><pre><code>dmesg | grep ttyUSB</code></pre><p>or typing command:</p><pre><code>lsusb</code></pre><pre><code>Bus 001 Device 009: ID 12d1:1406 Huawei Technologies Co., Ltd. E1750
</code></pre><p>My hardware support both SD card reader and mode, I have to use usb_modswitch to switch it to modem mode:</p><pre><code>usb_modeswitch -W -v 05c6 -p 1000 -K</code></pre><p>I'll also make this config persistent by adding this line to /etc/rc.local right before exit 0 (Debian).</p><p>Now lsusb return</p><pre><code>Bus 001 Device 004: ID 05c6:6000 Qualcomm, Inc. Siemens SG75</code></pre><h2 id="prevent-rules-to-assign-a-wrong-tty-device">Prevent rules to assign a wrong tty device</h2><p>This is specific to my modem. I experienced my modem jumping from a tty port to another, since I mount the device using docker, this was ruining my server, hopefully you can assign dev rule to prevent this :</p><pre><code>echo 'SUBSYSTEM=="tty", ATTRS{idVendor}=="05c6", ATTRS{idProduct}=="6000", SYMLINK+="mobile"' | tee -a /etc/udev/rules.d/10-local.rules
sudo udevadm trigger
ls -l /dev/mobile
</code></pre><blockquote>I picked up the vendor id and product id using the lsusb command</blockquote><p>This will ensure your device is always mounted under /dev/mobile</p><h2 id="expose-an-http-server-using-docker">Expose an HTTP server using Docker</h2><p></p><p>We use Gammu to communicate with our sim card, it is a "phone" software written in C designed to work on both Windows and UNIX system. A quick GitHub search to get a ready to use soft : <a href="https://github.com/pajikos/sms-gammu-gateway">https://github.com/pajikos/sms-gammu-gateway</a></p><p>You can use the following docker compose file to start the service </p><pre><code class="language-yaml">version: '3'
services:
  sms-gammu-gateway:
    container_name: sms-gammu-gateway
    restart: always
    image: pajikos/sms-gammu-gateway
    ports:
      - "5000:5000"
    devices:
      - /dev/mobile:/dev/mobile
</code></pre><p>Run:</p><pre><code class="language-bash">docker-compose up -d</code></pre><p>When you run this application, you can simply send SMS using REST API:</p><pre><code>POST http://xxx.xxx.xxx.xxx:5000/sms
Content-Type: application/json
Authorization: Basic admin password
{
  "text": "Hello, how are you?",
  "number": "+420xxxxxxxxx"
}</code></pre><p>example:</p><pre><code>AUTH=$(echo -ne "admin:password" | base64 --wrap 0)
curl -H 'Content-Type: application/json' -H "Authorization: Basic $AUTH" -X POST --data '{"text":"Hello, how are you?", "number":"+420xxxxxxxxx"}' http://localhost:5000/sms
1</code></pre><p>If you need to customize the smsc number:</p><pre><code>curl -H 'Content-Type: application/json' -H "Authorization: Basic $AUTH" -X POST --data '{"text":"Hello, how are you?", "number":"+420xxxxxxxxx","smsc": "+33695000695"}' http://localhost:5000/sms</code></pre><p>or you can simply get the current signal strength:</p><pre><code>GET http://xxx.xxx.xxx.xxx:5000/signal</code></pre><p>and the response:</p><pre><code>{
  "SignalStrength": -83,
  "SignalPercent": 45,
  "BitErrorRate": -1
}</code></pre><p>That's it, you have a quick and clean running free sms server running.</p><p>To think further, you could have many instances of this basic and secure endpoint for multiple SIM card and use a more complexe back end with fancy features such as:</p><ul><li>deciding which sim card to use when sending an sms</li><li>reading response and replying to original user</li><li>handle roundrobin</li><li>away message</li><li>handle available credit with broadband provider</li><li>credit system for users</li><li>...</li></ul>]]></content:encoded></item><item><title><![CDATA[How to wait for a service to be up in Bash using cURL]]></title><description><![CDATA[Within a CI process, you might want to hold the process until service is starting up, this is how you can do with bash and curl
]]></description><link>https://blog.kop.ax/wait-for-service-to-be-up-in-bash/</link><guid isPermaLink="false">5f9386021dd6530001939e44</guid><category><![CDATA[Linux]]></category><category><![CDATA[Bash]]></category><category><![CDATA[Continuous Integration]]></category><dc:creator><![CDATA[Dimitri Kopriwa]]></dc:creator><pubDate>Sat, 24 Oct 2020 01:40:21 GMT</pubDate><media:content url="https://blog.kop.ax/content/images/2020/11/continuous-integration.872e63c.188319ea436898ccd16bb57b701d4182.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.kop.ax/content/images/2020/11/continuous-integration.872e63c.188319ea436898ccd16bb57b701d4182.jpg" alt="How to wait for a service to be up in Bash using cURL"><p>This happened to me in a CI process before where I had to configure multiple process and wait for them to be up.</p><p>The following bash script will wait for the service running at <em>service:8000</em> to be up before continuing:</p><pre><code class="language-javascript">found_message_in_a_bottle() {
 curl --connect-timeout 2 -s service:8000 2&gt;/dev/null| grep -q Welcome
}
wait_for_saltmaster() {
 while ! found_message_in_a_bottle; do
   echo wait for service... 
   sleep 1
 done
}</code></pre><p>Now run <em>wait_for_saltmaster</em> and the CI will hang until the service is up.</p>]]></content:encoded></item><item><title><![CDATA[How to neutralize or destroy your Linux operating system in one command]]></title><description><![CDATA[This is no joke, you might want to neutralize your Linux system, learn how here.]]></description><link>https://blog.kop.ax/destroy-your-linux/</link><guid isPermaLink="false">5f9386021dd6530001939e42</guid><category><![CDATA[Linux]]></category><category><![CDATA[Bash]]></category><dc:creator><![CDATA[Dimitri Kopriwa]]></dc:creator><pubDate>Tue, 20 Oct 2020 01:40:00 GMT</pubDate><media:content url="https://blog.kop.ax/content/images/2020/11/1200px-Fork_bomb.svg.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.kop.ax/content/images/2020/11/1200px-Fork_bomb.svg.png" alt="How to neutralize or destroy your Linux operating system in one command"><p></p><p>If you don't want to completely destroy your Linux system but just neutralize it, you can go with a fork bomb using the following command:</p><pre><code class="language-bash">:(){ :|: &amp; };:</code></pre><p>This will create a process which will duplicate it self infinitely until the system crash. </p><p>If you are in a situation where you receive unwanted guest (like Kim Dotcom), you might want to quickly delete all your hard drive content in a safe way (Use a hammer and crash it) or a programmatic way.</p><p>If you have too many hard-drive, the programmatic way will do it. This command will write random data on your hard drive without worriying for a sec for files or partitions.</p><pre><code class="language-bash">sudo dd if=/dev/random of=/dev/sda</code></pre><p>Replace <em>/dev/sda</em> with the hard drive you wish to delete.</p><blockquote>Don't use this just to test or worst, to have "fun"</blockquote>]]></content:encoded></item><item><title><![CDATA[Generate a printable booklet on Debian]]></title><description><![CDATA[I often prefer to print my task list, this script will help you to create a printable booklet on Debian to save paper (and the planet)]]></description><link>https://blog.kop.ax/how-to-generate-a-printable-booklet-on-debian/</link><guid isPermaLink="false">5fac6885f5ec9a0001b4be29</guid><category><![CDATA[Linux]]></category><category><![CDATA[Bash]]></category><category><![CDATA[Debian]]></category><dc:creator><![CDATA[Dimitri Kopriwa]]></dc:creator><pubDate>Fri, 16 Oct 2020 21:42:00 GMT</pubDate><media:content url="https://blog.kop.ax/content/images/2020/11/microsoft-office-booklet.jpg.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.kop.ax/content/images/2020/11/microsoft-office-booklet.jpg.jpg" alt="Generate a printable booklet on Debian"><p>I would like to thanks Nicolas Bernaerts for sharing on his <a href="https://github.com/NicolasBernaerts/ubuntu-scripts">GitHub repository</a> the script to generate a booklet from a PDF file. This script was written for Ubuntu but it also work on Debian.</p><p>First of all, download the script and give it execution permission:</p><pre><code class="language-bash">wget --header='Accept-Encoding:none' https://raw.githubusercontent.com/NicolasBernaerts/ubuntu-scripts/master/pdf/generate-booklet-install.sh
chmod +x generate-booklet-install.sh</code></pre><p>If you use Debian, you must edit the installation script:</p><pre><code class="language-bash">sed -i 's/Ubuntu/Debian/g' generate-booklet-install.sh
</code></pre><p>Run the installation:</p><pre><code class="language-bash">./generate-booklet-install.sh</code></pre><p>It will add to your file manager an option to generate a booklet. Right click on any PDF file, choose <em>Generate Booklet</em>, then A4 and print with "Long edge stapling".</p><p>Your booklet is ready!</p>]]></content:encoded></item><item><title><![CDATA[Blog opening]]></title><description><![CDATA[After decades of sofware development, I finally opened this blog which is under active development, stay tuned for futur news]]></description><link>https://blog.kop.ax/blog-opening/</link><guid isPermaLink="false">5f9386021dd6530001939e3e</guid><category><![CDATA[News]]></category><dc:creator><![CDATA[Dimitri Kopriwa]]></dc:creator><pubDate>Wed, 07 Oct 2020 01:40:00 GMT</pubDate><media:content url="https://blog.kop.ax/content/images/2020/12/year-5026133_1920.jpg" medium="image"/><content:encoded><![CDATA[<h2 id="under-construction">Under construction</h2><img src="https://blog.kop.ax/content/images/2020/12/year-5026133_1920.jpg" alt="Blog opening"><p>After decades of sofware development, I finally opened this blog which is under active development, stay tuned for futur news</p>]]></content:encoded></item></channel></rss>