<?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">
    <channel>
        <title><![CDATA[Luis Adame]]></title>
        <description><![CDATA[A frontend engineer in search of making a better world through software, and advocate of a nature driven humanity.]]></description>
        <link>https://luis.adame.dev</link>
        <image>
            <url>https://luis.adame.dev/favicon.svg</url>
            <title>Luis Adame</title>
            <link>https://luis.adame.dev</link>
        </image>
        <generator>RSS for Node</generator>
        <lastBuildDate>Fri, 31 Dec 2021 20:07:10 GMT</lastBuildDate>
        <atom:link href="https://luis.adame.dev/feed.xml" rel="self" type="application/rss+xml"/>
        <pubDate>Fri, 31 Dec 2021 20:07:09 GMT</pubDate>
        <copyright><![CDATA[2021 Luis Adame]]></copyright>
        <language><![CDATA[en]]></language>
        <managingEditor><![CDATA[Luis Adame]]></managingEditor>
        <webMaster><![CDATA[Luis Adame]]></webMaster>
        <ttl>43200</ttl>
        <category><![CDATA[Software engineering]]></category>
        <category><![CDATA[Technology]]></category>
        <item>
            <title><![CDATA[Scroll to anchor on dynamic interfaces]]></title>
            <description><![CDATA[<p>Scroll to anchor is a technique widely used to move the scroll position to an specific element that has an id assigned. This can have a lot of use cases and you can find it in landing pages, articles with multiple headings, and any other use that you can come up with right now.</p><p>The code is really simple to achieve this</p><pre><code class="language-html">&lt;a href=&quot;#second-header&quot;&gt;Go to second header&lt;/a&gt;
&lt;h2 id=&quot;second-header&quot;&gt;My second header&lt;/h2&gt;
</code></pre><p>If you click the anchor link the browser will scroll to where the second header is located.</p><p>This is simple until the dom in the first load does not have the element with the id assigned. If it&#x27;s not present the user will not scroll to anywhere. And the actual problem is that if the element is dinamically injected to the page using javascript the browser <strong>will not</strong> scroll either.</p><p>In my quest to achieve a solution to this I came up with this reusable react hook:</p><pre><code class="language-typescript">import { useLayoutEffect } from &quot;react&quot;;
import { useLocation } from &quot;react-router-dom&quot;;

export function useAsyncScrollAnchoring() {
  const { hash } = useLocation();
  useLayoutEffect(() =&gt; {
    if (!hash) return () =&gt; {};
    const getLinkedElement = () =&gt; document.getElementById(hash.substr(1));
    let element = getLinkedElement();
    if (element) {
      element.scrollIntoView();
      return () =&gt; {};
    } else {
      const onMutation: MutationCallback = (entries, observer) =&gt; {
        const element = getLinkedElement();
        if (element) {
          element.scrollIntoView();
          observer.disconnect();
        }
      };
      const mutationObserver = new MutationObserver(onMutation);
      mutationObserver.observe(document.body, {
        subtree: true,
        childList: true,
      });
      return () =&gt; {
        mutationObserver.disconnect();
      };
    }
  }, [hash]);
}
</code></pre><p>What this does is, whenever react finishes all dom mutations, the effect is ran and check if there is a hash set first, if there isn&#x27;t stop there and we are good to go.
If that&#x27;s not the case we check if the element is already in the page and scroll into it, this behavior is native on all browsers, however if the content is displayed asynchronously we still need to do this ourselves. Then, if it&#x27;s not there already we have to listen for mutations in the document, so for every dom mutation that happens inside the body (perhaps it would be better to attach it to the react root but I&#x27;d leave that to your own choice) we check if exists an element with the id equal to the hash, in that case scroll that element into the view and disconnect the observer. Otherwise, do nothing and keep listening.</p><p>I&#x27;ll <a href="https://codesandbox.io/embed/festive-sky-hxnmi?fontsize=14&amp;hidenavigation=1&amp;theme=dark">leave a codesandbox here</a> demonstrating the use case of this.</p><p>That&#x27;s it then, hope this trick would be useful to any of you.</p><p>Until next time 👋</p>]]></description>
            <link>https://luis.adame.dev/blog/scroll-anchoring-on-dynamic-interfaces</link>
            <guid isPermaLink="true">https://luis.adame.dev/blog/scroll-anchoring-on-dynamic-interfaces</guid>
            <pubDate>Mon, 26 Jul 2021 20:29:02 GMT</pubDate>
            <enclosure url="https://luis.adame.dev/images/no-cover-fallback.jpg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Custom snackbar with notistack]]></title>
            <description><![CDATA[<p>Long time no see.</p><p>Almost a year ago I had to build a notification system for an application. And a college recommended the use of <a href="https://github.com/iamhosseindhv/notistack">Notistack</a> which integrated well with its React Native project and that&#x27;s what drove him to suggest it.</p><p>I glued all the pieces together, and had a working notification system in a very short time. However, the notifications didn&#x27;t look good with the rest of the application.</p><p>Notistack has a section in their documentation specifically for custom snackbars so you can integrate them with the overall design of your application.
By default, Notistack snackbar&#x27;s design follows a Material Design style. So, perhaps you don&#x27;t have to customize much and get away with it by modifying a few bits here and there in ten lines of css or override the styles with your own classes.
However, you don&#x27;t always have that luxury and need to revamp the whole thing.</p><p>Let&#x27;s start by reviewing how Notistack works and which options give us to achieve our goal.</p><p>For starters, we need to render a context provider which will store the state of notifications. This provider, which is called <code>SnackbarProvider</code>, should wrap our application or the parts of the application that are going to display them. The documentation warns us that if we are using MaterialUI, and want to leverage its styles, the context provider should live under MaterialUI&#x27;s <code>ThemeProvider</code>. I used Styled Components, so the <code>SnackbarProvider</code> should be a child of Styled Components <code>ThemeProvider</code>.</p><p>Let&#x27;s say we have a component called <code>App</code> which encapsulates our whole application and routes. Then, <code>SnackbarProvider</code> should wrap our <code>App</code> component.</p><pre><code class="language-tsx" metastring="filename=Root.tsx" filename="Root.tsx">import { SnackbarProvider } from &quot;notistack&quot;;

export function Root() {
  return (
    &lt;SnackbarProvider&gt;
      &lt;App /&gt;
    &lt;/SnackbarProvider&gt;
  );
}
</code></pre><p>Perfect.</p><p>Next, we have to execute a function that will show the snackbar. Let&#x27;s make use of the hook that will use the snackbar context and destructure the method <code>enqueueSnackbar</code> which will tell the snackbar context that we want to display a new snackbar.<br/>
The method accepts two parameters. The first one is a message like for example &quot;User created&quot;, and the second parameter is an object of options for the snackbar being queued. This data will be fed into the snackbar context and push it into an array of snackbars and based on the stack of snackbars it will display the snackbar added.</p><p>In our <code>App</code> component we could have something like this:</p><pre><code class="language-tsx" metastring="filename=App.tsx copy" filename="App.tsx">import { useSnackbar } from &quot;notistack&quot;;

export function App() {
  const { enqueueSnackbar } = useSnackbar();

  function showSnackbar() {
    enqueueSnackbar(&quot;User created&quot;, { variant: &quot;success&quot; });
  }

  return &lt;button onClick={showSnackbar}&gt;Show snackbar&lt;/button&gt;;
}
</code></pre><p>And when the button is clicked, the snackbar will be shown.</p><p>Now, the issue comes when we want to have a completely different component for the snackbar than the default one so we can have more flexibility.</p><p>Let&#x27;s create our own snacbkar component.</p><pre><code class="language-tsx" metastring="filename=Snackbar.tsx" filename="Snackbar.tsx">import { useSnackbar } from &#x27;notistack&#x27;;

interface Props {
  id: string;
  message: string;
  variant: &#x27;success&#x27; | &#x27;error&#x27;;
}

export function Snackbar({ id, message, variant }: Props) {
  const { closeSnackbar } = useSnackbar();
  const handleCloseSnackbar = () =&gt; closeSnackbar(id);

  return (
    &lt;SnackbarContent&gt;
      &lt;Container&gt;
        {variant === &#x27;success&#x27; ? &lt;CheckIcon /&gt; : &lt;TimesIcon /&gt;}
        &lt;MessageContainer&gt;
          {message}
        &lt;/MessageContainer&gt;
        &lt;DismissButton onClick={handleCloseSnackbar}&gt;
          &lt;ScreenReaderOnlyText&gt;Close snackbar&lt;ScreenReaderOnlyText&gt;
          &lt;CloseIcon aria-hidden /&gt;
        &lt;/DismissButton&gt;
      &lt;/Container&gt;
    &lt;/SnackbarContent&gt;
  );
}
</code></pre><p>With this in place we can use it as our default snackbar component as <a href="https://iamhosseindhv.com/notistack/demos#custom-snackbar">notistack&#x27;s custom snackbar documentation section says</a></p><p>We go back to our <code>Root</code> component where the <code>SnackbarProvider</code> is living:</p><pre><code class="language-tsx" metastring="filename=Root.tsx" filename="Root.tsx">import { SnackbarProvider } from &quot;notistack&quot;;
import { Snackbar } from &quot;components/Snackbar&quot;;

export function Root() {
  return (
    &lt;SnackbarProvider
      content={(key, message) =&gt; &lt;Snackbar id={key} message={message} /&gt;}
    &gt;
      &lt;App /&gt;
    &lt;/SnackbarProvider&gt;
  );
}
</code></pre><p>But. Wait. Where is the variant prop?</p><p>Yes.</p><p>The render function does not receive more arguments than those, only <code>key</code> and <code>message</code>. So, we&#x27;re done here right?</p><p>No. Let&#x27;s come up with a solution. If we take a closer look to the documentation, the <code>enqueueSnackbar</code> function&#x27;s second argument is an options object and between those options there is a <code>content</code> prop. Therefore, we can make our own custom hook calling the <code>enqueueSnackbar</code> function but providing our own snackbar component with the options we want. This custom hook should accept the same parameters as the <code>enqueueSnackbar</code> function but extending the functionality and the types of them.</p><pre><code class="language-tsx" metastring="filename=useEnqueueSnackbar.tsx" filename="useEnqueueSnackbar.tsx">import { useSnackbar as useDefaultSnackbar, OptionsObject } from &quot;notistack&quot;;
import { Snackbar } from &quot;components/Snackbar&quot;;

export const useEnqueueSnackbar = () =&gt; {
  const { enqueueSnackbar } = useDefaultSnackbar();

  const pushSnackbar = (
    message: string,
    // extend the default options object
    options?: OptionsObject &amp;
      Partial&lt;{ variant: &quot;success&quot; | &quot;error&quot; | &quot;warning&quot; }&gt;
  ) =&gt; {
    enqueueSnackbar(message, {
      ...options,
      content: (key) =&gt; {
        // destructure the options we need from the extended options
        // object, and provide a default case if we didn&#x27;t provide any
        const { variant } = options || { variant: undefined };
        return (
          &lt;Snackbar
            id={`${key}`}
            message={message}
            variant={variant || &quot;success&quot;}
          /&gt;
        );
      },
    });
  };

  return pushSnackbar;
};
</code></pre><p>Perfect. This is looking good. Now, instead of using the snackbar context, we can import this hook, execute it to get the callback and run the callback in the place we want to show the snackbar.</p><p>Moving to our <code>App</code> component we should do this:</p><pre><code class="language-tsx" metastring="filename=App.tsx" filename="App.tsx">import { useEnqueueSnackbar } from &quot;hooks/useEnqueueSnackbar&quot;;

export function App() {
  const enqueueSnackbar = useEnqueuSnackbar();

  function showSnackbar() {
    enqueueSnackbar(&quot;User created&quot;, { variant: &quot;success&quot; });
  }

  return &lt;button onClick={showSnackbar}&gt;Show snackbar&lt;/button&gt;;
}
</code></pre><p>And this should show our own snackbar component with the <code>variant</code> prop provided.</p><p>Phew! That was a short but intense journey.</p><p>When I stumbled upon this problem I looked into notistack&#x27;s repository and found out that this was actually an issue that was being tracked.</p><p>I provided this article&#x27;s solution <a href="https://github.com/iamhosseindhv/notistack/pull/259#issuecomment-696814874">as a comment</a> in <a href="https://github.com/iamhosseindhv/notistack/pull/259">the PR that attempted to fix this problem</a> so anyone could benefit from it.</p><p>References:</p><ul><li><a href="https://iamhosseindhv.com/notistack/api#mutual">https://iamhosseindhv.com/notistack/api#mutual</a></li></ul>]]></description>
            <link>https://luis.adame.dev/blog/custom-snackbar-with-notistack</link>
            <guid isPermaLink="true">https://luis.adame.dev/blog/custom-snackbar-with-notistack</guid>
            <pubDate>Fri, 28 May 2021 11:00:00 GMT</pubDate>
            <enclosure url="https://luis.adame.dev/images/custom-snackbar-with-notistack/custom-snackbar-with-notistack.jpg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[How to install Laravel Telescope on a dedicated database]]></title>
            <description><![CDATA[<h2>Pre-installation</h2><p>One of the dependencies that telescope requires is <a href="https://github.com/moontoast/math">&quot;moontoast/math&quot;</a> which in fact requires a php extension called &quot;bcmath&quot;:</p><pre><code class="language-json">// &quot;moontoast/math&quot; - &quot;composer.json&quot;
&quot;require&quot;: {
        &quot;php&quot;: &quot;&gt;=5.3.3&quot;,
        &quot;ext-bcmath&quot;: &quot;*&quot;
},
</code></pre><p>This php extension is easily installable on Ubuntu by just running:</p><p><code>sudo apt install php-bcmath</code></p><p>Once you have that extension installed, you are ready to require via composer the Telescope package by running in your project&#x27;s root:</p><p><code>composer require laravel/telescope --dev</code></p><h2>Configuration</h2><p>Now you will have available new artisan commands:</p><pre><code>telescope
  telescope:clear      Clear all entries from Telescope
  telescope:install    Install all of the Telescope resources
  telescope:prune      Prune stale entries from the Telescope database
  telescope:publish    Publish all of the Telescope resources
</code></pre><p>We need to run <code>telescope:install</code> which it will write into the configuration folder of your project a new file called <code>telescope.php</code></p><h3>Security</h3><p>Laravel Telescope provides a lot of information of your application which you do not want anyone to see, so you&#x27;ll have to secure the installation.
By default, after installing telescope it will be accesible in every environment. And we want it just on the <strong>local environment</strong>. Therefore, we head to <code>config/app.php</code> and remove the line with the <strong>TelescopeServiceProvider</strong> from the providers array.</p><p>And now register it in the <code>app/Providers/AppServiceProvider.php</code> file:</p><pre><code class="language-php">/**
* Register any application services.
*
* @return void
*/
public function register()
{
    if ($this-&gt;app-&gt;isLocal()) {
        $this-&gt;app-&gt;register(TelescopeServiceProvider::class);
    }
}
</code></pre><p>This will detect your environment on the application booting process and register the Telescope Service Provider a.k.a make telescope available only on your <em>local</em> environment.</p><h3>Database connection</h3><p>This is the key of this tutorial. In order to separate laravel&#x27;s telescope information from our main database we need to create a new one</p><h4>First</h4><p>Open your sql interpreter and create a new database running the next sql query:</p><p><code>create database laravel_telescope;</code></p><h4>Second</h4><p>Open your <code>config/database.php</code> and head to the connections array, <strong>copy the entire mysql connection</strong> (if you are using mysql if not copy the connection information of your database), append the copied information at the end of the <em>connections</em> array, then change all of the constants that start with <strong>DB_</strong> and change them to <strong>TELESCOPE<em>DB</em></strong> looking like this:</p><pre><code class="language-php">&#x27;telescope&#x27; =&gt; [
    &#x27;driver&#x27; =&gt; &#x27;mysql&#x27;,
    &#x27;host&#x27; =&gt; env(&#x27;TELESCOPE_DB_HOST&#x27;, &#x27;127.0.0.1&#x27;),
    &#x27;port&#x27; =&gt; env(&#x27;TELESCOPE_DB_PORT&#x27;, &#x27;3306&#x27;),
    &#x27;database&#x27; =&gt; env(&#x27;TELESCOPE_DB_DATABASE&#x27;, &#x27;forge&#x27;),
    &#x27;username&#x27; =&gt; env(&#x27;TELESCOPE_DB_USERNAME&#x27;, &#x27;forge&#x27;),
    &#x27;password&#x27; =&gt; env(&#x27;TELESCOPE_DB_PASSWORD&#x27;, &#x27;&#x27;),
    &#x27;unix_socket&#x27; =&gt; env(&#x27;TELESCOPE_DB_SOCKET&#x27;, &#x27;&#x27;),
    &#x27;charset&#x27; =&gt; &#x27;utf8mb4&#x27;,
    &#x27;collation&#x27; =&gt; &#x27;utf8mb4_unicode_ci&#x27;,
    &#x27;prefix&#x27; =&gt; &#x27;&#x27;,
    &#x27;prefix_indexes&#x27; =&gt; true,
    &#x27;strict&#x27; =&gt; true,
    &#x27;engine&#x27; =&gt; null,
]
</code></pre><h4>Third</h4><p>Go to your <strong>.env</strong> file and add the new constants:</p><pre><code>TELESCOPE_DB_CONNECTION=telescope
TELESCOPE_DB_HOST=127.0.0.1
TELESCOPE_DB_PORT=3306
TELESCOPE_DB_DATABASE=myproject_telescope
TELESCOPE_DB_USERNAME=secret
TELESCOPE_DB_PASSWORD=secret
</code></pre><p><strong>Psst!</strong> Don&#x27;t forget to change the credentials above according to your project&#x27;s needs, we all know you have copied these :)</p><h4>Fourth</h4><p>Go to <code>config/telescope.php</code> and change the line where it says:</p><pre><code class="language-php">&#x27;storage&#x27; =&gt; [
    &#x27;database&#x27; =&gt; [
        &#x27;connection&#x27; =&gt; env(&#x27;DB_CONNECTION&#x27;, &#x27;mysql&#x27;),
    ],
]
</code></pre><p>for:</p><pre><code class="language-php">&#x27;storage&#x27; =&gt; [
    &#x27;database&#x27; =&gt; [
        &#x27;connection&#x27; =&gt; env(&#x27;TELESCOPE_DB_CONNECTION&#x27;, &#x27;mysql&#x27;),
    ],
]
</code></pre><h2>Final step! Yay!</h2><p>Now head to the terminal again and run <code>php artisan migrate</code>
If you see these lines:</p><pre><code>Migrating: 2018_08_08_100000_create_telescope_entries_table
Migrated:  2018_08_08_100000_create_telescope_entries_table
</code></pre><p>Everything is looking in the right direction.</p><h2>Give your information Laravel!</h2><p>Now, go to your browser of liking and write in that pretty url bar the domain with the <code>/telescope</code> path. For instance if my project is running under <a href="https://myawesomeproject.test">https://myawesomeproject.test</a> then you&#x27;ll head to <a href="https://myawesomeproject.test/telescope">https://myawesomeproject.test/telescope</a></p><p>If you see something like this</p><img src="images/dedicated-laravel-telescope/laravel-telescope.png" alt="Laravel telescope home page"/><p>You have finished the installation, now make good use of the information telescope provides to enhance your programming productivity!</p><h2>Update</h2><h3>Testing environment</h3><p>If you are going to run <code>phpunit</code> after you&#x27;ve install Laravel Telescope this way, you&#x27;ll notice there will be some errors thrown, that&#x27;s because we keep using the same connection for the database and when we try to make use of the trait <code>RefreshDatabase</code> it will try to migrate also Telescope&#x27;s migrations.</p><p>In order to disable laravel telescope migrations in your tests head to <code>tests/CreatesApplication.php</code> and change the <code>createApplication()</code> method like this:</p><pre><code class="language-php">/**
  * Creates the application.
  *
  * @return \Illuminate\Foundation\Application
  */
public function createApplication()
{
    $app = require __DIR__.&#x27;/../bootstrap/app.php&#x27;;

    Telescope::ignoreMigrations();

    $app-&gt;make(Kernel::class)-&gt;bootstrap();

    return $app;
}
</code></pre><p>Notice the <code>Telescope::ignoreMigrations();</code> line is right <strong>before</strong> bootstraping your application!</p>]]></description>
            <link>https://luis.adame.dev/blog/how-to-install-laravel-telescope-on-a-dedicated-database</link>
            <guid isPermaLink="true">https://luis.adame.dev/blog/how-to-install-laravel-telescope-on-a-dedicated-database</guid>
            <pubDate>Tue, 26 Feb 2019 15:54:08 GMT</pubDate>
            <enclosure url="https://luis.adame.dev/images/dedicated-laravel-telescope/dedicated-laravel-telescope.jpg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Css Exclusions]]></title>
            <description><![CDATA[<figure><img style="max-width:500px" src="images/css-exclusions/terminology.png" alt="exclusions terminology"/><figcaption>Source: <a href="https://www.chenhuijing.com/blog/css-exclusions-with-queen-bey">CSS exclusions with Queen Bey - Chen Huijing</a></figcaption></figure><p>Let&#x27;s introduce: <strong>Exclusions</strong>. This is a new feature coming up to the CSS of the future. And I say that because currently this feature is only supported in two browsers: IE and Edge 😮 and there is a <a href="https://www.w3.org/TR/css3-exclusions/">working draft spec</a>.</p><p>Now, what does this new feature do? Well, do you remember <em>floats</em>? Perfect, because <em>exclusions</em> are somewhat floats but behave differently. OK, let me explain it. Floats are used for (<del>layout</del>) wrapping content around an element that is floated. Therefore...</p><blockquote><p>Exclusions are a block-level element which is not a float and generates an exclusion box.</p></blockquote><p>And... exclusions are required to be used in conjunction with <code>wrap-flow</code> in order to define how the inlined content is going to surround the excluded element. The value of the <code>wrap-flow</code> property has to be other than <code>auto</code> to make this feature kick in. Also, exclusions won&#x27;t work if we position the element <em>floated</em>. Having these things in mind, exclusions will work.</p><p>As I said <a href="https://caniuse.com/#feat=css-exclusions">the support of this feature</a> is not spreaded at all although is a pretty interesting feature to have, and some use cases are going to be discussed in this article.</p><h2><code>wrap-flow</code></h2><p>This property is going to specify where should the inline content surround the element.</p><p>Its values are: auto, both, start, end, minimum, maximum, and clear.</p><p><strong>auto</strong>: it is not going to create any exclusion box.</p><p><strong>both</strong>: the content will flow on all sides of the exclusion.</p><figure><img src="images/css-exclusions/wrap-flow.png" alt="wrap flow both visualization"/><figcaption>Source: <a href="https://www.chenhuijing.com/blog/css-exclusions-with-queen-bey">CSS exclusions with Queen Bey - Chen Huijing</a></figcaption></figure><p><strong>start</strong>: the content will flow around the left side or start edge of the excluded element.</p><p><strong>end</strong>: the content will flow around the right side or end edge of the excluded element.</p><p><strong>minimum</strong>: the content will flow around the side which has less available space.</p><p><strong>maximum</strong>: the content will flow around the side which has more available space.</p><p><strong>clear</strong>: the content won&#x27;t flow, the excluded element will break the content.</p><p>This property is what makes the exclusion work, there is no excluded property or anything like that, exclusions are just a concept, or a way to name this behavior.</p><h2><code>wrap-through</code></h2><p>With this property we can specify how the content that flows is going to behave. There are two values for this property: wrap and none.</p><p><strong>wrap</strong>: it inherits the parent node&#x27;s wrapping context. Nothing happens, flow it is still happening.</p><p><strong>none</strong>: the element does not inherit its parent wrapping context. Flow won&#x27;t happen.</p><figure><img src="images/css-exclusions/wrap-through.png" alt="wrap through both visualization"/><figcaption>Source: <a href="https://www.chenhuijing.com/blog/css-exclusions-with-queen-bey">CSS exclusions with Queen Bey - Chen Huijing</a></figcaption></figure><h2>A use case</h2><p>Editorial layout - discussed by Rachel Andrew in <a href="https://rachelandrew.co.uk/archives/2018/11/09/editorial-layouts-exclusions-and-css-grid/">this article</a> and also by Rob Weychert in <a href="https://v6.robweychert.com/blog/2018/11/css-grid-editorial-layouts/">this other blog post</a></p><p>In this use case Rob says that floats are not compatible with grid, which is true, and using actually grid values to solve this problem, however, Rachel in her article discusses this problem and solves it by using exclusions.</p><h2>IMO</h2><p>Exclusions definitely have a great potential in layouts. And again developers don&#x27;t do many efforts to make the people from the browser vendors to know this spec exists and implement it. This can be done through their forums and bug fillers and so on. We already have a lot of tools to make great layouts but sometimes we may get stuck on accomplishing some design and start to make some hacks, while in reality we should be able to have enough features to make really complex layouts without having to use &quot;hacks&quot;. Finally, this part is what makes web development exiting because developers actually have a real impact on what features are going to be shipped into browsers. <strong>If you really want to learn MUCH more of this topic, please, check the sources out.</strong></p><h2>Sources</h2><ul><li><a href="https://css-tricks.com/exclusions-will-hopefully-be-like-more-powerful-grid-friendly-floats/">Exclusions will hopefully be like more powerful grid-friendly floats - CSS-TRICKS</a></li><li><a href="https://v6.robweychert.com/blog/2018/11/css-grid-editorial-layouts/">Editorial Layouts, Floats, and CSS Grid - Rob Weychert</a></li><li><a href="https://rachelandrew.co.uk/archives/2018/11/09/editorial-layouts-exclusions-and-css-grid/">Editorial Layouts, Exclusions, and CSS Grid - Rachel Andrew</a></li><li><a href="https://www.w3.org/TR/css3-exclusions/">CSS Exclusions Module Level 1 - Rossen Atanassov, Vincent Hardy, Alan Stearns</a></li><li><a href="https://www.chenhuijing.com/blog/css-exclusions-with-queen-bey">CSS exclusions with Queen Bey - Chen Huijing</a></li></ul>]]></description>
            <link>https://luis.adame.dev/blog/css-exclusions</link>
            <guid isPermaLink="true">https://luis.adame.dev/blog/css-exclusions</guid>
            <pubDate>Sun, 25 Nov 2018 20:38:33 GMT</pubDate>
            <enclosure url="https://luis.adame.dev/images/css-exclusions/css-exclusions.jpg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Scroll Snap Property]]></title>
            <description><![CDATA[<h2>Introduction</h2><p>Popular products that require a a well-controlled scroll system make use of Javascript to divide the sections of the scrollable content in order to display it always in the viewport. What these products try to achieve is a paging experience. Because it is more appealing to a user to scroll like pages rather than controlling by itself the scroll. So what this means after all is: is better to make sections that list items with a controlled scroll than letting the user to scroll it.</p><p>For example: if we have a section where we display items horizontally and the scroll is not controlled then the user has to scroll by itself the whole panel, while if we have the scroll controlled the user may just swipe to left and the system will scroll for itself.</p><p>This pattern provides a better user experience and will improve the time of engagement with the users.</p><p>For many years this improvement had to be done with javascript and it had an impact in the website performance because it required a lot of calculations if we wanted to have animations in the scrolling or calculating items width to show them in the viewport without being cut.</p><h2>Introducing scroll-snap property</h2><p>Today we can use a CSS property called <code>scroll-snap-type</code> which allows us to achieve the same result that we made with javascript but with css, meaning great improvements in performance.</p><p>This feature is meant to be used in conjunction with a container and its children. Therefore, we&#x27;ll have two kinds of places to use the scroll snap feature.</p><p>For the container we have the following properties:</p><ul><li>scroll-snap-type</li><li>scroll-snap-stop</li><li>scroll-snap-padding and its derivatives</li></ul><p>For the children we have:</p><ul><li>scroll-snap-align</li><li>scroll-snap-margin and its derivatives</li></ul><h3>scroll-snap-type</h3><p>This property defines how snap points are enforced. Its values are: <code>none</code>, <code>x</code>, <code>y</code>, <code>block</code>, <code>inline</code>, <code>both</code>, <code>mandatory</code>, and <code>proximity</code>.</p><p>The none value will tell the container to ignore snap points. X and Y will tell the container to snap positions in their axis. Block will tell to snap in its block axis, and inline in its inline axis.</p><p>Mandatory, the container will rest on a snap point if its not scrolled. It will snap when the scroll action is finished. If content is added, resized, or removed it will be auto adjusted to maintain the resting.</p><p>Proximity, the mandatory acts like if the container has been scrolled then we have to finish that scroll action, but proximity doesn&#x27;t act until the next item is near to that threshold.</p><p>Mandatory and Proximity are optional values but these are actually the <strong>key</strong> to this feature.</p><h3>scroll-snap-align</h3><p>This property defines where should stop the scroll. Its values are: <code>start</code>, <code>center</code>, <code>end</code>. Therefore, if we set the value to <code>start</code> the container will leave the start of the child at the left of the container. If we have it on <code>center</code> the center of the child will be centered with the container, and finally the <code>left</code> value will leave the left side of the child at the left of the container.</p><img style="width:auto;height:320px" src="images/scroll-snap-property/start.jpg" alt="Scroll snap type start"/><img style="width:auto;height:320px" src="images/scroll-snap-property/center.jpg" alt="Scroll snap type center"/><img style="width:auto;height:320px" src="images/scroll-snap-property/end.jpg" alt="Scroll snap type end"/><h3>Support</h3><p><a href="https://caniuse.com/#feat=css-snappoints">Can I use says</a> that Chrome and Safari are up to date with this feature, althought Firefox, Edge and IE 11 support and <a href="https://www.w3.org/TR/2015/WD-css-snappoints-1-20150326/">older version of the spec</a>, and you probably will have to use some tool to extend the support to the other browsers. So in order to see the demo below use Chrome or Safari, because I haven&#x27;t added the older properties to the demo.</p><h3>Example - Gallery</h3><pre><code class="language-html">&lt;div class=&quot;gallery&quot;&gt;
  &lt;div class=&quot;img&quot;&gt;1&lt;/div&gt;
  &lt;div class=&quot;img&quot;&gt;2&lt;/div&gt;
  &lt;div class=&quot;img&quot;&gt;3&lt;/div&gt;
  &lt;div class=&quot;img&quot;&gt;4&lt;/div&gt;
  &lt;div class=&quot;img&quot;&gt;5&lt;/div&gt;
  &lt;div class=&quot;img&quot;&gt;6&lt;/div&gt;
  &lt;div class=&quot;img&quot;&gt;7&lt;/div&gt;
  &lt;div class=&quot;img&quot;&gt;8&lt;/div&gt;
  &lt;div class=&quot;img&quot;&gt;9&lt;/div&gt;
  &lt;div class=&quot;img&quot;&gt;10&lt;/div&gt;
&lt;/div&gt;
</code></pre><p>The css is summarize, check out the pen if you want to see the whole css code.</p><pre><code class="language-css">.gallery {
  display: flex;
  flex-wrap: nowrap;
  overflow-x: hidden;
  scroll-snap-type: x mandatory;
}

.img {
  scroll-snap-align: start;
  display: flex;
  flex: 0 0 320px;
  height: 200px;
  background: rgb(100, 100, 255);
  margin-right: 1rem;
}
</code></pre><p>Result:</p><iframe height="480" style="width:100%" scrolling="no" title="Css Scroll Snap Gallery" src="https://codepen.io/lewis_adame/embed/MzoPyZ?height=480&amp;theme-id=dark&amp;default-tab=result" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">See the Pen <a href="https://codepen.io/lewis_adame/pen/MzoPyZ">Css Scroll Snap Gallery</a> by Luis Adame (<a href="https://codepen.io/lewis_adame">@lewis_adame</a>) on <a href="https://codepen.io">CodePen</a>.</iframe>]]></description>
            <link>https://luis.adame.dev/blog/scroll-snap-property</link>
            <guid isPermaLink="true">https://luis.adame.dev/blog/scroll-snap-property</guid>
            <pubDate>Fri, 16 Nov 2018 11:53:07 GMT</pubDate>
            <enclosure url="https://luis.adame.dev/images/scroll-snap-property/scroll-snap-property.jpg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Firefox 63 New Features]]></title>
            <description><![CDATA[<p>So, here is a new version of one of the most beloved browser in the scene right now. Since the release of Firefox Quantum, Firefox has seen some growth in their user base, and that&#x27;s not only why people has switched to the Fox browser, there seems to be a trend on getting away from Google Services and try to give some power to other companies in order to improve the balance of market share. However, there is still a long way to go. Now you&#x27;ll think that I&#x27;m against Google and that&#x27;s not the case, I think that Google is between the three companies that have made the world advance regarding technology, but Google is <strong>really</strong> big, and owns a lot of things. And, in the blink of an eye the company which motto is: <a href="https://en.wikipedia.org/wiki/Don%27t_be_evil"><em>Don&#x27;t be evil</em></a> can suddenly change.</p><p>Anyways, this is not the scope of this article.</p><p>Let&#x27;s talk about the new features that Firefox 63 ships in:</p><ul><li><a href="#accesibility-menu">Accesibility menu enabled by default</a></li><li><a href="#web-components">Web Components support (finally!)</a></li><li><a href="#fonts-editor">Fonts editor</a></li><li><a href="#reduced-motion-preferences">Reduced motion preferences</a></li></ul><p>We&#x27;ll talk briefly about <a href="#other-improvements">other improvements</a> which in my opinion deserve an spot here.</p><h2>Accesibility menu</h2><img src="images/accesibility_menu.png" alt="Accesibility menu tab"/><p>The accesibility menu is now enabled by default which is really helpful for developers nowadays (in case you don&#x27;t know, some big companies in America get sued because they do not comply with accesibility rules imposed by governments).</p><img src="images/accesibility_tool_overview.png" alt="Accesibility tool overview"/><p>This tool will help you get information which is exposed to assitive technologies and you will be able to check what&#x27;s missing. You&#x27;ll get information from each of the page&#x27;s elements.</p><h2>Web components</h2><p>Alright, this is probably the most important point to talk about in this article.</p><h3>What are Web Components, Luis 🤷‍? (you&#x27;ll say)</h3><p>Quoting the <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components">Web components section</a> from <a href="https://developer.mozilla.org/">Mozilla Developer Network</a>:</p><blockquote><p>Web Components is a suite of different technologies allowing you to create reusable custom elements — with their functionality encapsulated away from the rest of your code — and utilize them in your web apps.</p></blockquote><p>The set of technologies that they talk about are:</p><ul><li>Custom elements: basically, the ability to create or define your own HTML tag 😎</li><li>Shadow DOM: the shadow DOM is a DOM tree attached to an element and you can&#x27;t see, in order to keep an element&#x27;s features private. This prevents collisions with other elements from the page. 💪</li><li>HTML Templates: this enables the <code>&lt;template&gt;</code> and <code>&lt;slot&gt;</code> elements which allow you to define templates that can be reused in a custom element&#x27;s structure.</li></ul><p>And this, friends, opens up a <strong>new universe of possibilities</strong> in the web development industry and <strong>at the same time</strong> could mean a <em>disaster</em>, because now anyone can create their own elements and there will be elements that will be called the same and there&#x27;s no specification for that.</p><h3>Short intro to custom elements</h3><p>Let&#x27;s create an element that will be underlined and when it&#x27;s hovered it will show an alert dialog, why not?</p><pre><code class="language-javascript">class ScaryDialog extends HTMLElement {
  constructor() {
    super();
    this.addEventListener(&quot;mouseover&quot;, this.showDialog, false);
    this.style.textDecoration = &quot;underline&quot;;
  }
  connectedCallback() {
    console.log(&quot;Dialog ready!&quot;);
  }
  disconnectedCallback() {
    console.log(&quot;Short but intense...&quot;);
  }
  showDialog() {
    alert(&quot;BUUUUH!&quot;);
  }
}
customElements.define(&quot;scary-dialog&quot;, ScaryDialog);
</code></pre><p>If you have a web browser that <a href="https://caniuse.com/#feat=custom-elementsv1">supports web components</a> you&#x27;ll see the result beneath.</p><p>If you can&#x27;t see it, then your browser doesn&#x27;t support yet custom elements. Currently only Chrome 67 to newer and Firefox 63 to newer fully support it, other browser may partially support it.
We could have created a <em>template</em> and added it to our custom element using <em>Shadow Dom</em> but I think this is okay for now. If you are interested in this technology go checkout the <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components">MDN section for this</a>.</p><h2>Fonts Editor</h2><img style="height:500px;width:auto" alt="Fonts editor panel" src="images/fonts_editor_panel.png"/><p>The fonts panel from the inspector tool it&#x27;s a pretty handy tool. It allows you to see what fonts are being used in the page. You can see all the possibilities for font debugging with the demonstration below.</p><img alt="Fonts editor in action" src="/images/fonts_editor.gif"/><h2>Reduced motion preferences</h2><p>Now, you can detect via the <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion"><code>prefers-reduce-motion</code> media query</a> that the user or system has preferred not to use animations. Animations give the website a better impression and gives more dynamism but sometimes there are some low end devices that can&#x27;t render those animations at a constant frame rate or simply they don&#x27;t have the resources. So, now with this media query we can target that audience and provide them a better user experience disabling animations for them. And everyone will be happy 😁</p><p><a href="https://css-tricks.com/introduction-reduced-motion-media-query/">An Introduction to the Reduced Motion Media Query</a> this is a good article from <em>Eric Bailey</em> on Css-Tricks that explains more deeply this subject.</p><h2>Other improvements</h2><p>Well, this may not seem important to us developers, but every little step counts towards a better ecosystem, and I think every improvement should be noticed, not just because may be better for us but also because other developers have contributed and spent time improving the browser and they deserve their contributions to be told.</p><p>First, improvements for Windows users: Firefox uses now the <a href="https://clang.llvm.org/docs/Toolchain.html">Clang toolchain</a> which provides better performance.</p><p>And second, for macOS users:</p><ul><li>The reactivity of the browser has been improved</li><li>There is a faster tab switching</li><li>In multi-GPU systems WebGL preferences allow non-performance-critical applications and applets to request the low-power GPU instead of the high-power.</li></ul><p>And last but not least, WebExtensions now run in their own process on Linux 🎉, thumbs up for component decoupling in browsers.</p><h2>Sources</h2><p>To write this article I&#x27;ve used the information given by these articles, you can check them out and get a more in-depth knowledge about the subjects written here.</p><ul><li><a href="https://hacks.mozilla.org/2018/10/firefox-63-tricks-and-treats/">Firefox 63 – Tricks and Treats!</a> by <a href="potch.me">Potch</a></li><li><a href="https://www.mozilla.org/en-US/firefox/63.0/releasenotes/">Firefox 63 Release Notes</a></li></ul>]]></description>
            <link>https://luis.adame.dev/blog/firefox-63-new-features</link>
            <guid isPermaLink="true">https://luis.adame.dev/blog/firefox-63-new-features</guid>
            <pubDate>Sat, 03 Nov 2018 19:01:22 GMT</pubDate>
            <enclosure url="https://luis.adame.dev/images/no-cover-fallback.jpg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Vue Next Version 3]]></title>
            <description><![CDATA[<h1>Vue&#x27;s next version (3.0) changes and features</h1><p>As the time goes on, all major browsers have adopted ES2015 and a lot features that Vue tries to solve are already solved in this language version, so Vue will get rid of this features and leverage on those implemented in the language itself in order to make the core of the framework smaller, faster and more powerful.</p><h3>High-level API changes</h3><p>Regarding the API of the framework <strong>everything</strong> is gonna be <strong>untouched except for render functions and scoped-slots</strong> which will probably change their syntax. This change could be compatible with the 2.x version by a compatibility build.</p><p>An interesting feature that is going to come in the next release is the <strong>support to class-based components</strong>. Meaning that we will be able to <strong>write components just using the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/class#Syntax">class syntax</a></strong> without the need of transpilation or stage-x features. This doesn&#x27;t mean that we could not use some futuristic stage-x features cause there will be a mapping with those classes so you would still be able to use features from next generation EcmaScript versions. <strong>The object-based component format will still be supported transforming that object into a class internally</strong>.</p><p>Functional components will be plain functions and async components will need the use of a helper function.</p><h3>Architecture</h3><p>As the new version is going to be rewritten in TypeScript the decoupling of the internal modules is gonna be much better.</p><p>What does this actually mean to me?</p><p>Alright, so having more modular internal components means that the tree-shaking of the build is going to be better and will result in smaller bundle sizes in your application.</p><h3>Observation Mechanism</h3><p>The observation mechanism in the current version of VueJs is based on the JavaScript feature <code>Object.defineProperty</code>method. So this creates a few problems that may not seem visible at first but that are there. For example, if we have a Vue instance we have to declare the data in that object passed in the constructor, and we can&#x27;t change the data object and expect Vue to change it by itself. This means...</p><pre><code class="language-javascript">const vm = new Vue({
  data: {
    a: 1, // a is reactive
  },
});

vm.b = 2; // b is not reactive
</code></pre><p>In the example above we can see clearer what I explained before. The property <code>a</code>is reactive because it was defined in the object passed in the constructor which made Vue create internally some <code>getters/setters</code> that are used by Vue to make it&#x27;s famous reactivity work. So, because of that creation of getters and setters in the initialization process the new property added to the data object (<code>b</code>) is not reactive because there are no getters and setters for that property. We can see this cycle more clearly on this diagram:</p><img src="https://vuejs.org/images/data.png" alt="Vue render life cycle"/><p>Then, to solve this problem we need to implicitly tell Vue to add a property to the data object, to do so we need the use of the method <code>Vue.set(object, key, value)</code>. However, this is still a problem because, what happens if we want to add multiple properties to the data object? Fortunately we have a feature in the JavaScript language that let us merge two objects which is <code>Object.assign({}, ob1, {p1: 1, p2: 2})</code> , and using this feature we can do the following solution:</p><pre><code class="language-javascript">const vm = new Vue({
  data: {
    message: &quot;Hello&quot;,
  },
});

// then I want to add dynamically a user property
vm.$set(this.data, &quot;user&quot;, { name: &quot;Luis&quot; });

// or if we want to add multiple properties
let moreData = {
  user: {
    name: &quot;Luis&quot;,
  },
  post: {
    slug: &quot;new-changes-vue&quot;,
  },
};

let data = Object.assign({}, vm.data, moreData);
vm.$set(this, &quot;data&quot;, data);
</code></pre><p>But, this is <strong>ANNOYING!</strong></p><p>Vue&#x27;s next version uses <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy">Proxies</a> as the saviors of this mess. This will solve mainly:</p><ul><li>Detection of property addition / deletion.</li><li>Detection of Array index mutation / .length mutation.</li><li>Support for Map, Set, WeakMap and WeakSet.</li></ul><p>Another interesting improvement that Proxies will bring is right on the startup of the application, where if you had a huge dataset it would cause a noticeable overhead but now only the data used to render the view is observed.</p><p>In conclusion, Proxies will make Vue have more complete, precise, efficient and debuggable reactivity tracking &amp; API for creating observables.</p><h3>Other improvements</h3><p>As we said before, having a more modular codebase means that is better for tree-shaking and this translates to a smaller size. More precisely: <strong>&lt; 10kb for the new runtime</strong>.</p><p>The benchmarks state that there seems to be a performance improvement up to 100%.</p><p>There will be support for Fragments and Portals. <strong>Fragments</strong> are components that <strong>return multiple node roots</strong> , which was impossible before because you needed a div to wrap your components markup that would serve as the component root node. So Fragments allow you to have multiple root nodes, meaning there is no single div needed to wrap up all your markup. And Portals allow you to render a sub-tree in another part of the DOM.</p><h3>IE11 Support</h3><p>When we talk about Proxies we talk about saying goodbye to IE 11 which doesn&#x27;t support them as <a href="https://caniuse.com/#feat=proxy">CanIUse states</a>, currently there is a 87.17% global support for proxies. But Vue will have a compatible build ready to use for IE11 support.</p><p><strong>Source</strong>: If you want to see a more detailed version of this article head to the source <a href="https://medium.com/the-vue-point/plans-for-the-next-iteration-of-vue-js-777ffea6fabf">article written by the creator of Vue (Evan You) on The Vue Point</a>.</p>]]></description>
            <link>https://luis.adame.dev/blog/vue-next-version-3.0</link>
            <guid isPermaLink="true">https://luis.adame.dev/blog/vue-next-version-3.0</guid>
            <pubDate>Sat, 13 Oct 2018 19:08:17 GMT</pubDate>
            <enclosure url="https://luis.adame.dev/images/no-cover-fallback.jpg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Kubernetes Introduction]]></title>
            <description><![CDATA[<h2>What is Kubernetes?</h2><p>A system for managing containerized applications across multiple hosts, providing basic mechanisms for deployment, maintenance, and scaling of applications.</p><p>Some examples of the possibilities of Kubernetes are:</p><ul><li>Automation of deployment and replication of containers.</li><li>Scaling in or out containers on the fly.</li><li>Group containers and provide load balancing between them.</li><li>Simplicity on rolling out new versions of application containers on production, without downtime.</li><li>The resilience of containers. If a container dies, it gets automatically replaced.</li></ul><h2>Kubernetes&#x27; Infrastructure</h2><img src="images/kubernetes-introduction/kubernetes-infrastructure.jpg" alt="Basic Kubernetes Cluster Diagram"/><p>Basically, the core fundamental objects in the cluster are Pods, Services, Volumes, and Namespaces.</p><h3>Pods</h3><p>A pod is the basic building block in the system. Is the smallest unit in the object model. And this represents a running process in the cluster. This object encapsulates an application container (or multiple), storage resources, a unique network IP, and options to manage the container&#x27;s behavior.
The most common container runtime used is Docker.</p><h4>And what is docker?</h4><p>Well, docker is a platform to <em>develop, deploy and run</em> an application within containers. This concept leads to <em>many</em> advantages over the conventional way of developing applications. Having applications containerized let&#x27;s you port the application to other environments with the same characteristics of the <strong>image</strong> hence making sure it will always work. An <strong>image</strong> is an executable package which contains everything needed to run your application: the code, libraries, configuration files, servers, etc. An image is a perfect environment for your application because it is configured <em>programmatically</em> via the <em>Dockerfile</em> defined by the developer. These packages only contain the dependencies specified and nothing else.</p><h4>Isn&#x27;t Docker and Kubernetes the same thing?</h4><p>No. Docker is what helps you create the perfect environment for your application and Kubernetes is an orchestration platform which is responsible for making sure the deployments are successful, the application is always up by creating replicas and load balancing the requests. And by <em>application</em> I mean all the components that make your application a single unit. That is, for example, the front-end is made with Flask in python but some data is processed in another pod with a micro-service written in Go, and the images are stored in away from these two. So Kubernetes is the tool to allow your multiple containers work in harmony between them.</p><p><strong>NOTE</strong>: Kubernetes supports other containerization platforms such as Rocket.</p><h4>Networking</h4><p>A pod has a unique IP address. Containers inside the pod talk with each other through <code>localhost</code>, because containers share the same namespace (IP and ports). But containers can communicate with other entities outside the Pod and the containers coordinate themselves on how they use the shared network resources.</p><h4>Storage</h4><p>A pod can have multiple storage volumes and containers can share data between those volumes.</p><hr/><p>A pod is not designed for durability, these objects are created only for the specific process given, this is if a node fails or something happens the pods are terminated, and controllers are the responsible for recreating the pods based on the template given.</p><h4>Labels</h4><p>Pods can have defined Labels. Which are key-value pairs and convey user-defined attributes. A clear advantage of Labels is that we can target pods by labels and apply them unique Services or Replication Controllers.</p><h3>Services</h3><p>As I said before, Pods are not durable and neither are designed for that. Pods are just instances of containers that may suddenly die, because of anything. So, let&#x27;s actually imagine that we have a set of Pods which are responsible for a specific part of our app, and another set of Pods that are responsible for another part. How do any of them communicate with each other? Well, Pods are given a unique IP but this IP may change. And the pod that wants to communicate with other pods shouldn&#x27;t be tracking those changes, we would be handing Pods a task that shouldn&#x27;t be for them. That&#x27;s where <strong>Services</strong> take part in.</p><p>Services define a logical set of pods and a policy by which to access them. Usually, pods are contained in a Service because they are defined to do so by a <em>Label Selector</em>. Services provide a stable virtual IP address (VIP). What this means is that it provides a traffic forwarding to one or more pods.</p><p>In summary, the service will create a stable unique IP address which will be visible to other objects that want communicate with it by the Label. And the service provides traffic forwarding incoming from outside and decide to which pods should be handed the incoming request.</p><h3>Volumes</h3><p>Volumes solve two main problems in Kubernetes. As Pods are volatile the files are not saved when the pod dies. It will start again in a clean state. And also when a pod has multiple containers they need to share files. So, Volumes are the solution for that.</p><p>They are directories accessible to all containers running in a Pod. And the data that is stored in a Pod is preserved after restarts.</p><p>However, there are several types of Volumes:</p><ul><li>node-local (<code>emptyDir</code>)</li><li>file-sharing (<code>nfs</code>)</li><li>cloud storage (Cloud providers like Azure or AWS. <code>awsElasticBlockStore</code> and <code>azureDisk</code>)</li><li>distributed file system (<code>glusterfs</code>)</li><li>special purpose (<code>gitRepo</code> and <code>secret</code>)</li></ul><p>There are more providers but they serve the same purpose stated in the list above.</p><h3>Namespaces</h3><p>Namespaces provide a scope for the object inside of it. It is considered a place where users work on it, and there are objects that are namespaced while others don&#x27;t. With Namespaces, you can set up access control and resource quotas. Namespaces also serve to divide cluster resources between users.</p><p>Low-level objects like nodes and persistenVolumes are not in any namespace.</p><p>Resource quotas exist to limit the usage of resources of a cluster between users. So that a group of users is limited to use a certain amount of cpu usage for instance.</p><p>Namespaces are not that usual, it&#x27;s actually for big teams.</p><h2>Controllers</h2><h3>ReplicaSet</h3><p>These Controllers are the supervisors for long-running pods. They initiate a specified number of pods (specified in configuration files or by command) and make sure those replicas (pods) keep always running. For instance, if a node or pod fails the replica set is in charge of creating a new one that replaces it.</p><p>However, it is recommended to use Deployments, instead of ReplicaSets, which are a higher-level concept that manages Replication Controllers and provides declarative updates to pods along with many more useful features.</p><h3>Deployments</h3><p>With <em>Deployments</em>, you described a state in a configuration file and it changes the actual state of pods to the desired one.</p><p>There are several use cases where Deployments take part in. For example, we would use Deployment Controllers to make the rollout of a new version of our application and kill the pods with the old version. An also in the reversed way, to move controllers with the new version to a previous one.</p><p>Deployment Controllers help us handling the scalability of our application in case of a heavy load.</p><h3>Other controllers</h3><p>There are other controllers, but the most used are the described above.
The controllers left are:</p><ul><li>StatefulSets: they ensure that pods maintain a persistent identifier across any rescheduling. But the functionality is the same as <em>Deployments</em>.</li><li>DaemonSets: ensures that all or some Nodes run a copy of a Pod.</li><li>Jobs: ensures that a specified number of pods successfully terminate.</li></ul><h2>Ingress</h2><p>It is interesting to note that a lot of new features in Kubernetes are still in beta, and that&#x27;s the case of Ingress.</p><p>An Ingress is an api object that manages external access to the services in a cluster, typically HTTP.</p><p>The interesting part about Ingresses is that they provide load-balancing, SSL termination, and name-based virtual hosting.</p><h2>References</h2><ul><li><a href="https://kubernetes.io/docs/concepts/">Kubernetes Concepts</a></li><li><a href="http://kubernetesbyexample.com/">Kubernetes By Example</a></li><li><a href="http://omerio.com/2015/12/18/learn-the-kubernetes-key-concepts-in-10-minutes/">Learn the Kubernetes Key Concepts in 10 Minutes</a></li><li><a href="http://www.dasblinkenlichten.com/kubernetes-101-networking/">Kubernetes 101 – Networking</a></li></ul>]]></description>
            <link>https://luis.adame.dev/blog/kubernetes-introduction</link>
            <guid isPermaLink="true">https://luis.adame.dev/blog/kubernetes-introduction</guid>
            <pubDate>Sat, 09 Jun 2018 03:09:45 GMT</pubDate>
            <enclosure url="https://luis.adame.dev/images/kubernetes-introduction/kubernetes-introduction.jpg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Color contrast aware using Machine Learning]]></title>
            <description><![CDATA[<p>In the past year or so people in tech have experienced an increment in the appearance rate of the following concepts: machine learning, artificial intelligence, deep learning, convolutional network, training, dataset, neural networks, etc...</p><p>In this article I&#x27;m going to cover some of this concepts before getting our hands dirt.</p><p><strong>Disclaimer</strong>: i&#x27;m not an expert of this field. I&#x27;ve just got into this by myself and I could be wrong.</p><h2>What is <em>machine learning</em>?</h2><p>According to <a href="https://en.wikipedia.org/wiki/Machine_learning">Wikipedia&#x27;s article</a>:</p><blockquote><p>Machine learning is a field of computer science that gives computer systems the ability to &quot;learn&quot; (i.e., progressively improve performance on a specific task) with data, without being explicitly programmed.</p></blockquote><p>Alright, with that brief explanation you are going to get the basic idea. Basically, machine learning is a way or technique to make a computer system (program, software, whatever) <strong>&quot;intelligent&quot;</strong>. And by that I mean that is capable of solving a problem by itself with the <strong>given time or data</strong>.</p><p>And I say time or data because there are different ways to apply machine learning to an specific task. For example the problem that we are going to cover in this article is a <em>Supervised learning</em> task. Which is to give a guide to the program on how to act depending on an input. Obviously, we do not have always that guide, and have to dinamically create it, that would be the case of <em>Unsupervised learning</em> task. An example of this is learning how to drive a car, we can&#x27;t give always the instructions on how to drive, we first drive it on our own and the system learns how we drive and then drives by itself based on our driving.</p><h2>What is brain.js?</h2><p><a href="https://github.com/BrainJS/brain.js">Brain.js</a> is a library of neural networks written in JavaScript. Probably, if you don&#x27;t know anything about ML (machine learning), you are wondering what are neural networks?
Well, here you have a video that will give you enough understanding.</p><iframe width="100%" height="415" src="https://www.youtube.com/embed/aircAruvnKk?rel=0" frameBorder="0" allow="autoplay; encrypted-media" allowfullscreen=""></iframe><h2>Description of the project</h2><p>Well, what we are going to build it&#x27;s a webpage in which you are able to change the color of the background and at the same time change the color of the text accordingly to the background so that the text stays readable.</p><p>To make this clear, if the background is black then the text should be white and viceversa. But not always the background color of a web page is black or white it could have a wide variety of different colors.</p><p>Therefore, if we try to make a algorithm to detect the color and change the text according to that color we would have to support <strong>a lot</strong> of colors. And we don&#x27;t want that because it would look similar to this:</p><pre><code class="language-javascript">// WE DO NOT WANT THIS!
function changeTextColor(text, bg) {
    if(bg === &quot;white&quot;) {
        text.style.color = &quot;black&quot;;
    } else if (bg === &quot;black&quot;) {
        text.style.color = &quot;white&quot;;
    } else if...
}
</code></pre><p>Wouldn&#x27;t be awesome if the system could recognise which are light or dark backgrounds and based on that return the color for the text? These are the kind of problems that we should solve by using machine learning.</p><p>So, let&#x27;s do it!</p><h2>Development of the project</h2><p>First, the skeleton:</p><pre><code class="language-html">&lt;div class=&quot;container&quot;&gt;
  &lt;h1&gt;Example&lt;/h1&gt;
  Choose a color: &lt;input type=&quot;color&quot; id=&quot;color&quot; /&gt;
&lt;/div&gt;
</code></pre><p>Second, the styles:</p><pre><code class="language-css">body {
  min-height: 100vh;
  background: black;
  color: white;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  font-size: 1.5em;
  font-family: &quot;Raleway&quot;, sans-serif;
  transition: color 200ms ease;
}
</code></pre><p>Append this tag to the end of the document body to use the library:</p><pre><code class="language-html">&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/brain/0.6.3/brain.min.js&quot;&gt;&lt;/script&gt;
</code></pre><p>Finally, the best part:</p><pre><code class="language-javascript">// First train the neural network
var net = new brain.NeuralNetwork();
net.train([
  { input: { r: 0.0, g: 0.0, b: 0.0 }, output: { white: 1 } },
  { input: { r: 1.0, g: 1.0, b: 1.0 }, output: { black: 1 } },
  { input: { r: 0.03, g: 0.7, b: 0.5 }, output: { black: 1 } },
  { input: { r: 0.16, g: 0.09, b: 0.2 }, output: { white: 1 } },
  { input: { r: 0.5, g: 0.5, b: 1.0 }, output: { white: 1 } },
  { input: { r: 0.07, g: 0.34, b: 0.0 }, output: { white: 1 } },
  { input: { r: 1.0, g: 0.5, b: 0.5 }, output: { black: 1 } },
]);
var output;

// Color handling
const input = document.getElementById(&quot;color&quot;);

// Here happens the magic.
function changeColor(e) {
  document.body.style.backgroundColor = e.target.value;
  color = hexToRgb(e.target.value);
  Object.keys(color).map(function (key, index) {
    color[key] = +(color[key] / 255).toFixed(2);
  });
  output = net.run(color);
  document.body.style.color = likely(output);
}

function hexToRgb(hex) {
  // Expand shorthand form (e.g. &quot;03F&quot;) to full form (e.g. &quot;0033FF&quot;)
  var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
  hex = hex.replace(shorthandRegex, function (m, r, g, b) {
    return r + r + g + g + b + b;
  });

  var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  return result
    ? {
        r: parseInt(result[1], 16),
        g: parseInt(result[2], 16),
        b: parseInt(result[3], 16),
      }
    : null;
}

function likely(result) {
  return result.white &gt; result.black ? &quot;white&quot; : &quot;black&quot;;
}

input.addEventListener(&quot;input&quot;, changeColor);
</code></pre><p>Now, let&#x27;s split this into chunks to explain it better.</p><pre><code class="language-javascript">var net = new brain.NeuralNetwork();
net.train([
  { input: { r: 0.0, g: 0.0, b: 0.0 }, output: { white: 1 } },
  { input: { r: 1.0, g: 1.0, b: 1.0 }, output: { black: 1 } },
  { input: { r: 0.03, g: 0.7, b: 0.5 }, output: { black: 1 } },
  { input: { r: 0.16, g: 0.09, b: 0.2 }, output: { white: 1 } },
  { input: { r: 0.5, g: 0.5, b: 1.0 }, output: { white: 1 } },
  { input: { r: 0.07, g: 0.34, b: 0.0 }, output: { white: 1 } },
  { input: { r: 1.0, g: 0.5, b: 0.5 }, output: { black: 1 } },
]);
var output;
</code></pre><p>In this piece of code we are creating a <em>Neural network</em> and training it by giving a <em>dataset</em>. This dataset is an array of objects that contains two entries:</p><h1>Input</h1><p>The input consists of three entries representing the red, green and blue values of a color. These values are between 0 and 1 because that is what, in this case, the library will accept. To make the original values from a rgb color to these we simply divide them by 255 and we get the number we want.</p><h1>Output</h1><p>The output is what the text should look like given the input before.</p><p>Then we set a variable to hold the result of the execution.</p><pre><code class="language-javascript">function changeColor(e) {
  document.body.style.backgroundColor = e.target.value;
  color = hexToRgb(e.target.value);
  Object.keys(color).map(function (key, index) {
    color[key] = +(color[key] / 255).toFixed(2);
  });
  output = net.run(color);
  document.body.style.color = likely(output);
}
</code></pre><p>This is the function that will be called when the input color changes.</p><ol><li>We set the background of the page to the value of the input</li><li>We convert the hexadecimal color to rgb.</li><li>Pass the color to the neural network and compute the result.</li><li>Set the text color to the result of the computation.</li></ol><h2>Demo</h2><p>You can visit this <a href="https://codepen.io/lewis_adame/pen/qorLKG">link</a> or see it in action in the iframe below:</p><iframe width="100%" height="450" scrolling="no" title="Color contrast aware [Machine learning]" src="//codepen.io/lewis_adame/embed/preview/qorLKG/?height=450&amp;theme-id=0&amp;default-tab=result&amp;embed-version=2" frameBorder="no" allowTransparency="true" allowfullscreen="" style="width:100%">See the Pen <a href="https://codepen.io/lewis_adame/pen/qorLKG/">Color contrast aware [Machine learning]</a> by Luis Adame (<a href="https://codepen.io/lewis_adame">@lewis_adame</a>) on <a href="https://codepen.io">CodePen</a>.</iframe>]]></description>
            <link>https://luis.adame.dev/blog/color-contrast-aware-using-machine-learning</link>
            <guid isPermaLink="true">https://luis.adame.dev/blog/color-contrast-aware-using-machine-learning</guid>
            <pubDate>Wed, 21 Mar 2018 12:41:39 GMT</pubDate>
            <enclosure url="https://luis.adame.dev/images/color-contrast-aware-with-machine-learning/color-contrast-aware-with-machine-learning.jpg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[How to unmask hidden files on USB drives on Windows]]></title>
            <description><![CDATA[<p>Suddenly, a few days ago, someone asked me for my flash drive and he was acquaintance of me so I gracefully handed it, furthermore it seemed that he was in a rush so I didn&#x27;t carefully thought about it.</p><p>Half an hour past that event I asked him for the usb because I noticed he wasn&#x27;t using it anymore.
I took the usb and inserted onto a machine (not my personal one, thankfully) and weirdly all of the files on the drive had the appearance of a shortcut icon. At first I didn&#x27;t care pretty much because I was able to browse my files perfectly. Although when I opened these on my machine Windows threw an error:</p><blockquote><p>F:\Manuel.doc does not exists</p></blockquote><p>These could only meant one thing, when I open one of those &quot;shortcuts&quot; something in the background runs before opening the files and directories.
Note: When I opened the directories these were opened in a new window.
So I inspect the properties of the shortcuts and the target was a command and was referencing other file to execute which was a vscript. I couldn&#x27;t find that script that according to the shortcut properties was located in my flash drive.</p><p>I ran an scan through the drive and some kind of worm was detected which the antivirus handled the deletion of it. These part was <strong>critical</strong> because now there wasn&#x27;t an script running in the background doing whatever malicious actions it would do. However the shortcuts were still there, I opened a command window and inspected the content of the drive (showing also the hidden files) and they were there. So I did some little research and found that there is a command, like in unix systems: <code>chmod</code>, that handles the permissions of the files which in Windows is: <strong>attrib</strong>.</p><p>So the attrib syntax looks like this:
<code>attrib [{+r|-r}] [{+a|-a}] [{+s|-s}] [{+h|-h}] [[Drive:][Path] FileName] [/s[/d]]</code></p><p>You can read more about this command <a href="https://technet.microsoft.com/en-us/library/bb490868.aspx"><strong>here</strong></a>.</p><p>After reading how this command worked I ran the following:</p><blockquote><p><code>attrib -h -s &quot;.&quot; /s /d</code></p></blockquote><p>This means: remove hidden and system file attributes to every file and folder. </p><p>According to the source linked above these options do:</p><ul><li>/s: Applies attrib and any command-line options to matching files in the current directory and all of its subdirectories.</li><li>/d: Applies attrib and any command-line options to directories. </li></ul><p>The proccess actually took a while because changed the attributes on a lot of files that were stored on the drive, but at the end of the day it solved the problem which is what matters.</p>]]></description>
            <link>https://luis.adame.dev/blog/unmask-hidden-files-windows-usb</link>
            <guid isPermaLink="true">https://luis.adame.dev/blog/unmask-hidden-files-windows-usb</guid>
            <pubDate>Thu, 16 Nov 2017 22:46:49 GMT</pubDate>
            <enclosure url="https://luis.adame.dev/images/no-cover-fallback.jpg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Firefox Fullscreen Transition (Fade) & The Warning]]></title>
            <description><![CDATA[<h2>TL;DR</h2><p>Go to about:config, look for these settings and change their values.</p><ul><li>To remove the fullscreen fading:<ul><li><code>full-screen-api.transition-duration.enter</code> =&gt; 0 0</li><li><code>full-screen-api.transition-duration.leave</code> =&gt; 0 0</li><li><code>full-screen-api.transition.timeout</code> =&gt; 0</li></ul></li><li>To remove the fullscreen warning:<ul><li><ul><li><code>full-screen-api.warning.timeout</code> =&gt; 0</li></ul></li></ul></li></ul><hr/><p>Did you ever notice how long does a video go fullscreen on Firefox? I mean, you double click it, the screen goes black, and a second-ish later the video actually appears. I was so intrigued about this (and <strong>annoyed</strong> at the same time) and began my research about this. The first thing anyone (and me included) would do is to try to google the problem, but this time I took courage and typed on my url bar <code>about:config</code> and then started to try randomly related words like: screen, transition, fullscreen, etc. However, after some tries didn&#x27;t catched my eye any of the options, anyways <em>I finally achieved what I actually thought was unconfigurable</em>.</p><p>So, the actual solution is a mix of some options to reach the desirable transition (the chrome transition, like it&#x27;s instant).
So those options and its values are:</p><ul><li><code>full-screen-api.transition-duration.enter</code> =&gt; 0 0</li><li><code>full-screen-api.transition-duration.leave</code> =&gt; 0 0</li><li><code>full-screen-api.transition.timeout</code> =&gt; 0</li></ul><p>With these set of values the transition feels instant.</p><p>Now, on the side of the warning that slides down from the top when you enter on full screen.</p><img src="images/firefox-transition-warning/firefox-fullscreen-warning.png" alt="Fullscreen warning on Firefox"/><p>If you want to get rid of that is quite easy too. Searching <code>full-screen</code> on about:config is going to give us some wonderful settings to be change. However you are going to focus on the one that says:</p><ul><li><code>full-screen-api.warning.timeout</code> and this should be set to 0.</li></ul><p>By this way the timeout is nonexistent so that means it&#x27;s never going to show up.</p>]]></description>
            <link>https://luis.adame.dev/blog/firefox-fullscreen-transition-timeout</link>
            <guid isPermaLink="true">https://luis.adame.dev/blog/firefox-fullscreen-transition-timeout</guid>
            <pubDate>Sat, 04 Nov 2017 20:39:28 GMT</pubDate>
            <enclosure url="https://luis.adame.dev/images/firefox-transition-warning/firefox-transition-warning.jpg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[How to autoplay videos on Firefox]]></title>
            <description><![CDATA[<p>It&#x27;s been a couple of weeks since I switched to Firefox because I want to support The Open Internet and Mozilla says it&#x27;s an ethical browser. Even though,  being ethical or not, I don&#x27;t agree with the idea of Google controlling every corner of the web. So after switching I noticed something that really itched me instantly: <strong>opening autoplayed videos pages in new tab doesn&#x27;t autoplay.</strong></p><p>In Chrome autplay videos do not auplay until the tab is in foreground or active.
So, time to get a solution for this. Firefox it&#x27;s pretty famous for it&#x27;s customizability.</p><p>How can we change this behaviour? Well just follow these steps:</p><ol><li>Open <code>about:config</code></li><li>Search by autoplay</li><li>Enable <code>media.block-autoplay-until-in-foreground</code><ul><li>to do so just double click it :)</li></ul></li></ol><p>And that&#x27;s it, the behaviour you are used to is back. Happy Sunday!</p>]]></description>
            <link>https://luis.adame.dev/blog/autoplay-videos-on-firefox</link>
            <guid isPermaLink="true">https://luis.adame.dev/blog/autoplay-videos-on-firefox</guid>
            <pubDate>Fri, 18 Aug 2017 12:22:38 GMT</pubDate>
            <enclosure url="https://luis.adame.dev/images/no-cover-fallback.jpg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[How to mass unfollow on Twitter]]></title>
            <description><![CDATA[<p>Hello people, I am realising that the most effortless way for me to think on blog topics is to talk about relatively recent problems that I&#x27;ve had to solve. So that&#x27;s what I&#x27;m gonna do today, well not today actually, because I write this articles in a course of days and not in a single day.</p><p>After this brief introductory paragraph about my thoughts I&#x27;m gonna start to relate how did I solve the problem stated in the title.</p><p>So as I said I recently had to manage a Twitter account and it had loads of people following. The previous guy that was taking care of this account was very sloppy about this subject, he actually <strong>followed back every account</strong> that followed this account and I also have reasons to believe that he intentionally followed inappropiate accounts. <strong>But</strong> this is not a rant article, although this information was necessary to build a base of the context.</p><p>As I have been put in charge of this account I started to cleaning up the profile, like username, name, biography, website url and all of that information that comes handy if a customer wants to get in touch with the company of the account. And also to make the profile prettier. Therefore I encountered the big problem: <strong>2789 following people.</strong></p><p>Solution: unfollow everyone except the proper people related to the account and other featured people.</p><p>How can you solve this problem in an easy way? Well, there are plenty of applications out there that claim to mass unfollow and all of that stuff, but the reality is that those application get advantage of your desesperation and throttle the number of people you can unfollow unless you <strong>subscribe or pay some amount of money to get &quot;premium&quot; features</strong>.</p><p>Staring at this little problem I went straight to the following page of the account and you can see that there are <em>buttons</em> that you have to click to unfollow an account, and I told myself: &quot;why can&#x27;t I open the developer tools and make a multiple click?&quot; And I did so.</p><p>What did I do? Look for a button node that handles the unfollow event, and store a few of the buttons that are shown on the page (because the accounts are displayed paginated, so you have to scroll to unveil the rest). Let&#x27;s go straigth to the code:</p><h4>General way</h4><pre><code class="language-javascript">// Select the buttons and store them in a variable, convert the node list to an array.
var buttons = Array.from(document.querySelectorAll(&quot;.unfollow-text&quot;));
// Then fire the click event on each of those buttons
buttons.forEach((button) =&gt; {
  button.click();
});
</code></pre><h4>My way</h4><pre><code class="language-javascript">// Select the buttons and store them in a variable, convert the node list to an array.
var buttons = Array.from(document.querySelectorAll(&quot;.unfollow-text&quot;));
// Cause I wanted to keep the initial followed accounts
// I sliced the array
buttons = buttons.slice(0, buttons.length - 5);
// Then fire the click event on each of those buttons
buttons.forEach((button) =&gt; {
  button.click();
});
</code></pre><h4>One liner</h4><pre><code class="language-javascript">Array.from(document.querySelectorAll(&quot;.unfollow-text&quot;)) // get the buttons
  .slice(0, buttons.length - 5) // get a range of them
  .forEach((button) =&gt; {
    button.click(); // click every button
  });
</code></pre><p>Based on the executions I did there&#x27;s a maximum number of people that you can unfollow in a period of time. It&#x27;s around 550-600 accounts. Although I am not completely sure about it. I don&#x27;t know exactly if it happens because I kept unfollowing a big amount of people in a short time (around 500 accounts four times in less than 5 minutes). However, it is not a big deal because you can keep doing this technique just waiting a few minutes.
Anyways, this approach is much better than any other web application or doing it manually.</p><p><em>Important</em>: Keep in mind that firing a click event 500 times consumes memory and may freeze the window a few seconds.</p>]]></description>
            <link>https://luis.adame.dev/blog/how-to-mass-unfollow-on-twitter</link>
            <guid isPermaLink="true">https://luis.adame.dev/blog/how-to-mass-unfollow-on-twitter</guid>
            <pubDate>Fri, 18 Aug 2017 12:22:38 GMT</pubDate>
            <enclosure url="https://luis.adame.dev/images/twitter-mass-unfollow/twitter-mass-unfollow.jpg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Sending emails through SMTP with PHP]]></title>
            <description><![CDATA[<p>Hi, this is my first blog post, and I am going to describe the process (<em>that I recently had to take</em>) to send emails with PHP and using a SMTP server.</p><p>First of all what we need is a SMTP Server that we can get freely in <a href="https://mail.google.com">Gmail</a> or other Free Mail Services such as <a href="zoho.com">Zoho</a>. Once signed up you need to know the server settings and credentials, usually the smtp server is a subdomain of said service so for example in Gmail the smtp would be: smtp.gmail.com, the port is usually 465 if the encryption used is SSL if not (TLS) would be 567. Apart from these minimal settings we need the credentials that are the username that you registered with and the password.</p><p><strong>Be aware</strong> that in case you are using Gmail the first time you try to connect to the SMTP server its going to send an email to that account to warn you about the safety of your account being compromised but if you are <strong>sure</strong> that it is you then add it as a safe application. In other services I don&#x27;t know if they warn you about this but Zoho doesn&#x27;t.</p><p>Now, regarding the backend part, we need the code to compose the email (headers, content type, encoding, etc), and we have several options to choose from:</p><ul><li>We could use the <em>native</em> <code>mail()</code> function. <em><a href="http://php.net/manual/en/function.mail.php">Reference</a></em></li><li>Choose between a wide variety of php libraries to make this part easier.</li></ul><p>As always you are free to choose anyone and each are valid and I am going to cover both of them.</p><h3>Mail function</h3><p>Alright, so the <code>mail()</code> function depends on the php configuration to send emails. And the php configuration is set in the <code>php.ini</code> file that is located in the installation php folder.</p><p>You can find the setting under the [mail function] section in the php.ini file, it will be like this:</p><pre><code class="language-apacheconf">[mail function]
; For Win32 only.
; http://php.net/smtp
SMTP = localhost
; http://php.net/smtp-port
smtp_port = 25

; For Win32 only.
; http://php.net/sendmail-from
;sendmail_from = me@example.com

; For Unix only.  You may supply arguments as well (default: &quot;sendmail -t -i&quot;).
; http://php.net/sendmail-path
;sendmail_path =

; Force the addition of the specified parameters to be passed as extra parameters
; to the sendmail binary. These parameters will always replace the value of
; the 5th parameter to mail().
;mail.force_extra_parameters =

; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename
mail.add_x_header = On

; The path to a log file that will log all mail() calls. Log entries include
; the full path of the script, line number, To address and headers.
;mail.log =
; Log mail to syslog (Event Log on Windows).
;mail.log = syslog
</code></pre><p>As you can see above there is no username and password field, and that&#x27;s because the <code>mail()</code> function <strong>doesn&#x27;t support SMTP authentication</strong> what makes it pretty useless but it is worth mention it.</p><h3>PHP Mail Libraries</h3><p>Alright, there are <strong>tons</strong> of libraries out there that will achieve the same results, some will be simpler and others more complex or more feature-full, and depending on your needs you&#x27;ll choose one, I highly recommend to use <a href="https://packagist.org">Packagist</a> as your php libraries search engine. Jus search for &quot;email&quot; and libraries will show up, but I will say that two of the most popular are <a href="https://github.com/PHPMailer/PHPMailer">PHPMailer</a> (3M downloads) and <a href="http://swiftmailer.org">Swift Mailer</a> (42M downloads) .</p><p>These kind of libraries are using the native mail function but they are wrapped around it and their purpose is to make it easier for you.</p><p>And for the sake of simplicity I am going to use PHPMailer as an example, but most of the libraries follow the same pattern for email creation.</p><p>So first we will have to download the library, and I will use composer to autoload the class, although you are able to <code>git clone</code> the library and use it by <code>require_once &quot;mailer_class.php&quot;;</code>.</p><p>Then the class will be instantiated and start to use it&#x27;s own methods to add meta data information, content types, subjects, from&#x27;s, to&#x27;s, body, etc. It will be like this for PHPMailer and <a href="https://getcomposer.org">Composer</a> as the autoloader:</p><pre><code class="language-php">&lt;?php
    
require_once &quot;vendor/autoload.php&quot;;

$mail = new PHPMailer;

// As we are using an external SMTP server we&#x27;ll have to activate this
$mail-&gt;isSMTP();

$mail-&gt;Host = &#x27;smtp1.example.com;smtp2.example.com&#x27;; // Main and backup smtp server, you could use only one
$mail-&gt;SMTPAuth = true; // Enable smtp auth, as almost all smtp&#x27;s use this
$mail-&gt;Username = &#x27;user@example.com&#x27;; // Your username
$mail-&gt;Password = &#x27;supersecretpassword&#x27;; // Your password
$mail-&gt;SMTPSecure = &#x27;tls&#x27;; // The encryption protocol used by the smtp
$mail-&gt;Port = 587; // And its port

// Now  compose the mail
$mail-&gt;setFrom(&#x27;from@example.com&#x27;);
$mail-&gt;addAddres(&#x27;recipient@example.com&#x27;);
$mail-&gt;Subject = &quot;The super interesting and explanatory subject&quot;;

$mail-&gt;msgHTML(file_get_contents(&#x27;template.html&#x27;), dirname(__FILE__)); //I&#x27;ll explain this below
$mail-&gt;CharSet = &quot;UTF-8&quot;;

$mail-&gt;send(); //Send email
</code></pre><p>As you have seen above, the body is going to be an html file which contains the email content, I prefer this way because you can make more engaging emails. Usually I&#x27;ll use an email designer tool that exports to html and then implement it like this. However, you can still write plain text, depending on the library it could differ, but in the case of PHPMailer it would be:</p><pre><code class="language-php">$mail-&gt;Body = &quot;Really exciting email content&quot;;
</code></pre><p>As a conclusion I have to say that it is far better to use a well tested library to send emails and not reinventing the wheel. Furthermore the fact that the native mail function doesn&#x27;t support SMTP authentication makes it useless because nowadays every SMTP Server requires authentication to be used as far as I know.</p>]]></description>
            <link>https://luis.adame.dev/blog/send-php-emails</link>
            <guid isPermaLink="true">https://luis.adame.dev/blog/send-php-emails</guid>
            <pubDate>Fri, 18 Aug 2017 12:22:38 GMT</pubDate>
            <enclosure url="https://luis.adame.dev/images/no-cover-fallback.jpg" length="0" type="image/jpeg"/>
        </item>
    </channel>
</rss>