<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>RSSPaper</title>
    <link rel="icon" type="image/png" href="favicon.png">
    <meta name="theme-color" content="#3c790a">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no">
    <meta name="author" content="Tu nombre">
    <meta name="generator" content="RSSpaper">
    <meta name="keywords" content="html, css, javascript">
    <meta name="description" content="My news">
    <meta property="og:image" content="img/screenshot.png">
    <meta property="og:title" content="The Rock">
    <meta property="og:type" content="website">
    <meta property="og:url" content="">
    <meta name="twitter:card" content="summary">
    <meta name="twitter:site" content="@cuenta">
    <meta name="twitter:creator" content="@cuenta">
    <meta property="og:image:secure_url" content="https://...">
    <meta property="og:image:type" content="image/jpeg">
    <meta property="og:image:width" content="400">
    <meta property="og:image:height" content="300">
    <meta property="og:image:alt" content="">
    <!-- Normalize -->
    <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css">
    <!-- End Normalize -->
    <!-- Fonts -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Newsreader:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet">
    <!-- End Fonts -->
    <!-- CSS -->
    <style>
        /* Global */
        :root {
            --color-black: black;
            --color-gray: gray;
        }
        body {
            margin: 0;
            padding: 0;
            font-family: 'Newsreader', serif;
            color: var(--color-black);
        }
        img {
            object-fit: cover;
            object-position: center;
        }
        img, video, iframe {
            width: 100%;
        }
        a {
            color: var(--color-black);
            text-decoration: none;
        }
        pre {
            overflow-x: auto;
        }
        .container {
            max-width: 62rem;
            margin: 0 auto;
            padding: 1rem;
        }

        .header {
            margin-bottom: 2rem;
        }

        .title {
            text-align: center;
            font-size: 4rem;
            font-weight: normal;
            margin-bottom: 0;
            margin-top: 1rem;
        }
        .subtitle {
            display: flex;
            justify-content: center;
            align-items: center;
            margin-top: -1rem;
            font-weight: normal;
            font-size: 1.5rem;
        }
        .subtitle__separator {
            font-size: 3rem;
            font-weight: bold;
        }
        .separator {
            border: 0;
            background: var(--color-black);
            height: 1px;
        }
        .footer__text {
            text-align: center;
            padding: 1rem 0;
        }
        .footer__link {
            font-weight: bold;
        }
        .footer__heard {
            display: inline-block;
            margin-left: .3rem;
        }
        .article__title, .article__feed {
            font-weight: normal;
        }
    </style>
    <style media="all and (max-width: 600px)">
        /* Mobile */
        body {
            background: red;
        }
    </style>
    <style media="all and (min-width: 601px)">
        /* Desktop */
        .main {
            display: grid;
            grid-gap: 1rem;
            grid-template-columns: repeat(12, 1fr);
        }

        /* First column. */
        .feed__article:nth-child(3n-2){
            grid-column: 9 / 13;
        }

        /* Second column */
        .feed__article:nth-child(3n+2){
            grid-column: 1 / 5;
        }

        /* Third column */
        .feed__article:nth-child(3n+3) {
            grid-column: 5 / 9;
        }

        .article__title {
            font-size: 1.5rem;
        }

        .article__feed {
            font-size: 1rem;
        }

        .article__date {
            font-size: .9rem;
            color: var(--color-gray);
        }

        .feed__article:nth-child(1) .article__title {
            font-size: 2rem;
        }

        .feed__article:nth-child(1) .article__feed {
            font-size: 1rem;
        }

        .feed__article:nth-child(1) {
            grid-column: 1 / 9;
            grid-row: 1 / 4;
            text-align: center;
        }

        .feed__article:nth-child(2) {
            grid-column: 9 / 13;
            grid-row: 1 / 2;

        }

        .feed__article:nth-child(3) {
            grid-column: 9 / 13;
            grid-row: 2 / 3;

        }

        .feed__article:nth-child(4) {
            grid-column: 9 / 13;
            grid-row: 3 / 4;
        }

        .feed__article:nth-child(2) .article__header,
        .feed__article:nth-child(3) .article__header,
        .feed__article:nth-child(4) .article__header
        {
            display: flex;
            justify-content: space-between;
            flex-direction: row-reverse;
            grid-gap: 1rem;
        }

        .article__header > p {
            margin: 0;
        }

        .article__header-img > img {
            height: 12rem;
        }

        .feed__article:nth-child(1) .article__header-img > img,
        .feed__article:nth-child(2) .article__header-img > img,
        .feed__article:nth-child(3) .article__header-img > img,
        .feed__article:nth-child(4) .article__header-img > img
        {
            height: initial;
        }

        .feed__article:nth-child(2) .article__titles,
        .feed__article:nth-child(3) .article__titles,
        .feed__article:nth-child(4) .article__titles,
        .feed__article:nth-child(2) .article__header-img,
        .feed__article:nth-child(3) .article__header-img,
        .feed__article:nth-child(4) .article__header-img
        {
            width: 50%;
        }

        .feed__article:nth-child(2) .article__title,
        .feed__article:nth-child(3) .article__title,
        .feed__article:nth-child(4) .article__title
        {
            font-size: 1.2rem;
        }

        .feed__article:nth-child(2) .article__feed,
        .feed__article:nth-child(3) .article__feed,
        .feed__article:nth-child(4) .article__feed
        {
            font-size: 1rem;
        }



        .article__main {
            position: fixed;
            left: -100%;
            top: 0;
            bottom: 0;
            overflow-y: auto;

        }
    </style>
    <!-- End CSS -->
</head>
<body>
    <div class="container">
        <header class="header">
            <h1 class="title">RSSPaper</h1>
            <h2 class="subtitle"><span class="subtitle__separator">~</span> <span class="subtitle__text">My static generate newspaper</span> <span class="subtitle__separator">~</span></h2>
            <hr class="separator">
        </header>
        <main class="main">
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Martes 06 de julio | Combatiendo las Estafas y Blanqueo de Capitales en el Mundo de Cripto Activos por @avalBit</h1>
                            <h2 class="article__feed"><a target="_blank" href="">VLCTechHub Feed</a> <span class="article__date">09 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Reprogramamos nuestra nuestro próximo Meetup donde conversaremos con Jose Cosín sobre su trabajo combatiendo las Estafas y Blanqueo de Capitales en el Mundo de los Cripto Activos.

Las estafas y el blanqueo de capitales son dos serias amenazas para el desarrollo de la comunidad cripto. Los profesionales que nos dedicamos al mundo Bitcoin tenemos herramientas a nuestro alcance para evitar que nos engañen o que nos utilicen para blanquear el dinero obtenido con sus crímenes.

Jose Cosín es abogado economista ejerciente en Marbella. Autor del libro "Mafia y corrupción, el gilismo que no muere" Impulsor de causas solidarias como el Banco de Alimentos "El Banco Bueno". Desde hace 3 años administro el coworking Our Space, coworking que se gestiona de manera descentralizada a través de una DAO, de forma que los clientes ahora son socios.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Martes 06 de julio | Operación bikini, quítate esos servers que te sobran por @awsvalenciaes</h1>
                            <h2 class="article__feed"><a target="_blank" href="">VLCTechHub Feed</a> <span class="article__date">08 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Hola mundo serverless

El verano ya está aquí, por eso adaptamos nuestro horario para el Meetup del 8 de Julio a las 17:00 y aceleramos la operación bikini ...

Para ello contaremos con Ángel Marín, Chief Architect en Capgemini, que nos contará cómo quitar esos servidores de más y hablará de serverless.

Para terminar nos enseñará unos ejercicios para ver cómo orquestar transacciones entre distintas lambdas con step functions, así no recuperaremos los servidores después del verano.

Esperemos que os apetezca tanto como a nosotros.

¡¡¡ Os esperamos !!!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">WhatsApp permitirá enviar fotografías y vídeos que se eliminan automáticamente tras ser vistos</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://i0.wp.com/workchronicles.com/wp-content/uploads/2020/07/cropped-workchronicles-site-icon-1.png?fit=32%2C32&amp;ssl=1" alt="How to be more productive">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to be more productive</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Work Chronicles</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The post <a rel="nofollow" href="https://workchronicles.com/how-to-be-more-productive/">How to be more productive</a> appeared first on <a rel="nofollow" href="https://workchronicles.com">Work Chronicles</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">
Software Engineering Manager (Clojure Team)
</h1>
                            <h2 class="article__feed"><a target="_blank" href="">
Brave Clojure Jobs
</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<div><h1>Software Engineering Manager (Clojure Team)</h1><div class="company-name">Banzai Inc. | Anywhere | US & Canada</div><div>remote</div><div><em>Unparalleled financial education.</em></div><div>$125000 - $200000</div><div><a href="https://teachbanzai.com">https://teachbanzai.com</a></div><br /><div><h2>tl;dr</h2>
<ul>
  <li>Manager, or senior-level developer moving to management</li>
  <li>Direct software engineering for a growing ed-tech firm</li>
  <li>Functional programming experience a plus</li>
  <li>Remote (if desired), competitive salary, unbeatable health insurance, and generous PTO</li>
</ul><h2>What we're looking for</h2><p>Senior-level developer looking for management experience, or experienced manager furthering his or her career. </p><p>Culturally, we tend to promote from within; for this position, however, we want you to introduce <strong>stronger programming standards</strong>, <strong>mentor younger developers</strong>, and generally <strong>help us reach bigger goals</strong> we have as a company.</p><h2>What you will do</h2><p>Banzai's development group consists of three Clojure devs, an architect, and two JavaScript devs, with one more front-end position currently open. You will <strong>shape the team</strong> according to your own vision; vet and <strong>hire future engineers</strong>; measure individual performance; and demonstrate how to <strong>hit company goals</strong>. You will lead by example. </p><p>We have two initiatives: create more complex types of interactive software for schools, banks, and credit unions; and complete a greenfield project for small- to mid-size businesses helping employers deepen their employees' understanding of their benefits. </p><p><strong>While you will be a manager first, you may also contribute to the code</strong>: we believe great managers stay close to the problems their teams face daily. You will report to the Head of Product.</p><h2>What we expect</h2><p>You have well-developed opinions about leading people, organizing processes, and writing software. </p><p>Our front-end stack is built on JavaScript, with a Clojure backend. While you do not need Clojure experience, <strong>familiarity with innovative tooling native to functional programming is a plus</strong> (e.g. REPL-driven development, React, Vue, Elm, RxJS, Elixir, F#, etc.). </p><p>You have a deep understanding of programming for the web, including monitoring performance, deploying, testing, reviewing code, and generally helping us understand what's required of a company with more developers than we have.</p><h2>Our architecture</h2><p>Our software architecture is based around a monolithic repository with several application and worker subsystems running on a PaaS. Three of our web applications are SPAs, and two are server-driven templating engines. The Clojure code has more than 50% test coverage. We use a host of caching mechanisms to help keep the site running at or below 50ms at the 95th percentile. </p><p>We hope you will find new ways to help us improve the architecture for the sake of the business.</p><h2>What we're offering</h2><p>Our goal is to make sure <em>you're not worried</em> about benefits: </p><p>Our product team offers a <strong>competitive salary, reviewed every six months</strong>. We don't like offer wars, and you shouldn't have to switch jobs for a raise. Every six months we'll discuss your pay in a simple performance review. It's common for employees to get raises at each review, assuming the company is growing and you're regularly hitting expectations. </p><p>You may <strong>work remotely</strong> or <strong>join us at our office</strong>. </p><p>Best of all we offer <strong>full-health care coverage</strong>. We cover <strong>~95% of your insurance premium, and all of your out-of-pocket expenses</strong> via a reimbursable account. You will get access to a Flexible Spending Account (FSA), letting you purchase things like eyeglasses and over-the-counter medications tax free. </p><p><strong>Paid time off (PTO) is very flexible.</strong> We recommend three business weeks per year, in addition to a generous holiday schedule. There is, however, no technical limit inasmuch as it is approved with your manager and you're regularly hitting company goals. </p><p>We offer a <strong>401(k) with a generous 5% match</strong>, with a wide variety of investment options. Half of your employer contributions will vest in one year, the remainder in two. </p><p>You <strong>will be eligible for company stock options</strong>. The options plan is simple and straightforward, with a four-year vesting schedule. When your options vest, you will have the opportunity to buy them and become an owner of company stock, if you choose. </p><p>You will be <strong>set you up with a phone and company-paid service</strong>. </p><p>Additional benefits include <strong>life and disability insurance</strong>, <strong>food and drinks</strong> on company premises, and other fringes. Should you <strong>become a parent</strong> (either for the first time or again!), you will have access to plenty of paid leave. </p><p>Finally, while strong benefits are essential to Banzai's compensation package, more importantly, you will have varied and interesting opportunities to <strong>grow in your career</strong>and <strong>assume meaningful responsibility</strong>. You will be expected to learn new things on your own, but we also make time for training.</p><h2>Tell me about the company</h2><p>Banzai is an independent, owner-operated technology company dedicated to helping people become wise stewards of their finances through online solutions and local partnerships. We employ over 50 professionals in management, sales, sponsor relations, support, public relations, and product development.</p><p><strong>Owner operated</strong></p><p>Banzai has been in business for nearly 15 years, and the company's co-founders continue to lead it today. While we are aggressively growth-minded, the company is profitable, self-sustaining, and it requires neither debt nor venture funding. </p><p>Banzai is unique in the technology industry---our mindset is long-term. No unrealistic growth targets; no investor drama; no chasing unicorns. We aim for steady, reliable growth that compounds over time, making the company a more lucrative, happier place for employees in the long run. </p><p>Oh, and you can be an owner too: every full-time employee receives a stock option grant.</p>
<ul>
  <li><a href="http://www.teachbanzai.com/">www.teachbanzai.com</a></li>
  <li>Located @ 2230 N. University Pkwy., Bldg. 14, Provo Utah</li>
</ul><h2>Tell me about the culture</h2><p>Banzai's culture marries a high level of <strong>trust and flexibility</strong> with equally high levels of <strong>responsibility</strong>. We place important jobs on our employees' shoulders, even juniors. For leadership, we tend to promote from within. </p><p>We ask you to bring your best self to work. </p><p>Meeting these expectations also earns you a great deal of freedom. At Banzai we don't count hours, nor do we set your schedule. (Although it is generally expected that you will work 40 hours per week.) Your personal time is your own; there's plenty of space in the day to take breaks and run errands; and our holiday schedule and PTO policy is generous. Fire drills and late nights are rare.</p><h2>How do I apply?</h2><p>We want to see what you've accomplished. Please send a portfolio and cover letter explaining why you're a great fit to Kendall Buchanan, CTO, kendall [at] teachbanzai.com.</p></div></div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Microsoft recomienda Linux como reemplazo de SQL Server en Windows Containers</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MuyLinux</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        La llegada de Satya Nadella al puesto de CEO de Microsoft fue el inicio de una revolución para la compañía. El gigante originario de Redmond, que en el pasado se autoproclamó enemigo público del software libre y dijo que Linux[...]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">IV Mar i jazz</h1>
                            <h2 class="article__feed"><a target="_blank" href="">AU Agenda</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>La entrada <a rel="nofollow" href="https://au-agenda.com/iv-mar-i-jazz/">IV Mar i jazz</a> aparece primero en <a rel="nofollow" href="https://au-agenda.com">AU Agenda</a>.</p>
<p>PARC DR. LLUCH marijazz.es Ara més que mai necessitem música, oci i cultura, i millor si és en un espai obert. D’aqueixa necessitat nasqueren les  Jam Sesions en 27 Amigos, un bar insígnia del barri del Cabanyal que ara, amb recolzament de l’Ajuntament de València, Sedajazz i l’Associació de Comerciants del Marítim, ens porta Mar [&#8230;]</p>
<p>La entrada <a rel="nofollow" href="https://au-agenda.com/iv-mar-i-jazz/">IV Mar i jazz</a> aparece primero en <a rel="nofollow" href="https://au-agenda.com">AU Agenda</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">XI Russafa Escència</h1>
                            <h2 class="article__feed"><a target="_blank" href="">AU Agenda</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>La entrada <a rel="nofollow" href="https://au-agenda.com/xi-russafa-escencia/">XI Russafa Escència</a> aparece primero en <a rel="nofollow" href="https://au-agenda.com">AU Agenda</a>.</p>
<p>russafaescenica.com El festival Russafa Escènica se expande como una gota de aceite, ahora con un proyecto de residencias artísticas en diferentes municipios de la provincia llamado Via Escènica. Al cierre de la edición de esta revista, el festival estaba en pleno proceso de selección de los viveros (30 min.) y los bosques (60 min.) de [&#8230;]</p>
<p>La entrada <a rel="nofollow" href="https://au-agenda.com/xi-russafa-escencia/">XI Russafa Escència</a> aparece primero en <a rel="nofollow" href="https://au-agenda.com">AU Agenda</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Descubren 9 aplicaciones Android que roban credenciales de Facebook</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">31è MIM</h1>
                            <h2 class="article__feed"><a target="_blank" href="">AU Agenda</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>La entrada <a rel="nofollow" href="https://au-agenda.com/31e-mim-2/">31è MIM</a> aparece primero en <a rel="nofollow" href="https://au-agenda.com">AU Agenda</a>.</p>
<p>mimsueca.com Torna la Mostra Internacional de MIM de Sueca aquest setembre amb companyies de Portugal, Brasil, Xile, Alemanya, França i Regne Unit, sense por a les fronteres. De les illes britàniques venen Gandini Juggling per presentar 4&#215;4: Ephemeral architectures, on quatre malabaristes i quatre ballarins de ballet comparteixen escenari. Francesos son Cie. Bivouac, que alternen [&#8230;]</p>
<p>La entrada <a rel="nofollow" href="https://au-agenda.com/31e-mim-2/">31è MIM</a> aparece primero en <a rel="nofollow" href="https://au-agenda.com">AU Agenda</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Bürstner Club</h1>
                            <h2 class="article__feed"><a target="_blank" href="">AU Agenda</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>La entrada <a rel="nofollow" href="https://au-agenda.com/burstner-club-2/">Bürstner Club</a> aparece primero en <a rel="nofollow" href="https://au-agenda.com">AU Agenda</a>.</p>
<p>ESPACIO INESTABLE. Aparisi i Guijarro, 7 Dels altres es una joven compañía valenciana fundada en el año 2020 y dirigida por Eleonora Gronchi i Pablo Meneu para darle una vuelta al circo contemporáneo. Han creado piezas como Staged para la compañía Circumference (galardonada con el Total TheatreAward del Festival Fringe de Edinburgo 2019 como mejor espectáculo de [&#8230;]</p>
<p>La entrada <a rel="nofollow" href="https://au-agenda.com/burstner-club-2/">Bürstner Club</a> aparece primero en <a rel="nofollow" href="https://au-agenda.com">AU Agenda</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Espaldas de plata</h1>
                            <h2 class="article__feed"><a target="_blank" href="">AU Agenda</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>La entrada <a rel="nofollow" href="https://au-agenda.com/espaldas-plata-2/">Espaldas de plata</a> aparece primero en <a rel="nofollow" href="https://au-agenda.com">AU Agenda</a>.</p>
<p>SALA ULTRAMAR. Alzira, 9 De veritat en Àfrica s&#8217;escolten tambors en la llunyania, a totes hores, com en els sons d&#8217;ambient insufribles dels zoos? Walter no ho sap, mai ha estat allí. En l&#8217;agència de publicitat en la qual treballa té l&#8217;“oportunitat” d&#8217;acceptar un encàrrec per a un home, un polític a qui detesta, però [&#8230;]</p>
<p>La entrada <a rel="nofollow" href="https://au-agenda.com/espaldas-plata-2/">Espaldas de plata</a> aparece primero en <a rel="nofollow" href="https://au-agenda.com">AU Agenda</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Señora de rojo sobre fondo gris</h1>
                            <h2 class="article__feed"><a target="_blank" href="">AU Agenda</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>La entrada <a rel="nofollow" href="https://au-agenda.com/senora-rojo-fondo-gris-2/">Señora de rojo sobre fondo gris</a> aparece primero en <a rel="nofollow" href="https://au-agenda.com">AU Agenda</a>.</p>
<p>TEATRO OLYMPIA. Sant Vicent Màrtir, 44 Delibes y José Sacristán, una fórmula que ya ha demostrado funcionar a la perfección en este soliloquio dirigido por José Sámano. Un pintor con una carrera dilatada, Nicolás, padece una importante crisis existencial, su creatividad se ha esfumado tras la muerte de su mujer. El fondo gris que imprima [&#8230;]</p>
<p>La entrada <a rel="nofollow" href="https://au-agenda.com/senora-rojo-fondo-gris-2/">Señora de rojo sobre fondo gris</a> aparece primero en <a rel="nofollow" href="https://au-agenda.com">AU Agenda</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">V Cicle Escèniques LGTBI</h1>
                            <h2 class="article__feed"><a target="_blank" href="">AU Agenda</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>La entrada <a rel="nofollow" href="https://au-agenda.com/v-cicle-esceniques-lgtbi/">V Cicle Escèniques LGTBI</a> aparece primero en <a rel="nofollow" href="https://au-agenda.com">AU Agenda</a>.</p>
<p>CARME TEATRE. Gregori Gea, 6 Dansa de València, Madrid, Galícia i Canàries és el que ofereix la cinquena edició del Cicle Escèniques LGTBI del Carme Teatre, on el plat primícia arriba en forma d’entrant. Arrenca la mostra amb l’estrena absoluta de Nus-altres possibles del valencià Javier J. Hedrosa [2-5], un habitual de La Coja Dansa [&#8230;]</p>
<p>La entrada <a rel="nofollow" href="https://au-agenda.com/v-cicle-esceniques-lgtbi/">V Cicle Escèniques LGTBI</a> aparece primero en <a rel="nofollow" href="https://au-agenda.com">AU Agenda</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Maixabel</h1>
                            <h2 class="article__feed"><a target="_blank" href="">AU Agenda</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>La entrada <a rel="nofollow" href="https://au-agenda.com/maixabel/">Maixabel</a> aparece primero en <a rel="nofollow" href="https://au-agenda.com">AU Agenda</a>.</p>
<p>Icíar Bollaín · España · 2021 · Guion: Icíar Bollaín e Isa Campo · Intérpretes: Blanca Portillo, Luis Tosar, Bruno Sevilla… Reparto de lujo con dos grandes de la interpretación en España como Blanca Portillo y Luis Tosar. Maixabel cuenta la historia de Maixabel Lasa, mujer del político Juan María Jaúregui, asesinado por ETA en el [&#8230;]</p>
<p>La entrada <a rel="nofollow" href="https://au-agenda.com/maixabel/">Maixabel</a> aparece primero en <a rel="nofollow" href="https://au-agenda.com">AU Agenda</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cuestión de sangre</h1>
                            <h2 class="article__feed"><a target="_blank" href="">AU Agenda</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>La entrada <a rel="nofollow" href="https://au-agenda.com/cuestion-de-sangre/">Cuestión de sangre</a> aparece primero en <a rel="nofollow" href="https://au-agenda.com">AU Agenda</a>.</p>
<p>Tom McCarthy · USA · 2021 · Guión: Thomas Bidegain, Noé Debré, Marcus Hinchey y Tom McCarthy · Intérpretes: Matt Damon, Abigail Breslin, Camille Cottin… El realizador de la galardonada Spotlight regresa con este largometraje que transita los códigos del thriller y el drama político y social. En Cuestión de sangre, Matt Damon interpreta a [&#8230;]</p>
<p>La entrada <a rel="nofollow" href="https://au-agenda.com/cuestion-de-sangre/">Cuestión de sangre</a> aparece primero en <a rel="nofollow" href="https://au-agenda.com">AU Agenda</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">BABii</h1>
                            <h2 class="article__feed"><a target="_blank" href="">AU Agenda</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>La entrada <a rel="nofollow" href="https://au-agenda.com/babii/">BABii</a> aparece primero en <a rel="nofollow" href="https://au-agenda.com">AU Agenda</a>.</p>
<p>CENTRE DEL CARME. Museu, 2 Escoltar MiiRROR, l’àlbum de la talentosa artista multidisciplinària britànica BABii, és endinsar-se en l&#8217;atmosfera vaporosa i etèria d&#8217;un pop electrònic i garage, és evolucionar en el cor d&#8217;una realitat paral·lela que explora les emocions íntimes i els dimonis interiors de la seua creadora. BABii, en una estètica alienadora do it [&#8230;]</p>
<p>La entrada <a rel="nofollow" href="https://au-agenda.com/babii/">BABii</a> aparece primero en <a rel="nofollow" href="https://au-agenda.com">AU Agenda</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://thehistoryoftheweb.com/wp-content/uploads/2017/09/cropped-thotw-logo-square-1-32x32.jpg" alt="An Hour About… Psuedo.com">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">An Hour About… Psuedo.com</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The History of the Web</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Pseudo.com is a forgotten relic of the dot-com era. Was it ahead of its time? A moonshot that went too far? Or simply a piece of elaborate performance art?</p>
<p>The post <a rel="nofollow" href="https://thehistoryoftheweb.com/postscript/an-hour-about-psuedo-com/">An Hour About&#8230; Psuedo.com</a> appeared first on <a rel="nofollow" href="https://thehistoryoftheweb.com">The History of the Web</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Acusan a Audacity de convertirse en ‘spyware’ y cada vez pinta peor todo</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MuyLinux</a> <span class="article__date">05 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Es el tema del día y toca hablar de ello, aunque lo cierto es que no está del todo claro el asunto. Sea como fuere, ya hay medios acusando a Audacity de spyware nada menos y como ya hemos tropezado con la misma[...]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">darktable 3.6 llega con grandes mejoras en la gestión del color</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MuyLinux</a> <span class="article__date">05 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        La versión 3.6 del conocido editor de imágenes RAW darktable ha visto la luz con una gran cantidad de novedades que le darán otro empujón en la dirección correcta en el ámbito de la fotografía, donde es una aplicación de[...]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Ciberataque global del ransomware REvil afecta a miles de empresas</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">05 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://cdn.evilmartians.com/front/blocks/common/images/social-5e5bfff.png" alt="Designing Machine Learning for DVC Studio">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Designing Machine Learning for DVC Studio</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Martian Chronicles, Evil Martians’ team blog</a> <span class="article__date">05 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-4KZkaChhZjM/YNdYtotO8-I/AAAAAAAABds/K2rimWHsA1MPEKutwD4_IHrQ6y9udm2pwCLcBGAsYHQ/w640-h640/cunados_.jpg" alt="CUÑADOS">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">CUÑADOS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Cinestudio d&#39;Or</a> <span class="article__date">04 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p> <a href="https://www.cinestudiodor.es/2021/07/cunados.html"><img border="0" data-original-height="1200" data-original-width="1200" height="640" src="https://1.bp.blogspot.com/-4KZkaChhZjM/YNdYtotO8-I/AAAAAAAABds/K2rimWHsA1MPEKutwD4_IHrQ6y9udm2pwCLcBGAsYHQ/w640-h640/cunados_.jpg" width="640"></a><br><span style="color: #444444; font-style: inherit;"><b>del 5 al 11 de julio<br></b></span><span style="color: #444444;">17:15h. </span><span style="color: #444444;">20:55h.</span><span style="color: #444444;"> </span><span style="color: #444444;"><span><span style="font-size: x-small;">versión doblada / digital<br></span></span></span></p><div style="text-align: left;"><span style="color: #444444;"><span><span style="font-size: x-small;"><a href="https://www.reservaentradas.com/cine/valencia/cinestudiodor" style="font-size: x-small; padding: 1px;" target="_blank"><input type="button" value="COMPRA ONLINE"></a> <span style="color: #444444; font-size: xx-small;">(solo 1ª sesión) </span></span></span></span></div><p></p><p></p><p></p><p></p><p></p><a href="https://www.cinestudiodor.es/2021/07/cunados.html#more"></a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-0yab0oRmHqg/YNdVIKuoKxI/AAAAAAAABdk/44qG5FedO7wtUR0txQtlP4cmXpfstOdagCLcBGAsYHQ/w640-h640/historial_.jpg" alt="BORRAR EL HISTORIAL">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">BORRAR EL HISTORIAL</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Cinestudio d&#39;Or</a> <span class="article__date">04 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p> <a href="https://www.cinestudiodor.es/2021/07/borrar-el-historial.html"><img border="0" data-original-height="1200" data-original-width="1200" height="640" src="https://1.bp.blogspot.com/-0yab0oRmHqg/YNdVIKuoKxI/AAAAAAAABdk/44qG5FedO7wtUR0txQtlP4cmXpfstOdagCLcBGAsYHQ/w640-h640/historial_.jpg" width="640"></a><br><span style="color: #444444; font-style: inherit;"><b>del 5 al 11 de julio<br></b></span><span style="color: #444444;">19:00h. </span><span style="color: #444444;"><span><span style="font-size: x-small;">versión doblada / digital<br></span></span></span></p><div style="text-align: left;"><span style="color: #444444;"><span><span style="font-size: x-small;"><a href="https://www.reservaentradas.com/cine/valencia/cinestudiodor" style="font-size: x-small; padding: 1px;" target="_blank"><input type="button" value="COMPRA ONLINE"></a><span style="color: #444444; font-size: small;"> </span><span style="color: #444444; font-size: xx-small;">(activa desde 1h antes) </span></span></span></span></div><p></p><p></p><p></p><p></p><p></p><a href="https://www.cinestudiodor.es/2021/07/borrar-el-historial.html#more"></a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-TVjHvu383kA/YODXh2nVDJI/AAAAAAAABek/MFTljg-4ufMNhbapJ-9EHtPkrV-Zf-iJgCLcBGAsYHQ/w640-h640/joven_.jpg" alt="UNA JOVEN PROMETEDORA">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">UNA JOVEN PROMETEDORA</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Cinestudio d&#39;Or</a> <span class="article__date">04 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p></p><div class="separator" style="clear: both; text-align: left;"><a href="https://www.cinestudiodor.es/2021/07/una-joven-prometedora.html"><img border="0" data-original-height="1200" data-original-width="1200" height="640" src="https://1.bp.blogspot.com/-TVjHvu383kA/YODXh2nVDJI/AAAAAAAABek/MFTljg-4ufMNhbapJ-9EHtPkrV-Zf-iJgCLcBGAsYHQ/w640-h640/joven_.jpg" width="640"></a><br><span style="color: #444444; font-style: inherit;"><b>del 12 al 18 de julio<br></b></span><span style="color: #444444;">17:00h. 20:45h. </span><span style="color: #444444;"><span><span style="font-size: x-small;">versión doblada / digital<br><div style="text-align: left;"><a href="https://www.reservaentradas.com/cine/valencia/cinestudiodor" style="font-size: x-small; padding: 1px;" target="_blank"><input type="button" value="COMPRA ONLINE"></a><span style="color: #444444; font-size: small;"> </span><span style="color: #444444; font-size: xx-small;">(a partir del 12 de julio) </span></div></span></span></span></div><p></p><p></p><p></p><p></p><p></p><p></p><a href="https://www.cinestudiodor.es/2021/07/una-joven-prometedora.html#more"></a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Radar verano mix Parte 1">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Radar verano mix Parte 1</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">03 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Debido a un error de grabación la pista de Antony no está disponible. Esta primera parte es una versión editada con las partes de Antony (que no salen en la mezcla). Intentaremos que Antony grabe sus enlaces por separado para la parte 2.</p>



<p>Despedimos temporada 4 del podcast con un episodio cargado de enlaces de interés, salpicados eso sí, con nuestras anotaciones personales. Como es habitual en la sección Radar, este episodio recoge recursos y herramientas que nos parecen valiosas para nuestro trabajo. En esta primera parte se incluyen las recomendaciones recopiladas por Javier y Andros. También al inicio del podcast David Vaquero hace un valoración del Congreso Eslibre que se celebró la semana pasada, y que tuvo al propio David participando como colaborador y dando un taller. Andros también participó ofreciendo una charla sobre el desarrollo de Glosa, su solución personal para agregar comentarios en un sitio web estático.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-YKwl6PiDzyk/YODZa3K8k0I/AAAAAAAABes/RPLjaQEqLNEA99Y-MEBCs7Vg5GxS-z41QCLcBGAsYHQ/w640-h640/ruega_.jpg" alt="RUEGA POR NOSOTROS">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">RUEGA POR NOSOTROS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Cinestudio d&#39;Or</a> <span class="article__date">03 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p></p><div class="separator" style="clear: both; text-align: left;"><a href="https://www.cinestudiodor.es/2021/07/ruega-por-nosotros.html"><img border="0" data-original-height="1200" data-original-width="1200" height="640" src="https://1.bp.blogspot.com/-YKwl6PiDzyk/YODZa3K8k0I/AAAAAAAABes/RPLjaQEqLNEA99Y-MEBCs7Vg5GxS-z41QCLcBGAsYHQ/w640-h640/ruega_.jpg" width="640"></a><br><span style="color: #444444; font-style: inherit;"><b>del 12 al 18 de julio<br></b></span><span style="color: #444444;">19:00h. </span><span style="color: #444444;"><span><span style="font-size: x-small;">versión doblada / digital<br><div style="text-align: left;"><a href="https://www.reservaentradas.com/cine/valencia/cinestudiodor" style="font-size: x-small; padding: 1px;" target="_blank"><input type="button" value="COMPRA ONLINE"></a><span style="color: #444444; font-size: small;"> </span><span style="color: #444444; font-size: xx-small;">(a partir del 12 de julio) </span></div></span></span></span></div><p></p><p></p><p></p><p></p><p></p><p></p><p></p><a href="https://www.cinestudiodor.es/2021/07/ruega-por-nosotros.html#more"></a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://i0.wp.com/workchronicles.com/wp-content/uploads/2020/07/cropped-workchronicles-site-icon-1.png?fit=32%2C32&amp;ssl=1" alt="Greatest weakness">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Greatest weakness</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Work Chronicles</a> <span class="article__date">03 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The post <a rel="nofollow" href="https://workchronicles.com/greatest-weakness/">Greatest weakness</a> appeared first on <a rel="nofollow" href="https://workchronicles.com">Work Chronicles</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Publicada herramienta descifrado gratuita para víctimas del ransomware Lorenz</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">03 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Europol cierra servicio de VPN DoubleVPN utilizado por cibercriminales</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">02 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">KDE Connect: la mejor integración con Android llega a Windows</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MuyLinux</a> <span class="article__date">02 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        KDE Connect es una de las aplicaciones más interesantes de KDE. Sus cómodas y aprovechables posibilidades han animado a portarlo a GNOME con GSConnect y e incluso ha llegado macOS. Dos años después de llegar al sistema de escritorio de[...]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Apply to be the FSF&#39;s next executive director</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FSF News</a> <span class="article__date">02 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The Free Software Foundation (FSF), a Massachusetts 501(c)(3) charity
with a worldwide mission to protect computer user freedom, seeks a
principled, compassionate, and capable leader to be its new executive
director. This position can be remote or based in our Boston office.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Operadores de Telefonía añaden enlaces publicidad en los mensajes SMS recibidos</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">02 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure Deref (July 2, 2021)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">02 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Welcome to the Clojure Deref! This is a weekly link/news roundup for the Clojure ecosystem. (<a href="https://twitter.com/ClojureDeref">@ClojureDeref</a> <a href="https://clojure.org/feed.xml">RSS</a>)</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_highlights"><a class="anchor" href="#_highlights"></a>Highlights</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Clojurists Together <a href="https://www.clojuriststogether.org/news/the-next-phase-of-clojurists-together/">announced</a> a more varied set of funding models moving forward to better match what projects have been seeking.</p>
</div>
<div class="paragraph">
<p>All of the <a href="http://clojured.de/">clojureD</a> <a href="https://www.youtube.com/playlist?list=PLaSn8eiZ631nON7le-wdZxTR0c5bxqPYi">2021 videos</a> are now available, including <a href="https://www.youtube.com/watch?v=BTAx-gFz6Ks">my video</a> discussing a set of new Clojure CLI features and the tools.build library. We have been hard at work polishing documentation and finalizing a last few bits of the source prep functionality and we expect it will be available soon for you to work with! For now, the video is a good overview of what&#8217;s coming: expanded source for source-based libs, a new tools.build library, and some extensions to tool support in the Clojure CLI.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_in_the_core"><a class="anchor" href="#_in_the_core"></a>In the core</h2>
<div class="sectionbody">
<div class="paragraph">
<p>We have mostly been working on Clojure CLI and tools.build lately but these items went by this week, maybe of interest:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://clojureverse.org/t/do-clojure-still-have-rooms-to-improve-at-compiler-level">Does Clojure still have rooms to improve at compiler level?</a> - some discussion at ClojureVerse</p>
</li>
<li>
<p><a href="https://clojure.atlassian.net/browse/CLJ-2637">CLJ-2637 - Automatic argument conversion to Functional Interface (Lambda) from Clojure fn</a> - this patch was proposed to do automatic SAM conversion for Clojure functions in the compiler.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>This is an area we&#8217;ve actually spent a lot of time thinking about for Clojure 1.11, (tracking under <a href="https://clojure.atlassian.net/browse/CLJ-2365">CLJ-2365</a> although most of the work has happened off ticket). In particular we have talked about a long list of possible use cases for functional interop and also a long list of ideas for making functional interop less cumbersome, both syntax and implementation. The examples given in CLJ-2637 are primarily about the Java Stream API but we don&#8217;t think that&#8217;s particularly high on the list of what&#8217;s interesting (if you&#8217;re in Clojure, just use Clojure&#8217;s apis!). But there are cases where you have Java APIs in the JDK or elsewhere that now take one of the SAM-style interfaces, or a java.function interface and it would be nice to reduce the friction in passing a Clojure function without needing to reify - either by automatic detection and conversion, or helper fns, or even new syntax and compiler support. No conclusions yet.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_podcasts_and_videos"><a class="anchor" href="#_podcasts_and_videos"></a>Podcasts and videos</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p><a href="https://www.youtube.com/watch?v=URR6iu6l3fc">Apropos</a> - Mia, Mike, Ray, and Eric chat about Clojure</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_blogs_discussions_tutorials"><a class="anchor" href="#_blogs_discussions_tutorials"></a>Blogs, discussions, tutorials</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p><a href="https://www.clojuremorsels.com/">Clojure Morsels</a> - a new biweekly mailing list for Clojure news starting soon</p>
</li>
<li>
<p><a href="https://vlaaad.github.io/clj-vs-cli">REPL vs CLI: IDE wars</a> - Vlad thinks about REPLs vs the command line for dev</p>
</li>
<li>
<p><a href="https://gustavosantos.dev/a/clojure-building-blocks">Clojure Building Blocks</a> - Gustavo Santos</p>
</li>
<li>
<p><a href="https://gustavosantos.dev/a/getting-started-with-clojure">Getting Started with Clojure</a> - Gustavo Santos</p>
</li>
<li>
<p><a href="https://betweentwoparens.com/blog/rich-comment-blocks/">Rich Comment Blocks</a> - Thomas Mattacchione</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_training_and_hiring"><a class="anchor" href="#_training_and_hiring"></a>Training and hiring</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p><a href="https://learndatomic.com/">Learn Datomic</a> - is a new course for learning Datomic and Datalog by Jacek Schae, coming soon!</p>
</li>
<li>
<p><a href="https://www.reddit.com/r/Clojure/comments/ob7nkk/who_is_hiring_june_30_2021/">Who&#8217;s Hiring</a> - monthly hiring thread on Clojure subreddit</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_libraries_and_tools"><a class="anchor" href="#_libraries_and_tools"></a>Libraries and tools</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Some interesting library and tool updates and posts this week:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/alekcz/pcp">PCP</a> - Clojure replacement for PHP</p>
</li>
<li>
<p><a href="https://github.com/FieryCod/holy-lambda">holy-lambda</a> <a href="https://github.com/FieryCod/holy-lambda/blob/master/CHANGELOG.md#022-01-07-2021">0.2.2</a> - A micro-framework that integrates Clojure with AWS Lambda on either Java, Clojure Native, or Babashka runtime</p>
</li>
<li>
<p><a href="https://github.com/clojure-lsp/clojure-lsp">clojure-lsp</a> <a href="https://github.com/clojure-lsp/clojure-lsp/releases/tag/2021.07.01-13.46.18">2021.07.01-13.46.18</a> - Language Server (LSP) for Clojure, this release with new API/CLI support!</p>
</li>
<li>
<p><a href="https://github.com/sauercrowd/clojureflare">clojureflare</a> - a new ClojureScript lib for using Cloudflare workers</p>
</li>
<li>
<p><a href="https://github.com/BetterThanTomorrow/calva">Calva</a> 2.0.202 - Clojure &amp; ClojureScript in Visual Studio Code</p>
</li>
</ul>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Debugging Series 2021: Summer Break!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Giant Robots Smashing Into Other Giant Robots</a> <span class="article__date">02 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Sometimes, the debugger needs a break.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">30 millones ordenadores Dell vulnerables por culpa software preinstalado</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">01 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Descubren un importante fallo de seguridad en los paquetes RPM</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MuyLinux</a> <span class="article__date">01 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Dmitry Antipov, un desarrollador de CloudLinux, ha descubierto un importante fallo de seguridad en el formato de paquetes RPM que permite llevar a cabo un proceso de actualización o parcheo con las claves de dichos paquetes revocadas o sin existir.[...]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://i0.wp.com/workchronicles.com/wp-content/uploads/2020/07/cropped-workchronicles-site-icon-1.png?fit=32%2C32&amp;ssl=1" alt="Speed of execution">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Speed of execution</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Work Chronicles</a> <span class="article__date">01 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The post <a rel="nofollow" href="https://workchronicles.com/speed-of-execution/">Speed of execution</a> appeared first on <a rel="nofollow" href="https://workchronicles.com">Work Chronicles</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">FSF takes next step in commitment to improving board governance</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FSF News</a> <span class="article__date">01 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://nosinmiscookies.com/wp-content/uploads/2019/03/cropped-favicon-32x32.png" alt="">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title"></h1>
                            <h2 class="article__feed"><a target="_blank" href="">No sin mis cookies</a> <span class="article__date">01 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Si hasta 2020 el SEO local era importante, ahora toma el carácter de plenamente imprescindible. Si competir ya es de por sí difícil, hacerlo con tus vecinos de localidad es todo un desafío.</p>
<p>The post <a rel="nofollow" href="https://nosinmiscookies.com/destacar-seo-local/"></a> appeared first on <a rel="nofollow" href="https://nosinmiscookies.com">No sin mis cookies</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Deepin estrena tienda de software con soporte para aplicaciones de Android</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MuyLinux</a> <span class="article__date">01 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Hay lanzamiento fresquito de Deepin y aunque su número de versión indique lo contrario, llega con novedades destacadas en su haber. A destacar una nueva tienda de software cuya gran sorpresa es la de contar con soporte para instalar aplicaciones[...]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Grupo MASMOVIL España hackeado por el ransomware de origen ruso REvil (Sodinokibi)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">01 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Grave vulnerabilidad en el servicio de impresión de Windows: PrintNightmare </h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">01 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">WD recuperará los datos borrados durante el ataque a sus NAS My Book Live y ofrecerá descuentos</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">30 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">System76 anuncia Pop!_OS 21.04 con COSMIC, su nuevo escritorio</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MuyLinux</a> <span class="article__date">30 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Pues ya es oficial. Después de presentarlo el pasado mes de abril y cumpliendo con los plazos previstos, System76 ha anunciado el lanzamiento de Pop!_OS 21.04 con su propio entorno de escritorio derivado de GNOME (en esta ocasión la versión[...]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">667</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Extra Ordinary</a> <span class="article__date">30 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">GitHub presenta Copilot; herramienta capaz de autocompletar y generar código con Inteligencia Artificial (IA)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">30 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://i0.wp.com/workchronicles.com/wp-content/uploads/2020/07/cropped-workchronicles-site-icon-1.png?fit=32%2C32&amp;ssl=1" alt="Expertise">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Expertise</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Work Chronicles</a> <span class="article__date">30 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The post <a rel="nofollow" href="https://workchronicles.com/expertise/">Expertise</a> appeared first on <a rel="nofollow" href="https://workchronicles.com">Work Chronicles</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">JWM Logo</h1>
                            <h2 class="article__feed"><a target="_blank" href="">tonsky.me</a> <span class="article__date">30 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Detectan colisiones entre estrellas de neutrones y agujeros negros</h1>
                            <h2 class="article__feed"><a target="_blank" href="">NeoFronteras</a> <span class="article__date">29 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Detectan las emisiones asociadas a sendos eventos de colisión entre un agujero negro y una estrella de neutrones. La colaboración LIGO-Virgo hace público ahora el registro de dos eventos en los que una estrella de neutrones choca contra un agujero negro y es absorbida por este. A los largo de la corta vida de los [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A la venta base de datos con datos del 92% usuarios de Linkedin</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">29 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Sin agua en Venus y posiblemente sin vida</h1>
                            <h2 class="article__feed"><a target="_blank" href="">NeoFronteras</a> <span class="article__date">29 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        La escasez de agua en la atmósfera de Venus reduce mucho las posibilidades de vida allí pese a la supuesta presencia de fosfano. Incluso la atmósfera de Júpiter parece ser un mejor lugar para la vida tal y como la conocemos. El destino trágico de Venus, pese a ser un planeta gemelo en tamaño a [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Nitrux 1.5 llega con KDE Plasma 5.22 y el reciente Linux 5.13</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MuyLinux</a> <span class="article__date">29 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Uri Herrera ha anunciado la publicación de Nitrux 1.5, la última versión de la distribución basada ahora en Debian que destaca por el uso de Qt mediante Nomad Desktop, un KDE Plasma modificado con un atractivo acabado estético, y por[...]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Herramientas gratuitas análisis forense digital</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">29 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://github.blog/wp-content/uploads/2019/01/cropped-github-favicon-512.png?fit=32%2C32" alt="Introducing GitHub Copilot: your AI pair programmer">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Introducing GitHub Copilot: your AI pair programmer</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The GitHub Blog</a> <span class="article__date">29 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Today, we're launching a technical preview of GitHub Copilot, a new AI pair programmer that helps you write better code.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Windows 11 TPM; requisitos y características</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">29 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">New Case Study &amp; Updated Services for Early-Stage Teams</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Giant Robots Smashing Into Other Giant Robots</a> <span class="article__date">29 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        After a successful project with Oromoon and others, we&rsquo;ve updated our services to better support early-stage companies and entrepreneurs.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://programadorwebvalencia.com/img/blog/2021/06/comision.png" alt="Comisiones cuando vendes en Apple Store">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Comisiones cuando vendes en Apple Store</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Programador Web Valencia</a> <span class="article__date">28 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://programadorwebvalencia.com/img/blog/2021/06/comision.png" alt="Comisión" /></p>

<p>¿Quieres vender en la Apple Store? Lo siento pero tenemos que hablar.</p>

<p>Cuando decides poner a la venta algún elemento dentro de un App <strong>no todas las ganancias van a tu bolsillo</strong>. Dependiendo de ciertas variables <strong>Apple se llevará un porcentaje</strong> por cada transacción, que puede ser de un <strong>0% (ninguna), 15% o un 30%</strong>.</p>

<p>Un ejemplo rápido. Acabas de publicar un App de cocina donde ofreces deliciosas recetas veganas para perros. Decides que la vas a monetizar por media de una suscripción a un precio de 10 euros al mes. Solamente quienes paguen podrán visualizar las recetas completas con todos sus pasos; el resto únicamente disfrutaran del primer paso. En este caso de cada suscripción a ti te llegará 7 euros (un 70%) mientras que Apple se quedará una comisión de 3 euros (un 30%). Y esta situación ser repetirá en cada usuario y renovación.</p>

<p>Existen 2 servicios que no debes confundir, ya que su uso es completamente diferente a pesar que ambos gestionen dinero.</p>

<ul>
  <li>
    <p><strong>Apple Pay</strong>: Implementación para hacer pagos en una web o App por medio de una tarjeta que ha sido vinculada con la cartera de Apple.</p>
  </li>
  <li>
    <p><strong>In-App Purchase</strong>: Implementación para realizar pagos dentro de un App. Orientado a ofrecer contenido como: productos digitales, suscripciones y contenido premium.</p>
  </li>
</ul>

<p>El último servicio es el que nos interesa. Dentro podremos encontrar 3 subcategorías de posibles pagos:</p>

<ul>
  <li><strong>Consumibles</strong>: como gemas en un videojuego o incrementar la visibilidad de un perfil temporalmente en un red de citas.</li>
  <li><strong>No consumibles</strong>: características premium que son compradas en una ocasión y no expiran.</li>
  <li><strong>Suscripciones</strong>: características premium o acceso a contenido a través de un pago recurrente. Cuando el usuario decide cancelar el siguiente pago, estas características dejan de ser accesibles transcurrido el periodo pagado.</li>
</ul>

<p>Es importante que sepas donde encaja el App en estas subcategorías porque las comisiones cambiarán.</p>

<h2 id="comisiones">Comisiones</h2>

<ul>
  <li><strong>El App es gratis en tienda, no se vende nada</strong>: 0%.</li>
  <li><strong>El App es gratis en tienda pero posee anuncios</strong>: 0%.</li>
  <li><strong>El App es gratis en tienda pero se vende productos o servicios físicos</strong>: 0%.</li>
  <li><strong>El App es gratis en tienda aunque puedes pagar por consumibles</strong>: 30%.</li>
  <li><strong>El App es de pago, no se vende nada</strong>: 30%.</li>
  <li><strong>El App es gratis en tienda aunque puedes pagar una suscripción</strong>: 30%, aunque después del primer año baja a 15%.</li>
  <li><strong>Existe pagos o suscripciones fuera del App</strong>: 0%, sin embargo no debe existir ningún enlace o referencia al lugar donde se pueden realizar los pagos.</li>
  <li><strong>Existen pagos o suscripciones fuera del App con posibilidad de hacerlo también dentro de un dispositivo Apple</strong>: 0% si no es en el ecosistema de Apple, dentro del App se debe pagar las comisiones anteriormente mencionadas.</li>
</ul>

<h2 id="tabla-de-precios-disponibles">Tabla de precios disponibles</h2>

<p>Los precios <strong>no los eliges libremente, Apple te da una tabla</strong> de posibilidades que si o si debes seleccionar la opción que más se ajuste con tu negocio. Te aviso que las cantidades a percibir varían dependiendo del país. Puede darse el caso que marques 10 euros, pero en un lugar como la India se venda por 4 euros.</p>

<p><img src="https://programadorwebvalencia.com/img/blog/2021/06/tabla-precios-apple-store.png" alt="Tabla precios In-App" /></p>

<h2 id="otras-comisiones">Otras comisiones</h2>

<p>No olvides que independientemente de Apple <strong>debes integrar una pasarela de pago</strong>. Alguien debe gestionar el movimiento de dinero entre la tarjeta del cliente y tu cuenta bancaria. Corre por tu cuenta. Las más populares son las siguientes.</p>

<ul>
  <li><strong>Stripe</strong>: Se lleva una comisión de 1,4 % + 0,25 € para tarjetas europeas y 2,9 % + 0,25 € para tarjetas no europeas.</li>
  <li><strong>Paypal</strong>: Se lleva una comisión de 2,8 % + una tarifa fija dependiendo de la moneda.</li>
</ul>

<p>Sin olvidar el pago anual de <strong>Apple Developer Program</strong>, que son 100 dolares. Es el precio para que tu App esté accesible en la tienda. En caso de no pagarlo sería retirada.</p>

<p>Y por último los impuestos locales de cada país. Pero esto es inabarcable de explicar en un artículo de blog.</p>

<h2 id="conclusión">Conclusión</h2>

<p>Para publicar un App en la Apple Store debemos tener en cuenta las siguientes comisiones.</p>

<ul>
  <li><strong>Apple Developer Program</strong>: 100 dolares anuales.</li>
  <li><strong>In-App Purchase</strong>: Entre 0% al 30%.</li>
  <li><strong>Pasarela de pagos</strong>: Los mencionados rondan de entre 1,4% al 2.9% + una tarifa fija.</li>
  <li><strong>Reducción de precio</strong> en algunos países.</li>
  <li><strong>Impuestos</strong> locales.</li>
</ul>

<p>Aún así, sigue siendo la plataforma más rentable dentro del desarrollo de Apps.</p>

<h2 id="más-información">Más información</h2>

<p>Todas las funciones: <a href="https://developer.apple.com/in-app-purchase/">In‑App Purchase</a></p>

<p>Comisiones: <a href="https://www.apple.com/ie/ios/app-store/principles-practices/">Principales prácticas</a></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Google Summer of Code 2021: Student Stats</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">28 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Trickbot: botnet malware-as-a-service</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">28 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Disponible Linux 5.13 con soporte inicial para el Apple M1 y mejoras de seguridad</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MuyLinux</a> <span class="article__date">28 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Linus Torvalds ha anunciado la publicación como estable de Linux 5.13. Como ya es habitual en cada nueva versión mayor del kernel, nos encontramos con lo de siempre, o sea, soporte para nuevo hardware o la mejora de este, aunque[...]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://i0.wp.com/stratechery.com/wp-content/uploads/2018/03/cropped-android-chrome-512x512-1.png?fit=32%2C32&amp;ssl=1" alt="The Lightness of Windows">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Lightness of Windows</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Stratechery by Ben Thompson</a> <span class="article__date">28 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The Windows 11 announcement was fun and interesting, but there is a reason that Windows is no longer the center of Microsoft's business.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://i0.wp.com/workchronicles.com/wp-content/uploads/2020/07/cropped-workchronicles-site-icon-1.png?fit=32%2C32&amp;ssl=1" alt="Follow Through">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Follow Through</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Work Chronicles</a> <span class="article__date">28 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The post <a rel="nofollow" href="https://workchronicles.com/follow-through/">Follow Through</a> appeared first on <a rel="nofollow" href="https://workchronicles.com">Work Chronicles</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Tecnología GPON - FTTH</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">28 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The next phase of Clojurists Together</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">28 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Expanding Clojurists Together to three new funding types
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Demystifying styled-components</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">27 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        For so many React devs, styled-components seems kinda magical. It isn't at all clear how it uses traditional CSS features under-the-hood, and that lack of clarity can cause real problems when things go awry. In this post, we'll learn exactly how styled-components works by building our own mini-version.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Graves vulnerabilidades NAS WD My Book Live provocan ataque externo con borrado entero de la unidad</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">26 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Microsoft presenta oficialmente Windows 11</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">26 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">El interferómetro magnético podría explorar la gravedad cuántica</h1>
                            <h2 class="article__feed"><a target="_blank" href="">NeoFronteras</a> <span class="article__date">25 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Un nuevo montaje experimental combina el experimento de la doble rendija con el experimento de Stern-Gerlach. Sin experimentos no hay Física. La Mecánica Cuántica pudo avanzar a principios del siglo pasado gracias fundamentalmente a dos montajes experimentales: el experimento de la doble rendija y el experimento de Stern-Gerlach. Sin embargo, seguimos estancados a la hora [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://i0.wp.com/workchronicles.com/wp-content/uploads/2020/07/cropped-workchronicles-site-icon-1.png?fit=32%2C32&amp;ssl=1" alt="Wonder Why">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Wonder Why</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Work Chronicles</a> <span class="article__date">25 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The post <a rel="nofollow" href="https://workchronicles.com/wonder-why/">Wonder Why</a> appeared first on <a rel="nofollow" href="https://workchronicles.com">Work Chronicles</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://github.blog/wp-content/uploads/2019/01/cropped-github-favicon-512.png?fit=32%2C32" alt="Seven years of the GitHub Security Bug Bounty program">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Seven years of the GitHub Security Bug Bounty program</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The GitHub Blog</a> <span class="article__date">25 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        GitHub’s bug bounty program is now a mature component of how we improve product security. We're excited to highlight some achievements (and interesting vulnerabilities)!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Canonical ofrecerá soporte empresarial para Blender LTS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MuyLinux</a> <span class="article__date">25 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Canonical se ha asociado con Blender Foundation para ofrecer soporte de nivel de profesional para las versiones LTS de la solución de creación y renderización de gráficos 3D, y la cosa tiene más miga de la que aparenta en un[...]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure Deref (June 25, 2021)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">25 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Welcome to the Clojure Deref! This is a weekly link/news roundup for the Clojure ecosystem. (<a href="https://twitter.com/ClojureDeref">@ClojureDeref</a> <a href="https://clojure.org/feed.xml">RSS</a>)</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_highlights"><a class="anchor" href="#_highlights"></a>Highlights</h2>
<div class="sectionbody">
<div class="paragraph">
<p>It is common to see complaints that both Clojure jobs and Clojure developers are hard to find. The real truth is: both exist, but there is sometimes a mismatch in either experience or geographic distribution. We don&#8217;t typically highlight jobs in the Deref but here are some great places to find Clojure jobs:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://jobs.braveclojure.com/">Brave Clojure</a> - job board</p>
</li>
<li>
<p><a href="https://functional.works-hub.com/functional-programming-jobs">Functional Works</a> - job board</p>
</li>
<li>
<p><a href="http://clojurians.net">Clojurians slack</a> - #jobs and #remote-jobs channel</p>
</li>
<li>
<p><a href="https://clojureverse.org/c/community-center/jobs/52">Clojureverse</a></p>
</li>
<li>
<p><a href="https://www.reddit.com/r/Clojure/comments/npeien/who_is_hiring_may_31_2021/">Clojure subreddit</a> - monthly thread</p>
</li>
<li>
<p><a href="https://kennytilton.github.io/whoishiring/">Who is hiring</a> - search at HackerNews</p>
</li>
<li>
<p><a href="https://twitter.com/search?q=clojure%20job&amp;src=spelling_expansion_revert_click&amp;f=live">Twitter search</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Also, I want to highlight that <a href="https://www.youtube.com/playlist?list=PLaSn8eiZ631nON7le-wdZxTR0c5bxqPYi">clojureD 2021 conference</a> videos are coming out now, about one per day, check them out!</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_sponsorship_spotlight"><a class="anchor" href="#_sponsorship_spotlight"></a>Sponsorship spotlight</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Over the last couple years, the <a href="https://calva.io/">Calva</a> team has been putting a ton of effort into making VS Code a great place to Clojure. If you enjoy the fruits of that effort, consider supporting one of these fine folks working in this area:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/PEZ">Peter Strömberg</a> - <a href="https://github.com/sponsors/PEZ">sponsor</a> for Calva</p>
</li>
<li>
<p><a href="https://github.com/bpringe">Brandon Ringe</a> - <a href="https://github.com/sponsors/bpringe">sponsor</a> for Calva</p>
</li>
<li>
<p><a href="https://github.com/ericdallo">Eric Dallo</a> - <a href="https://www.patreon.com/ericdallo">sponsor</a> for clojure-lsp</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_podcasts_and_videos"><a class="anchor" href="#_podcasts_and_videos"></a>Podcasts and videos</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p><a href="https://www.case-podcast.org/45-eric-normand-on-functional-thinking">CaSE</a> - Conversations about Software Engineering talks with Eric Normand</p>
</li>
<li>
<p><a href="https://podcasts.apple.com/us/podcast/s4-e32-lacinia-with-howard-lewis-ship/id1461500416?i=1000526576095">ClojureScript podcast</a> - Jacek Schae interviews Howard Lewis Ship</p>
</li>
<li>
<p><a href="https://www.youtube.com/watch?v=CR1faH3S1pA">Apropos</a> - Mia, Mike, Ray, Eric chat plus special guest Martin Kavalar</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_blogs_discussions_tutorials"><a class="anchor" href="#_blogs_discussions_tutorials"></a>Blogs, discussions, tutorials</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p><a href="https://danielgregoire.dev/posts/2021-06-18-open-closed-systems-clojure/">Open and Closed Systems with Clojure</a> - Daniel Gregoire</p>
</li>
<li>
<p><a href="https://blog.jakubholy.net/2021/simplicity/">What is simplicity in programming and why does it matter?</a> - Jakub Holý</p>
</li>
<li>
<p><a href="https://www.michaelnygard.com/blog/2021/06/counterfactuals-are-not-causality/">Counterfactuals are not Causality</a> - Michael Nygard - not about Clojure but worth a read!</p>
</li>
<li>
<p><a href="https://robhaisfield.com/notes/how-i&#8217;m-learning-clojure">How I&#8217;m learning Clojure</a> - Rob Haisfield</p>
</li>
<li>
<p><a href="https://ostash.dev/posts/2021-06-18-clojure-metadata/">Clojure metadata</a> - Roman Ostash</p>
</li>
<li>
<p><a href="https://ostash.dev/posts/2021-06-24-edn-data-notation/">Data notation in Clojure</a> - Roman Ostash</p>
</li>
<li>
<p><a href="https://blog.jakubholy.net/2021/specific-vs-general-cryogen/">Specific vs. general: Which is better?</a> - Jakub Holý</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_libraries"><a class="anchor" href="#_libraries"></a>Libraries</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Some interesting library updates and posts this week:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/mauricioszabo/spock/">spock</a> 0.1.1 - a Prolog in Clojure</p>
</li>
<li>
<p><a href="https://github.com/pfeodrippe/recife">recife</a> 0.3.0 - model checker library in Clojure</p>
</li>
<li>
<p><a href="https://github.com/tonsky/datascript">datascript</a> 1.2.1 - immutable in-memory database and Datalog query engine</p>
</li>
<li>
<p><a href="https://github.com/ont-app/sparql-endpoint">sparql-endpoint</a> 0.1.2 - utilities for interfacing with SPARQL 1.1 endpoints</p>
</li>
<li>
<p><a href="https://github.com/modern-energy/pulumi-cljs">pulumi-cljs</a> - ClojureScript wrapper for Pulumi&#8217;s infrastructure as code Node API</p>
</li>
<li>
<p><a href="https://gitlab.com/domaindrivenarchitecture/c4k-keycloak">c4k-keycloak</a> - k8s deployment for keycloak</p>
</li>
<li>
<p><a href="https://github.com/lucywang000/clj-statecharts">clj-statecharts</a> 0.1.0 - State Machine and StateCharts for Clojure(Script)</p>
</li>
<li>
<p><a href="https://github.com/clojure-lsp/clojure-lsp">clojure-lsp</a> 2021.06.24-14.24.11 - Language Server (LSP) for Clojure</p>
</li>
<li>
<p><a href="https://github.com/juxt/tick">tick</a> 0.4.32 - Time as a value</p>
</li>
<li>
<p><a href="https://github.com/cognitect-labs/aws-api">aws-api</a> 0.8.515 - programmatic access to AWS services from Clojure</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_tools"><a class="anchor" href="#_tools"></a>Tools</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p><a href="https://www.libhunt.com/l/clojure">Clojure LibHunt</a> - find Clojure open source projects!</p>
</li>
<li>
<p><a href="https://github.com/Tyruiop/syncretism">syncretism</a> - options search engine based on Yahoo! Finance market data</p>
</li>
<li>
<p><a href="https://gitlab.com/yogthos/mastodon-bot">mastodon-bot</a> - bot for mirroring Twitter/Tumblr accounts and RSS feeds on Mastodon</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_fun_and_games"><a class="anchor" href="#_fun_and_games"></a>Fun and Games</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Chris Ford did a <a href="https://www.youtube.com/watch?v=BRBR45k2Yw4">live coding performance</a> (on keytar!) - see the <a href="https://github.com/ctford/tin-ear">code</a></p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_throwback_friday_i_know_im_doing_it_wrong"><a class="anchor" href="#_throwback_friday_i_know_im_doing_it_wrong"></a>Throwback Friday (I know, I&#8217;m doing it wrong)</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In this recurring segment, we harken back to talks from an older time of yore. This week, we&#8217;re featuring:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://www.youtube.com/watch?v=dPK6t7echuA">How to Think about Parallel Programming: Not!</a> by Guy L. Steele Jr from Strange Loop 2010 - it&#8217;s a decade+ old but still worth watching for how we think about what languages should provide, and a particular inspiration to the later design of Clojure reducers</p>
</li>
<li>
<p><a href="https://www.youtube.com/watch?v=lU3awBr5C7E">Advent of Code 2020, Day 17</a> by Zach Tellman - a wonderful example of how to work in Clojure. write code in your editor, eval small exprs to your REPL, building iteratively up to a final solution</p>
</li>
</ul>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://github.blog/wp-content/uploads/2019/01/cropped-github-favicon-512.png?fit=32%2C32" alt="Run online campus events with your favorite tools at no cost with the new GitHub Virtual Event Kit">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Run online campus events with your favorite tools at no cost with the new GitHub Virtual Event Kit</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The GitHub Blog</a> <span class="article__date">24 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        We're excited to announce the newest addition to the Student Developer Pack, the GitHub Virtual Event Kit! Access the best virtual event tools in one place at no cost.  
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">¿Estuvo implicada una estrella de quarks en GW190814?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">NeoFronteras</a> <span class="article__date">24 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Proponen que el evento de ondas gravitacionales GW190814 fue el resultado de la colisión de un agujero negro y una estrella de quarks extraños El 14 de agosto de 2019, la colaboración LIGO-Virgo detectó una señal de ondas gravitacionales que se cree está asociada con la fusión de un sistema estelar binario compuesto por un [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">
Clojure Engineer (Remote)
</h1>
                            <h2 class="article__feed"><a target="_blank" href="">
Brave Clojure Jobs
</a> <span class="article__date">24 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<div><h1>Clojure Engineer (Remote)</h1><div class="company-name">Composer | US & Canada</div><div>remote</div><div><em>Build, test, and deploy automated trading strategies without any code!</em></div><div>$130000 - $200000</div><div><a href="https://www.investcomposer.com/">https://www.investcomposer.com/</a></div><br /><div><p><strong>Build the infrastructure powering our automated portfolio management platform!</strong></p><p>Composer is a no-code platform for automated investment management. Composer allows you to build, test, deploy, and manage automated investing strategies - all without writing a line of code.</p><p><strong>As an early backend engineer at Composer you will:</strong></p>
<ul>
  <li>Be responsible for designing and building critical pieces of our infrastructure</li>
  <li>Work closely with the executive team to guide our decisions regarding technical architecture</li>
</ul><p><strong>Projects you will work on:</strong></p>
<ul>
  <li>Creating a language that clients can use to define any conceivable trading strategy ("strategies as data")</li>
  <li>Determining the best way to collaborate on, share, and/or monetize strategies</li>
  <li>Allowing clients to develop custom logic to further personalize their strategies</li>
  <li>See <a href="https://benjaminrollert.medium.com/the-composer-manifesto-168654aecf23">here</a> for more ideas!</li>
</ul><p><strong>We're looking for someone who:</strong></p>
<ul>
  <li>Loves Clojure! (Clojurescript a bonus)</li>
  <li>Has familiarity with cloud platforms (We use GCP)</li>
  <li>Will be a technical thought leader within the company</li>
  <li>Understands database design</li>
  <li>Makes educated decisions when faced with uncertainty</li>
</ul><p><strong>What's it like to work at Composer?</strong></p>
<ul>
  <li>We believe diverse perspectives are necessary if we aim to disrupt finance. To that end, we are an equal opportunity employer and welcome a wide array of backgrounds, experiences, and abilities.</li>
  <li>We believe the simplest solution is most likely the best one</li>
  <li>We encourage self-improvement and learning new skills</li>
  <li>We are venture-backed by <a href="https://firstround.com/companies/?selected=composer">top investors</a></li>
  <li>We are 100% remote :)</li>
  <li>We offer generous equity!</li>
  <li><a href="https://drive.google.com/file/d/1sJKzYshCgjxOPoxhPx0ibljPR4y1Wry5/view">Our Values</a></li>
</ul></div></div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Escasas perspectivas a la vida compleja en exoplanetas</h1>
                            <h2 class="article__feed"><a target="_blank" href="">NeoFronteras</a> <span class="article__date">24 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Los exoplanetas que orbioten estrellas más frías que el Sol no podrńa albergar vida compleja cuyos ecosistemas estḉen basados en la fotosíntesis oxigénica tal y como la de la Tierra. Un nuevo análisis sobre los exoplanetas conocidos indica que las condiciones para la vida similares a las de la Tierra en planetas potencialmente habitables pueden [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Nos podrían estar detectando</h1>
                            <h2 class="article__feed"><a target="_blank" href="">NeoFronteras</a> <span class="article__date">24 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Más de mil sistemas planetarios están en la posición adecuada como para detectar la Tierra si es que cuentan con vida inteligente. Un estudio de los sistemas estelares dice que dentro de una esfera con un radio de unos 325 años luz y centrada en la Tierra hay 2034 de ellos que están, han estado [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">I complete. You?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Manuel Uberti</a> <span class="article__date">24 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Tracking the Emacs development by building its master branch may not be a smooth
experience for everyone, but for the average enthusiast is the perfect way to
see their favourite tool evolve, trying experimental things, and reporting back
to the core developers to help them. Sure, one has to deal with occasional build
failures, but with Git at one’s service it’s always easy to reset to a working
commit and find happiness again.</p>

<p>Recently a shiny new mode has been implemented on master:
<code class="language-plaintext highlighter-rouge">icomplete-vertical-mode</code>. Now, if you had the chance to read this blog in the
past you know that when it comes to candidate completion I am a gangsta jumping
back and forth among packages with excessive self-satisfaction. But you should
also already know that I like to use as many Emacs built-ins as possible. Hence,
I could not wait to give <code class="language-plaintext highlighter-rouge">icomplete-vertical-mode</code> a try.</p>

<p>Turning it on is trivial:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nv">icomplete-mode</span> <span class="mi">+1</span><span class="p">)</span>
<span class="p">(</span><span class="nv">add-hook</span> <span class="ss">'icomplete-mode-hook</span> <span class="nf">#'</span><span class="nv">icomplete-vertical-mode</span><span class="p">)</span>
</code></pre></div></div>

<p>Since other completion systems have spoiled me, I prefer scrolling over the
rotating behaviour of the standard <code class="language-plaintext highlighter-rouge">icomplete</code>:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">setq</span> <span class="nv">icomplete-scroll</span> <span class="no">t</span><span class="p">)</span>
</code></pre></div></div>

<p>Furthermore, I always want to see the candidate list:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">setq</span> <span class="nv">icomplete-show-matches-on-no-input</span> <span class="no">t</span><span class="p">)</span>
</code></pre></div></div>

<p>This is pretty much it. I use <code class="language-plaintext highlighter-rouge">icomplete-fido-backward-updir</code> to move up one
directory and I have <code class="language-plaintext highlighter-rouge">exit-minibuffer</code> bound to <kbd>C-j</kbd> for convenience.</p>

<p>I have been using <code class="language-plaintext highlighter-rouge">icomplete-vertical-mode</code> daily for a while now and everything
has been working as expected. For the record, this mode works seamlessly with
your favourite <code class="language-plaintext highlighter-rouge">completion-styles</code> settings, so moving from, say, Vertico to
<code class="language-plaintext highlighter-rouge">icomplete-vertical-mode</code> is simple and easy.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">I complete. You?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Manuel Uberti</a> <span class="article__date">24 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Tracking the Emacs development by building its master branch may not be a smooth
experience for everyone, but for the average enthusiast is the perfect way to
see their favourite tool evolve, trying experimental things, and reporting back
to the core developers to help them. Sure, one has to deal with occasional build
failures, but with Git at one’s service it’s always easy to reset to a working
commit and find happiness again.</p>

<p>Recently a shiny new mode has been implemented on master:
<code class="language-plaintext highlighter-rouge">icomplete-vertical-mode</code>. Now, if you had the chance to read this blog in the
past you know that when it comes to candidate completion I am a gangsta jumping
back and forth among packages with excessive self-satisfaction. But you should
also already know that I like to use as many Emacs built-ins as possible. Hence,
I could not wait to give <code class="language-plaintext highlighter-rouge">icomplete-vertical-mode</code> a try.</p>

<p>Turning it on is trivial:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nv">icomplete-mode</span> <span class="mi">+1</span><span class="p">)</span>
<span class="p">(</span><span class="nv">add-hook</span> <span class="ss">'icomplete-mode-hook</span> <span class="nf">#'</span><span class="nv">icomplete-vertical-mode</span><span class="p">)</span>
</code></pre></div></div>

<p>Since other completion systems have spoiled me, I prefer scrolling over the
rotating behaviour of the standard <code class="language-plaintext highlighter-rouge">icomplete</code>:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">setq</span> <span class="nv">icomplete-scroll</span> <span class="no">t</span><span class="p">)</span>
</code></pre></div></div>

<p>Furthermore, I always want to see the candidate list:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">setq</span> <span class="nv">icomplete-show-matches-on-no-input</span> <span class="no">t</span><span class="p">)</span>
</code></pre></div></div>

<p>This is pretty much it. I use <code class="language-plaintext highlighter-rouge">icomplete-fido-backward-updir</code> to move up one
directory and I have <code class="language-plaintext highlighter-rouge">exit-minibuffer</code> bound to <kbd>C-j</kbd> for convenience.</p>

<p>I have been using <code class="language-plaintext highlighter-rouge">icomplete-vertical-mode</code> daily for a while now and everything
has been working as expected. For the record, this mode works seamlessly with
your favourite <code class="language-plaintext highlighter-rouge">completion-styles</code> settings, so moving from, say, Vertico to
<code class="language-plaintext highlighter-rouge">icomplete-vertical-mode</code> is simple and easy.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://github.blog/wp-content/uploads/2019/01/cropped-github-favicon-512.png?fit=32%2C32" alt="Introducing the new GitHub Issues">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Introducing the new GitHub Issues</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The GitHub Blog</a> <span class="article__date">23 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Announcing new beta features for GitHub Issues for better planning and tracking of your projects in GitHub, including project tables, task lists, and issue forms. 
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Navegador Brave publica nuevo buscador basado en la privacidad</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">23 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">666</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Extra Ordinary</a> <span class="article__date">23 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Disponible nueva versión navegador Tor corrige errores rastreo mediante aplicaciones instaladas</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">23 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Ransomware DarkRadiation afecta a Linux y contenedores Docker</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">22 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://programadorwebvalencia.com/img/blog/2021/06/don-clojure-de-la-mancha.jpg" alt="Don Clojure de la Mancha">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Don Clojure de la Mancha</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Programador Web Valencia</a> <span class="article__date">22 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://programadorwebvalencia.com/img/blog/2021/06/don-clojure-de-la-mancha.jpg" alt="Don Clojure de la Mancha" /></p>

<p>Próximamente será publicado el libro: <strong>Don Clojure de la Mancha.</strong> ¿Quieres ser el <strong>primero en enterarte</strong>? Tan solo debes <strong>dejar un comentario</strong>. El email que introduzcas no será visible y solo le daré uso para avisarte del momento y lugar. <strong>NO TE ESTAS SUSCRIBIENDO A UNA NEWSLETTER</strong>.</p>

<p>Gracias por apoyar al <strong>software libre</strong>, la <strong>programación funcional</strong> y la comunidad hispana de <strong>Clojure</strong>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://github.blog/wp-content/uploads/2019/01/cropped-github-favicon-512.png?fit=32%2C32" alt="A framework for building Open Graph images">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">A framework for building Open Graph images</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The GitHub Blog</a> <span class="article__date">22 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        We recently set about creating a framework and service for automatically generating social sharing images for repositories and other resources on GitHub.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Sobre la fluctuación en la población de vanesas</h1>
                            <h2 class="article__feed"><a target="_blank" href="">NeoFronteras</a> <span class="article__date">22 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        La cantidad de mariposas vanesas de los cardos que hay en primavera en Europa está fuertemente influenciada por la cantidad de lluvia monzónica en el África subsahariana occidental durante el verano y el otoño anteriores. La mariposa vanesa de los cardos (Vanessa cardui) es una especie de lepidóptero de la familia Nymphalidae. Es una mariposa [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Superenfriamiento de un cuerpo macroscópico</h1>
                            <h2 class="article__feed"><a target="_blank" href="">NeoFronteras</a> <span class="article__date">22 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Logran enfriar un cuerpo con una masa equivalente a los 10 kilogramos hasta los 77 nanokelvins, casi cerca de su estado cuántico fundamental. Un objeto macroscópico y estacionario parece que está quieto y completamente en reposo. Sin embargo, a la escala de átomos individuales, es una colección de partículas vibrantes. A ese movimiento colectivo lo [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Valida tu modelo de datos con FluentValidation en C#</h1>
                            <h2 class="article__feed"><a target="_blank" href="">En Mi Local Funciona</a> <span class="article__date">22 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        La idea de este artículo es mostrarte las funcionalidades más destacadas y las ventajas de usar Fluent Validation.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Custom Scrollbars In CSS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Ahmad Shadeed Blog</a> <span class="article__date">22 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://cdn.evilmartians.com/front/blocks/common/images/social-5e5bfff.png" alt="Custom &quot;cops&quot; for RuboCop: an emergency service for your Ruby code">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Custom &quot;cops&quot; for RuboCop: an emergency service for your Ruby code</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Martian Chronicles, Evil Martians’ team blog</a> <span class="article__date">22 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://github.blog/wp-content/uploads/2019/01/cropped-github-favicon-512.png?fit=32%2C32" alt="GitHub Packages Container registry is generally available">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">GitHub Packages Container registry is generally available</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The GitHub Blog</a> <span class="article__date">21 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Throughout the beta, we added features to improve the experience of using the Container registry. Today, we’re excited to announce that the Container registry is generally available as part of GitHub Packages! 
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://nosinmiscookies.com/wp-content/uploads/2019/03/cropped-favicon-32x32.png" alt="5 errores de SEO que perjudican tu blog">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">5 errores de SEO que perjudican tu blog</h1>
                            <h2 class="article__feed"><a target="_blank" href="">No sin mis cookies</a> <span class="article__date">21 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Los blogs están a la orden del día. Cada vez son más las personas que ganan dinero con sus propios dominios, apostando por una idea de negocio innovadora. Si tú también has optado por la creación de un blog, estoy seguro de que sabes de lo que te hablo. Pero entonces ocurre el primer desencuentro: ... <a title="5 errores de SEO que perjudican tu blog" class="read-more" href="https://nosinmiscookies.com/5-errores-seo-blog/" aria-label="Más en 5 errores de SEO que perjudican tu blog">Read more</a></p>
<p>The post <a rel="nofollow" href="https://nosinmiscookies.com/5-errores-seo-blog/">5 errores de SEO que perjudican tu blog</a> appeared first on <a rel="nofollow" href="https://nosinmiscookies.com">No sin mis cookies</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">La plataforma en la nube de la OTAN ha sido hackeada</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">21 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://i0.wp.com/stratechery.com/wp-content/uploads/2018/03/cropped-android-chrome-512x512-1.png?fit=32%2C32&amp;ssl=1" alt="Pandemic Progress">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Pandemic Progress</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Stratechery by Ben Thompson</a> <span class="article__date">21 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Marc Andreessen has changed his tone over the past year; there is a cynical interpretation, but I think the shift is justified.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Guía NSA sobre la protección de las comunicaciones unificadas y los sistemas de voz y video sobre IP</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">21 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://i0.wp.com/workchronicles.com/wp-content/uploads/2020/07/cropped-workchronicles-site-icon-1.png?fit=32%2C32&amp;ssl=1" alt="Accountability">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Accountability</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Work Chronicles</a> <span class="article__date">20 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The post <a rel="nofollow" href="https://workchronicles.com/accountability/">Accountability</a> appeared first on <a rel="nofollow" href="https://workchronicles.com">Work Chronicles</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Paraceratherium linxiaense</h1>
                            <h2 class="article__feed"><a target="_blank" href="">NeoFronteras</a> <span class="article__date">20 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Descubren una nueva especie de rinoceronte gigante de hace 26 millones de años. Paraceratherium (o «bestia casi cornuda») es un género extinto de mamíferos perisodáctilos, suborden Ceratomorpha de la familia Hyracodontidae. Estos animales serían de los mamíferos terrestres más grandes conocidos, con unos ocho metros de longitud. Están relacionados con los rinocerontes. Sin embargo, a [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://programadorwebvalencia.com/img/blog/2021/06/django-con-acento.png" alt="Django ordenar ignorando los acentos">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Django ordenar ignorando los acentos</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Programador Web Valencia</a> <span class="article__date">19 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://programadorwebvalencia.com/img/blog/2021/06/django-con-acento.png" alt="Django con acento" /></p>

<p>En caso que intentes ordenar una consulta de la base de datos y <strong>no uses PosgreSQL</strong> como base de datos principal te vas a encontrar un pequeño problema: Cuando hay acentos no se ordena de una forma lógica. Si utilizas <strong>SQLite</strong> te lo habrás encontrado de frente. Por ejemplo, si yo tengo una tabla con nombres e intento ordenarlas con <code class="highlighter-rouge">order_by</code> pasaré de:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Zaragoza, Ávila, Murcia, Albacete...
</code></pre></div></div>

<p>al siguiente orden</p>

<pre><code class="language-plain-text">Albacete, Murcia, Zaragoza, Ávila...
</code></pre>

<p>Las palabras con acento, con <em>ñ</em> u otros carácteres acabarán al final de la lista.</p>

<p>Para arreglarlo he creado la siguiente solución que debes copiarlo en el archivo donde necesites realizar el orden deseado.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">re</span>
<span class="kn">import</span> <span class="nn">functools</span>


<span class="k">def</span> <span class="nf">order_ignore_accents</span><span class="p">(</span><span class="n">queryset</span><span class="p">,</span> <span class="n">column</span><span class="p">):</span>
    <span class="s">"""Order Queryset ignoring accents"""</span>

    <span class="k">def</span> <span class="nf">remove_accents</span><span class="p">(</span><span class="n">raw_text</span><span class="p">):</span>
        <span class="s">"""Removes common accent characters."""</span>
        <span class="n">sustitutions</span> <span class="o">=</span> <span class="p">{</span>
            <span class="s">"[àáâãäå]"</span><span class="p">:</span> <span class="s">"a"</span><span class="p">,</span>
            <span class="s">"[ÀÁÂÃÄÅ]"</span><span class="p">:</span> <span class="s">"A"</span><span class="p">,</span>
            <span class="s">"[èéêë]"</span><span class="p">:</span> <span class="s">"e"</span><span class="p">,</span>
            <span class="s">"[ÈÉÊË]"</span><span class="p">:</span> <span class="s">"E"</span><span class="p">,</span>
            <span class="s">"[ìíîï]"</span><span class="p">:</span> <span class="s">"i"</span><span class="p">,</span>
            <span class="s">"[ÌÍÎÏ]"</span><span class="p">:</span> <span class="s">"I"</span><span class="p">,</span>
            <span class="s">"[òóôõö]"</span><span class="p">:</span> <span class="s">"o"</span><span class="p">,</span>
            <span class="s">"[ÒÓÔÕÖ]"</span><span class="p">:</span> <span class="s">"O"</span><span class="p">,</span>
            <span class="s">"[ùúûü]"</span><span class="p">:</span> <span class="s">"u"</span><span class="p">,</span>
            <span class="s">"[ÙÚÛÜ]"</span><span class="p">:</span> <span class="s">"U"</span><span class="p">,</span>
            <span class="s">"[ýÿ]"</span><span class="p">:</span> <span class="s">"y"</span><span class="p">,</span>
            <span class="s">"[ÝŸ]"</span><span class="p">:</span> <span class="s">"Y"</span><span class="p">,</span>
            <span class="s">"[ß]"</span><span class="p">:</span> <span class="s">"ss"</span><span class="p">,</span>
            <span class="s">"[ñ]"</span><span class="p">:</span> <span class="s">"n"</span><span class="p">,</span>
            <span class="s">"[Ñ]"</span><span class="p">:</span> <span class="s">"N"</span><span class="p">,</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">functools</span><span class="p">.</span><span class="nb">reduce</span><span class="p">(</span>
            <span class="k">lambda</span> <span class="n">text</span><span class="p">,</span> <span class="n">key</span><span class="p">:</span> <span class="n">re</span><span class="p">.</span><span class="n">sub</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">sustitutions</span><span class="p">[</span><span class="n">key</span><span class="p">],</span> <span class="n">text</span><span class="p">),</span>
            <span class="n">sustitutions</span><span class="p">.</span><span class="n">keys</span><span class="p">(),</span>
            <span class="n">raw_text</span><span class="p">,</span>
        <span class="p">)</span>

    <span class="k">return</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">queryset</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">remove_accents</span><span class="p">(</span><span class="nb">eval</span><span class="p">(</span><span class="s">f"x.</span><span class="si">{</span><span class="n">column</span><span class="si">}</span><span class="s">"</span><span class="p">)))</span>
</code></pre></div></div>

<p>Supongamos, por ejemplo, que necesitas ordenar unos pueblos o municipios. Lo que haría cualquier desarrollador es:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">towns</span> <span class="o">=</span> <span class="n">Town</span><span class="p">.</span><span class="n">objects</span><span class="p">.</span><span class="nb">all</span><span class="p">().</span><span class="n">order_by</span><span class="p">(</span><span class="s">'name'</span><span class="p">)</span>
</code></pre></div></div>

<p>En su lugar, omitirás <code class="highlighter-rouge">order_by</code> y añadirás la consulta a la función <code class="highlighter-rouge">order_ignore_accents</code>. Y como segundo argumento la columna que quieres usar para ordenar. En este caso será <code class="highlighter-rouge">name</code>.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">towns_order</span> <span class="o">=</span> <span class="n">order_ignore_accents</span><span class="p">(</span><span class="n">Town</span><span class="p">.</span><span class="n">objects</span><span class="p">.</span><span class="nb">all</span><span class="p">(),</span> <span class="s">'name'</span><span class="p">)</span>
</code></pre></div></div>

<p>Se ordenará como esperamos.</p>

<pre><code class="language-plain-text">Albacete, Ávila, Murcia, Zaragoza...
</code></pre>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Actualizaciones de seguridad para Microsoft y Google Chrome</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">19 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://i0.wp.com/workchronicles.com/wp-content/uploads/2020/07/cropped-workchronicles-site-icon-1.png?fit=32%2C32&amp;ssl=1" alt="Honest Review">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Honest Review</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Work Chronicles</a> <span class="article__date">19 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The post <a rel="nofollow" href="https://workchronicles.com/honest-review/">Honest Review</a> appeared first on <a rel="nofollow" href="https://workchronicles.com">Work Chronicles</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Estado de Drupal con Borja Vicente de escueladrupal.com">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Estado de Drupal con Borja Vicente de escueladrupal.com</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">19 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Vuelve Drupal al podcast y para esta ocasión contamos con la compañía del desarrollador web especializado en Drupal Borja Vicente, creador de la web y el canal <a href="https://escueladrupal.com/" data-type="URL" data-id="https://escueladrupal.com/">escueladrupal.com</a> Invitamos a Borja para que nos cuente muchas cosas sobre su proyecto y el estado actual de Drupal. Borja desarrolla en backend con Drupal desde hace más de 10 años y actualmente su labor profesional se desarrolla con Drupal, aunque suele también experimentar con Symfony, Laravel, Django y también Ruby on Rails. Además Borja también tiene publicado cursos especializados en Drupal a través de la plataforma Udemy.</p>



<p>Con Borja tratamos muchas cuestiones relacionados con Drupal y su proyecto de contenidos:</p>



<ul><li>Evolución de Drupal hasta su última versión </li><li>Comunidad Drupal a nivel internacional y nacional</li><li>Proyectos o casos de uso ideales para desarrollar con Drupal 9?</li><li>Recomendaciones esenciales para gestionar una instalación de Drupal</li><li>Motivaciones para crear Escuela Drupal y lo que gustaría conseguir.</li><li>Entorno de desarrollo usado para Drupal.</li><li>Módulos que más te ayudan al desarrollo web con Drupal.</li></ul>



<p>Muy agradecidos a <a href="https://twitter.com/managume" data-type="URL" data-id="https://twitter.com/managume">Manu</a> por propiciar en Twitter este episodio sobre Drupal con Borja.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Malware sin nombre fue capaz de robar 26 millones de credenciales de 3,25 millones de ordenadores</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog elhacker.NET</a> <span class="article__date">19 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">
Senior Software Engineer (Clojure)
</h1>
                            <h2 class="article__feed"><a target="_blank" href="">
Brave Clojure Jobs
</a> <span class="article__date">19 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<div><h1>Senior Software Engineer (Clojure)</h1><div class="company-name">Compute Software | USA and Canada</div><div>remote</div><div><em>Startup that helps enterprises to run optimally on the public cloud.</em></div><div><a href="https://www.computesoftware.com">https://www.computesoftware.com</a></div><br /><div><p><strong>About Us</strong></p><p>With ever-growing workloads on the cloud, companies face significant challenges in managing productivity and spending, and maximizing impact to their businesses. Compute Software is addressing a huge market opportunity to help companies make good business decisions and run optimally on the public cloud. We're building a powerful platform to give customers the tools they need to gain transparency, optimize their usage, and execute change across their organizations.</p><p>We're a small, distributed team, currently spanning California to Quebec, and we offer early stage market-rate compensation (including equity), health and dental insurance, and 401K benefits. You'll be joining a venture capital-backed, distributed team with ambitious goals, and you will have the ability to make a direct and lasting impact on the team and product.</p><p><strong>Your Role</strong></p><p>Be one of the earliest employees and join our early-stage engineering team as a Senior Software Engineer. You will be essential in shaping the features and functionality of our SaaS platform, culture and processes.</p><p>You'll spend your day enveloped in Clojure. The backend is written in Clojure and driven by data in Datomic and InfluxDB. The frontend is written in ClojureScript using <a href="https://github.com/day8/re-frame">re-frame</a> and communicates with the backend using <a href="https://github.com/wilkerlucio/pathom">Pathom</a>. We deploy to AWS Fargate and Datomic Ions.</p><p>For product development, we follow <a href="https://basecamp.com/shapeup">Shape Up</a>. We use Notion, Slack, and ClubHouse.</p><p><strong>What will you do at Compute Software?</strong></p>
<ul>
  <li>Write Clojure and ClojureScript.</li>
  <li>Design, build, and deploy features and bug fixes across the entire stack.</li>
  <li>Become an expert in all the nuances of the various cloud platforms like Amazon Web Services, Google Cloud, and Microsoft Azure.</li>
  <li>Provide product feedback and evaluate trade-offs to impact product direction.</li>
  <li>Debug production problems.</li>
</ul><p><strong>What We're Looking For Passion</strong> - you are excited about the large, high-growth cloud computing market and figuring out how to help customers, who are using cloud computing solutions today. You are excited by being one of the earliest employees and getting to work with a small team.</p><p><strong>Engineering experience</strong> - you're a Clojure practitioner with 6+ years of professional experience. You know what it takes to create large-scale b2b software. You can create effective and simple solutions to problems quickly, and communicate your ideas clearly to your teammates.</p><p><strong>Product-minded</strong> - you love building products and you care about the details of creating a great user experience. You have an interest in how users will use our platform and the impact we will have on them. You can balance your consideration of the product and user requirements with technical complexity and implementation details to make appropriate decisions when things are unclear.</p><p><strong>Effective communication</strong> - you're great at communicating. If something is unclear you reach out and ask questions. You're comfortable owning, communicating and presenting information on specific projects or initiatives, both in writing and in person.</p><p><strong>Organizational and project management</strong> - you are highly organized and able to self-manage projects in a fast-moving company. You are able to take high level goals and break them down into achievable steps.</p></div></div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Updated Debian 10: 10.10 released</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Debian News</a> <span class="article__date">19 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
    The Debian project is pleased to announce the tenth update of its
stable distribution Debian 10 (codename <q>buster</q>).
This point release mainly adds corrections for security issues,
along with a few adjustments for serious problems. Security advisories
have already been published separately and are referenced where available.
  
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://i0.wp.com/workchronicles.com/wp-content/uploads/2020/07/cropped-workchronicles-site-icon-1.png?fit=32%2C32&amp;ssl=1" alt="Turn on your cameras">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Turn on your cameras</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Work Chronicles</a> <span class="article__date">18 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The post <a rel="nofollow" href="https://workchronicles.com/turn-on-your-cameras/">Turn on your cameras</a> appeared first on <a rel="nofollow" href="https://workchronicles.com">Work Chronicles</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure Deref (June 18, 2021)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">18 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Welcome to the Clojure Deref! This is a periodic link/news roundup for the Clojure ecosystem. (<a href="https://twitter.com/ClojureDeref">@ClojureDeref</a> <a href="https://clojure.org/feed.xml">RSS</a>)</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_highlights"><a class="anchor" href="#_highlights"></a>Highlights</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p><a href="https://hopl4.sigplan.org/">HOPL IV</a> (History of Programming Languages) at <a href="https://conf.researchr.org/home/pldi-2021">PLDI 2021</a> is happening on Monday and Tuesday and includes a talk from Rich Hickey about the <a href="https://clojure.org/about/history">History of Clojure</a> paper. Registration is still available and the conference is online and features many other fine language developers!</p>
</li>
<li>
<p>The results are out from the <a href="https://snyk.io/jvm-ecosystem-report-2021/">JVM Ecosystem Report 2021</a> and Clojure continues to make a strong showing as one of the most popular JVM languages (other than Java), rising from 2.9% last year to 8.4% this year. Lots of other interesting tidbits in there as well.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_sponsorship_spotlight"><a class="anchor" href="#_sponsorship_spotlight"></a>Sponsorship Spotlight</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Lately <a href="https://twitter.com/cgrand">Christophe Grand</a> and <a href="https://twitter.com/BaptisteDupuch">Baptiste Dupuch</a> have been <a href="https://twitter.com/cgrand/status/1404446965778292736">teasing</a> their work on a new ClojureDart runtime with Flutter support. You can support their work on GitHub: <a href="https://github.com/sponsors/cgrand">cgrand</a> <a href="https://github.com/sponsors/dupuchba">dupuchba</a>. <a href="https://github.com/nubank">Nubank</a> (users of both Clojure and Flutter) are now supporting both!</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_podcasts_and_videos"><a class="anchor" href="#_podcasts_and_videos"></a>Podcasts and videos</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p><a href="https://lispcast.com/what-is-missing-from-stratified-design/">LispCast</a> - Eric Normand talks about stratified design</p>
</li>
<li>
<p><a href="https://soundcloud.com/defn-771544745/73-paula-gearon">defn</a> - Vijay Kiran and Ray McDermott interview Paula Gearon</p>
</li>
<li>
<p><a href="https://www.youtube.com/watch?v=oTy4JYY3CoQ">REPL-driven development</a> - demo from Jakub Holý</p>
</li>
<li>
<p><a href="https://www.youtube.com/watch?v=hSqpJpowazg">FizzBuzz in Clojure</a></p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_blogs_discussions_tutorials"><a class="anchor" href="#_blogs_discussions_tutorials"></a>Blogs, discussions, tutorials</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p><a href="https://joannecheng.me/2021/06/11/transducers.html">Clojure Transducers</a> - Joanne Cheng explains transducers</p>
</li>
<li>
<p><a href="https://danielgregoire.dev/posts/2021-06-13-code-observation-clojure-destructuring/">Clojure&#8217;s Destructuring</a> - Daniel Gregoire dives into destructuring</p>
</li>
<li>
<p><a href="https://dawranliou.com/blog/better-performance-with-java-arrays-in-clojure/">Better performance with Java arrays in Clojure</a> - Daw-Ran Liou on using Java arrays in Clojure</p>
</li>
<li>
<p><a href="https://tilton.medium.com/backpressure-99501f23881f">Backpressure</a> - Kenny Tilton talks about core.async and ETL</p>
</li>
<li>
<p><a href="https://sidesteps.github.io/posts/fun-of-clojure.html">Fun of clojure - wrap some code around data</a> - <a href="https://twitter.com/Sharas_">@Sharas_</a> on the data ethos of Clojure</p>
</li>
<li>
<p><a href="https://lambdaisland.com/blog/2021-06-17-lambdaisland-is-changing">Lambda Island is Changing</a> - Arne Brasseur and his merry band of Clojurists at Gaiwan are changing directions a bit</p>
</li>
<li>
<p><a href="https://shivekkhurana.medium.com/should-you-adopt-clojure-at-your-company-6e10c92be154">Should you adopt Clojure at your company?</a> - Shivek Khurana, TLDR: yes! :)</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_libraries_and_tools"><a class="anchor" href="#_libraries_and_tools"></a>Libraries and Tools</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Some interesting library updates and posts this week:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/nubank/ordnungsamt">ordnungsamt</a> - a tool for running ad-hoc migrations over a code repository</p>
</li>
<li>
<p><a href="https://github.com/nubank/clj-github">clj-github</a> - a library for working with the GitHub developer API</p>
</li>
<li>
<p><a href="https://github.com/nubank/umschreiben-clj">umschreiben-clj</a> - extensions to <a href="https://github.com/clj-commons/rewrite-clj">rewrite-clj</a></p>
</li>
<li>
<p><a href="https://www.fulcrologic.com/copilot">Copilot</a> - Tony Kay teased a new upcoming code analysis tool for Clojure and ClojureScript</p>
</li>
<li>
<p><a href="https://github.com/borkdude/scittle">scittle</a> - Michiel Borkent did the <a href="https://github.com/borkdude/scittle/releases/tag/v0.0.1">first release</a> of the SCI interpreter for <a href="https://borkdude.github.io/scittle/">use in script tags</a></p>
</li>
<li>
<p><a href="https://github.com/clojure-lsp/clojure-lsp/">clojure-lsp</a> - Eric Dallo <a href="https://clojure-lsp.github.io/clojure-lsp/CHANGELOG/#20210614-170047">released</a> a new version with enhanced path support for deps.edn projects</p>
</li>
<li>
<p><a href="https://github.com/FieryCod/holy-lambda">holy-lambda</a> - Karol Wójcik <a href="https://github.com/FieryCod/holy-lambda/blob/master/CHANGELOG.md#021-10-06-2021">released</a> a new version</p>
</li>
<li>
<p><a href="https://github.com/seancorfield/honeysql">honeysql</a> - Sean Corfield <a href="https://cljdoc.org/d/com.github.seancorfield/honeysql/2.0.0-rc3/doc/readme">added</a> :distinct syntax and some other features and fixes</p>
</li>
<li>
<p><a href="https://github.com/fulcrologic/fulcro">Fulcro</a> - Tony Kay released 3.5.0-RC1 with more support for non-React apps</p>
</li>
<li>
<p><a href="https://github.com/seancorfield/next.jdbc">next.jdbc</a> - Sean Corfield <a href="https://cljdoc.org/d/com.github.seancorfield/next.jdbc/1.2.674/doc/readme">released</a> 1.2.674</p>
</li>
<li>
<p><a href="https://github.com/borkdude/refl">refl</a> - Michiel Borkent released a new example project to clean up reflection configs for GraalVM for Clojure projects</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_fun_and_games"><a class="anchor" href="#_fun_and_games"></a>Fun and Games</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p><a href="https://tylerxhobbs.com/fidenza">Fidenza</a> - Tyler Hobbs has a long history of doing interesting generative art with Clojure and he has published a rundown of his newest generative algorithm. Not explicitly Clojure but fascinating to read.</p>
</li>
<li>
<p><a href="https://ertugrulcetin.github.io/racing-game-cljs/">ClojureScript racing game</a> - Ertuğrul Çetin published this game this week</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_throwback_friday_i_know_im_doing_it_wrong"><a class="anchor" href="#_throwback_friday_i_know_im_doing_it_wrong"></a>Throwback Friday (I know, I&#8217;m doing it wrong)</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In this recurring segment, we harken back to a talk from an older time to a favorite talk of yore. This week, we&#8217;re featuring:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://www.youtube.com/watch?v=xmCrMUhhg9c">Why is a Monad Like a Writing Desk?</a> by Carin Meier from Clojure/West 2012</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>In this lovely story from 2012, Carin Meier talks about monads through the lens of Clojure and Alice in Wonderland.</p>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Contaminación luminosa e insectos</h1>
                            <h2 class="article__feed"><a target="_blank" href="">NeoFronteras</a> <span class="article__date">17 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Nuestra iluminación nocturna está matando a los insectos y esto altera los ecosistemas. En momentos de sequía de resultados científicos relevantes puede merecer la pena echar un vistazo a noticias de hace algunas semanas, como una que apareció en Science el mes pasado. El asunto de la contaminación luminosa es un caso más que ejemplifica [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://i0.wp.com/workchronicles.com/wp-content/uploads/2020/07/cropped-workchronicles-site-icon-1.png?fit=32%2C32&amp;ssl=1" alt="Virtual Meetings">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Virtual Meetings</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Work Chronicles</a> <span class="article__date">16 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The post <a rel="nofollow" href="https://workchronicles.com/virtual-meetings/">Virtual Meetings</a> appeared first on <a rel="nofollow" href="https://workchronicles.com">Work Chronicles</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://github.blog/wp-content/uploads/2019/01/cropped-github-favicon-512.png?fit=32%2C32" alt="GitHub Desktop 2.9 includes squashing, reordering, amending, and more!">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">GitHub Desktop 2.9 includes squashing, reordering, amending, and more!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The GitHub Blog</a> <span class="article__date">16 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The latest version of GitHub Desktop allows you to squash commits, squash and merge, reorder, amend your last commit, check out a branch from a previous commit, and more.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://blogs.windows.com/wp-content/uploads/prod/sites/33/2021/06/cropped-browser-icon-logo-32x32.jpg" alt="Dark Mode for HTML Form Controls">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Dark Mode for HTML Form Controls</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Microsoft Edge Blog</a> <span class="article__date">16 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>If you build a web application, chances are good that you’ve received user requests for dark mode support in the past couple of years. While some users may simply prefer the aesthetics of dark UI, others may find that dark mode helps ease eye strai</p>
<p>The post <a rel="nofollow" href="https://blogs.windows.com/msedgedev/2021/06/16/dark-mode-html-form-controls/">Dark Mode for HTML Form Controls</a> appeared first on <a rel="nofollow" href="https://blogs.windows.com/msedgedev">Microsoft Edge Blog</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">665</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Extra Ordinary</a> <span class="article__date">16 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://cdn.evilmartians.com/front/blocks/common/images/social-5e5bfff.png" alt="AnyCable Goes Pro: Fast WebSockets for Ruby, at scale">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AnyCable Goes Pro: Fast WebSockets for Ruby, at scale</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Martian Chronicles, Evil Martians’ team blog</a> <span class="article__date">16 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Update to the FSF and GNU&#39;s plan to move IRC channels to Libera.Chat</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FSF News</a> <span class="article__date">15 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Nos vamos al Congreso esLibre 2021">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Nos vamos al Congreso esLibre 2021</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">15 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>En este episodio Andros Fenollosa y David Vaquero hablan sobre la edición del <a href="https://eslib.re/2021/" data-type="URL" data-id="https://eslib.re/2021/">Congreso esLibre 2021,</a> una nueva edición en formato virtual, sobre tecnologías libres enfocadas a compartir conocimiento. Esta edición contará con la participación de una charla de Andros sobre su sistema Glosa de comentarios para sitios estáticos y un taller de David sobre su contenedor Docker para Drupal.</p>



<p>En el episodio también se habla sobre la participación de algunas personas que han pasado por el podcast como <a href="https://republicaweb.es/podcast/los-amos-de-internet-con-eduardo-collado/" data-type="URL" data-id="https://republicaweb.es/podcast/los-amos-de-internet-con-eduardo-collado/">Eduardo Collado</a>, <a href="https://republicaweb.es/podcast/virtualizacion-y-contenedores-con-sergio-lopez/" data-type="URL" data-id="https://republicaweb.es/podcast/virtualizacion-y-contenedores-con-sergio-lopez/">Sergio López</a>, <a href="https://republicaweb.es/podcast/aprendiendo-rust-con-lorenzo-carbonell-atareao/" data-type="URL" data-id="https://republicaweb.es/podcast/aprendiendo-rust-con-lorenzo-carbonell-atareao/">Lorenzo Carbonell</a>, <a href="https://republicaweb.es/podcast/wikimedia-es-mucho-mas-que-wikipedia-con-ruben-ojeda/" data-type="URL" data-id="https://republicaweb.es/podcast/wikimedia-es-mucho-mas-que-wikipedia-con-ruben-ojeda/">Rubén Ojeda</a> o <a href="https://republicaweb.es/podcast/estado-del-ecosistema-php-con-jesus-amieiro/" data-type="URL" data-id="https://republicaweb.es/podcast/estado-del-ecosistema-php-con-jesus-amieiro/">Jesús Amieiro</a>. Como ha comentado David Vaquero con anterioridad, en esta edición se ha apostado por involucrar a la comunidad en español de podcasts tecnológicos, para lograr dar mayor difusión a los contenidos del Congreso.</p>



<p></p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://blogs.windows.com/wp-content/uploads/prod/sites/33/2021/06/cropped-browser-icon-logo-32x32.jpg" alt="Improving contrast in Microsoft Edge DevTools: A bugfix case study">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Improving contrast in Microsoft Edge DevTools: A bugfix case study</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Microsoft Edge Blog</a> <span class="article__date">15 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Creating accessible products means most of all being aware of the usability issues your designs and code can cause. When creating new products, Microsoft follows a strict workflow of accessibility reviews of designs, code reviews and mandatory audits</p>
<p>The post <a rel="nofollow" href="https://blogs.windows.com/msedgedev/2021/06/15/improving-contrast-in-microsoft-edge-devtools-a-bugfix-case-study/">Improving contrast in Microsoft Edge DevTools: A bugfix case study</a> appeared first on <a rel="nofollow" href="https://blogs.windows.com/msedgedev">Microsoft Edge Blog</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://i0.wp.com/stratechery.com/wp-content/uploads/2018/03/cropped-android-chrome-512x512-1.png?fit=32%2C32&amp;ssl=1" alt="The Cicilline Salvo">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Cicilline Salvo</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Stratechery by Ben Thompson</a> <span class="article__date">15 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A package of new proposed laws for regulating tech companies are in part a negotiating ploy, but also an indicator of change.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2021/220-measure-twice-cut-once.png" alt="Measure Twice, Cut Once">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Measure Twice, Cut Once</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">15 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2021/220-measure-twice-cut-once.png" alt="Measure Twice Cut Once" title="test" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Importance of Learning CSS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">13 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I know so many super-talented developers who share the same achilles heel: CSS. Instead of trying to “outrun” CSS, this article explores why leaning in and going deeper can be a tremendous boon for your development life and your career.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">FSF and GNU move official IRC channels to Libera.Chat network</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FSF News</a> <span class="article__date">11 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure Deref (June 11, 2021)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">11 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Welcome to the Clojure Deref! This is a periodic link/news roundup for the Clojure ecosystem. (<a href="https://clojure.org/feed.xml">RSS feed</a>)</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_highlights"><a class="anchor" href="#_highlights"></a>Highlights</h2>
<div class="sectionbody">
<div class="paragraph">
<p>This week <a href="https://www.reuters.com/article/us-nubank-funding-berkshire-idUSKCN2DK1FI">Nubank announced</a> a new $750M investment, led by $500M from Berkshire Hathaway at a $30B valuation. Nubank is the largest user of Clojure and Datomic in the world and a great example of the benefits of Clojure&#8217;s approach to managing complexity at scale.</p>
</div>
<div class="paragraph">
<p>Chris Nuernberger <a href="https://www.youtube.com/watch?v=5mUGu4RlwKE">presented a great talk</a> this week for London Clojurians about his work on high performance data processing with the <a href="https://github.com/cnuernber/dtype-next">dtype-next</a> and <a href="https://github.com/techascent/tech.ml.dataset">tech.ml.dataset</a> libraries.</p>
</div>
<div class="paragraph">
<p>The <a href="https://clojured.de/">ClojureD conference</a> last weekend was great with lots of interesting Clojure (and some non-Clojure) talks! Keep an eye out for videos soon.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_podcasts"><a class="anchor" href="#_podcasts"></a>Podcasts</h2>
<div class="sectionbody">
<div class="paragraph">
<p>We have a bumper crop of Clojure-related podcast episodes this week, put these in your ears&#8230;&#8203;</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://www.cognitect.com/cognicast/160">Cognicast</a> - Christian Romney interviews Jarrod Taylor from the Datomic team</p>
</li>
<li>
<p><a href="https://getsmarterandmakestuff.com/2021/06/06/podcast-episode-005-michael-fogus/">Get Smarter and Make Stuff</a> - Craig Andera interviews Michael Fogus from the Clojure core team</p>
</li>
<li>
<p><a href="https://anchor.fm/lostinlambduhhs/episodes/puredanger-Alex-Miller&#8212;&#8203;Clojures-Cool-dad-e12botj">Lost in Lambduhhs</a> - Jordan Miller interviews Alex Miller from the Clojure core team</p>
</li>
<li>
<p><a href="https://clojurescriptpodcast.com/">ClojureScript Podcast</a> - Jacek Schae interviews Tommi Reiman about Malli</p>
</li>
<li>
<p><a href="https://soundcloud.com/defn-771544745/72-chris-badahdah-from-phoenix">defn</a> - Vijay Kiran and Ray McDermott interview Chris Badahdah about Portal</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_libraries_and_databases"><a class="anchor" href="#_libraries_and_databases"></a>Libraries and Databases</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Some interesting library updates and posts this week:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/mcorbin/mirabelle">Mirabelle</a> - 0.1.0 of this stream processing tool inspired by Riemann - check out the <a href="https://www.mirabelle.mcorbin.fr/">docs</a> and a <a href="https://www.mcorbin.fr/posts/2021-06-07-mirabelle-cabourotte-blackbox/">use case</a></p>
</li>
<li>
<p><a href="https://github.com/sicmutils/sicmutils">sicmutils</a> - Sam Ritchie released version 0.19.0 of this math and physics based library (based on the books by Sussman and Wisdom)</p>
</li>
<li>
<p><a href="https://github.com/kiranshila/cybermonday">Cybermonday</a> - Kiran Shila releases the first release of this Clojure data interface to Markdown (like Hiccup for Markdown)</p>
</li>
<li>
<p><a href="https://github.com/graphqlize/honeyeql/">HoneyEQL</a> - Tamizhvendan S introduced <a href="https://cljdoc.org/d/org.graphqlize/honeyeql/0.1.0-alpha36/doc/readme">0.1.0-alpha36</a> for EQL queries to relational databases</p>
</li>
<li>
<p><a href="https://github.com/clojure-expectations/clojure-test">Expectations</a> - Sean Corfield released <a href="https://cljdoc.org/d/com.github.seancorfield/expectations/2.0.0-alpha2/doc/readme">2.0.0-alpha2</a> of this clojure.test-compatible implementation of Expectations</p>
</li>
<li>
<p><a href="https://github.com/CrypticButter/snoop">Snoop</a> - Luis Thiam-Nye announced the initial release of a library for runtime function validation using Malli</p>
</li>
<li>
<p><a href="https://clojurelog.github.io/">OSS Clojure DBs</a> - a summary and comparison of open-source Clojure databases (but don&#8217;t forget <a href="https://www.datomic.com">Datomic</a>! :)</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_blogs_discussions_tutorials"><a class="anchor" href="#_blogs_discussions_tutorials"></a>Blogs, discussions, tutorials</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p><a href="https://shaunlebron.github.io/t3tr0s-slides/#0">Tetris in ClojureScript</a> - by Shaun Lebron</p>
</li>
<li>
<p><a href="http://hariomgaur.in/2021/06/06/consume-from-kafka.html">Apache Kafka &amp; Ziggurat</a> - Ziggurat is an event stream processing tool written in Clojure and this article shows how to use it to consume events from Kafka</p>
</li>
<li>
<p><a href="https://lambdaisland.com/blog/2021-06-04-clojure-beginners-just-like-vegans-searching-for-good-cheese">Why are Clojure beginners just like vegans searching for good cheese?</a> - on Lambda Island</p>
</li>
<li>
<p><a href="https://github.com/prestancedesign/pingcrm-clojure">Ping CRM on Clojure</a> - a demo of implementing Ping CRM on Clojure+ClojureScript</p>
</li>
<li>
<p><a href="https://clojureverse.org/t/organizing-clojure-code-a-real-problem/7567">Organizing Clojure code</a> - a discussion from Clojureverse</p>
</li>
<li>
<p><a href="https://markm208.github.io/cljbook/">An Animated Introduction to Clojure</a> - by Mark Mahoney</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_throwback_friday_i_know_im_doing_it_wrong"><a class="anchor" href="#_throwback_friday_i_know_im_doing_it_wrong"></a>Throwback Friday (I know, I&#8217;m doing it wrong)</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In this recurring segment, we harken back to a talk from an older time to a favorite talk of yore. This week, we&#8217;re featuring:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://www.youtube.com/watch?v=ShEez0JkOFw">Clojure: Programming with Hand Tools</a> by Tim Ewald</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Is it about woodworking? Is it about Clojure? Is it about how to work? Yes.</p>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://github.blog/wp-content/uploads/2019/01/cropped-github-favicon-512.png?fit=32%2C32" alt="Blacktocats turn five">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Blacktocats turn five</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The GitHub Blog</a> <span class="article__date">10 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        What began as a small group effort in 2015 has now turned into a global initiative here at GitHub to amplify Black voices and talent in the tech community. 
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://github.blog/wp-content/uploads/2019/01/cropped-github-favicon-512.png?fit=32%2C32" alt="What’s new from GitHub Changelog? May 2021 Recap">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">What’s new from GitHub Changelog? May 2021 Recap</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The GitHub Blog</a> <span class="article__date">10 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        In May, GitHub shipped a total of 20 new features. We love what we do, but we know it’s a lot to keep up with. So we’re trying something new on the GitHub Blog—a monthly recap of everything that shipped to Changelog in the past month. Check out some of the updates you might have missed.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://github.blog/wp-content/uploads/2019/01/cropped-github-favicon-512.png?fit=32%2C32" alt="Privilege escalation with polkit: How to get root on Linux with a seven-year-old bug">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Privilege escalation with polkit: How to get root on Linux with a seven-year-old bug</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The GitHub Blog</a> <span class="article__date">10 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        polkit is a system service installed by default on many Linux distributions. It’s used by systemd, so any Linux distribution that uses systemd also uses polkit. As a member of GitHub Security Lab, my job is to help improve the security of open source software by finding and reporting vulnerabilities. A few weeks ago, I found a privilege escalation vulnerability in polkit. 
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Becoming a Software Developer Without a CS Degree</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">10 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A look at how hundreds of developers got their start in the industry despite not having a Computer Science or Software Engineering degree. We'll sort responses into 6 categories, and detail strategies that you can use to ensure you capture the attention of potential employers!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Announcing “use-sound”, a React Hook for Sound Effects</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">10 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        By and large, using the web is a visual experience. This is in terrible contrast to mobile apps, which interact with three of our human senses (sight, sound, and touch, through haptic feedback). I just released a library to make it easy to add sound to your React app, and I make the case that you should consider using it!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Boop!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">10 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        An in-depth tutorial that teaches how to create one of the most adorable interactions I've ever created. We'll learn how to use React components and hooks to abstract behaviours, and see how to design the perfect API. Even if you're not into animations, I think you'll find it interesting!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Let&#39;s Bring Spacer GIFs Back!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">10 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The 90s web gave us many delightful things: web rings, guestbooks, “under construction” animations, and spacer GIFs. In this article, we'll see how I use a Spacer component to solve common layout problems, and why it's often a great tool for the job in the modern web.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Let&#39;s Learn About Aspect Ratio In CSS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Ahmad Shadeed Blog</a> <span class="article__date">10 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Rules of Margin Collapse</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">09 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        “Margin collapse” has a dastardly reputation, one of the trickier parts of CSS. Fortunately, it gets a lot easier once you learn a few rules! In this tutorial, we take a deep dive into the governing principles, and learn how to use them to our advantage.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">An Interactive Guide to CSS Transitions</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">09 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        This comprehensive guide shows how to use CSS transitions! A back-to-basics look at the fundamental building blocks we need to create microinteractions and other animations.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">What the heck, z-index??</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">09 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The z-index property can be a tricky little bugger. Sometimes, no matter how much you crank up the number, the element never rises to the top! In this article, we explore stacking contexts, and see how they can thwart our efforts to use z-index. We'll also learn how to use this mechanism to our advantage.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Building a Magical 3D Button</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">09 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Every action we take on the web starts with a button click, and yet most buttons are ho-hum and uninspired. In this tutorial, we'll build an animated 3D button with HTML and CSS that sparks joy.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How I Built My Blog</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">09 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        An in-depth look at the technical stack behind this very blog! We'll see how I use Next's API routes to implement my hit and like counters, how I use MDX to add interaction and customization, and how I organize my codebase, among others.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">664</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Extra Ordinary</a> <span class="article__date">09 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Resolviendo side-effects en React</h1>
                            <h2 class="article__feed"><a target="_blank" href="">En Mi Local Funciona</a> <span class="article__date">09 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        El uso de side-effects en nuestro estado de React es un problema resuelto con muchas soluciones. Queremos ayudarte a encontrar la mejor para tu proyecto.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://i0.wp.com/stratechery.com/wp-content/uploads/2018/03/cropped-android-chrome-512x512-1.png?fit=32%2C32&amp;ssl=1" alt="Integrated Apple and App Store Risk">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Integrated Apple and App Store Risk</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Stratechery by Ben Thompson</a> <span class="article__date">08 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        WWDC highlighted how Apple's differentiation is based on integration; the company ought not risk that differentiation for exploitive App Store policies.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2021/219-exposed.png" alt="Exposed">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Exposed</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">08 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2021/219-exposed.png" alt="Exposed" title="Programming is not about typing, it's about thinking. - Rich Hickey" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">
Data Platform Engineer
</h1>
                            <h2 class="article__feed"><a target="_blank" href="">
Brave Clojure Jobs
</a> <span class="article__date">07 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<div><h1>Data Platform Engineer</h1><div class="company-name">Analytical Flavor Systems | Remote/NY,NY</div><div>remote</div><div><em>Advancing sensory science and reaching new taste buds</em></div><div>$120000 - $180000</div><div><a href="https://gastrograph.com/">https://gastrograph.com/</a></div><br /><div><h2>Description</h2><p>Analytical Flavor Systems is a venture-backed startup that models human sensory perception of flavor, aroma, and texture using proprietary machine learning in order to predict consumer preference of food and beverage products. The work we do allows our clients in the food &#38; beverage industry to ask and answer questions about:</p>
<ul>
  <li>their competitive landscape ("what do people like and dislike about my competitors' products?")</li>
  <li>optimizing existing products ("how can I make this cookie taste better?")</li>
  <li>novel flavor combinations for new product development ("would people like it if I combined matcha and strawberry in yogurt?")</li>
</ul><p>Our data science capabilities are evolving from report generation to a data platform. That's where you come in.</p><p>The work expected of a data platform engineer at Analytical Flavor Systems covers several major areas:</p>
<ul>
  <li>Building out a data model on Datomic to capture the information generated by our day-to-day data processing tasks in an immutable and readily queryable data store.</li>
  <li>Creating a data platform application layer to serve the needs of our data science team, our web console and our mobile data collection app.</li>
  <li>Rewriting existing data science code for execution in a distributed rather than single-machine environment.</li>
  <li>Maintaining and enhancing batch processing jobs to make them faster, more reliable, and more observable.</li>
  <li>Refactoring an existing codebase to be more modular: separating data transformations, modeling, and prediction steps into discrete functions with well-understood inputs and outputs, while testing for regressions in predictive capabilities.</li>
</ul><p>Depending on your background and areas of expertise, your day-to-day work may focus more on one of these areas than others, but you should be able to keep the big picture in mind, and understand how the changes you make to one part of our system affect the whole. Your work will improve our ability to execute this code reliably, and replicate previous results. This work will also help us observe and capture the outputs of the analytical operations we perform so we get better insight into the state of the systems built atop our data science code.</p><p>You will be expected to become comfortable working in both Clojure and R, though no prior experience in R is required. This role offers you the chance to help develop the language of our research domain, which may help us identify potential new avenues of theoretical research in human sensory perception. </p><p>We are only considering candidates with USA work authorization or work visa (including OPT). AFS can sponsor H1-B renewals or transfers. </p><h2>Requirements</h2><p><strong>​</strong>Candidates should have at least 4 years of total programming experience, with at least 1 year of work in either a data engineering context or in building backend systems. Experience with Clojure or other functional programming languages is a plus, but not a requirement. Functional programming is as much a style and idiom of development as it is a family of languages. Candidates that have experience building modular systems that put data front and center, regardless of the implementation language, should be attracted to this role.</p><p>Candidates with experience supporting the work of researchers and data scientists are also strongly encouraged to apply. Have you made an analytical method production-ready after reading through someone else's prototype code? Are you interested in interoperability between R and Clojure? Have you helped deploy and monitor models in production? Experience with these questions gives you a good understanding of the requirements and scope of the systems we build.</p><p>The company is roughly 15 people total, so candidates will be working closely with other teams and areas of the business. Good communication skills, especially across varying levels of technical depth and skill, are preferred.</p><p>A good candidate should have experience in at least two of the following areas:</p>
<ul>
  <li><strong>Data science and analytics</strong>: you have enabled more powerful access to data for both technical and non-technical stakeholders. You understand how to support and enhance systems based on machine learning, and aren't afraid of diving in to build a more efficient implementation of an algorithm than one provided by a library.</li>
  <li><strong>Data modeling:</strong> you have, either on your own or as part of a team, designed or extended a relational database schema to support application and business requirements.</li>
  <li><strong>System design and maintenance:</strong> you know how to build and extend existing systems to make them more observable, fault-tolerant, and performant. You can ssh into a remote box to contextualize a problem that doesn't have an obvious cause.</li>
  <li><strong>Automated QA and testing</strong>: you know what the invariant properties of both individual functions and system components are, and can represent those properties in code.</li>
</ul><h2>Benefits</h2>
<ul>
  <li>Competitive salary</li>
  <li>Standard benefits package (health insurance/vision/dental + 401k)</li>
  <li>Equity stake (Restricted Stock Units with 4-year annual vesting schedule)</li>
  <li>Remote-friendly (who isn't these days?). While we do plan on an eventual return to our office space in Manhattan once it's safe, immediate relocation to the NYC area is not an expectation of this role.</li>
  <li>That said, if you do end up in our NYC office you'll be able to join regular in-person tasting panels to get hands-on experience with the sensory data collection methods we use.</li>
  <li>Unlimited vacation policy</li>
  <li>Professional development budget</li>
</ul></div></div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cómo instalar Git en Centos 7</h1>
                            <h2 class="article__feed"><a target="_blank" href="">ochobitshacenunbyte</a> <span class="article__date">07 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Aprendemos a instalar Git en Centos 7. Aunque este programa de control de versiones ya viene en los repositorios de Centos o de Red Hat, si utilizamos la distribución del sombrero rojo, lo cierto&#46;&#46;&#46;</p>
<p>La entrada <a rel="nofollow" href="https://www.ochobitshacenunbyte.com/2021/06/07/como-instalar-git-en-centos-7/">Cómo instalar Git en Centos 7</a> se publicó primero en <a rel="nofollow" href="https://www.ochobitshacenunbyte.com">ochobitshacenunbyte</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://programadorwebvalencia.com/img/blog/2021/06/twing.png" alt="Tutorial rápido de Twing para PHP">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Tutorial rápido de Twing para PHP</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Programador Web Valencia</a> <span class="article__date">06 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://programadorwebvalencia.com/img/blog/2021/06/twing.png" alt="Twing" class="medium" /></p>

<p>Trabajar con un <strong>motor de plantillas en PHP</strong> simplifica la labor de concadenar variables en ficheros con mucho texto, como puede ser un <code class="highlighter-rouge">html</code>. Cualquier Framework que imagines incorpora un sistema similar pero podemos usarlo de manera independiente para <strong>pequeñas páginas o funcionalidades</strong>.</p>

<p>Primero debemos instalar <code class="highlighter-rouge">Twig</code> en su versión más reciente en la raíz del proyecto. Esto lo podemos realizar con <code class="highlighter-rouge">composer</code>.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>composer require <span class="s2">"twig/twig:^3.0"</span>
</code></pre></div></div>

<p>Ahora creamos una carpeta donde almacenaremos todas las plantillas.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir </span>templates
</code></pre></div></div>

<p>Dentro creamos el archivo <code class="highlighter-rouge">contacto.txt</code> con el siguiente contenido.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
Hola {{ nombre }},
gracias por escribirnos desde {{ email }} con el asunto "{{ asunto }}".
¡Nos vemos!

</code></pre></div></div>

<p>Como es un ejemplo, vamos a crear otro archivo, llamado <code class="highlighter-rouge">contacto.html</code>,  con el contenido:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="nt">&lt;h1&gt;</span>Hola {{ nombre }},<span class="nt">&lt;/h1&gt;</span>
<span class="nt">&lt;p&gt;</span>gracias por escribirnos desde {{ email }} con el asunto "{{ asunto }}".<span class="nt">&lt;/p&gt;</span>
<span class="nt">&lt;p&gt;</span>¡Nos vemos!<span class="nt">&lt;/p&gt;</span>

</code></pre></div></div>

<p>Todas las variables entre <code class="highlighter-rouge">{{ }}</code> serán sustituidas por las variables que se definan. Si no ha quedado claro en breve lo entenderás.</p>

<p>En estos momentos disponemos de 2 plantillas con diferentes extensiones y formatos. No es obligatorio disponer de varias plantillas, busque aprecies que funciona de manera independiente con cualquier formato en texto plano.</p>

<p>Ahora creamos un archivo PHP donde ejecutaremos el código. Podemos llamarlo, por ejemplo, <code class="highlighter-rouge">renderizar.php</code>. Añadimos:</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Cargamos todas las extensiones. En este caso solo disponemos de Twig</span>
<span class="k">require_once</span><span class="p">(</span><span class="s1">'vendor/autoload.php'</span><span class="p">);</span>
<span class="c1">// Indicamos en Twig el lugar donde estarán las plantillas.</span>
<span class="nv">$loader</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">\Twig\Loader\FilesystemLoader</span><span class="p">(</span><span class="s1">'templates'</span><span class="p">);</span>
<span class="c1">// Cargamos las plantillas al motor de Twig</span>
<span class="nv">$twig</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">\Twig\Environment</span><span class="p">(</span><span class="nv">$loader</span><span class="p">);</span>
<span class="c1">// Definimos las variables que deseamos rellenar en las plantillas.</span>
<span class="nv">$variablesEmail</span> <span class="o">=</span> <span class="p">[</span>
    <span class="s1">'nombre'</span> <span class="o">=&gt;</span> <span class="s1">'Cid'</span><span class="p">,</span>
    <span class="s1">'email'</span> <span class="o">=&gt;</span> <span class="s1">'cid@campeador.vlc'</span><span class="p">,</span>
    <span class="s1">'asunto'</span> <span class="o">=&gt;</span> <span class="s1">'Reconquista'</span>
<span class="p">];</span>
<span class="c1">// Renderizamos con la plantilla 'contacto.txt'</span>
<span class="nv">$plantillaPlana</span> <span class="o">=</span>  <span class="nv">$twig</span><span class="o">-&gt;</span><span class="na">render</span><span class="p">(</span><span class="s1">'contacto.txt'</span><span class="p">,</span> <span class="nv">$variablesEmail</span><span class="p">);</span>
<span class="c1">// Renderizamos con la plantilla 'contacto.html'</span>
<span class="nv">$plantillaHTML</span> <span class="o">=</span>  <span class="nv">$twig</span><span class="o">-&gt;</span><span class="na">render</span><span class="p">(</span><span class="s1">'contacto.html'</span><span class="p">,</span> <span class="nv">$variablesEmail</span><span class="p">);</span>
</code></pre></div></div>

<p>Si yo hiciera un <code class="highlighter-rouge">echo</code> de cada variable podemos ver el trabajo realizado.</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">echo</span> <span class="nv">$plantillaPlana</span><span class="p">;</span>
<span class="cd">/**
Hola Cid,
gracias por escribirnos desde cid@campeador.vlc con el asunto "Reconquista".
¡Nos vemos!
**/</span>
</code></pre></div></div>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">echo</span> <span class="nv">$plantillaHTML</span><span class="p">;</span>
<span class="cd">/**
&lt;h1&gt;Hola Cid,&lt;/h1&gt;
&lt;p&gt;gracias por escribirnos desde cid@campeador.vlc con el asunto "econquista".&lt;/p&gt;
&lt;p&gt;¡Nos vemos!&lt;/p&gt;
**/</span>
</code></pre></div></div>

<p>Y eso es todo.</p>

<p>Es realmente <strong>interesante para trabajar con emails</strong>, plantillas más complejas o en la búsqueda de renderizar un PDF. Sea cual sea tu objetivo final, disponer de <strong>un motor de plantillas en PHP hará más fácil tu trabajo</strong>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/wp-content/uploads/2021/06/encuesta-telegram.png" alt="Porqué cambiamos de trabajo en tecnología">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Porqué cambiamos de trabajo en tecnología</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">05 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>A diferencia de otros sectores, los profesionales de las habilidades relacionadas con la tecnología, suelen contar con más opciones y oportunidades laborales. Por si fuera poco ese mercado de programadores, desarrolladores y consultores tecnológicos, opta desde hace tiempo, a trabajos en remoto y a condiciones laborales que durante la pandemia han experimentado un notable auge.</p>



<p>Los developers&#160; están por tanto en una especie de burbuja laboral, donde a la hora de valorar un puesto de trabajo o un cambio, existen diferentes motivaciones que merece la pena discutir.</p>



<p>En este episodio queremos hablar sobre los motivos que tienen los developers a la hora de afrontar cambios laborales y el punto de vista que a menudo tienen con respecto a su vida profesional. Aunque en muchas ocasiones esas motivaciones coincidan con otros perfiles profesionales, creemos muy interesante poder contar las experiencias o casos que hayamos visto o vivido.</p>



<figure class="wp-block-image size-large img-responsive"><img loading="lazy" width="782" height="734" src="/wp-content/uploads/2021/06/encuesta-telegram.png" alt="" class="wp-image-2479" srcset="https://republicaweb.es/wp-content/uploads/2021/06/encuesta-telegram.png 782w, https://republicaweb.es/wp-content/uploads/2021/06/encuesta-telegram-300x282.png 300w, https://republicaweb.es/wp-content/uploads/2021/06/encuesta-telegram-768x721.png 768w" sizes="(max-width: 782px) 100vw, 782px" /><figcaption>Resultados de la encuesta en el grupo Malditos Webmasters Telegram</figcaption></figure>



<blockquote class="twitter-tweet" sytle="margin-top:40px;margin-bottom:40px"><p lang="es" dir="ltr">El próximo episodio del podcast irá sobre los motivos que llevan a los «developers» a cambiar de trabajo. ¿Qué te motiva **principalmente** para valorar un cambio de trabajo?</p>— Podcast República Web (@republicawebes) <a href="https://twitter.com/republicawebes/status/1400775003923169280?ref_src=twsrc%5Etfw">June 4, 2021</a></blockquote> <script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure Deref (June 4, 2021)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">04 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Welcome to the Clojure Deref! This is a new periodic (thinking bi-weekly) link/news roundup for the Clojure ecosystem. We&#8217;ll be including links to Clojure articles, Clojure libraries, and when relevant, what&#8217;s happening in the Clojure core team.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_highlights"><a class="anchor" href="#_highlights"></a>Highlights</h2>
<div class="sectionbody">
<div class="paragraph">
<p><a href="https://clojurescript.org/">ClojureScript</a> turns 10 this week! Happy birthday ClojureScript! :cake: We mark this from the <a href="https://github.com/clojure/clojurescript/commit/515900f9762102987bda7d53b919dafc0b6c0580">first commit</a> by Rich Hickey in the repo. Several thousand commits later things are still going strong and David Nolen and Mike Fikes continue to lead the project. ClojureScript recently released version <a href="https://github.com/clojure/clojurescript/blob/master/changes.md#110866">1.10.866</a>.</p>
</div>
<div class="paragraph">
<p>The <a href="https://stackoverflow.com/dev-survey/start">StackOverflow developer&#8217;s survey</a> for 2021 just opened. Last year they removed Clojure from the survey because they were scared we were growing too powerful (I assume). But this year&#8217;s survey includes Clojure as an option again, so let them know you&#8217;re out there! (It also seems a lot shorter this year.)</p>
</div>
<div class="paragraph">
<p>The <a href="https://clojured.de/">:clojureD Conference</a> is just hours away! Ticket sales have ended but presumably talks will be made available afterwards. If you&#8217;re going, we&#8217;ll see you there!</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_experience_reports"><a class="anchor" href="#_experience_reports"></a>Experience reports</h2>
<div class="sectionbody">
<div class="paragraph">
<p>This week we saw several interesting Clojure experience reports worth mentioning:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Red Planet Labs <a href="https://tech.redplanetlabs.com/2021/06/03/tour-of-our-250k-line-clojure-codebase/">gave an overview</a> of their codebase and some of the techniques they use pervasively - using Schema, monorepo, Specter for polymorphic data, Component, with-redefs for testing, macros and more.</p>
</li>
<li>
<p>Jakub Holý at Telia talked about the importance of <a href="https://engineering.telia.no/blog/slow-restarts-rescued-by-clojure">interactive development with Clojure</a>.</p>
</li>
<li>
<p>Crossbeam did a talk at Philly Tech Week about <a href="https://technical.ly/philly/2021/06/04/crossbeam-clojure/">why they bet on Clojure</a> and their experience with hiring.</p>
</li>
<li>
<p>Shivek Khurana talked about <a href="https://shivekkhurana.medium.com/mysterious-clojure-jobs-and-where-to-find-them-f784ebab4dea">how to find a job using Clojure</a>. There are now many companies using and hiring for Clojure, although sometimes it&#8217;s challenging to find a Clojure job that is a good match for your location and/or experience - these are some great tips!</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_libraries"><a class="anchor" href="#_libraries"></a>Libraries</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Some interesting library updates and posts this week:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/threatgrid/asami">Asami</a> - Paula Gearon wrote a <a href="https://github.com/threatgrid/asami/wiki/Introduction">nice overivew of querying graph dbs</a></p>
</li>
<li>
<p>Joe Littlejohn at Juxt wrote an overview of the <a href="https://www.juxt.pro/blog/json-in-clojure">Clojure JSON ecosystem</a> covering many popular libraries and their tradeoffs</p>
</li>
<li>
<p><a href="https://github.com/oakes/odoyle-rules">odoyle-rules</a> - Zach Oakes added a new section on <a href="https://github.com/oakes/odoyle-rules#defining-rules-dynamically">defining rules dynamically</a></p>
</li>
<li>
<p><a href="https://vlaaad.github.io/reveal/">Reveal</a> - Vlad wrote about viewing Vega charts in Reveal</p>
</li>
<li>
<p><a href="https://github.com/wilkerlucio/pathom">Pathom</a> - Wilker Lucio gives some <a href="https://blog.wsscode.com/pathom-updates-10/">updates on many features</a></p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_art"><a class="anchor" href="#_art"></a>Art</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>As always Jack Rusher has been up to making beautiful art with Clojure, in particular exploring 3D rendered attractors like the <a href="https://twitter.com/jackrusher/status/1398336040260231171">Golden Aizwa Attractor</a> (the <a href="https://twitter.com/jackrusher/status/1398368701058011141">Clojure code</a>) and <a href="https://twitter.com/jackrusher/status/1398573268894900227">Three-Scroll Uunified Attractor</a>, and <a href="https://twitter.com/jackrusher/status/1398674759110561798">one made in bone</a>. Hit his <a href="https://twitter.com/jackrusher">feed</a> for lots more cool projects, often made with Clojure.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_feedback"><a class="anchor" href="#_feedback"></a>Feedback</h2>
<div class="sectionbody">
<div class="paragraph">
<p>You can find future episodes on the <a href="https://clojure.org/feed.xml">RSS feed</a> for this blog. Should it be an email newsletter too?</p>
</div>
<div class="paragraph">
<p>Let us know!</p>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2021/218-loading-weekend.png" alt="Loading Weekend">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Loading Weekend</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">04 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2021/218-loading-weekend.png" alt="Loading Weekend" title="Fixing issues is a wonderful way to spend a Friday night" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://i0.wp.com/stratechery.com/wp-content/uploads/2018/03/cropped-android-chrome-512x512-1.png?fit=32%2C32&amp;ssl=1" alt="Passport">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Passport</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Stratechery by Ben Thompson</a> <span class="article__date">03 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Announcing Passport, the new infrastructure supporting Stratechery.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Introducing the Open Source Insights Project</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">03 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">
Senior Software Developer
</h1>
                            <h2 class="article__feed"><a target="_blank" href="">
Brave Clojure Jobs
</a> <span class="article__date">03 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<div><h1>Senior Software Developer</h1><div class="company-name">LegalMate | Toronto || Anywhere</div><div>remote</div><div><em>We are bringing progressive and modern financial services to the legal world.</em></div><div>$110000 - $140000</div><div><a href="https://legalmate.co">https://legalmate.co</a></div><br /><div><h1>About LegalMate</h1><p><strong>Our mission is make access to justice affordable.</strong> In North America, almost <strong>$400 billion dollars</strong> is spent <strong>every year</strong> on legal services, yet <strong>86%</strong> of of civil legal problems faced by low-income individuals receive either <strong>inadequate</strong> or <strong>no legal help at all</strong>. The legal system is intended to benefit us all, not just the top 10% of income earners.</p><p>We are bringing progressive and modern financial services to the legal world, opening the door for more people to access legal services and seek justice.</p>
<ul>
  <li>We're VC-backed and well capitalized</li>
  <li>We have paying customers and exciting MoM growth</li>
  <li>Our founding team has an exceptional track record</li>
  <li>($2.5 <strong>billion</strong> in shareholder value created in previous 3 ventures)</li>
  <li>Our first product is "Buy Now Pay Later" for legal services: think <strong>Affirm for lawyers</strong></li>
</ul><h1>Role &#38; Responsibilities</h1><p>This is the first full-time hire on our engineering team, apart from our CTO. Consequently, candidates should expect a high degree of trust and autonomy. We intend to do great work together over the long-term, and we insist that anybody joining LegalMate at this stage is ready to grow with the company and take on more responsibility as we scale.</p><p>We are a Clojure shop and are looking to work with engineers eager to apply functional programming concepts. <strong>We are happy to train folks up on Clojure!</strong></p>
<ol>
  <li>Write production-grade Clojure and ClojureScript</li>
  <li>Review code, and provide constructive and useful feedback</li>
  <li>Create and collaborate on technical designs, document them</li>
  <li>Coach and mentor junior Clojurians in the making</li>
</ol>
<ul>
  <li>Introducing new developers to Clojure is a <strong>critical</strong> to our strategy</li>
</ul>
<ol>
  <li>Elevate the test-ability and re-usability of existing code</li>
  <li>Help evaluate and hire additional engineering team members (in the future)</li>
</ol><h1>Recommended Experience</h1><p>These are provided for you to understand the relative skill and experience level of the candidates we're seeking. If you don't meet or exceed these 100%, that's OK! Please consider applying regardless.</p>
<ul>
  <li>5+ yrs of professional software development experience (Clojure or otherwise)</li>
  <li>2+ yrs of Clojure development experience (professional or hobby)</li>
  <li>Previous experience working on small teams that scaled up</li>
  <li>You have a track record of leading successful projects</li>
  <li>You can give concrete examples of when you've received some hard feedback, and when you've had to deliver some hard feedback too</li>
</ul><h1>About You</h1><p>This role is ideal for a senior developer who's comfortable with Clojure (or wants to learn), and who wants to participate in building and growing a world-class engineering team and company.</p>
<ul>
  <li>You're more motivated to help humans than you are to solve coding puzzles</li>
  <li>You're comfortable with Clojure idioms (or want to learn) and functional programming concepts</li>
  <li>The idea of working with functional programming (Clojure) full-time is exciting and motivating</li>
  <li>You use data to help make decisions and inform designs</li>
  <li>You know how to manage your energy and time</li>
</ul><h3>Nice-to-have Qualities You Might Have</h3>
<ul>
  <li>You have prior experience in financial technology, or legal technology</li>
  <li>To you, working on legal financial tech doesn't sound boring: it sounds awesome</li>
  <li>You're ready to quit programming if you don't get to use functional programming in you're next position</li>
</ul></div></div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://cdn.evilmartians.com/front/blocks/common/images/social-5e5bfff.png" alt="Premium design: Building a mobile app for Loewe">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Premium design: Building a mobile app for Loewe</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Martian Chronicles, Evil Martians’ team blog</a> <span class="article__date">03 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">
Remote Clojure Developer
</h1>
                            <h2 class="article__feed"><a target="_blank" href="">
Brave Clojure Jobs
</a> <span class="article__date">02 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<div><h1>Remote Clojure Developer</h1><div class="company-name">Insight Global | US Based</div><div>remote</div><div>$135000 - $165000</div><div><a></a></div><br /><div><p>Do you like solving interesting problems? Are you passionate about working in one of the fastest growing product lines in the cybersecurity industry? Want a competitive salary and benefits to support a stable, high-quality life outside of work? Want to work for an organization that will assist in developing your skills, talents, help you grow? Are you someone who wants flexibility and good work/life balance? Do you love working from home?</p><p>If you enjoy working with a group of creative, talented and enthusiastic individuals on problems at the intersection of data design, transparency and interaction, then please apply so we can make the connection to the decision makers for this opening. </p><p>Required: - Bachelor’s Degree - 8+ years industry experience - 2+ years’ experience in Clojure/ClojureScript </p><p>Ideal but not Required: - Advanced UI and visualization in the browser (SVG, D3, Grammar of Graphics, Tufte, Bertin) - Systems architecture (Object orientation, patterns, service orientation, reactive, functional-relational, and back again) - Logic programming (Prolog, rule systems) - Databases, inverted indexes, message queueing (Elasticsearch, Kafka, etc.) - Provisioning and configuration management (cough, cloud)</p><p>On behalf of our Client, we are seeking 3 Remote Clojure Developers to join a team of experienced Senior Clojure developers to on their Threat Response team. They use Clojure to mesh large volumes of high dimensional network, host and service information with taxonomic information about malicious software. Much of our work involves understanding and reasoning about this data, which describes the behavior of systems, and by extension, the capabilities, and intentions of these systems’ users. </p><p>Consequently, there is a lot of room to explore and apply techniques of logic programming in a practical, useful, fascinating, expansive, and evolving problem domain. The overarching goal is to provide tools that benefit the security of their end customers’ infrastructure.</p><p>The Threat Response team is distributed across North America and Europe, working from home, key characteristics included excellent verbal and written communication skills, sociability, and pride in carrying out duties and discharging responsibilities with exuberance and alacrity. The team draws on the best of agile themes and techniques of the past 30 years—continuous integration and deployment, testing, flexible collaboration with globally distributed team members via chat and video, and gradual, deliberate optimization of process in the name of keeping projects and releases flowing smoothly, in order to provide an excellent product to customers. The team is surrounded by talented QA, UX, support, documentation writers, and management - we hold ourselves to high standards. </p></div></div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://blogs.windows.com/wp-content/uploads/prod/sites/33/2021/06/cropped-browser-icon-logo-32x32.jpg" alt="Improving font rendering in Microsoft Edge">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Improving font rendering in Microsoft Edge</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Microsoft Edge Blog</a> <span class="article__date">02 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Today we are excited to announce improved font rendering in the latest Canary builds of Microsoft Edge on Windows. We have improved the contrast enhancement and gamma correction to match the quality and clarity of other native Windows applications. F</p>
<p>The post <a rel="nofollow" href="https://blogs.windows.com/msedgedev/2021/06/02/improving-font-rendering-in-microsoft-edge/">Improving font rendering in Microsoft Edge</a> appeared first on <a rel="nofollow" href="https://blogs.windows.com/msedgedev">Microsoft Edge Blog</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">663</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Extra Ordinary</a> <span class="article__date">02 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">
Software Developer, Full Stack
</h1>
                            <h2 class="article__feed"><a target="_blank" href="">
Brave Clojure Jobs
</a> <span class="article__date">02 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<div><h1>Software Developer, Full Stack</h1><div class="company-name">Pilloxa | Remote, 4h overlap with Stockholm (CET) during workday</div><div>remote</div><div>€40000 - €80000</div><div><a href="https://www.pilloxa.com">https://www.pilloxa.com</a></div><br /><div><p><strong>About Pilloxa</strong> </p><p>Pilloxa is on a mission to improve patients' adherence to their treatment. Non-adherence to one's treatment plan is all too common. It is estimated to be the root cause of every 10th hospitalization and 8 deaths daily, in Sweden alone. Adherence to treatment is hard, and at Pilloxa we have set our minds to making it easier. </p><p>Pilloxa is a medtech company based in Stockholm, Sweden working with the latest technologies in an effort to improve the patient journey and quality of life for patients. We work together with patients, healthcare and pharmaceutical companies in bringing together all actors that have an impact on patients' treatment. </p><p><strong>Role</strong> </p><p>You'll be an integral part of our small and flat team, working closely with the product and building a first-class user experience. The app is the centerpiece of Pilloxa's service and this is where you'll likely spend most of your time hacking in ClojureScript. As we grow you'll also likely be extending our still small Clojure backend and dabble with all parts of the stack. </p><p><strong>Preferred experience</strong> </p><p>The more boxes you tick, the better. </p>
<ul>
  <li>Passion for making a positive impact in peoples' lives</li>
  <li>2+ years full-stack engineer</li>
  <li>MSc in Computer Science or equivalent</li>
  <li>Experience with Clojure</li>
  <li>Experience with React Native</li>
  <li>Experience with reagent/re-frame</li>
  <li>Startup experience</li>
</ul><p><strong>Process</strong> </p>
<ul>
  <li>Call with CTO</li>
  <li>Call with Co-founder</li>
  <li>Technical assignment (max 8h)</li>
  <li>Presentation of assignment</li>
  <li>Call with CEO</li>
  <li>Reference calls</li>
</ul></div></div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Phaser 3: Mi primer juego HTML5/JS (Parte 3)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">En Mi Local Funciona</a> <span class="article__date">02 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Continúanos hablándoos de cómo desarrollar un videojuego completo con Phaser3. Veremos la creación de clases, delay, solapamientos, textos en pantalla y más.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://blogs.windows.com/wp-content/uploads/prod/sites/33/2021/06/cropped-browser-icon-logo-32x32.jpg" alt="Available for preview: Automatic HTTPS helps keep your browsing more secure">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Available for preview: Automatic HTTPS helps keep your browsing more secure</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Microsoft Edge Blog</a> <span class="article__date">01 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Starting with Microsoft Edge 92, users can preview the Automatic HTTPS feature, which automatically switches your connections to websites from HTTP to HTTPS.</p>
<p>As you browse the web, you may notice that the Microsoft Edge address bar displays a “not</p>
<p>The post <a rel="nofollow" href="https://blogs.windows.com/msedgedev/2021/06/01/available-for-preview-automatic-https-helps-keep-your-browsing-more-secure/">Available for preview: Automatic HTTPS helps keep your browsing more secure</a> appeared first on <a rel="nofollow" href="https://blogs.windows.com/msedgedev">Microsoft Edge Blog</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://thehistoryoftheweb.com/wp-content/uploads/2017/09/cropped-thotw-logo-square-1-32x32.jpg" alt="May 2021 Weblog: Communities Long Gone">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">May 2021 Weblog: Communities Long Gone</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The History of the Web</a> <span class="article__date">01 06 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>A look at how we can save our websites from ourselves, and the stories that keep us going.</p>
<p>The post <a rel="nofollow" href="https://thehistoryoftheweb.com/postscript/may-2021-weblog-communities-long-gone/">May 2021 Weblog: Communities Long Gone</a> appeared first on <a rel="nofollow" href="https://thehistoryoftheweb.com">The History of the Web</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://programadorwebvalencia.com/img/blog/2021/06/env.png" alt="Cómo cargar variables de entorno para un Back-End">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cómo cargar variables de entorno para un Back-End</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Programador Web Valencia</a> <span class="article__date">31 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://programadorwebvalencia.com/img/blog/2021/06/env.png" alt="Enviroment" class="medium" /></p>

<p>Una buena práctica es <strong>no dejar secretos</strong>, como contraseñas o Tokens, dentro del código. Y ni mencionar el peligro que conlleva subirlo a un repositorio. En  gran medida se hace hincapié en esta <strong>omisión de variables por no dejar expuesto al resto del equipo un contenido sensible</strong>. Además otorga la posibilidad de jugar con <strong>diferentes credenciales durante el desarrollo</strong>, algunas pueden ser solo para hacer pruebas y otras las que serán usadas en el proyecto final.</p>

<p>Muchos <strong>Frameworks ya incorporan un sistema similar</strong> al que vamos a mencionar. En breve descubrirás que la <strong>técnica es tan sencilla que puedes montártelo</strong> por tu cuenta.</p>

<p>Primero crea un archivo plano con el siguiente contenido. Yo lo llamaré: <code class="highlighter-rouge">.env</code></p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">TOKEN</span><span class="o">=</span>123456789
<span class="nv">USER</span><span class="o">=</span>TUX
<span class="nv">PASSWORD</span><span class="o">=</span>qwe123
</code></pre></div></div>

<p>Son 3 futuras variables de entorno con sus valores.</p>

<p>A continuación ejecuta el siguiente comando en el terminal, en la misma carpeta donde se encuentra el fichero. Convertirá cada línea del fichero en una variable de entorno.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">export</span> <span class="si">$(</span><span class="nb">cat</span> .env | egrep <span class="nt">-v</span> <span class="s2">"(^#.*|^</span><span class="nv">$)</span><span class="s2">"</span> | xargs<span class="si">)</span>
</code></pre></div></div>

<p>Si quieres comprobar que se ha ejecutado correctamente puedes hacer un <code class="highlighter-rouge">echo</code> con cualquier variable añadiendo el prefijo <code class="highlighter-rouge">$</code>.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="nv">$TOKEN</span>
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>123456789
</code></pre></div></div>

<p>Tarea terminada. Recuerda que si cierras el terminal o modificas el archivo, debes volver a ejecutar el comando.</p>

<h2 id="leer-variables-de-entorno-en-php">Leer variables de entorno en PHP</h2>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$token</span> <span class="o">=</span> <span class="nb">getenv</span><span class="p">(</span><span class="s1">'TOKEN'</span><span class="p">);</span>
<span class="nv">$user</span> <span class="o">=</span> <span class="nb">getenv</span><span class="p">(</span><span class="s1">'USER'</span><span class="p">);</span>
<span class="nv">$password</span> <span class="o">=</span> <span class="nb">getenv</span><span class="p">(</span><span class="s1">'PASSWORD'</span><span class="p">);</span>

<span class="k">echo</span> <span class="nv">$token</span><span class="p">;</span>
<span class="c1">// 123456789</span>
</code></pre></div></div>

<h2 id="leer-variables-de-entorno-en-python">Leer variables de entorno en Python</h2>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import os

token <span class="o">=</span> os.getenv<span class="o">(</span><span class="s1">'TOKEN'</span><span class="o">)</span>
user <span class="o">=</span> os.getenv<span class="o">(</span><span class="s1">'USER'</span><span class="o">)</span>
password <span class="o">=</span> os.getenv<span class="o">(</span><span class="s1">'PASSWORD'</span><span class="o">)</span>
</code></pre></div></div>

<h2 id="leer-variables-de-entorno-en-clojure">Leer variables de entorno en Clojure</h2>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">token</span><span class="w"> </span><span class="p">(</span><span class="nf">System/getenv</span><span class="w"> </span><span class="s">"TOKEN"</span><span class="p">))</span><span class="w">
</span><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">user</span><span class="w"> </span><span class="p">(</span><span class="nf">System/getenv</span><span class="w"> </span><span class="s">"USER"</span><span class="p">))</span><span class="w">
</span><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">password</span><span class="w"> </span><span class="p">(</span><span class="nf">System/getenv</span><span class="w"> </span><span class="s">"PASSWORD"</span><span class="p">))</span><span class="w">
</span></code></pre></div></div>

<p>Aunque también puedes usar la dependencia <code class="highlighter-rouge">environ</code>.</p>

<p>Añade en <code class="highlighter-rouge">project.clj</code>.</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="n">environ</span><span class="w"> </span><span class="s">"0.5.0"</span><span class="p">]</span><span class="w">
</span></code></pre></div></div>

<p>Y usa con total libertad.</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">require</span><span class="w"> </span><span class="p">[</span><span class="n">environ.core</span><span class="w"> </span><span class="no">:refer</span><span class="w"> </span><span class="p">[</span><span class="n">env</span><span class="p">]])</span><span class="w">

</span><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">token</span><span class="w"> </span><span class="p">(</span><span class="nf">env</span><span class="w"> </span><span class="no">:TOKEN</span><span class="p">))</span><span class="w">
</span><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">user</span><span class="w"> </span><span class="p">(</span><span class="nf">env</span><span class="w"> </span><span class="no">:USER</span><span class="p">))</span><span class="w">
</span><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">password</span><span class="w"> </span><span class="p">(</span><span class="nf">env</span><span class="w"> </span><span class="no">:PASSWORD</span><span class="p">))</span><span class="w">
</span></code></pre></div></div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://mustcomunicacion.es/wp-content/uploads/2017/05/logo-must-mano-chat-100x100.png" alt="Mejores temas de WordPress para el sitio web de una inmobiliaria">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Mejores temas de WordPress para el sitio web de una inmobiliaria</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Must Comunicación</a> <span class="article__date">31 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Todo agente inmobiliario necesita un sitio web. Navega a través de esta colección de increíbles temas de WordPress para encontrar el diseño adecuado. Puede resultar difícil diferenciarse en el sector inmobiliario, pero disponer de un atractivo sitio web puede ciertamente ayudar. Encontrar el tema inmobiliario perfecto es un reto, considerando la ingente cantidad de temas [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Perils of Rehydration</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">30 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A surprisingly-common misconception can lead to big rendering issues that are difficult to debug. This deep-dive tutorial examines how React and Gatsby can be used to pre-render content, and how we can work around the constraints to build dynamic, personalized web apps.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="La evolución del Jamstack">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">La evolución del Jamstack</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">28 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Dedicamos este episodio a comentar el artículo de Matt Biilmann publicado recientemente en Smashing Magazine titulado<a href="https://www.smashingmagazine.com/2021/05/evolution-jamstack/" data-type="URL" data-id="https://www.smashingmagazine.com/2021/05/evolution-jamstack/" target="_blank" rel="noreferrer noopener"> The evolution of Jamstack.</a> Mathias Biilmann es CEO de <a href="https://netlify.com" data-type="URL" data-id="https://netlify.com" target="_blank" rel="noreferrer noopener">Netlify </a>y uno de los precursores del termino Jamstack. En este artículo Biilmann empieza rememorando su presentación en el 2016 durante la SmashingConf, donde daba a conocer los principios que sustentan la<a href="https://jamstack.org" data-type="URL" data-id="https://jamstack.org" target="_blank" rel="noreferrer noopener"> arquitectura Jamstack</a>. Ahora en 2021 Matt quiere ofrecer una   perspectiva sobre cómo están evolucionando las técnicas y las soluciones orientadas a esta arquitectura de Jamstack.</p>



<p>Empezamos el episodio hablando recordando los principios del Jamstack, como son la prioridad a que el front se construya lo antes posible y que exista un sólido desacople entre el front y el back. El segundo principio del Jamstack hace referencia a la obtención de datos bajo demanda (JavaScript y APIs).</p>



<p>En la segunda parte hablamos de los tres puntos que según Matt marcan la evolución del Jamstack:</p>



<ul><li>Renderizado Persistente Distribuido o DPR.</li><li>Actualizaciones en streaming desde la capa de datos.</li><li>Colaboración entre desarrolladores se hace popular.</li></ul>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://evercade.co.uk/wp-content/uploads/2021/04/cropped-heart-32x32-1.png" alt="Evercade VS Pre-Orders NOW OPEN">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Evercade VS Pre-Orders NOW OPEN</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Evercade</a> <span class="article__date">28 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The Evercade VS Pre-Orders are now open! You can pre-order your Starter and Premium Packs from your preferred retailer right now. Find the link to your local retailer below, or visit the Retailers Page: AUSTRALIA PIXEL CRIB: Starter Pack &#8211; https://www.pixelcrib.com.au/collections/evercade/products/evercade-vs Premium Pack &#8211; https://www.pixelcrib.com.au/collections/evercade/products/evercade-vs-premium-pack CANADA AMAZON.CA: Starter Pack &#8211; https://www.amazon.ca/dp/B094F6GJ83 Premium Pack &#8211; https://www.amazon.ca/dp/B094F5ZGX8... <a class="view-article" href="https://evercade.co.uk/evercade-vs-where-to-buy/">View Article</a></p>
<p>The post <a rel="nofollow" href="https://evercade.co.uk/evercade-vs-where-to-buy/">Evercade VS Pre-Orders NOW OPEN</a> appeared first on <a rel="nofollow" href="https://evercade.co.uk">Evercade</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://evercade.co.uk/wp-content/uploads/2021/04/cropped-heart-32x32-1.png" alt="Evercade VS – What’s in the Box?">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Evercade VS – What’s in the Box?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Evercade</a> <span class="article__date">27 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The Evercade VS will be available to Pre-Order from May 28th with the release date of November 3rd 2021. The console is available in two packs: STARTER PACK The Evercade VS Starter Pack is the entry point to the new Evercade home console system. This package comes with: Evercade VS Console Evercade VS Controller Technos... <a class="view-article" href="https://evercade.co.uk/evercade-vs-whats-in-the-box/">View Article</a></p>
<p>The post <a rel="nofollow" href="https://evercade.co.uk/evercade-vs-whats-in-the-box/">Evercade VS &#8211; What&#8217;s in the Box?</a> appeared first on <a rel="nofollow" href="https://evercade.co.uk">Evercade</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://evercade.co.uk/wp-content/uploads/2021/04/cropped-heart-32x32-1.png" alt="Evercade VS Founder Edition – How to get Your Name in the Evercade VS Credits">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Evercade VS Founder Edition – How to get Your Name in the Evercade VS Credits</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Evercade</a> <span class="article__date">26 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>When we came up with the idea for the Evercade VS Founder Edition, we wanted to reward our fans and our most passionate adopters. To give them something that really allows them to become a part of the console and in some way to thank everyone for the passion, dedication and love shown from the... <a class="view-article" href="https://evercade.co.uk/name-in-the-credits/">View Article</a></p>
<p>The post <a rel="nofollow" href="https://evercade.co.uk/name-in-the-credits/">Evercade VS Founder Edition &#8211; How to get Your Name in the Evercade VS Credits</a> appeared first on <a rel="nofollow" href="https://evercade.co.uk">Evercade</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">662</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Extra Ordinary</a> <span class="article__date">26 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Primeros pasos en Forge: Cómo desarrollar Apps en Atlassian Cloud (Parte 2: App para Confluence)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">En Mi Local Funciona</a> <span class="article__date">26 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        El objetivo de este post es ampliar los conocimientos adquiridos sobre la plataforma Forge vistos en el post anterior.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://i0.wp.com/stratechery.com/wp-content/uploads/2018/03/cropped-android-chrome-512x512-1.png?fit=32%2C32&amp;ssl=1" alt="App Store Arguments">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">App Store Arguments</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Stratechery by Ben Thompson</a> <span class="article__date">25 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        There are all kinds of arguments to make about the App Store, and nearly all of them are good ones; that's why the best solution can only come from Apple.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://blogs.windows.com/wp-content/uploads/prod/sites/33/2021/06/cropped-browser-icon-logo-32x32.jpg" alt="What’s new for Microsoft Edge at Microsoft Build 2021">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">What’s new for Microsoft Edge at Microsoft Build 2021</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Microsoft Edge Blog</a> <span class="article__date">25 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome back to Microsoft Build! Wherever this finds you, we hope that you’re safe and healthy.</p>
<p>Since last Build, the Microsoft Edge platform continues to empower developers with the latest tools ready for today’s evolving web land</p>
<p>The post <a rel="nofollow" href="https://blogs.windows.com/msedgedev/2021/05/25/whats-new-edge-build-2021/">What’s new for Microsoft Edge at Microsoft Build 2021</a> appeared first on <a rel="nofollow" href="https://blogs.windows.com/msedgedev">Microsoft Edge Blog</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">CSS Container Queries For Designers</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Ahmad Shadeed Blog</a> <span class="article__date">25 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2021/217-observer.png" alt="Observer">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Observer</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">25 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2021/217-observer.png" alt="Observer" title="Warning: Legacy Code" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">
Principal Software Engineer
</h1>
                            <h2 class="article__feed"><a target="_blank" href="">
Brave Clojure Jobs
</a> <span class="article__date">24 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<div><h1>Principal Software Engineer</h1><div class="company-name">Barracuda Networks | United States</div><div>remote</div><div><a href="https://www.barracuda.com/">https://www.barracuda.com/</a></div><br /><div><p>****Description****</p>
<blockquote><p>Come Join Our Passionate Team! At Barracuda, we make the world a safer place. We believe every business deserves access to cloud-enabled, enterprise-grade security solutions that are easy to buy, deploy, and use. We protect email, networks, data and applications with innovative solutions that grow and adapt with our customers' journey. More than 220,000 organizations worldwide trust Barracuda to protect them --- in ways they may not even know they are at risk --- so they can focus on taking their business to the next level. </p><p>We know a diverse workforce adds to our collective value and strength as an organization. Barracuda Networks is proud to be an Equal Opportunity Employer, committed to equal employment opportunity and equitable compensation regardless of race, gender, religion, sex, sexual orientation, national origin, or disability. </p><p>Envision yourself at Barracuda</p><p>We are looking for a Principal Software Engineer to join our distributed team. This is a great opportunity to work on large scale distributed systems underpinning our SaaS cloud applications for email security. These products process massive data coming at us in a steady stream with performance requirements in near real time. Our engineers know they make a difference because the solutions developed are protecting our customers against a growing number of threats. Each of our team members has varied talents that, together create an environment with a depth of knowledge. This allows for autonomy and innovation in developing solutions. The products we work on evolve with your added experience and likewise, you'll be immersed in a rewarding environment. We solve tough problems related to scalability and system architecture. </p><p>Tech Stack:</p>
  <ul>
    <li>Clojure, Elasticsearch, Kafka, Postgres, Kubernetes, Docker, AWS, Amazon Managed Services, Redis, Sumo Logic, etc.</li>
  </ul><p>What you'll be working on:</p>
  <ul>
    <li>Solve important scaling problems around processing of huge volumes of data in near real-time and providing features atop petabytes of data under management.</li>
    <li>Introduce advanced security features.</li>
    <li>Drive design, implementation, and review of major areas of the codebase, adding new features and evolving our next generation architecture.</li>
    <li>Contribute to a team that values code quality, innovative thinking, good communication, occasional pair programming, sound testing practices, and opportunities for mentoring.</li>
  </ul><p>What you bring to the role:</p>
  <ul>
    <li>8+ years of relevant experience delivering well-designed, scalable cloud software</li>
    <li>Experience with functional programming (e.g. Clojure, java, etc.)</li>
    <li>Experience with Lucene or Elasticsearch, or Streaming systems like Kafka</li>
    <li>Demonstrated success in an Agile/Scrum development environment</li>
    <li>Ability to communicate in a collaborative environment - in your code, in the documentation, and in chats and conversations with others</li>
    <li>Bachelor's degree in a technology field or equivalent work experience</li>
    <li>Ability to learn and adapt quickly in a high-energy environment</li>
    <li>Knowledge of search, content management, and analytics is a plus</li>
    <li>Exposure to Kubernetes is a plus</li>
  </ul><p>What you'll get from us</p><p>A team where you can voice your opinion, make an impact, and where you and your experience are valued. Internal mobility -- there are opportunities for cross training and the ability to attain your next career step within Barracuda.</p>
  <ul>
    <li>High-quality health benefits</li>
    <li>Retirement Plan with employer match</li>
    <li>Career-growth opportunities</li>
    <li>Flexible Time Off and Paid Time Off benefits</li>
    <li>Volunteer opportunities</li>
  </ul>
</blockquote>
<ul>
  <li>Job ID 22-081</li>
</ul></div></div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/images/lispworks/two-sided-view.png" alt="Discovering the Lispworks IDE">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Discovering the Lispworks IDE</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">24 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p><a href="http://www.lispworks.com/">LispWorks</a> is a Common Lisp implementation
that comes with its own Integrated Development Environment (IDE) and
its share of unique features, such as the CAPI GUI toolkit.  It is
<strong>proprietary</strong> and provides a <strong>free limited version</strong>.</p>

<p>Here, we will mainly explore its IDE, asking ourselves what it can
offer to a seasoned lisper used to Emacs and Slime. The short answer
is: more graphical tools, such as an easy to use graphical stepper, a
tracer, a code coverage browser or again a class browser. Setting and
using breakpoints was easier than on Slime.</p>

<p>LispWorks also provides more integrated tools (the Process browser
lists all processes running in the Lisp image and we can
stop, break or debug them) and presents many information in the form of
graphs (for example, a graph of function calls or a graph of all the
created windows).</p>

<div class="info-box info">
<!-- if inside a <p> then bootstrap adds 10px padding to the bottom -->
<strong>Note:</strong> you will find updated versions of this review on the <a href="https://lispcookbook.github.io/cl-cookbook/">Cookbook</a>.
</div>

<p><img src="/images/lispworks/two-sided-view.png" width="700" alt="LispWorks' listener and editor in the Mate desktop environment"/></p>

<h2 id="lispworks-features">LispWorks features</h2>

<p>We can see a matrix of LispWorks features by edition and platform here: <a href="http://www.lispworks.com/products/features.html">http://www.lispworks.com/products/features.html</a>.</p>

<p>We highlight:</p>

<ul>
<li>32-bit, 64-bit and ARM support on Windows, MacOS, Linux, Solaris, FreeBSD,</li>
<li><a href="http://www.lispworks.com/documentation/lw61/CAPRM/html/capiref.htm">CAPI portable GUI toolkit</a>: provides native look-and-feel on Windows, Cocoa, GTK+ and Motif.

<ul>
<li>comes with a graphical &ldquo;Interface Builder&rdquo; (think QtCreator) (though not available on MacOS (nor on mobile))</li>
</ul></li>
<li><a href="http://www.lispworks.com/products/lw4mr.html">LispWorks for mobile runtime</a>, for Android and iOS,</li>
<li>optimized application delivery: LispWorks can use a tree shaker to
remove unused lisp code from the delivered applicatiion, thus
shipping lighter binaries than existing open-source implementations.</li>
<li>ability to deliver a dynamic library,</li>
<li>a <a href="http://www.lispworks.com/documentation/lw71/LW/html/lw-113.htm">Java interface</a>, allowing to call from Lisp to Java or the other way around,</li>
<li>an Objective-C and Cocoa interface, with drag and drop and multi-touch support,</li>
<li>a Foreign Language Interface,</li>
<li>TCP/UDP sockets with SSL &amp; IPv6 support,</li>
<li>natived threads and symmetric multiprocessing, unicode support, and all other Common Lisp features, and all other LispWorks Enterprise features.</li>
</ul>

<p>And, of course, a built-in IDE.</p>

<p>LispWorks is used in diverse areas of the industry. They maintain <a href="http://www.lispworks.com/success-stories/index.html">a list of success stories</a>. As for software that we can use ourselves, we find <a href="https://scorecloud.com/">ScoreCloud</a> amazing (a music notation software: you play an instrument, sing or whistle and it writes the music) or <a href="https://github.com/openmusic-project/openmusic/">OpenMusic</a> (opensource composition environment).</p>

<h3 id="free-edition-limitations">Free edition limitations</h3>

<p>The download instructions and the limitations are given <a href="http://www.lispworks.com/downloads/index.html">on the download page</a>.</p>

<p>The limitations are the following:</p>

<ul>
<li>There is a <strong>heap size limit</strong> which, if exceeded, causes the image to exit. A warning is provided when the limit is approached.</li>
</ul>

<p>What does it prevent us to do? As an illustration, we can not load this set of libraries together in the same image:</p>

<pre><code class="language-lisp">(ql:quickload '(&quot;alexandria&quot; &quot;serapeum&quot; &quot;bordeaux-threads&quot; &quot;lparallel&quot; &quot;dexador&quot; &quot;hunchentoot&quot; &quot;quri&quot; &quot;ltk&quot; &quot;cl-ppcre&quot; &quot;mito&quot;))
</code></pre>

<ul>
<li><p>There is a <strong>time limit of 5 hours</strong> for each session, after which LispWorks Personal exits, possibly without saving your work or performing cleanups such as removing temporary files. You are warned after 4 hours of use.</p></li>

<li><p>It is <strong>impossible to build a binary</strong>. Indeed, the functions <a href="http://www.lispworks.com/documentation/lw71/LW/html/lw-95.htm">save-image</a>, <a href="http://www.lispworks.com/documentation/lw71/DV/html/delivery-4.htm#pgfId-852223">deliver</a> (<em>the</em> function to create a stand-alone executable), and load-all-patches are not available.</p></li>

<li><p><strong>Initialization files are not loaded</strong>. If you are used to initializing Quicklisp from your <code>~/.sbclrc</code> on Emacs, you&rsquo;ll have to load an init file manually every time you start LispWorks (<code>(load #p&quot;~/.your-init-file</code>)).</p></li>
</ul>

<p>For the record, the snippet provided by Quicklisp to put in one&rsquo;s startup file is the following:</p>

<pre><code class="language-lisp">;; provided you installed quicklisp in ~/quicklisp/
(let ((quicklisp-init (merge-pathnames &quot;quicklisp/setup.lisp&quot; (user-homedir-pathname))))
  (when (probe-file quicklisp-init)
    (load quicklisp-init)))
</code></pre>

<p>You&rsquo;ll have to paste it to the listener window (with the <code>C-y</code> key, y as &ldquo;yank&rdquo;).</p>

<ul>
<li>Layered products that are part of LispWorks Professional and Enterprise Editions (CLIM, KnowledgeWorks, Common SQL and LispWorks ORB) are not included. But <strong>we can try the CAPI toolkit</strong>.</li>
</ul>

<p>The installation process requires you to fill an HTML form to receive
a download link, then to run a first script that makes you accept the
terms and the licence, then to run a second script that installs the software.</p>

<h3 id="licencing-model">Licencing model</h3>

<p>LispWorks actually comes in four paid editions. It&rsquo;s all explained by themselves here: <a href="http://www.lispworks.com/products/lispworks.html">http://www.lispworks.com/products/lispworks.html</a>. In short, there is:</p>

<ul>
<li>a Hobbyist edition with <code>save-image</code> and <code>load-all-patches</code>, to apply updates of minor versions, without the obvious limitations, for non-commercial and non-academic use,</li>
<li>a HobbyistDV edition with the <code>deliver</code> function to create executables (still for non-commercial and non-academic uses),</li>
<li>a Professional edition, with the <code>deliver</code> function, for commercial and academic uses,</li>
<li>an Enterprise one, with their enterprise modules: the Common SQL interface, LispWorks ORB, KnowledgeWorks.</li>
</ul>

<p>At the time of writing, the licence of the hobbyist edition costs 750 USD, the pro version the double. They are bought for a LW version, per platform. They have no limit of time.</p>

<div class="info-box info">
<!-- if inside a <p> then bootstrap adds 10px padding to the bottom -->
<strong>NB:</strong> Please double check their upstream resources and don't hesitate to contact them.
</div>

<h2 id="lispworks-ide">LispWorks IDE</h2>

<p>The LispWorks IDE is self-contained, but it is also possible to use LispWorks-the-implementation from Emacs and Slime (see below).</p>

<h3 id="the-editor">The editor</h3>

<p>The editor offers what&rsquo;s expected: a TAB-completion pop-up, syntax
highlighting, Emacs-like keybindings (including the <code>M-x</code> extended
command). The menus help the discovery.</p>

<p>We personally found the editing experience a bit &ldquo;raw&rdquo;. For example:
- indention after a new line is not automatic, one has to press TAB
again.
- the auto-completion is not fuzzy.
- there are no plugins similar to Paredit or Lispy, nor a Vim layer.</p>

<p>We also had an issue, in that the go-to-source function bound to <code>M-.</code>
did not work out for built-in Lisp symbols. This is probably a free
edition limitation too.</p>

<p>The editor provides an interesting tab: Changed Definitions. It lists the functions and methods that were redefined since, at our choosing: the first edit of the session, the last save, the last compile.</p>

<p>See also:</p>

<ul>
<li>the <a href="http://www.lispworks.com/documentation/lw71/EDUG-U/html/eduser-u.htm">Editor User Guide</a>.</li>
</ul>

<h3 id="keybindings">Keybindings</h3>

<p>Most of the keybindings are similar to Emacs, but not all. Here are some differences:</p>

<ul>
<li>to <strong>compile a function</strong>, use <code>C-S-c</code> (control, shift and c), instead of C-c C-c.</li>
<li>to <strong>compile the current buffer</strong>, use <code>C-S-b</code> (instead of C-c C-k).</li>
</ul>

<p>Similar ones include:</p>

<ul>
<li><code>C-g</code> to cancel what you&rsquo;re doing,</li>
<li><code>C-x C-s</code> to save the current buffer,</li>
<li><code>M-w</code> and <code>C-y</code> to copy and paste,</li>
<li><code>M-b</code>, <code>M-f</code>, <code>C-a</code>, <code>C-e</code>… to move around words, to go to the beginning or the end of the line,</li>
<li><code>C-k</code> to kill until the end of the line, <code>C-w</code> to kill a selected region,</li>
<li><code>M-.</code> to find the source of a symbol,</li>
<li><code>C-x C-e</code> to evaluate the current defun,</li>
<li>…</li>
</ul>

<p>Some useful functions don&rsquo;t have a keybinding by default, for example:</p>

<!-- - delete selected text with `M-x delete-region` (or kill the region with `C-w`) -->

<ul>
<li>clear the REPL with <code>M-x Clear Listener</code></li>
<li><code>Backward Kill Line</code></li>
</ul>

<p>It is possible to use <strong>classical keybindings</strong>, à la KDE/Gnome. Go to the
Preferences menu, Environment and in the Emulation tab.</p>

<p>There is <strong>no Vim layer</strong>.</p>

<h3 id="searching-keybindings-by-name">Searching keybindings by name</h3>

<p>It is possible to search for a keybinding associated to a function, or
a function name from its keybinding, with the menu (Help -&gt; Editing -&gt;
Key to Command / Command to Key) or with <code>C-h</code> followed by a key,
as in Emacs. For example type <code>C-h k</code> then enter a keybinding to
get the command name. See more with <code>C-h ?</code>.</p>

<h3 id="tweaking-the-ide">Tweaking the IDE</h3>

<p>It is possible to change keybindings. The editor&rsquo;s state is accessible
from the <code>editor</code> package, and the editor is built with the CAPI
framework, so we can use the <code>capi</code> interface too. Useful functions
include:</p>

<pre><code class="language-lisp">`
editor:bind-key
editor:defcommand
editor:current-point
editor:with-point  ;; save point location
editor:move-point
editor:*buffer-list*
editor:*in-listener* ;; returns T when we are in the REPL
…
</code></pre>

<p>Here&rsquo;s how you can bind keys:</p>

<pre><code class="language-lisp">;; Indent new lines.
;; By default, the point is not indented after a Return.
(editor:bind-key &quot;Indent New Line&quot; #\Return :mode &quot;Lisp&quot;)

;; Insert pairs.
(editor:bind-key &quot;Insert Parentheses For Selection&quot; #\( :mode &quot;Lisp&quot;) ;;
(editor:bind-key &quot;Insert Double Quotes For Selection&quot; #\&quot; :mode &quot;Lisp&quot;)
</code></pre>

<p>Here&rsquo;s how to define a new command. We make the <code>)</code> key
to go past the next closing parenthesis.</p>

<pre><code class="language-lisp">(editor:defcommand &quot;Move Over ()&quot; (p)
  &quot;Move past the next close parenthesis.
Any indentation preceeding the parenthesis is deleted.&quot;
  &quot;Move past the next close parenthesis.&quot;
  ;; thanks to Thomas Hermann
  ;; https://github.com/ThomasHermann/LispWorks/blob/master/editor.lisp
  (declare (ignore p))
  (let ((point (editor:current-point)))
    (editor:with-point ((m point))
      (cond ((editor::forward-up-list m)
	     (editor:move-point point m)
             (editor::point-before point)
             (loop (editor:with-point ((back point))
                     (editor::back-to-indentation back)
                     (unless (editor:point= back point)
                       (return)))
                   (editor::delete-indentation point))
	     (editor::point-after point))
	    (t (editor:editor-error))))))

(editor:bind-key &quot;Move Over ()&quot; #\) :mode &quot;Lisp&quot;)
</code></pre>

<p>And here&rsquo;s how you can change indentation for special forms:</p>

<pre><code class="language-lisp">(editor:setup-indent &quot;if&quot; 1 4 1)
</code></pre>

<p>See also:</p>

<ul>
<li>a list of LispWork keybindings: <a href="https://www.nicklevine.org/declarative/lectures/additional/key-binds.html">https://www.nicklevine.org/declarative/lectures/additional/key-binds.html</a></li>
</ul>

<h3 id="the-listener">The listener</h3>

<p>The listener is the REPL.</p>

<p>Its interactive debugger is primarily textual but you can also
interact with it with graphical elements. For example, you can use the
Abort button of the menu bar, which brings you back to the top
level. You can invoke the graphical debugger to see the stacktraces
and interact with them. See the Debugger button at the very end of the
toolbar.</p>

<p><img src="/images/lispworks/toolbar-debugger.png" alt="" /></p>

<p>If you see the name of your function in the stacktraces (you will if
you wrote and compiled your code in a file, and not directly wrote it
in the REPL), you can double-click on its name to go back to the
editor and have it highlight the part of your code that triggered the
error.</p>

<div class="info-box info">
<!-- if inside a <p> then bootstrap adds 10px padding to the bottom -->
<strong>NB:</strong> this is equivalent of pressing <code>M-v</code> in Slime.
</div>

<h3 id="the-stepper-breakpoints">The stepper. Breakpoints.</h3>

<p>The <a href="http://www.lispworks.com/documentation/lw61/IDE-W/html/ide-w-496.htm">stepper</a> is one
of the areas where LispWorks shines.</p>

<p>When your are writing code in the editor window, you can set
breakpoints with the big red &ldquo;Breakpoint&rdquo; button (or by calling <code>M-x Stepper Breakpoint</code>).
This puts a red mark in your code.</p>

<p>The next time your code is executed, you&rsquo;ll get a comprehensive Stepper pop-up window showing:</p>

<ul>
<li>your source code, with an indicator showing what expression is being evaluated</li>
<li>a lower pane with two tabs:

<ul>
<li>the backtrace, showing the intermediate variables, thus showing their evolution during the execution of the program</li>
<li>the listener, in the context of this function call, where you can evaluate expressions</li>
</ul></li>
<li>and the menu bar with the stepper controls: you can step into the next expression, step on the next function call, continue execution until the position of the cursor, continue the execution until the next breakpoint, etc.</li>
</ul>

<p><img src="/images/lispworks/stepper.gif" alt="" /></p>

<p>That&rsquo;s not all. The non-visual, REPL-oriented stepper is also nice. It shows the forms that are being evaluated and their results.</p>

<p>In this example, we use <code>:s</code> to &ldquo;step&rdquo; though the current form and its subforms. We are using the usual listener, we can write any Lisp code after the prompt (the little <code>-&gt;</code> here), and we have access to the local variables (<code>X</code>).</p>

<pre><code class="language-lisp">CL-USER 4 &gt; (defun my-abs (x) (cond ((&gt; x 0) x) ((&lt; x 0) (- x)) (t 0)))
CL-USER 5 &gt; (step (my-abs -5))
(MY-ABS -5) -&gt; :s
   -5 -&gt; :s
   -5
   (COND ((&gt; X 0) X) ((&lt; X 0) (- X)) (T 0)) &lt;=&gt; (IF (&gt; X 0) (PROGN X) (IF (&lt; X 0) (- X) (PROGN 0)))
   ;; Access to the local variables:
   (IF (&gt; X 0) (PROGN X) (IF (&lt; X 0) (- X) (PROGN 0))) -&gt; (format t &quot;Is X equal to -5? ~a~&amp;&quot; (if (equal x -5) &quot;yes&quot; &quot;no&quot;))
Is X equal to -5? yes
   (IF (&gt; X 0) (PROGN X) (IF (&lt; X 0) (- X) (PROGN 0))) -&gt; :s
      (&gt; X 0) -&gt; :s
         X -&gt; :s
         -5
         0 -&gt; :s
         0
      NIL
      (IF (&lt; X 0) (- X) (PROGN 0)) -&gt; :s
         (&lt; X 0) -&gt; :s
            X -&gt; :s
            -5
            0 -&gt; :s
            0
         T
         (- X) -&gt; :s
            X -&gt; :s
            -5
         5
      5
   5
5
</code></pre>

<p>Here are the available stepper commands (see <code>:?</code>):</p>

<pre><code>:s       Step this form and all of its subforms (optional +ve integer arg)
:st      Step this form without stepping its subforms
:si      Step this form without stepping its arguments if it is a function call
:su      Step up out of this form without stepping its subforms
:sr      Return a value to use for this form
:sq      Quit from the current stepper level
:bug-form &lt;subject&gt; &amp;key &lt;filename&gt;
         Print out a bug report form, optionally to a file.
:get &lt;variable&gt; &lt;command identifier&gt;
         Get a previous command (found by its number or a symbol/subform within it) and put it in a variable.
:help    Produce this list.
:his &amp;optional &lt;n1&gt; &lt;n2&gt;
         List the command history, optionally the last n1 or range n1 to n2.
:redo &amp;optional &lt;command identifier&gt;
         Redo a previous command, found by its number or a symbol/subform within it.
:use &lt;new&gt; &lt;old&gt; &amp;optional &lt;command identifier&gt;
         Do variant of a previous command, replacing old symbol/subform with new symbol/subform.
</code></pre>

<h3 id="the-class-browser">The class browser</h3>

<p>The class browser allows us to examine a class&rsquo;s slots, parent classes, available methods, and some more.</p>

<p>Let&rsquo;s create a simple class:</p>

<pre><code class="language-lisp">(defclass person ()
  ((name :accessor name
         :initarg :name
         :initform &quot;&quot;)
   (lisper :accessor lisperp
           :initform t)))
</code></pre>

<p>Now call the class browser:</p>

<ul>
<li>use the &ldquo;Class&rdquo; button from the listener,</li>
<li>or use the menu Expression -&gt; Class,</li>
<li>or put the cursor on the class and call <code>M-x Describe class</code>.</li>
</ul>

<p><img src="/images/lispworks/class-browser.png" alt="" /></p>

<p>It is composed of several panes:</p>

<ul>
<li>the <strong>class hierarchy</strong>, showing the superclasses on the left and the subclasses on the right, with their description to the bottom,</li>
<li>the <strong>superclasses viewer</strong>, in the form of a simple schema, and the same for subclasses,</li>
<li>the <strong>slots pane</strong> (the default),</li>
<li>the available <strong>initargs</strong>,</li>
<li>the existing <strong>generic functions</strong> for that class</li>
<li>and the <strong>class precedence list</strong>.</li>
</ul>

<p>The Functions pane lists all methods applicable to that class, so we can discover public methods provided by the CLOS object system: <code>initialize-instance</code>, <code>print-object</code>, <code>shared-initialize</code>, etc. We can double-click on them to go to their source. We can choose not to include the inherited methods too (see the &ldquo;include inherited&rdquo; checkbox).</p>

<p>You&rsquo;ll find buttons on the toolbar (for example, Inspect a generic
function) and more actions on the Methods menu, such as a way to see
the <strong>functions calls</strong>, a menu to <strong>undefine</strong> or <strong>trace</strong> a function.</p>

<p>See more:</p>

<ul>
<li><a href="http://www.lispworks.com/documentation/lw71/IDE-U/html/ide-u-55.htm#pgfId-871798">Chapter 8 of the documentation: the Class Browser</a></li>
</ul>

<h3 id="the-function-call-browser">The function call browser</h3>

<p>The function call browser allows us to see a graph of the callers and
the callees of a function. It provides several ways to filter the
displayed information and to further inspect the call stack.</p>

<div class="info-box info">
<!-- if inside a <p> then bootstrap adds 10px padding to the bottom -->
<strong>NB:</strong> The Slime functions to find such cross-references are <code>slime-who-[calls, references, binds, sets, depends-on, specializes, macroexpands]</code>.
</div>

<p>After loading a couple packages, here&rsquo;s a simple example showing who calls the <code>string-trim</code> function.</p>

<p><img src="/images/lispworks/function-call-browser.png" alt="The function call browser" /></p>

<p>It shows functions from all packages, but there is a select box to restrict it further, for example to the &ldquo;current and used&rdquo; or only to the current packages.</p>

<p>Double click on a function shown in the graph to go to its source. Again, as in many LispWorks views, the Function menu allows to further manipulate selected functions: trace, undefine, listen (paste the object to the Listener)…</p>

<p>The Text tab shows the same information, but textually, the callers and callees side by side.</p>

<p>We can see cross references for compiled code, and we must ensure the feature is on. When we compile code, LispWorks shows a compilation output likes this:</p>

<pre><code>;;; Safety = 3, Speed = 1, Space = 1, Float = 1, Interruptible = 1
;;; Compilation speed = 1, Debug = 2, Fixnum safety = 3
;;; Source level debugging is on
;;; Source file recording is  on
;;; Cross referencing is on
</code></pre>

<p>We see that cross referencing is on. Otherwise, activate it with <code>(toggle-source-debugging t)</code>.</p>

<p>See more:</p>

<ul>
<li><a href="http://www.lispworks.com/documentation/lw71/IDE-U/html/ide-u-114.htm#pgfId-852601">Chapter 15: the function call browser</a></li>
</ul>

<h3 id="the-process-browser">The Process Browser</h3>

<p>The Process Browser shows us a list of all threads running. The input area allows to filter by name. It accepts regular expressions. Then we can stop, inspect, listen, break into these processes.</p>

<p><img src="/images/lispworks/process-browser.png" alt="&quot;The process browser&quot;" /></p>

<p>See more:</p>

<ul>
<li><a href="http://www.lispworks.com/documentation/lw71/IDE-U/html/ide-u-178.htm#pgfId-852666">Chapter 28: the Process Browser</a></li>
</ul>

<h2 id="using-lispworks-from-emacs-and-slime">Using LispWorks from Emacs and Slime</h2>

<p>To do that, start LispWorks normally, start a Swank server and connect to it from Emacs (Swank is the backend part of Slime).</p>

<p>First, let&rsquo;s load the dependencies:</p>

<pre><code class="language-lisp">(ql:quickload &quot;swank&quot;)
;; or
(load &quot;~/.emacs.d/elpa/slime-20xx/swank-loader.lisp&quot;)
</code></pre>

<p>Start a server:</p>

<pre><code class="language-lisp">(swank:create-server :port 9876)
;; Swank started at port: 9876.
9876
</code></pre>

<p>From Emacs, run <code>M-x slime-connect</code>, choose <code>localhost</code> and <code>9876</code> for the port.</p>

<p>You should be connected. Check with: <code>(lisp-implementation-type)</code>. You are now able to use LispWorks&rsquo; features:</p>

<pre><code class="language-lisp">(setq button
      (make-instance 'capi:push-button
                     :data &quot;Button&quot;))
(capi:contain button)
</code></pre>

<h2 id="see-also">See also</h2>

<ul>
<li><a href="http://www.lispworks.com/documentation/lw71/IDE-U/html/ide-u.htm">LispWorks IDE User Guide</a> (check out the sections we didn&rsquo;t cover)</li>
<li><a href="https://en.wikipedia.org/wiki/LispWorks">LispWorks on Wikipedia</a></li>
<li>the <a href="https://github.com/fourier/awesome-lispworks">Awesome LispWorks</a> list</li>
</ul>

<hr />

<p>And voilà, our review ends here. I&rsquo;m happy to have this tool under my toolbet, and I want to explore the CAPI toolkit more. But for now I don&rsquo;t use LispWorks daily, so if you do, don&rsquo;t hesitate to leave a comment with a tip or to highlight a feature you really like. Thanks!</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://cdn.evilmartians.com/front/blocks/common/images/social-5e5bfff.png" alt="A broader picture: A guide on imgproxy for businesses">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">A broader picture: A guide on imgproxy for businesses</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Martian Chronicles, Evil Martians’ team blog</a> <span class="article__date">24 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://blogs.windows.com/wp-content/uploads/prod/sites/33/2021/06/cropped-browser-icon-logo-32x32.jpg" alt="Preview Microsoft Math Solver in Microsoft Edge">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Preview Microsoft Math Solver in Microsoft Edge</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Microsoft Edge Blog</a> <span class="article__date">21 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>For many students, math can be a particularly challenging subject in school. Math is sequential, in that each lesson is part of the foundation for future learning. If students do not have a solid understanding of each concept as they go, it may impac</p>
<p>The post <a rel="nofollow" href="https://blogs.windows.com/msedgedev/2021/05/21/preview-microsoft-math-solver-microsoft-edge/">Preview Microsoft Math Solver in Microsoft Edge</a> appeared first on <a rel="nofollow" href="https://blogs.windows.com/msedgedev">Microsoft Edge Blog</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://evercade.co.uk/wp-content/uploads/2021/04/cropped-heart-32x32-1.png" alt="Introducing the Evercade VS Founder Edition">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Introducing the Evercade VS Founder Edition</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Evercade</a> <span class="article__date">21 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>UPDATE (27/05/21): The Evercade VS Limited Founder Edition is available NOW! Click the link below to pre-order yours UPDATE (27/05/21): Evercade VS Limited Founder Edition Additional Controllers will be available to Pre-Order from May 27, while stocks last. UPDATE (26/05/21): We have added a final exclusive Feature: Your Name in the Credits of the Evercade VS!... <a class="view-article" href="https://evercade.co.uk/introducing-the-evercade-vs-founder-edition/">View Article</a></p>
<p>The post <a rel="nofollow" href="https://evercade.co.uk/introducing-the-evercade-vs-founder-edition/">Introducing the Evercade VS Founder Edition</a> appeared first on <a rel="nofollow" href="https://evercade.co.uk">Evercade</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">vxdump: copias de seguridad en HP-UX</h1>
                            <h2 class="article__feed"><a target="_blank" href="">ochobitshacenunbyte</a> <span class="article__date">19 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Hoy echamos un vistazo rápido, a la herramienta de copias de seguridad, para sistemas de ficheros VxFS, en sistemas HP-UX, llamada vxdump. Me he tenido que pelear últimamente un poco con ella en este,&#46;&#46;&#46;</p>
<p>La entrada <a rel="nofollow" href="https://www.ochobitshacenunbyte.com/2021/05/19/vxdump-copias-de-seguridad-en-hp-ux/">vxdump: copias de seguridad en HP-UX</a> se publicó primero en <a rel="nofollow" href="https://www.ochobitshacenunbyte.com">ochobitshacenunbyte</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">661</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Extra Ordinary</a> <span class="article__date">19 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://mustcomunicacion.es/wp-content/uploads/2017/05/logo-must-mano-chat-100x100.png" alt="Cómo crear rápidamente newsletters en Mailchimp con diseños de plantillas profesionales">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cómo crear rápidamente newsletters en Mailchimp con diseños de plantillas profesionales</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Must Comunicación</a> <span class="article__date">19 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        El marketing por correo electrónico es una de las mejores maneras de conectar con clientes potenciales. El único problema es que la creación de una atractiva newsletter por email puede costar algún un tiempo. Una de las formas más sencillas de crear una newsletter que encante a tus suscriptores consiste en usar una plantilla de [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://evercade.co.uk/wp-content/uploads/2021/04/cropped-heart-32x32-1.png" alt="Arcade Games are Coming to Evercade!">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Arcade Games are Coming to Evercade!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Evercade</a> <span class="article__date">18 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Arcade games are coming to the Evercade with the announcement of four new cartridges! All four Arcade collections will feature arcade versions of the included games, from classic hits to some rediscovered greats. These new cartridges follow the now traditional Evercade formula of providing something everyone loves and something new to discover. In total, there... <a class="view-article" href="https://evercade.co.uk/arcade-games-are-coming-to-evercade/">View Article</a></p>
<p>The post <a rel="nofollow" href="https://evercade.co.uk/arcade-games-are-coming-to-evercade/">Arcade Games are Coming to Evercade!</a> appeared first on <a rel="nofollow" href="https://evercade.co.uk">Evercade</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://i0.wp.com/stratechery.com/wp-content/uploads/2018/03/cropped-android-chrome-512x512-1.png?fit=32%2C32&amp;ssl=1" alt="Distribution and Demand">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Distribution and Demand</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Stratechery by Ben Thompson</a> <span class="article__date">18 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Distribution on the Internet is free; what matters is controlling demand. AT&#038;T and Verizon didn't understand the distinction.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://mustcomunicacion.es/wp-content/uploads/2017/05/logo-must-mano-chat-100x100.png" alt="Todo lo que los desarrolladores necesitan saber sobre el envío de emails transaccionales">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Todo lo que los desarrolladores necesitan saber sobre el envío de emails transaccionales</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Must Comunicación</a> <span class="article__date">18 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Imaginemos que estás desarrollando una nueva característica o aplicación. El final está a la vista. Toda la compleja infraestructura, las bases de datos, la API, las pruebas se ven bien. A continuación, te das cuenta de que hay puntos clave en el sistema en los que necesitas enviar correos electrónicos «transaccionales»; de restablecimiento de contraseña, [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://thehistoryoftheweb.com/wp-content/uploads/2017/09/cropped-thotw-logo-square-1-32x32.jpg" alt="The Right to Link">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Right to Link</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The History of the Web</a> <span class="article__date">18 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>You can link to anything on the web. That's a strength. And yet the right to link has been dragged into court on a regular basis for decades. Why is that?</p>
<p>The post <a rel="nofollow" href="https://thehistoryoftheweb.com/the-right-to-link/">The Right to Link</a> appeared first on <a rel="nofollow" href="https://thehistoryoftheweb.com">The History of the Web</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2021/216-new-library.png" alt="New Library">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">New Library</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">18 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2021/216-new-library.png" alt="New Library" title="New is not always better" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Google Summer of Code 2021 students are announced!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">17 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">
Frontend Engineer
</h1>
                            <h2 class="article__feed"><a target="_blank" href="">
Brave Clojure Jobs
</a> <span class="article__date">17 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<div><h1>Frontend Engineer</h1><div class="company-name">Multis  | Europe</div><div>remote</div><div><a href="https://multis.co">https://multis.co</a></div><br /><div><h2>About Multis</h2><p><a href="https://multis.co/">Multis</a> provides financial services for companies holding euros, dollars, and cryptocurrencies. We are building the best crypto wallet designed for businesses who need to scale, move fast, make the most of their crypto and fiat currencies. We're helping these companies to shape a global and borderless economy through Decentralized Finance (DeFi)!</p><p>We're a team of happy and passionate crypto-dreamers: <a href="https://twitter.com/fujisaha">Thibaut</a> (CEO) and <a href="https://twitter.com/GregJeanmart">Greg</a> (CTO), with backing from world-class US and European investors like <a href="https://multis.slite.com/app/channels/RWoS5odHRo/notes/ycombinator.com">Y Combinator</a>, <a href="https://ventures.coinbase.com/">Coinbase Ventures</a> and <a href="https://multis.slite.com/app/channels/RWoS5odHRo/notes/efounders.com">eFounders</a>. The company is incorporated in San Francisco but we're working from Europe for now. </p><h2>What's so special about engineering at Multis?</h2><p>Multis engineering is working at the cutting edge of FinTech and Blockchain with powerful technologies like ClojureScript, Re-frame and Firebase. </p><p>Our server-less architecture powered by functional programming is helping us to keep ourselves focused on our core domain and build a delightful experience. </p><p>Our engineering principles? Simplicity, quality and a magical UX!</p><h2>Mission</h2><p>We are looking for a frontend engineer to work hand-in-hand with the CTO and the engineering, product and design teams to build and maintain our next-gen business banking application in alignment with the different design prototypes. </p><p>As a core member, we also expect you to have major impact on shaping our culture and brand, and help us attract top talents!</p><h2>Responsibilities</h2>
<ul>
  <li>Conduct frontend developments --- from specs to tested production code --- along with the Product and Design teams</li>
  <li>Contribute to Multis technical thought leadership through articles on our blog</li>
  <li>Maintain product and handle company-wide support with the core team</li>
  <li>Help build a world-class engineering team</li>
</ul><h2>Requirements</h2>
<ul>
  <li>Based in Europe</li>
  <li>3+ years of experience as frontend engineer with React</li>
  <li>Acquainted with <a href="https://clojurescript.org/">ClojureScript</a> and <a href="https://day8.github.io/re-frame/">re-frame</a> (or strong willingness to learn --- our coding test is in ClojureScript)</li>
  <li>Experience with complex single-page applications</li>
  <li>Ability to lead projects and execute with pragmatism and velocity</li>
  <li>Startup experience</li>
  <li>Cultivate humility and curiosity about all things programming and tech</li>
  <li>Know how to relax 🏝️</li>
</ul><h2>Nice to have</h2>
<ul>
  <li>Experience in FinTech or Blockchain</li>
  <li>Experience with a Design System (we use Ant.Design)</li>
  <li>Previous remote experience</li>
  <li>Hawaïan outfit and prior <a href="https://www.tasteofhome.com/collection/healthy-one-pot-meals/">one-pot experience</a> 🍲</li>
</ul><h2>Benefits</h2>
<ul>
  <li>Challenging work experience building next-gen financial services with a frontier tech</li>
  <li>Fast-learning environment, entrepreneurial and strong team spirit</li>
  <li>Unique access to the Y Combinator and eFounders network</li>
  <li>Competitive salary &#38; equity</li>
  <li>Remote-friendly company with HQ in Paris downtown (75010)</li>
  <li>Team off-sites every 3 months (last one was in Berlin)</li>
  <li>Possibility to get all or part of your salary in crypto 🤑</li>
</ul><p>If you are interested, you are kindly asked to reach out to us by sending your CV on <a href="mailto:&#x6a;&#x6f;&#105;&#110;&#64;m&#x75;&#x6c;t&#105;&#115;&#46;&#99;&#111;">&#x6a;&#x6f;&#105;&#110;&#64;m&#x75;&#x6c;t&#105;&#115;&#46;&#99;&#111;</a> 😁</p><p>To learn more about Multis, our company and our mission <a href="https://www.welcometothejungle.com/en/companies/multis">check out our vital stats here.</a></p></div></div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://diarioestoico.com/wp-content/uploads/2020/03/cropped-logo-estoico-footer-150x150-1-32x32.png" alt="ASERTIVIDAD Y ESTOICISMO">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">ASERTIVIDAD Y ESTOICISMO</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Diario Estoico</a> <span class="article__date">16 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ENTIENDE Y GESTIONA LAS RELACIONES SOCIALES DESDE LA PSICOLOGÍA Y EL ESTOICISMO. En ocasiones nos perdemos a la hora de relacionarnos, sintiéndonos que no somos todo lo eficaces que querríamos e incluso que no nos mostramos tal y cómo somos, naturales y transparentes, sin disfraz. &#160; Por ello, la psicología y el estoicismo proponen múltiples [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="La web retorna a los 90">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">La web retorna a los 90</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">14 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Empezamos este episodio recordando la página web de la película Space Jam, que desde 1996 llevaba sin actualizarse. Un auténtica cápsula del tiempo en los inicios de la web, que muestra lo lejos que estamos de aquellos años. A pesar de todo, esos primeros años de la web, ayudaron a forjar unas herramientas de enorme utilidad, pero también una forma de producir y consumir los contenidos.</p>



<p>Este episodio parte de un estupendo artículo de Max Böck titulado <a href="https://mxb.dev/blog/the-return-of-the-90s-web/#webmentions" data-type="URL" data-id="https://mxb.dev/blog/the-return-of-the-90s-web/#webmentions">The return of the 90s web</a> (junio 2020) donde se cuenta cómo la actual web está volviendo a lo que vivimos en esos últimos años del pasado siglo. Como explica el autor, es un buen momento para volver a visitar aquella web para encontrar, si en efecto vuelven tendencias con un aire renovado.</p>



<p>Entre las tendencias que destaca Max y que se reproducen en el podcast nos encontramos:</p>



<ul><li>Renderizado en el servidor.</li><li>Herramientas no-code.</li><li>Sitios web personales.</li><li>Feeds curados, RSS y descubrimiento de contenido.</li><li>Comunidades y monetización de la web.</li></ul>



<p>Hace 25 años la web era un territorio sin mapas y algo anárquico. Hoy es un lugar que sigue creando oportunidades y propiciando conexiones. Como se comenta en el episodio del podcast, en estos años hemos aprendido mucho  y es bueno comprobar que las cosas con valor vuelven (si es que se han ido alguna vez).</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Modernizing Oracle operations with Kubernetes and El Carro</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">13 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Primeros pasos en Forge: Cómo desarrollar Apps en Atlassian Cloud (Parte 1: App para Jira)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">En Mi Local Funciona</a> <span class="article__date">12 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        En este post introducimos Forge, la nueva plataforma que proporciona Atlassian para desarrollar apps en su entorno Cloud sin necesidad de infraestructura adicional.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">660</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Extra Ordinary</a> <span class="article__date">12 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://i0.wp.com/stratechery.com/wp-content/uploads/2018/03/cropped-android-chrome-512x512-1.png?fit=32%2C32&amp;ssl=1" alt="Cloudflare on the Edge">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cloudflare on the Edge</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Stratechery by Ben Thompson</a> <span class="article__date">11 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Cloudflare is uniquely positioned to become a major player in an Internet 3.0 world, where politics matter more than economics.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A Look at Tailwind CSS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Ahmad Shadeed Blog</a> <span class="article__date">11 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Eleventy es mucho más que un generador de sitios estáticos">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Eleventy es mucho más que un generador de sitios estáticos</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">07 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Los sitios web estáticos vuelven a estar de moda y hay un generador de sitios estáticos en JavaScript que enamora a la comunidad de developers. Con una apuesta clara por la simplicidad,<a href="https://www.11ty.dev/" data-type="URL" data-id="https://www.11ty.dev/"> Eleventy </a>es mucho más que un generador de sitios estáticos. Creado y gestionado por Zach Leatherman, Eleventy es una potente herramienta para producir sitios web optimizados y preparados para el rendimiento.</p>



<p>En este episodio se realiza un análisis de Eleventy explicando qué lo hace tan especial para la comunidad. En poco tiempo Eleventy ha conseguido reunir una vibrante comunidad de desarrolladores, que comparten ingeniosas soluciones basadas en apalancar la formidable librería de JavaScript. Por si fuera poco Eleventy, gracias a servicios como Netlify o Vercel, está entre las herramientas más populares para producir sitios web basados en la arquitectura Jamstack. Entre las ventajas de Eleventy:</p>



<ul><li>Soporta 11 lenguajes de plantilla.</li><li>Cascada de datos locales, globales y externos.</li><li>Cero configuración (no asume ninguna convención).</li><li>Extensión a través de plugins, shortcodes y transformadores.</li><li>Orientado al rendimiento y a la velocidad.</li><li>Comunidad.</li></ul>



<p>Aunque Eleventy pueda ser usado para crear un sitio estático convencional,  la combinación de un servicio como Netlify o Vercel, te ofrece una secuencia perfecta para desarrollar sitios web modernos y orientados al rendimiento y la productividad.</p>



<p></p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://mustcomunicacion.es/wp-content/uploads/2017/05/logo-must-mano-chat-100x100.png" alt="Mejores plugins SEO para WordPress">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Mejores plugins SEO para WordPress</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Must Comunicación</a> <span class="article__date">06 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ¿Estás buscando mejorar tu posicionamiento en los motores de búsqueda sin contratar expertos en SEO? Google y otros motores de búsqueda utilizan algoritmos complejos para impulsar algunos sitios web a las posiciones de la primera página de resultados y relegar a otros a la oscuridad. La Optimización para los motores de búsqueda (SEO) es la [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://evercade.co.uk/wp-content/uploads/2021/04/cropped-heart-32x32-1.png" alt="Indie Heroes and Worms Delayed to July 30 2021">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Indie Heroes and Worms Delayed to July 30 2021</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Evercade</a> <span class="article__date">05 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>We have an update for you on the release date of Cartridges 17 &#38; 18, Indie Heroes Collection 1 and Worms Collection 1, and sadly it is not good news. The release date of these cartridges has unfortunately had to be delayed to July 30th, 2021 due to a supply issue beyond our control. This... <a class="view-article" href="https://evercade.co.uk/indie-heroes-and-worms-delayed-to-july-30-2021/">View Article</a></p>
<p>The post <a rel="nofollow" href="https://evercade.co.uk/indie-heroes-and-worms-delayed-to-july-30-2021/">Indie Heroes and Worms Delayed to July 30 2021</a> appeared first on <a rel="nofollow" href="https://evercade.co.uk">Evercade</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://evercade.co.uk/wp-content/uploads/2021/04/cropped-heart-32x32-1.png" alt="The Bitmap Brothers Collection 1 Announced">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Bitmap Brothers Collection 1 Announced</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Evercade</a> <span class="article__date">05 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>We are delighted to announce another brand new collection that highlights some of the best games in the history of British video game development with The Bitmap Brothers Collection 1 for Evercade devices. This new collection, in partnership with owners Rebellion, features 5 of the best games from the British development team that was dubbed... <a class="view-article" href="https://evercade.co.uk/the-bitmap-brothers-collection-1-announced/">View Article</a></p>
<p>The post <a rel="nofollow" href="https://evercade.co.uk/the-bitmap-brothers-collection-1-announced/">The Bitmap Brothers Collection 1 Announced</a> appeared first on <a rel="nofollow" href="https://evercade.co.uk">Evercade</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://mustcomunicacion.es/wp-content/uploads/2017/05/logo-must-mano-chat-100x100.png" alt="Mejores temas de WordPress para contenido viral">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Mejores temas de WordPress para contenido viral</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Must Comunicación</a> <span class="article__date">05 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Hacer que el contenido se vuelva viral es un sueño para muchos al hacer negocios online. Esto implica en gran medida un proceso de creación de contenido viral. Sin embargo, antes de que puedas hacer algo de esto, debes establecer tu hogar en la web. Crear un sitio web al que puedas dirigir a las [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://i0.wp.com/stratechery.com/wp-content/uploads/2018/03/cropped-android-chrome-512x512-1.png?fit=32%2C32&amp;ssl=1" alt="Market-Making on the Internet">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Market-Making on the Internet</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Stratechery by Ben Thompson</a> <span class="article__date">05 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        More and more opportunities on the web come from market marking, not for advertisers, but for real goods and services paid for with real money.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">
Clojure developer
</h1>
                            <h2 class="article__feed"><a target="_blank" href="">
Brave Clojure Jobs
</a> <span class="article__date">05 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<div><h1>Clojure developer</h1><div class="company-name">Ardoq | flexible remote in/around Oslo. Visa sponsorship is possible</div><div><a href="http://www.ardoq.com">http://www.ardoq.com</a></div><br /><div><p>Ardoq is a fast-growing technology company in Norway with offices in London, New York, and Copenhagen. Our Graph platform enables our customers to map dependencies across strategic objectives, projects, applications, processes, and people, allowing them to assess the impact of change and make better and faster decisions. </p><p>Our company is backed by a solid commitment from investors and a majority of our employees are also shareholders. We're growing rapidly, and are looking for candidates to help scale our engineering team. </p><p>Ardoq's engineering team is a highly skilled group of people who like solving challenging problems, value feedback, continuous delivery, and automation of repetitive tasks. We maintain a high iteration speed through a focus on code quality and incremental change, not artificial deadlines. We believe working closely together and supporting each other is important if we are to achieve a common goal.</p><p>Who we're looking for</p><p>We're looking for caring, driven, and quality-focused engineers who can collaborate across the organization. You should have a learning and sharing mindset. That is, wanting to learn new things and being open and sharing your knowledge. As the company develops we implement our lessons learned and adapt to change. You should be proactive and take ownership.</p><p>We believe in finding people with the right qualities and skills rather than finding a person with the right degree. A BS/MS degree in Computer Science, Engineering, or related subject is always good but it's not a prerequisite.</p><p>You should have a good knowledge of web technologies and an interest in working with a functional language, as Clojure is our primary back-end language.</p><p>We think it's a plus if you consider yourself a full stack developer and don't mind getting your hands dirty. Since JavaScript/TypeScript and Clojure are quite different, we don't expect you to be an expert in both, but it is good to have an understanding of the other side.</p><p>Responsibilities</p><p>You'll be an integral part of the engineering team. This means both working with greenfield feature development, finding bugs, and focusing on continuous quality improvement. There's also the possibility of helping on cloud infrastructure, automation, and developer tooling depending on your personal interests.</p><p>Our best work is done in an environment of mutual trust and support. We share knowledge and value diversity. We are proactive and volunteer our best effort every day. If we see a problem, we fix a problem. </p><p>What we can offer you</p><p>Ardoq's values are Bold, Caring and Driven. Living by these values is part of what makes Ardoq a great place to work. We make bold decisions that push the product, ourselves and our customers forward. We voice our opinions, have difficult conversations, disagree, and learn. We take care of both our colleagues and our customers and empathize with the challenges they face every day. </p><p>We also offer many benefits including investment opportunities for employees and generous parental leave schemes. </p><p>Although we have offices in Oslo, London, New York, and Copenhagen, we embrace remote work and flexible schedules. </p><p>If you identify with this, we can offer you a really great place to work.</p><p><em>Work language</em></p><p>English &#38; Clojure. Although 44% of us are based at the Oslo headquarters, we are an international team representing many countries and languages.</p></div></div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">659</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Extra Ordinary</a> <span class="article__date">05 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Phaser 3: Mi primer juego HTML5/JS (Parte 2)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">En Mi Local Funciona</a> <span class="article__date">04 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        En esta segunda parte hablaremos de la creación de enemigo, de los rebotes, del sistemas de colisiones y de cómo añadir sonidos.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://thehistoryoftheweb.com/wp-content/uploads/2017/09/cropped-thotw-logo-square-1-32x32.jpg" alt="Checking “Under the Hood” of Code">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Checking “Under the Hood” of Code</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The History of the Web</a> <span class="article__date">04 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>If you're a developer today, you likely take advantage of built in tools for web debugging every day. They came from the smallest places, and it took years to get them where they are today.</p>
<p>The post <a rel="nofollow" href="https://thehistoryoftheweb.com/checking-under-the-hood-of-code/">Checking &#8220;Under the Hood&#8221; of Code</a> appeared first on <a rel="nofollow" href="https://thehistoryoftheweb.com">The History of the Web</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The State of CSS Cross-Browser Development</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Ahmad Shadeed Blog</a> <span class="article__date">04 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://diarioestoico.com/wp-content/uploads/2020/03/cropped-logo-estoico-footer-150x150-1-32x32.png" alt="LAS VIRTUDES ESTOICAS.">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">LAS VIRTUDES ESTOICAS.</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Diario Estoico</a> <span class="article__date">02 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Las virtudes cardinales en el estoicismo. Coraje, Templanza, Sabiduría y Justicia, y los juicios de valor exigen dedicación y compromiso, y aunque son únicamente 4, llevarlas a la práctica requerirá lo mejor de ti.Para entender las 4 virtudes del estoicismo, comparemos dos conductas en circunstancias parecidas.Un primer tipo de personas a las que el éxito [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="El apocalipsis de las cookies de terceros">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">El apocalipsis de las cookies de terceros</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">02 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Google anunció que a partir de mayo 2022 su navegador Chrome dejará de permitir la carga de cookies de terceros. Esto se añade a una larga lista de acciones que rematan las cookies de terceros como medio para la identificación y el seguimiento de usuarios para la industria de los anuncios publicitarios (AdTech).</p>



<p>En este episodio se habla sobre las implicaciones que traen el ocaso de las cookies de terceros y la tendencia hacia alternativas que sirvan para reemplazarlas. Teniendo en cuenta que las cookies de terceros han permitido la financiación de muchos servicios en internet, el hecho de que el navegador más usado en el mundo las deje de permitir, genera mucha incertidumbre entre la industria publicitaria y los creadores de contenido. </p>



<p>En la segunda parte del episodio ofrezco una serie de ideas para conciliar un internet abierta y que al mismo tiempo sea económicamente viable. La muerte de las cookies de terceros es la crónica de una muerte anunciada, pero que supone cambios en la forma en la que usamos gran parte de los servicios más populares en internet.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://evercade.co.uk/wp-content/uploads/2021/04/cropped-heart-32x32-1.png" alt="Intellivision Collection 1 Games Announced">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Intellivision Collection 1 Games Announced</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Evercade</a> <span class="article__date">01 05 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>That&#8217;s right, it&#8217;s been a few months but we&#8217;re finally ready to let you know exactly what is on the upcoming Intellivision Collection 1 Cartridge from Evercade! The Games list is: Astrosmash (Shoot &#8217;em Up) Buzz Bombers (Shoot &#8217;em Up) Frog Bog (Eat &#8217;em Up) Night Stalker (Action) Pinball Princess Quest (Platformer) Shark Shark (Puzzle)... <a class="view-article" href="https://evercade.co.uk/intellivision-collection-1-games-announced/">View Article</a></p>
<p>The post <a rel="nofollow" href="https://evercade.co.uk/intellivision-collection-1-games-announced/">Intellivision Collection 1 Games Announced</a> appeared first on <a rel="nofollow" href="https://evercade.co.uk">Evercade</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Free Software Wireless-N Mini Router v3 from ThinkPenguin, Inc. now FSF-certified to Respect Your Freedom</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FSF News</a> <span class="article__date">30 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        BOSTON, Massachusetts, USA -- Friday, April 30th, 2021 -- The Free
Software Foundation (FSF) today awarded Respects Your Freedom (RYF)
certification to the Free Software Wireless-N Mini Router v3
(TPE-R1300) from ThinkPenguin, Inc. The RYF certification mark means
that these products meet the FSF's standards in regard to users'
freedom, control over the product, and privacy.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">El Desconocido CSS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">En Mi Local Funciona</a> <span class="article__date">30 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Descubre en este post el lenguaje CSS: uno de los más fáciles de aprender, pero a la vez de los más difíciles de dominar

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">FSF board frequently asked questions (FAQ)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FSF News</a> <span class="article__date">28 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">
Clojurescript Engineer (Remote)
</h1>
                            <h2 class="article__feed"><a target="_blank" href="">
Brave Clojure Jobs
</a> <span class="article__date">28 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<div><h1>Clojurescript Engineer (Remote)</h1><div class="company-name">Composer | US & Canada</div><div>remote</div><div><em>Build, test, and deploy automated trading strategies without any code!</em></div><div>$130000 - $200000</div><div><a href="https://investcomposer.com/">https://investcomposer.com/</a></div><br /><div><p><strong>Build the platform that will disrupt the portfolio management industry!</strong></p><p>Composer is a no-code platform for automated investment management. Composer allows you to build, test, deploy, and manage automated investing strategies - all without writing a line of code.</p><p><strong>As an early frontend engineer at Composer you will:</strong></p>
<ul>
  <li>Be responsible for everything our clients interact with on our platform - empathy for user experience is a must</li>
  <li>Work closely with the executive team to guide our decisions regarding frontend architecture</li>
  <li>Work closely with our designer to bring the product to life</li>
</ul><p><strong>Projects you will work on:</strong></p>
<ul>
  <li>Bringing to life our simple yet powerful portfolio manager and strategy creation tool</li>
  <li>Unifying scattered brokerage accounts to create a holistic portfolio view</li>
</ul><p><strong>We're looking for someone who:</strong></p>
<ul>
  <li>Loves Clojurescript (particularly Reagent &#38; Reframe!)</li>
  <li>Has experience working with designers and translating complex designs into clean, simple code</li>
  <li>Has experience implementing design systems, or has a systems approach to building</li>
  <li>Will be a technical thought leader within the company</li>
</ul><p><strong>What's it like to work at Composer?</strong></p>
<ul>
  <li>We believe diverse perspectives are necessary if we aim to disrupt finance. To that end, we are an equal opportunity employer and welcome a wide array of backgrounds, experiences, and abilities.</li>
  <li>We believe the simplest solution is most likely the best one</li>
  <li>We encourage self-improvement and learning new skills</li>
  <li>We are venture-backed by top investors</li>
  <li>We are 100% remote :)</li>
  <li><a href="https://drive.google.com/file/d/1sJKzYshCgjxOPoxhPx0ibljPR4y1Wry5/view">Our Values</a></li>
</ul></div></div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Instalación de Icinga 2 e Icinga Web 2 en Centos 8</h1>
                            <h2 class="article__feed"><a target="_blank" href="">ochobitshacenunbyte</a> <span class="article__date">28 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Volvemos a la carga con el popular producto de monitoreo de infraestructuras llamado Icinga, en este caso vemos su instalación sobre un servidor con Centos 8. Ya he hablado en varias ocasiones sobre esta&#46;&#46;&#46;</p>
<p>La entrada <a rel="nofollow" href="https://www.ochobitshacenunbyte.com/2021/04/28/instalacion-de-icinga-2-e-icinga-web-2-en-centos-8/">Instalación de Icinga 2 e Icinga Web 2 en Centos 8</a> se publicó primero en <a rel="nofollow" href="https://www.ochobitshacenunbyte.com">ochobitshacenunbyte</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://i0.wp.com/stratechery.com/wp-content/uploads/2018/03/cropped-android-chrome-512x512-1.png?fit=32%2C32&amp;ssl=1" alt="Spotify’s Surprise">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Spotify’s Surprise</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Stratechery by Ben Thompson</a> <span class="article__date">28 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Spotify's new subscription podcast offerings embrace the open ecosystem of podcasts in multiple ways.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">658</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Extra Ordinary</a> <span class="article__date">28 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2021/215-confidence.png" alt="Confidence">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Confidence</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">28 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2021/215-confidence.png" alt="Confidence" title="If confidence is not the absence of fear, then what is it?" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cinco herramientas de backup de escritorio en Linux</h1>
                            <h2 class="article__feed"><a target="_blank" href="">ochobitshacenunbyte</a> <span class="article__date">27 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Os hablo sobre las cinco mejores herramientas de backup de escritorio, para sistemas GNU/Linux. Estas herramientas las he probado en una distribución Ubuntu 20.04, pero entiendo que deben estar disponibles para la mayoría de&#46;&#46;&#46;</p>
<p>La entrada <a rel="nofollow" href="https://www.ochobitshacenunbyte.com/2021/04/27/cinco-herramientas-de-backup-de-escritorio-en-linux/">Cinco herramientas de backup de escritorio en Linux</a> se publicó primero en <a rel="nofollow" href="https://www.ochobitshacenunbyte.com">ochobitshacenunbyte</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://thehistoryoftheweb.com/wp-content/uploads/2017/09/cropped-thotw-logo-square-1-32x32.jpg" alt="April 2021 Weblog: Holding on to our History">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">April 2021 Weblog: Holding on to our History</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The History of the Web</a> <span class="article__date">27 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>When websites disappear, how do we make sure that our history is preserved?</p>
<p>The post <a rel="nofollow" href="https://thehistoryoftheweb.com/postscript/april-2021-weblog-holding-on-to-our-history/">April 2021 Weblog: Holding on to our History</a> appeared first on <a rel="nofollow" href="https://thehistoryoftheweb.com">The History of the Web</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://enmilocalfunciona.io/content/images/2021/04/Perrete-SonarQube-Azure-2.png" alt="SonarQube: Ejecución de análisis e inspección continua (Parte 3)">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">SonarQube: Ejecución de análisis e inspección continua (Parte 3)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">En Mi Local Funciona</a> <span class="article__date">27 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>En el anterior post (<a href="https://enmilocalfunciona.io/como-montar-un-sonarqube-en-cloud-que-nos-sirva-de-spike-parte-1/">Cómo montar un SonarQube en cloud que nos sirva de Spike (Parte 1)</a>) se quiso dar una respuesta rápida a la instalación de SonarQube.</p>

<p><img src="http://enmilocalfunciona.io/content/images/2021/04/Perrete-SonarQube-Azure-2.png" alt=""></p>

<p>En este post, se quiere continuar el ciclo de vida, y explicar de manera abreviada los siguientes temas:</p>

<ul>
<li>Cómo se lanza una</li></ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Practical Use Cases For CSS Variables</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Ahmad Shadeed Blog</a> <span class="article__date">27 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Netplan: Configurar la red en Ubuntu 20.04</h1>
                            <h2 class="article__feed"><a target="_blank" href="">ochobitshacenunbyte</a> <span class="article__date">26 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Seguramente te habrás dado cuenta, que en las últimas versiones de Ubuntu la configuración de la red ha cambiado. Vamos a ver como configurar la red en Ubuntu 20.04 con la herramienta Netplan. La&#46;&#46;&#46;</p>
<p>La entrada <a rel="nofollow" href="https://www.ochobitshacenunbyte.com/2021/04/26/netplan-configurar-la-red-en-ubuntu-20-04/">Netplan: Configurar la red en Ubuntu 20.04</a> se publicó primero en <a rel="nofollow" href="https://www.ochobitshacenunbyte.com">ochobitshacenunbyte</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Practical SQL for Data Analysis</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">25 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Pandas is by far the most popular tool for data analysis. It's packed with useful features, it's battle tested and widely accepted. However, pandas comes at a cost which is often overlooked. SQL databases has been around since the 1970s. They contain many features that most developers never heard of, and I want to bring some of them to light.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://diarioestoico.com/wp-content/uploads/2020/03/cropped-logo-estoico-footer-150x150-1-32x32.png" alt="¿QUÉ ES EL ESTOICISMO? DEFINICIÓN DE ESTOICISMO, Y CLAVES PARA ENTENDER LA FILOSOFÍA ESTOICA.">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">¿QUÉ ES EL ESTOICISMO? DEFINICIÓN DE ESTOICISMO, Y CLAVES PARA ENTENDER LA FILOSOFÍA ESTOICA.</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Diario Estoico</a> <span class="article__date">25 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Hay infinidades de filosofías, sin embargo una rama de la filosofía fue construida únicamente para quienes deciden vivir despiertos y desarrollar una consciencia a través de la naturaleza de las cosas: el estoicismo. Es una filosofía creada para hacernos más felices, más virtuosos, más resistentes y más sabios y, como resultado, superiores personas, mejores atletas [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Testing de End-to-End (E2E) – Informe Testing (III)">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Testing de End-to-End (E2E) – Informe Testing (III)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">24 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Tercer episodio de la serie especial sobre testing donde tratamos el testing de extremo a extremo (End-2-End). Se trata del testing que involucra toda la experiencia de uso de una aplicación. El E2E es la técnica testing de más alto nivel dentro del desarrollo web. Ya no tocamos el código sino sus resultados en el navegador, ya que se pretende emular a través de pruebas determinados comportamientos que debe cumplir nuestra aplicación. Pensemos en este testing como un robot que usa nuestra aplicación, simulando acciones y peticiones realizadas desde un «navegador descabezado».</p>



<p>En este episodio Javier Archeni y Andros Fenollosa hablan sobre el testing E2E, dónde encaja y en especial los frameworks que existen para realizar este tipo de tests. En el episodio:</p>



<ul>
<li>¿Qué es E2E?</li>
<li>¿Por qué existe?</li>
<li>¿Cuándo debería utilizarse?</li>
<li>¿Cuáles son sus limitaciones?</li>
<li>Tipo de usos en escritorio y móviles</li>
<li>Frameworks de testing E2E</li>
</ul>




<p>Un episodio de introducción general a este tipo de testing que seguro dará para profundizar más. Os animamos a probar esta metodología como una forma de mejorar vuestro trabajo y al mismo tiempo ofrecer un mejor servicio en vuestros desarrollos.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2021/214-perfect-fit.png" alt="Perfect Fit">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Perfect Fit</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">23 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2021/214-perfect-fit.png" alt="Perfect Fit" title="Nothing can go wrong" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">pfSense cómo cortafuegos en red interna de VirtualBox</h1>
                            <h2 class="article__feed"><a target="_blank" href="">ochobitshacenunbyte</a> <span class="article__date">22 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Os explico en esta entrada cómo configurar un cortafuegos con el producto pfSense, en una red interna de VirtualBox. La idea es instalar y configurar el popular producto pfSense, usando la ISO que nos&#46;&#46;&#46;</p>
<p>La entrada <a rel="nofollow" href="https://www.ochobitshacenunbyte.com/2021/04/22/pfsense-como-cortafuegos-en-red-interna-de-virtualbox/">pfSense cómo cortafuegos en red interna de VirtualBox</a> se publicó primero en <a rel="nofollow" href="https://www.ochobitshacenunbyte.com">ochobitshacenunbyte</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">2021 Board Election Results</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">22 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together members have elected Chris Nuernberger, Heather Moore-Farley, Ikuru Kyogoku, and Daniel Compton.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Bases de datos seguras en Android</h1>
                            <h2 class="article__feed"><a target="_blank" href="">En Mi Local Funciona</a> <span class="article__date">21 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        En este post te guiamos paso a paso para conseguir cifrar la base de datos protegiendo la información de tus Apps.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://thehistoryoftheweb.com/wp-content/uploads/2017/09/cropped-thotw-logo-square-1-32x32.jpg" alt="Trying (and Failing) to be Cool">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Trying (and Failing) to be Cool</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The History of the Web</a> <span class="article__date">20 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The web's turn into commercial may have happened quickly—it was largely complete by the end of the 1990's—but that doesn't mean it didn't take a turn into the weird here and there. Case and point: Zima.</p>
<p>The post <a rel="nofollow" href="https://thehistoryoftheweb.com/postscript/trying-and-failing-to-be-cool/">Trying (and Failing) to be Cool</a> appeared first on <a rel="nofollow" href="https://thehistoryoftheweb.com">The History of the Web</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://programadorwebvalencia.com/img/blog/2020/06/terminal.png" alt="Comandos esenciales de un Full Stack en Linux">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Comandos esenciales de un Full Stack en Linux</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Programador Web Valencia</a> <span class="article__date">18 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://programadorwebvalencia.com/img/blog/2020/06/terminal.png" alt="Terminal" class="medium" /></p>

<p>Si quieres <strong>ser un buen desarrollador Web</strong>, o simplemente un usuario de Linux competente, <strong>defenderte con el terminal es básico</strong>. Por suerte gran parte de estos comandos pueden ser <strong>utilizados entre diversos sistemas operativos</strong> como <strong>Linux</strong>, <strong>BSD</strong>, <strong>MacOS X</strong> y <strong>Windows 10</strong> a través de Shell. Son un estándar para profundizar en tareas, trabajar rápidamente y ir directo a una funcionalidad.</p>

<p>Por ello mismo dejo una lista de los <strong>comandos que creo esenciales para un Fullstack</strong>: manipular documentos, archivos, directorios, búsquedas, trabajar con logs, instalar servicios… etc. A partir de aquí ya puedes ir creciendo.</p>

<h2 id="ls">ls</h2>

<p>Lista carpetas y archivos de un directorio.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ls</span>
</code></pre></div></div>

<p>Muestra más información.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ls</span> <span class="nt">-l</span>
</code></pre></div></div>

<p>Incluye los archivos ocultos.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ls</span> <span class="nt">-a</span>
</code></pre></div></div>

<h2 id="mkdir">mkdir</h2>

<p>Crea carpetas.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir </span>nueva_carpeta
</code></pre></div></div>

<p>Crea directorios recursivamente.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir</span> <span class="nt">-p</span> carpeta1/carpeta2
</code></pre></div></div>

<h2 id="less">less</h2>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>less archivo.txt
</code></pre></div></div>

<h2 id="touch">touch</h2>

<p>Crea un archivo vacío.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">touch </span>archivo.txt
</code></pre></div></div>

<h2 id="cd">cd</h2>

<p>Cambia de directorio.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd </span>carpeta
</code></pre></div></div>

<p>Subir un nivel</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> ..
</code></pre></div></div>

<h3 id="retroceder-un-directorio-subir-al-padre">Retroceder un directorio (subir al padre)</h3>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> ..
</code></pre></div></div>

<h3 id="directorio-del-usuario">Directorio del usuario</h3>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> ~
</code></pre></div></div>

<h3 id="volver-al-directorio-anterior">Volver al directorio anterior</h3>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> -
</code></pre></div></div>

<h2 id="ver-información">Ver información</h2>

<p>Muestra información de un archivo o carpeta.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>file paris.jpg
</code></pre></div></div>

<h2 id="buscar">Buscar</h2>

<p>Buscar archivos o carpetas.</p>

<p>Un fichero</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>find carpeta-donde-buscar <span class="nt">-name</span> feliz.jpg
</code></pre></div></div>

<p>Solo directorios</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>find carpeta-donde-buscar <span class="nt">-type</span> d <span class="nt">-name</span> vacaciones
</code></pre></div></div>

<h2 id="pwd">pwd</h2>

<p>Muestra la ruta absoluta del directorio donde nos encontramos.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">pwd</span>
</code></pre></div></div>

<h2 id="mv">mv</h2>

<p>Mueve o renombra un archivo o carpeta.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mv </span>fichero_original.txt fichero_nuevo_nombre.txt
</code></pre></div></div>

<h2 id="cp">cp</h2>

<p>Copia un archivo o carpeta.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cp </span>texto.txt texto_copiado.txt
</code></pre></div></div>

<p>Copia una carpeta</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cp</span> <span class="nt">-r</span> carpeta carpeta_copiada
</code></pre></div></div>

<h2 id="rm">rm</h2>

<p>Borra un archivo</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">rm </span>archivo.txt
</code></pre></div></div>

<p>Borrar carpeta</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">rm</span> <span class="nt">-r</span> carpeta
</code></pre></div></div>

<h2 id="fecha">Fecha</h2>

<p>Ver la fecha</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">date</span>
</code></pre></div></div>

<h3 id="convertir-tiempo-de-formato-unix-a-humano">Convertir tiempo de formato unix a humano</h3>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">date</span> <span class="nt">-r</span> 1619018708
</code></pre></div></div>

<h2 id="nombre-de-usuario">Nombre de usuario</h2>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">whoami</span>
</code></pre></div></div>

<h2 id="tar">tar</h2>

<p>Comprime o descomprime archivos en formato Linux: tar, gzip y bz2.</p>

<p><a href="https://programadorwebvalencia.com/comandos-para-comprimir-y-descomprimir/">Ver aquí</a></p>

<h2 id="grep">grep</h2>

<p>Imprime el contenido de un archivo filtrando por un patrón.</p>

<h3 id="filtrar-el-resultado-de-un-comando">Filtrar el resultado de un comando</h3>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ls</span> | <span class="nb">grep </span>texto
</code></pre></div></div>

<h3 id="filtrar-un-archivo">Filtrar un archivo</h3>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cat </span>archivo.txt | <span class="nb">grep </span>texto
</code></pre></div></div>

<h2 id="sudosu">sudo/su</h2>

<p>Ejecuta comando con otros permisos, como administrador u otro usuario.</p>

<h2 id="chmod">chmod</h2>

<p>Cambia los permisos de un archivo o carpeta.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chmod 744 script.sh
</code></pre></div></div>

<p>Otra forma es utilizado un trio con:</p>

<h3 id="rol">Rol</h3>

<ul>
  <li>
    <p><strong>u</strong> → usuario</p>
  </li>
  <li>
    <p><strong>g</strong> → grupo</p>
  </li>
  <li>
    <p><strong>o</strong> → Otros</p>
  </li>
  <li>
    <p><strong>a</strong> → Todos</p>
  </li>
</ul>

<h3 id="acción">Acción</h3>

<ul>
  <li>
    <p><strong>+</strong> → Añadir</p>
  </li>
  <li>
    <p><strong>-</strong> → Quitar</p>
  </li>
</ul>

<h3 id="permiso">Permiso</h3>

<ul>
  <li>
    <p><strong>r</strong> → Lectura</p>
  </li>
  <li>
    <p><strong>w</strong> → Escritura</p>
  </li>
  <li>
    <p><strong>x</strong> → Ejecución</p>
  </li>
</ul>

<p>Por ejemplo, se le quita el permiso de escritura a todos</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">chmod </span>a-w first.txt
</code></pre></div></div>

<p>Al usuario se le da permisos de ejecución</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">chmod </span>u+x script.sh
</code></pre></div></div>

<h2 id="chown">chown</h2>

<p>Cambia propiedad de un archivo o carpeta.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">chmod </span>debian:debian archivo.txt
</code></pre></div></div>

<h2 id="cat">cat</h2>

<p>Concadena archivos.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cat </span>archivo1.txt archivo2.txt
</code></pre></div></div>

<h2 id="echo">echo</h2>

<p>Imprime el contenido de un archivo.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo </span>archivo.txt
</code></pre></div></div>

<h2 id="man">man</h2>

<p>Muestra el manual de un comando.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>man <span class="nb">ls</span>
</code></pre></div></div>

<h2 id="history">history</h2>

<p>Muestra el historial de comandos.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">history</span>
</code></pre></div></div>

<h2 id="clear">clear</h2>

<p>Limpia el terminal.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>clear
</code></pre></div></div>

<h2 id="reboot">reboot</h2>

<p>Reinicia.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>reboot
</code></pre></div></div>

<h2 id="shutdown">shutdown</h2>

<p>Apaga.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>shutdown now
</code></pre></div></div>

<h2 id="tophtop">top/htop</h2>

<p>Monitor de procesos.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>htop
</code></pre></div></div>

<h2 id="nano">nano</h2>

<p>Editor de archivos simple.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano archivo.txt
</code></pre></div></div>

<h2 id="vimnvimemacs">vim/nvim/emacs</h2>

<p>Editor de archivos avanzado.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>emacs <span class="nt">-nw</span> archivo.txt
</code></pre></div></div>

<h2 id="curl">curl</h2>

<p>Realiza peticiones HTTP.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl programadorwebvalencia.com
</code></pre></div></div>

<h2 id="tail">tail</h2>

<p>Muestra el final de un archivo.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">tail </span>archivo.txt
</code></pre></div></div>

<h2 id="ip">ip</h2>

<p>Muestra información de tu red.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ip address show eth0
</code></pre></div></div>

<h2 id="lsof">lsof</h2>

<p>Muestra que servicio esta utilizando cierto puerto.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>lsof <span class="nt">-i</span> tcp:80
</code></pre></div></div>

<h2 id="df">df</h2>

<p>Muestra la información de espacio ocupado en el disco.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">df</span> <span class="nt">-h</span>
</code></pre></div></div>

<h2 id="du">du</h2>

<p>Muestra el espacio que ocupa los diferentes elementos de una carpeta.</p>

<h3 id="solo-un-nivel-y-en-formato-humano">Solo un nivel y en formato humano</h3>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">du</span> <span class="nt">-d</span> 1 <span class="nt">-h</span>
</code></pre></div></div>

<h2 id="journalctl">journalctl</h2>

<p>Muestra los logs en tiempo real.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>journalctl <span class="nt">-f</span>
</code></pre></div></div>

<p>Muestra los logs en tiempo real de un servicio.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>journalctl <span class="nt">-f</span> <span class="nt">-u</span> ssh
</code></pre></div></div>

<p>Muestra los logs de un servicio.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>journalctl <span class="nt">-u</span> ssh
</code></pre></div></div>

<p>Muestra las últimoas 20 líneas de un log.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>journalctl <span class="nt">-n</span> 20
</code></pre></div></div>

<p>Limpia los logs hasta alcanzar el peso que indiques.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>journalctl <span class="nt">--vacuum-size</span><span class="o">=</span>1G
</code></pre></div></div>

<p>Borra los logs con más de cierto tiempo.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>journalctl <span class="nt">--vacuum-time</span><span class="o">=</span>1years
</code></pre></div></div>

<h2 id="ejecutar-último-comando">Ejecutar último comando</h2>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">!!</span>
</code></pre></div></div>

<p>Ejecuta último comando con sudo.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo</span> <span class="o">!!</span>
</code></pre></div></div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://mustcomunicacion.es/wp-content/uploads/2017/05/logo-must-mano-chat-100x100.png" alt="Plugins prémium de gráficos para WooCommerce y WordPress (y 5 gratuitos)">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Plugins prémium de gráficos para WooCommerce y WordPress (y 5 gratuitos)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Must Comunicación</a> <span class="article__date">18 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ¿Deseas convertir datos aburridos en gráficos visualmente atractivos que empaticen con los visitantes de tu sitio web? Algunas cosas se pueden comunicar mejor usando gráficos. ¿Y cómo se crean gráficos de una manera que te ahorre tiempo para poder centrarte en la gestión de tu negocio? Aquí es donde entran en juego los plugins de [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Pipeline de servidor – Informe Testing (II)">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Pipeline de servidor – Informe Testing (II)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">17 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Segundo episodio de esta serie especial sobre testing. En esta ocasión Andros Fenollosa conversa con Antony Goetzschel sobre el testing en el lado de servidor. Entre las cuestiones que discuten en el episodio:</p>



<ul>
<li>¿Qué es un pipeline?</li>
<li>¿Dónde se ensambla el código?</li>
<li>¿Tienes sentido hacerlo en el CI/CD?</li>
<li>¿Cómo se puede empezar con un CI/CD?</li>
<li>¿Cuál es la utilidad de hacer testing en el despliegue?</li>
<li>¿Qué son las pruebas de estrés?</li>
<li>¿Cómo se hacen?</li>
<li>El monitoreo que se realiza a un servicio&#8230; ¿dónde podríamos caracterizarlo?</li>
<li>¿Qué técnicas utilizas en tu día a día? ¿Por qué?</li>
</ul>



<p>Este episodio ofrece una perspectiva muy amplia sobre lo que implica probar nuestro código en la parte del servidor, con recomendaciones de Andros y Antony.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Season of Docs announces participating organizations for 2021</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">16 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">SSMTP: Envío fácil de correo desde la consola de comandos en Linux</h1>
                            <h2 class="article__feed"><a target="_blank" href="">ochobitshacenunbyte</a> <span class="article__date">16 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Existen diferentes tipos de programas en GNU/Linux encargados de enviar correo. En el caso de hoy os hablaré de SSMTP, un programa que conozco desde hace no mucho, pero que me consta que en&#46;&#46;&#46;</p>
<p>La entrada <a rel="nofollow" href="https://www.ochobitshacenunbyte.com/2021/04/16/ssmtp-envio-facil-de-correo-desde-la-consola-de-comandos-en-linux/">SSMTP: Envío fácil de correo desde la consola de comandos en Linux</a> se publicó primero en <a rel="nofollow" href="https://www.ochobitshacenunbyte.com">ochobitshacenunbyte</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://evercade.co.uk/wp-content/uploads/2021/04/cropped-heart-32x32-1.png" alt="Mega Cat Studios Collection 2 is coming to Evercade">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Mega Cat Studios Collection 2 is coming to Evercade</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Evercade</a> <span class="article__date">15 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>We&#8217;re delighted to announce the Mega Cat Studios Collection 2 cartridge which will feature 8 more classic Mega Cat Studios games to the Evercade! The new 8 game collection, due for release on September 29th 2021, will bring more games from the independent publisher. following the great reception of Mega Cat Studios Collection 1 which... <a class="view-article" href="https://evercade.co.uk/mega-cat-studios-collection-2-is-coming-to-evercade/">View Article</a></p>
<p>The post <a rel="nofollow" href="https://evercade.co.uk/mega-cat-studios-collection-2-is-coming-to-evercade/">Mega Cat Studios Collection 2 is coming to Evercade</a> appeared first on <a rel="nofollow" href="https://evercade.co.uk">Evercade</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://mustcomunicacion.es/wp-content/uploads/2017/05/logo-must-mano-chat-100x100.png" alt="Los mejores plugins para crear tablas de WordPress">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Los mejores plugins para crear tablas de WordPress</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Must Comunicación</a> <span class="article__date">15 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ¿Deseas utilizar las tablas para presentar visualmente información de una manera fácil de usar? Los plugins de tabla ahorran tiempo y evitan los dolores de cabeza que implica la creación de tablas desde cero. No necesitas conocimientos sobre código. Los plugins también son responsivos y compatibles con los dispositivos móviles, por lo que las tablas [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Las tripas de SonarQube: Métricas y cómo calcula el Rating (Parte 2)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">En Mi Local Funciona</a> <span class="article__date">15 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        En este post vamos a verle las tripas a SonarQube y a entender por qué y cómo categoriza los proyectos y cada métrica con un determinado Rating.

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Meeting</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">15 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://mustcomunicacion.es/wp-content/uploads/2017/05/logo-must-mano-chat-100x100.png" alt="Mejores temas de WooCommerce para vender productos digitales">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Mejores temas de WooCommerce para vender productos digitales</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Must Comunicación</a> <span class="article__date">14 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        El comercio electrónico lo es todo. Pero probablemente es algo que ya sabías. Lo que quizás no sepas, sin embargo, es cuán dominantes son las ventas online y la venta de productos digitales, no en los últimos años, sino en los últimos meses. Sí, lo leíste correctamente. Meses. A principios de 2020, el comercio electrónico [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://mustcomunicacion.es/wp-content/uploads/2017/05/logo-must-mano-chat-100x100.png" alt="Mejores plugins de localización de tiendas para WordPress">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Mejores plugins de localización de tiendas para WordPress</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Must Comunicación</a> <span class="article__date">14 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Los plugins de localización de WordPress son la solución perfecta para proporcionar una manera adecuada para que tus clientes encuentren tu tienda más cercana y la ruta más corta de llegar allí, especialmente si tu negocio tiene varias ubicaciones. Es posible que los clientes quieran un contacto de cerca con un producto antes de realizar [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://mustcomunicacion.es/wp-content/uploads/2017/05/logo-must-mano-chat-100x100.png" alt="Mejores temas WooCommerce de muebles para WordPress">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Mejores temas WooCommerce de muebles para WordPress</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Must Comunicación</a> <span class="article__date">14 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Crear una tienda online es más fácil de lo que crees. Hoy en día, WordPress y WooCommerce facilitan la construcción de un completo negocio online. No solo es fácil, sino también rápido, rentable y altamente recomendado usar WordPress y WooCommerce como tu plataforma para la creación de sitios web. Juntos te permiten construir tu tienda [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Why My Blog is Closed-Source</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">14 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        In our community, it's so common for developer projects to be open-source. I'm breaking with this trend for my blog, but I have good reasons! In this article, I'll share my reasoning, as well as a workaround in case you _really_ want to see the source. If you're considering whether a project should be open-source or not, I hope you'll find it valuable.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://cdn.evilmartians.com/front/blocks/common/images/social-5e5bfff.png" alt="From zero to hero: Building and scaling Groupon Russia">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">From zero to hero: Building and scaling Groupon Russia</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Martian Chronicles, Evil Martians’ team blog</a> <span class="article__date">14 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://javierarcheni.com/wp-content/uploads/2021/04/cropped-favicon-javierarcheni-32x32.png" alt="Implementar un aviso de cookies para cumplir con la normativa RGPD en el 2021">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Implementar un aviso de cookies para cumplir con la normativa RGPD en el 2021</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Javier Archeni</a> <span class="article__date">13 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Actualización 19/04/2021: Tras valorar opciones he decidido que este sitio web no utilice cookies en la parte del visitante. No obstante el ejemplo expuesto sigue siendo válido para gestionar las cookies de un sitio web. A casi nadie se le escapa que navegar por internet es básicamente cerrar avisos y ventanas. Y pocos sitios web &#8230; <a href="https://javierarcheni.com/blog/implementar-un-aviso-de-cookies-para-cumplir-con-la-normativa-rgpd-en-el-2021/">Ver más</a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">YUM, solventar fatal error, run database recovery</h1>
                            <h2 class="article__feed"><a target="_blank" href="">ochobitshacenunbyte</a> <span class="article__date">13 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Ya sabéis que utilizo la web para mis apuntes personales, así que otra va, en este caso para solventar un problema con YUM, que como sabéis se encarga, en versiones antiguas de RHEL o&#46;&#46;&#46;</p>
<p>La entrada <a rel="nofollow" href="https://www.ochobitshacenunbyte.com/2021/04/13/yum-solventar-fatal-error-run-database-recovery/">YUM, solventar fatal error, run database recovery</a> se publicó primero en <a rel="nofollow" href="https://www.ochobitshacenunbyte.com">ochobitshacenunbyte</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Actuating Google Production: How Google’s Site Reliability Engineering Team Uses Go</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">13 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Phaser 3: Mi primer juego HTML5/JS (Parte 1)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">En Mi Local Funciona</a> <span class="article__date">13 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <h3 id="introduccin">Introducción</h3>

<p>¿Qué programador no ha soñado con participar en la creación de un videojuego? No sé vosotros, pero a mí siempre me ha gustado la idea de desarrollar un pequeño juego, ya desde los tiempos del <strong>Commodore 64</strong> o del <strong>Sinclair Spectrum</strong>, que me ponía a copiar el código <em>"Basic"</em></p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Say Hello To CSS Container Queries</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Ahmad Shadeed Blog</a> <span class="article__date">13 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2021/213-introduction.png" alt="Introduction">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Introduction</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">13 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2021/213-introduction.png" alt="Introduction" title="We also have deadline waiting" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Logica: organizing your data queries, making them universally reusable and fun</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">12 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://programadorwebvalencia.com/img/blog/2017/06/logo-debian.png" alt="¿Qué hacer después de instalar Debian en un VPS o servidor?">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">¿Qué hacer después de instalar Debian en un VPS o servidor?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Programador Web Valencia</a> <span class="article__date">12 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://programadorwebvalencia.com/img/blog/2017/06/logo-debian.png" alt="Logo Debian" class="medium" /></p>

<p>Estos son todos los pasos que realizo cuando creo un <strong>VPS</strong> o <strong>servidor en Debian</strong>. A lo largo del tiempo he ido añadiendo puntos, modificando y quitando elementos innecesarios; por lo que no lo percibáis como “La guía definitiva”. Sino más bien como unos “apuntes de apoyo”. Personalmente ejecuto todo, aunque cada proyecto es un desafío diferente.</p>

<h2 id="1-actualizar-a-la-última-versión-y-estable">1. Actualizar a la última versión y estable</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt update <span class="o">&amp;&amp;</span> <span class="se">\</span>
apt upgrade <span class="nt">-y</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
apt dist-upgrade
</code></pre></div></div>

<h2 id="2-instalar-software-mínimo">2. Instalar software mínimo</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install</span> <span class="nt">-y</span> build-essential fail2ban iptables-persistent msmtp-mta python3-dev python3-pip libcurl4-openssl-dev libssl-dev htop git neovim wget curl zsh tmux <span class="o">&amp;&amp;</span> <span class="se">\</span>
sh <span class="nt">-c</span> <span class="s2">"</span><span class="si">$(</span>curl <span class="nt">-fsSL</span> https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh<span class="si">)</span><span class="s2">"</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
apt autoremove <span class="nt">-y</span>
</code></pre></div></div>

<h2 id="3-configurar-el-cortafuegos">3. Configurar el cortafuegos</h2>

<p>Dejamos pasar 80 y 443 para permitir los protocolos http y https.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 80 <span class="nt">-j</span> ACCEPT <span class="o">&amp;&amp;</span>
iptables <span class="nt">-A</span> INPUT <span class="nt">-p</span> tcp <span class="nt">--dport</span> 443 <span class="nt">-j</span> ACCEPT
</code></pre></div></div>

<h2 id="4-cambiar-editor-por-defecto">4. Cambiar editor por defecto</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>update-alternatives <span class="nt">--config</span> editor
</code></pre></div></div>

<h2 id="5-ajustar-la-hora">5. Ajustar la hora</h2>

<p>En este ejemplo configura la hora a Madrid (España).</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ln</span> <span class="nt">-fs</span> /usr/share/zoneinfo/Europe/Madrid /etc/localtime <span class="o">&amp;&amp;</span> <span class="se">\</span>
dpkg-reconfigure <span class="nt">-f</span> noninteractive tzdata
</code></pre></div></div>

<h2 id="6-activa-las-actualizaciones-automáticas-de-seguridad-no-atendidas">6. Activa las actualizaciones automáticas de seguridad no atendidas</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt <span class="nb">install</span> <span class="nt">-y</span> unattended-upgrades apt-listchanges <span class="o">&amp;&amp;</span> <span class="se">\</span>
<span class="nb">echo </span>unattended-upgrades unattended-upgrades/enable_auto_updates boolean <span class="nb">true</span> | debconf-set-selections <span class="o">&amp;&amp;</span> <span class="se">\</span>
dpkg-reconfigure <span class="nt">-f</span> noninteractive unattended-upgrades
</code></pre></div></div>

<h2 id="7-crea-un-usuario">7. Crea un usuario</h2>

<p>Se llamará <code class="highlighter-rouge">debian</code>, aunque puedes llamarlo como desees.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd <span class="nt">--shell</span> /bin/zsh <span class="nt">-m</span> debian
</code></pre></div></div>

<p>Ahora nos metemos en el usuario.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>su debian
</code></pre></div></div>

<p>Configurarmos las claves <code class="highlighter-rouge">ssh</code> y <code class="highlighter-rouge">oh-my-zsh</code>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssh-keygen <span class="nt">-t</span> rsa
<span class="nb">exit</span>
</code></pre></div></div>

<p>Lo añadimos al grupo de <code class="highlighter-rouge">sudo</code>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>usermod <span class="nt">-a</span> <span class="nt">-G</span> <span class="nb">sudo </span>debian
</code></pre></div></div>

<p>Entramos en <code class="highlighter-rouge">visudo</code> para permitirle ejecutar <code class="highlighter-rouge">sudo</code>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>visudo
</code></pre></div></div>

<p>Editando la siguente línea.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>%sudo   <span class="nv">ALL</span><span class="o">=(</span>ALL:ALL<span class="o">)</span> NOPASSWD:ALL
</code></pre></div></div>

<p>Generamos la <code class="highlighter-rouge">keygen</code> de <code class="highlighter-rouge">ssh</code> para entrar en un futuro.</p>

<p>Copiamos las autorizaciones actuales asociadas con <code class="highlighter-rouge">root</code>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cp</span> /root/.ssh/authorized_keys /home/debian/.ssh/ <span class="o">&amp;&amp;</span> <span class="se">\</span>
<span class="nb">chown </span>debian:debian /home/debian/.ssh/authorized_keys
</code></pre></div></div>

<h2 id="8-medida-de-seguridad-ante-disco-lleno">8. Medida de seguridad ante disco lleno</h2>

<p>Añadimos una archivo con contenido aleatorio de, por ejemplo, 1Gb. En caso que se llene el disco, podremos borrarlo para tener un margen de acción.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">dd </span><span class="k">if</span><span class="o">=</span>/dev/urandom <span class="nv">of</span><span class="o">=</span>balloon.txt <span class="nv">bs</span><span class="o">=</span>1MB <span class="nv">count</span><span class="o">=</span>1000
</code></pre></div></div>

<h2 id="9-limita-el-espacio-de-los-logs">9. Limita el espacio de los logs</h2>

<p>Editas</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano /etc/systemd/journald.conf
</code></pre></div></div>

<p>Descomentas (quitas la <code class="highlighter-rouge">#</code>) a la vez que modificas la siguiente línea.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">SystemMaxUse</span><span class="o">=</span>1Gb
</code></pre></div></div>

<p>Para terminar reinicia el servicio.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>systemctl restart systemd-journald
</code></pre></div></div>

<h2 id="extras">Extras</h2>

<h3 id="instalar-docker">Instalar docker</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apt update <span class="o">&amp;&amp;</span> <span class="se">\</span>
apt <span class="nb">install</span> <span class="nt">-y</span> <span class="se">\</span>
    apt-transport-https <span class="se">\</span>
    ca-certificates <span class="se">\</span>
    curl <span class="se">\</span>
    gnupg <span class="se">\</span>
    lsb-release <span class="o">&amp;&amp;</span> <span class="se">\</span>
curl <span class="nt">-fsSL</span> https://download.docker.com/linux/debian/gpg | <span class="nb">sudo </span>gpg <span class="nt">--dearmor</span> <span class="nt">-o</span> /usr/share/keyrings/docker-archive-keyring.gpg <span class="o">&amp;&amp;</span> <span class="se">\</span>
<span class="nb">echo</span> <span class="se">\</span>
  <span class="s2">"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian </span><span class="se">\</span><span class="s2">
  </span><span class="si">$(</span>lsb_release <span class="nt">-cs</span><span class="si">)</span><span class="s2"> stable"</span> | <span class="nb">tee</span> /etc/apt/sources.list.d/docker.list <span class="o">&gt;</span> /dev/null <span class="o">&amp;&amp;</span> <span class="se">\</span>
apt update <span class="o">&amp;&amp;</span> <span class="se">\</span>
apt <span class="nt">-y</span> <span class="nb">install </span>docker-ce docker-ce-cli containerd.io docker-compose
</code></pre></div></div>

<h3 id="activar-swap">Activar Swap</h3>

<p>Habilitamos un espacio reservado en el disco en caso de que la <code class="highlighter-rouge">RAM</code> se llene.</p>

<p>Instalamos <code class="highlighter-rouge">zram</code>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install </span>zram-tools
</code></pre></div></div>

<p>Editamos su configuración.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>nano /etc/default/zramswap
</code></pre></div></div>

<p>Le marcamos que su capacidad sea la mitad de la <code class="highlighter-rouge">RAM</code>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">PERCENTAGE</span><span class="o">=</span>50
<span class="nv">ALLOCATION</span><span class="o">=</span>4096 <span class="c">#4Mb</span>
<span class="nv">ALLOCATION</span><span class="o">=</span>8192 <span class="c">#8Mb</span>
</code></pre></div></div>

<h3 id="instalar-snap">Instalar snap</h3>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install </span>snapd
</code></pre></div></div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Statement of FSF board on election of Richard Stallman</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FSF News</a> <span class="article__date">12 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">RMS addresses the free software community</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FSF News</a> <span class="article__date">12 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Would Alfred Hitchcock use Emacs?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Manuel Uberti</a> <span class="article__date">12 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>First you have to excuse the awful title, but a <a href="https://www.filmsinwords.eu">cinephile</a> cannot resist the
temptation of an easy reference when the Emacs package he is going to write
about is called <a href="https://github.com/minad/vertico">Vertico</a>.</p>

<p>Daniel Mendler has become such a prolific contributor to our Emacs world. His
work with Omar Antolín Camarena and Clemens Radermacher (to name a few!) has
been showing me how much can be done with little improvements on Emacs default
completion system. Actually, “little” is a bit unfair to them because they have
been putting a lot of effort in their packages and contributions. What “little”
stands for instead is the amount of code I had to add to my <code class="language-plaintext highlighter-rouge">init.el</code> to get a
superb completion UI. I combine Vertico with <a href="https://github.com/oantolin/orderless">Orderless</a> and I didn’t have to do
much beside this after the installation via <code class="language-plaintext highlighter-rouge">package.el</code>:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="p">(</span><span class="nb">require</span> <span class="ss">'orderless</span><span class="p">)</span>
 <span class="p">(</span><span class="k">setq</span> <span class="nv">completion-styles</span> <span class="o">'</span><span class="p">(</span><span class="nv">orderless</span><span class="p">))</span>
 
 <span class="p">(</span><span class="nb">require</span> <span class="ss">'vertico</span><span class="p">)</span>
 <span class="p">(</span><span class="nv">vertico-mode</span> <span class="mi">+1</span><span class="p">)</span>
</code></pre></div></div>

<p>Well, to be fair I did something more, like binding <code class="language-plaintext highlighter-rouge">vertico-exit-input</code> to <kbd>C-j</kbd>
and setting <code class="language-plaintext highlighter-rouge">orderless-matching-styles</code> to <code class="language-plaintext highlighter-rouge">orderless-regexp</code>, plus I am using
Daniel’s <a href="https://github.com/minad/consult">consult</a> to extend Vertico capabilities, but I guess you see where I am
going by now. The combination of small packages makes for a modular system that
I can interact with more easily. For instance, Daniel can go berserk and forget
about the lovely 500 lines of code limit he set himself to with Vertico. Why
should I trust this criminal mind, then? I can switch to <a href="https://github.com/raxod502/selectrum">Selectrum</a> and keep
using Consult and Orderless with it<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>.</p>

<p>The beauty of Vertico is that it is not about reinventing Emacs completion once
again. By sticking to Emacs built-in commands and completion facilities, Vertico
succeeds in staying close to the source without losing the chance to improve on
it. On the one hand, moving to Vertico means it is up to the user to configure
extra niceties. That is what packages like Consult, Orderless, <a href="https://github.com/oantolin/embark">Embark</a>, and
<a href="https://github.com/minad/marginalia">Marginalia</a> aim for, but again, the user is in charge of the right setup for
their needs, while a solution such as Helm offers a lot of functionalities out
of the box. On the other hand, tools such as Helm, Ivy, and Selectrum are more
complex than Vertico and may bring in code you do not necessarily need, which is
something even Emacs itself doesn’t shy away from<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup>.</p>

<p>I find it amazing that a seemingly simple and yet so central feature in my
everyday Emacs such as the completion system has pushed people to create all
these amazing packages. It seems to me that Helm has helped pave the way for a
more powerful experience when it comes to completion and that by studying Emacs
internals carefully one can achieve similar benefits with a different approach.
As humble end-users of all this we really are a lucky bunch.</p>

<h2 id="notes">Notes</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>The irony should be obvious. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>I don’t really need games in my text editor. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Would Alfred Hitchcock use Emacs?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Manuel Uberti</a> <span class="article__date">12 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>First you have to excuse the awful title, but a <a href="https://www.filmsinwords.eu">cinephile</a> cannot resist the
temptation of an easy reference when the Emacs package he is going to write
about is called <a href="https://github.com/minad/vertico">Vertico</a>.</p>

<p>Daniel Mendler has become such a prolific contributor to our Emacs world. His
work with Omar Antolín Camarena and Clemens Radermacher (to name a few!) has
been showing me how much can be done with little improvements on Emacs default
completion system. Actually, “little” is a bit unfair to them because they have
been putting a lot of effort in their packages and contributions. What “little”
stands for instead is the amount of code I had to add to my <code class="language-plaintext highlighter-rouge">init.el</code> to get a
superb completion UI. I combine Vertico with <a href="https://github.com/oantolin/orderless">Orderless</a> and I didn’t have to do
much beside this after the installation via <code class="language-plaintext highlighter-rouge">package.el</code>:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="p">(</span><span class="nb">require</span> <span class="ss">'orderless</span><span class="p">)</span>
 <span class="p">(</span><span class="k">setq</span> <span class="nv">completion-styles</span> <span class="o">'</span><span class="p">(</span><span class="nv">orderless</span><span class="p">))</span>
 
 <span class="p">(</span><span class="nb">require</span> <span class="ss">'vertico</span><span class="p">)</span>
 <span class="p">(</span><span class="nv">vertico-mode</span> <span class="mi">+1</span><span class="p">)</span>
</code></pre></div></div>

<p>Well, to be fair I did something more, like binding <code class="language-plaintext highlighter-rouge">vertico-exit-input</code> to <kbd>C-j</kbd>
and setting <code class="language-plaintext highlighter-rouge">orderless-matching-styles</code> to <code class="language-plaintext highlighter-rouge">orderless-regexp</code>, plus I am using
Daniel’s <a href="https://github.com/minad/consult">consult</a> to extend Vertico capabilities, but I guess you see where I am
going by now. The combination of small packages makes for a modular system that
I can interact with more easily. For instance, Daniel can go berserk and forget
about the lovely 500 lines of code limit he set himself to with Vertico. Why
should I trust this criminal mind, then? I can switch to <a href="https://github.com/raxod502/selectrum">Selectrum</a> and keep
using Consult and Orderless with it<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>.</p>

<p>The beauty of Vertico is that it is not about reinventing Emacs completion once
again. By sticking to Emacs built-in commands and completion facilities, Vertico
succeeds in staying close to the source without losing the chance to improve on
it. On the one hand, moving to Vertico means it is up to the user to configure
extra niceties. That is what packages like Consult, Orderless, <a href="https://github.com/oantolin/embark">Embark</a>, and
<a href="https://github.com/minad/marginalia">Marginalia</a> aim for, but again, the user is in charge of the right setup for
their needs, while a solution such as Helm offers a lot of functionalities out
of the box. On the other hand, tools such as Helm, Ivy, and Selectrum are more
complex than Vertico and may bring in code you do not necessarily need, which is
something even Emacs itself doesn’t shy away from<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup>.</p>

<p>I find it amazing that a seemingly simple and yet so central feature in my
everyday Emacs such as the completion system has pushed people to create all
these amazing packages. It seems to me that Helm has helped pave the way for a
more powerful experience when it comes to completion and that by studying Emacs
internals carefully one can achieve similar benefits with a different approach.
As humble end-users of all this we really are a lucky bunch.</p>

<h2 id="notes">Notes</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>The irony should be obvious. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>I don’t really need games in my text editor. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://cdn.evilmartians.com/front/blocks/common/images/social-5e5bfff.png" alt="Hotwire: Reactive Rails with no JavaScript?">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hotwire: Reactive Rails with no JavaScript?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Martian Chronicles, Evil Martians’ team blog</a> <span class="article__date">12 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://programadorwebvalencia.com/img/blog/2021/04/comprimir.png" alt="Comandos para comprimir y descomprimir">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Comandos para comprimir y descomprimir</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Programador Web Valencia</a> <span class="article__date">11 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://programadorwebvalencia.com/img/blog/2021/04/comprimir.png" alt="Comprimir" class="medium" /></p>

<p>Dentro de Linux y MacOS disponemos de una herramientas preinstalada que es fantásticas para comprimir y descomprimir cualquier tipo de archivo: fotos, vídeos, texto, carpetas… Con solo <code class="highlighter-rouge">tar</code> ya podremos realizar las tareas básicas.</p>

<p>Conceptos importantes.</p>

<ul>
  <li><code class="highlighter-rouge">tar</code>: Tarro o contenedor. Sirve para agrupar un conjuntos de archivos, no comprime.</li>
  <li><code class="highlighter-rouge">gzip</code>: Algoritmo de compresión malo pero rápido. Equivalente a un <code class="highlighter-rouge">zip</code>.</li>
  <li><code class="highlighter-rouge">bz2</code>: Algoritmo de compresión bueno pero lento. Equivalente a un <code class="highlighter-rouge">rar</code>.</li>
</ul>

<h2 id="comprimir">Comprimir</h2>

<h3 id="tar">tar</h3>

<p>Ejemplo de como crear un grupo o archivador usando <code class="highlighter-rouge">tar</code>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">tar</span> <span class="nt">-cvf</span> nombre.tar carpetas-o-archivos
</code></pre></div></div>

<p><code class="highlighter-rouge">c</code> —&gt; Crea un archivador (<code class="highlighter-rouge">tar</code>).</p>

<p><code class="highlighter-rouge">v</code> —&gt; Muestra el progreso.</p>

<p><code class="highlighter-rouge">f</code> —&gt; Indicamos que vamos a especificar el nombre final.</p>

<h3 id="gzip">gzip</h3>

<p>Ejemplo de como comprimir creado un <code class="highlighter-rouge">zip</code> equivalente en Linux.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">tar</span> <span class="nt">-czvf</span> futuro-comprimido.tar.gz carpetas-o-archivos-a-comprimir
</code></pre></div></div>

<p><code class="highlighter-rouge">c</code> —&gt; Crea un archivador (tar).</p>

<p><code class="highlighter-rouge">z</code> —&gt; Comprime usando gzip (zip)</p>

<p><code class="highlighter-rouge">v</code> —&gt; Muestra el progreso.</p>

<p><code class="highlighter-rouge">f</code> —&gt; Indicamos que vamos a especificar el nombre final.</p>

<h3 id="bz2">bz2</h3>

<p>Ejemplo de como comprimir creado un <code class="highlighter-rouge">rar</code> equivalente en Linux. (sustituye <code class="highlighter-rouge">z</code> por <code class="highlighter-rouge">j</code>)</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">tar</span> <span class="nt">-cjvf</span> futuro-comprimido.tar.bz2 carpetas-o-archivos-a-comprimir
</code></pre></div></div>

<p><code class="highlighter-rouge">c</code> —&gt; Crea un archivador (<code class="highlighter-rouge">tar</code>).</p>

<p><code class="highlighter-rouge">j</code> —&gt; Comprime usando bzip2 (equivalente a <code class="highlighter-rouge">rar</code>)</p>

<p><code class="highlighter-rouge">v</code> —&gt; Muestra el progreso.</p>

<p><code class="highlighter-rouge">f</code> —&gt; Indicamos que usaremos un archivo.</p>

<h2 id="descomprimir">Descomprimir</h2>

<p>Ejemplo de como descomprimir cualquier formato: <code class="highlighter-rouge">tar</code>, <code class="highlighter-rouge">tar.gz</code> o <code class="highlighter-rouge">tar.bz2</code>.  (sustituye <code class="highlighter-rouge">c</code> por <code class="highlighter-rouge">x</code>)</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">tar</span> <span class="nt">-xvf</span> comprimido.tar.gz
</code></pre></div></div>

<p><code class="highlighter-rouge">x</code> —&gt; Extrae.</p>

<p><code class="highlighter-rouge">v</code> —&gt; Muestra el progreso.</p>

<p><code class="highlighter-rouge">f</code> —&gt; Indicamos que usaremos un archivo.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Подкаст DevZen, эпизод 331</h1>
                            <h2 class="article__feed"><a target="_blank" href="">tonsky.me</a> <span class="article__date">10 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Announcing the First Group of Google Open Source Peer Bonus winners in 2021!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">08 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Announcing Board Nominations</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">08 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together members can now vote for the next board members.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Back to the roots</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Manuel Uberti</a> <span class="article__date">08 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><a href="https://www.manueluberti.eu/emacs/2021/03/08/package/">Last time</a> I left <code class="language-plaintext highlighter-rouge">straight</code> for the built-in <code class="language-plaintext highlighter-rouge">package.el</code>, a choice I have not had
the pleasure to regret so far. Now I am going to reason about a more ambitious
change in my Emacs configuration: I am not using <a href="https://github.com/jwiegley/use-package">use-package</a> any more.</p>

<p>Before answering your concerned <em>why!?</em> let me just say that if you are happy with
<code class="language-plaintext highlighter-rouge">use-package</code> you should stay with it. By wrapping all the settings to a built-in
feature or an external package with <code class="language-plaintext highlighter-rouge">use-package</code> you can easily notice what you
are doing wrong when tweaking something, while having control over the
installation and the loading of your favourite library as well. Despite some
unhappiness around the web<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>, <code class="language-plaintext highlighter-rouge">use-package</code> is just a great tool that any serious
Emacs hacker should consider when digging deep into their <code class="language-plaintext highlighter-rouge">.emacs.d</code>.</p>

<p>As for my choice to move away from it, it all started as an experiment. I wanted
to see if I could have the same amount of control and readability over my
<code class="language-plaintext highlighter-rouge">init.el</code> without an extra package. You see, most of the recent changes to my
setup involved trying to rely on Emacs own facilities to answer my needs, and
I am glad to say vanilla Emacs has been really a surprise in this regard. My
liaisons with <a href="https://www.manueluberti.eu/emacs/2020/09/18/project/">project.el</a> and <a href="https://www.manueluberti.eu/emacs/2020/09/23/flymake/">Flymake</a> are nice examples of this.</p>

<p>Removing <code class="language-plaintext highlighter-rouge">use-package</code> has meant rethinking the way I install packages, especially
if I want my setup to be ready to go any time I upgrade to a newer version of
Ubuntu. My solution was adding the packages I use to <code class="language-plaintext highlighter-rouge">package-selected-packages</code>
and have a check on startup to make sure they are installed. This works very
well combined with <code class="language-plaintext highlighter-rouge">package-autoremove</code>: if a package is not listed under
<code class="language-plaintext highlighter-rouge">package-selected-packages</code>, Emacs takes care of the mess.</p>

<p>All the <code class="language-plaintext highlighter-rouge">use-package</code> blocks have been replaced with a combination of
<code class="language-plaintext highlighter-rouge">with-eval-after-load</code>, <code class="language-plaintext highlighter-rouge">define-key</code>, and <code class="language-plaintext highlighter-rouge">add-hook</code>, which was not as complicated as
it might sound, and more often than not was similar to what I had in my days
before the <code class="language-plaintext highlighter-rouge">use-package</code> takeover. True, I lost the nice readability of
<code class="language-plaintext highlighter-rouge">use-package</code> with this massive edit. For example, its keywords have the benefit
of grouping settings together and clearly indicate when a new group starts, but
on the other hand now there is less macro-magic masking package-related
operations involved. As a result I have a more detailed insight of what is
really going on with my Emacs Lisp. For instance, I have gained a better
knowledge of what <code class="language-plaintext highlighter-rouge">run-with-idle-timer</code> actually does.</p>

<p>Again, it is a matter of personal preferences. By now the beauty of <code class="language-plaintext highlighter-rouge">use-package</code>
is well-known in the Emacs world and all the praises are well-deserved. Let me
stress it again: <code class="language-plaintext highlighter-rouge">use-package</code> makes your configuration simpler to manage and
easier to read. Those were the main reasons I switched to it years ago, anyway.</p>

<p>However, if you know what you are doing you can achieve a clean and pleasant
<code class="language-plaintext highlighter-rouge">init.el</code> with what Emacs already offers. Does it take more effort? Yes, it
probably does. Is it really worth it? It’s up to you, mate. Am I just showing
off? No, come on, don’t be rude.</p>

<h2 id="notes">Notes</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>See for instance <a href="https://github.com/conao3/leaf.el#description">here</a> or <a href="https://two-wrongs.com/migrating-away-from-use-package">here</a>. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Back to the roots</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Manuel Uberti</a> <span class="article__date">08 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><a href="https://www.manueluberti.eu/emacs/2021/03/08/package/">Last time</a> I left <code class="language-plaintext highlighter-rouge">straight</code> for the built-in <code class="language-plaintext highlighter-rouge">package.el</code>, a choice I have not had
the pleasure to regret so far. Now I am going to reason about a more ambitious
change in my Emacs configuration: I am not using <a href="https://github.com/jwiegley/use-package">use-package</a> any more.</p>

<p>Before answering your concerned <em>why!?</em> let me just say that if you are happy with
<code class="language-plaintext highlighter-rouge">use-package</code> you should stay with it. By wrapping all the settings to a built-in
feature or an external package with <code class="language-plaintext highlighter-rouge">use-package</code> you can easily notice what you
are doing wrong when tweaking something, while having control over the
installation and the loading of your favourite library as well. Despite some
unhappiness around the web<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>, <code class="language-plaintext highlighter-rouge">use-package</code> is just a great tool that any serious
Emacs hacker should consider when digging deep into their <code class="language-plaintext highlighter-rouge">.emacs.d</code>.</p>

<p>As for my choice to move away from it, it all started as an experiment. I wanted
to see if I could have the same amount of control and readability over my
<code class="language-plaintext highlighter-rouge">init.el</code> without an extra package. You see, most of the recent changes to my
setup involved trying to rely on Emacs own facilities to answer my needs, and
I am glad to say vanilla Emacs has been really a surprise in this regard. My
liaisons with <a href="https://www.manueluberti.eu/emacs/2020/09/18/project/">project.el</a> and <a href="https://www.manueluberti.eu/emacs/2020/09/23/flymake/">Flymake</a> are nice examples of this.</p>

<p>Removing <code class="language-plaintext highlighter-rouge">use-package</code> has meant rethinking the way I install packages, especially
if I want my setup to be ready to go any time I upgrade to a newer version of
Ubuntu. My solution was adding the packages I use to <code class="language-plaintext highlighter-rouge">package-selected-packages</code>
and have a check on startup to make sure they are installed. This works very
well combined with <code class="language-plaintext highlighter-rouge">package-autoremove</code>: if a package is not listed under
<code class="language-plaintext highlighter-rouge">package-selected-packages</code>, Emacs takes care of the mess.</p>

<p>All the <code class="language-plaintext highlighter-rouge">use-package</code> blocks have been replaced with a combination of
<code class="language-plaintext highlighter-rouge">with-eval-after-load</code>, <code class="language-plaintext highlighter-rouge">define-key</code>, and <code class="language-plaintext highlighter-rouge">add-hook</code>, which was not as complicated as
it might sound, and more often than not was similar to what I had in my days
before the <code class="language-plaintext highlighter-rouge">use-package</code> takeover. True, I lost the nice readability of
<code class="language-plaintext highlighter-rouge">use-package</code> with this massive edit. For example, its keywords have the benefit
of grouping settings together and clearly indicate when a new group starts, but
on the other hand now there is less macro-magic masking package-related
operations involved. As a result I have a more detailed insight of what is
really going on with my Emacs Lisp. For instance, I have gained a better
knowledge of what <code class="language-plaintext highlighter-rouge">run-with-idle-timer</code> actually does.</p>

<p>Again, it is a matter of personal preferences. By now the beauty of <code class="language-plaintext highlighter-rouge">use-package</code>
is well-known in the Emacs world and all the praises are well-deserved. Let me
stress it again: <code class="language-plaintext highlighter-rouge">use-package</code> makes your configuration simpler to manage and
easier to read. Those were the main reasons I switched to it years ago, anyway.</p>

<p>However, if you know what you are doing you can achieve a clean and pleasant
<code class="language-plaintext highlighter-rouge">init.el</code> with what Emacs already offers. Does it take more effort? Yes, it
probably does. Is it really worth it? It’s up to you, mate. Am I just showing
off? No, come on, don’t be rude.</p>

<h2 id="notes">Notes</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>See for instance <a href="https://github.com/conao3/leaf.el#description">here</a> or <a href="https://two-wrongs.com/migrating-away-from-use-package">here</a>. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Shy Coder</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">08 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Analyzing genomic data in families with deep learning</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">07 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Inspect Element As A Way To Increase Your Curiosity</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Ahmad Shadeed Blog</a> <span class="article__date">07 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Мы обречены — Open Source</h1>
                            <h2 class="article__feed"><a target="_blank" href="">tonsky.me</a> <span class="article__date">07 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="¿Qué es el testing? – Informe Testing I">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">¿Qué es el testing? – Informe Testing I</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">06 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Primer episodio de una serie especial que vamos a dedicar al mundo del testing. Para esta primera parte Andros Fenollosa repasa con David las metodologías de testing, discutiendo además las ventajas y las desventajas de seguir realizar pruebas en nuestro código. Entre las cuestiones habladas:</p>



<ul>

<li>Filosofías
<ul>
<li>Desarrollo guiado por pruebas (TDD).</li>
<li>Desarrollo guiado por el comportamiento (BDD).</li>
<li>Desarrollo guidado a datos (DDD).

</li></ul>
<li>Frameworks de testing</li>
</li>

<li>Pruebas dependiendo de la visibilidad

<ul>
<li>Pruebas de caja blanca.</li>
<li>Pruebas de caja gris.</li>
<li>Pruebas de caja negra</li>

</ul>
</li>


<li>Pruebas dependiendo de la ejecución de las aplicaciones

<ul>
<li>Pruebas estáticas</li>
<li>Pruebas dinámicas</li>
</ul>
</li>


<li>Pruebas Funcionales

<ul>
<li>Pruebas de unidad</li>
<li>Pruebas de integración</li>
<li>Pruebas de aceptación</li>
<li>Pruebas de extremo a extremo (E2E)</li>
</ul>
</li>

<li>Pruebas no Funcionales</li>

<li>Pruebas de rendimiento</li>

<li>Pruebas de seguridad</li>
<li>Pruebas aleatorias (Fuzzing).</li>

<li>Pruebas según el número de pruebas a realizar
<ul>
<li>Pruebas de humo</li>
<li>Pruebas de sanidad</li>
<li>Pruebas de regresión/sistema</li>
</ul>
</li>

</ul>



<p>Se trata de un episodio de introducción al testing, hablando también sobre las consideraciones habituales al tratar esta metodología en los equipos y empresas. También hablan de algunas experiencias relacionadas con el testing.</p>



<p></p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Lyra - enabling voice calls for the next billion users</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">06 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Mosh, un ssh más eficiente en Linux</h1>
                            <h2 class="article__feed"><a target="_blank" href="">ochobitshacenunbyte</a> <span class="article__date">06 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>La entrada de hoy va dedicada a mosh, que significa Mobile Shell Es una aplicación de línea de comandos, que se utiliza para conectarse al servidor desde una computadora cliente, a través de Internet.&#46;&#46;&#46;</p>
<p>La entrada <a rel="nofollow" href="https://www.ochobitshacenunbyte.com/2021/04/06/mosh-un-ssh-mas-eficiente-en-linux/">Mosh, un ssh más eficiente en Linux</a> se publicó primero en <a rel="nofollow" href="https://www.ochobitshacenunbyte.com">ochobitshacenunbyte</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://thehistoryoftheweb.com/wp-content/uploads/2017/09/cropped-thotw-logo-square-1-32x32.jpg" alt="The Internet Book Baron">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Internet Book Baron</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The History of the Web</a> <span class="article__date">06 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>This week I have something a bit different, written by longtime newsletter author Ernie Smith, best known for his history [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://thehistoryoftheweb.com/postscript/the-internet-book-baron/">The Internet Book Baron</a> appeared first on <a rel="nofollow" href="https://thehistoryoftheweb.com">The History of the Web</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cómo montar un SonarQube en Cloud que nos sirva de Spike (Parte 1)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">En Mi Local Funciona</a> <span class="article__date">06 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Muchas veces tenemos que hacer una prueba de concepto de herramientas que no tenemos disponibles, o licencias en ese momento. ¿Cómo tener un SonarQube no productivo en 10 minutos?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/images/content/news/2021-03-15/sizes.png" alt="State of Clojure 2021 Results">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">State of Clojure 2021 Results</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">06 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>While a challenging year overall, 2020 was another good year for Clojure and its ecosystem. One big newsworthy item was that <a href="https://building.nubank.com.br/nubank-acquires-cognitect-press-release">Cognitect joined Nubank</a>, the world’s largest independent digital bank, to <em>reinvent financial services across Latin America</em>. The news was well received, and the general sentiment is summarized by a comment left by one of the survey respondents:</p>
</div>
<div class="quoteblock">
<blockquote>
Great to see the Nubank acquisition of Cognitect. I think this has done wonders to bolster confidence in Clojure and Datomic for the long term. Also the subsequent support of open source developers sends a very positive message, and directly supports a healthy and robust ecosystem.
</blockquote>
<div class="attribution">
&#8212; anonymous survey respondent
</div>
</div>
<div class="paragraph">
<p>Indeed Ed Wible, the co-founder of Nubank <a href="https://building.nubank.com.br/welcoming-cognitect-nubank">talked about Nubank’s commitment to supporting and growing Clojure</a> (and Datomic) into the future.</p>
</div>
<div class="paragraph">
<p>In this post I&#8217;ll outline a few of the more salient points shown in the <a href="https://www.surveymonkey.com/results/SM-S2L8NR6K9">2021 survey</a>. Specifically, I&#8217;ll touch on the use of Clojure in production, the use of Clojure for start-ups, and how Clojure helps programmers and organizations to move quickly and confidently. As an added bonus I&#8217;ll highlight some of the amazing projects and people making the Clojure community strong.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_clojure_in_production"><a class="anchor" href="#_clojure_in_production"></a>Clojure in Production</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Continuing the trend from last year, Clojure has seen growth in large companies (i.e. those having 100-1000 employees).</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="/images/content/news/2021-03-15/sizes.png" alt="A breakdown of the companies sizes using Clojure in production">
</div>
</div>
<div class="paragraph">
<p>Nubank currently employs approximately 700 (at the time of writing) Clojure programmers, and Nubank is just one prominent example of the many banks, mortgage companies, and financial services companies using Clojure today, accounting for 22% (and growing) of the Clojure job market as reported by survey respondents. The survey shows healthy gains in the healthcare and retail markets as well.</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="/images/content/news/2021-03-15/industries.png" alt="Clojure finds adoption in a wide range of industries">
</div>
</div>
<div class="paragraph">
<p>Having said all of that, just where are Clojure projects deployed in production systems? Interestingly, the survey shows some nice growth in the way of public cloud and serverless deployments. The <a href="https://www.investopedia.com/how-amazon-makes-money-4587523">trends for AWS</a> indicate that the cloud market is booming and so it&#8217;s natural that the general increase for that segment would show specifically for Clojure deployments as well.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_clojure_still_for_start_ups"><a class="anchor" href="#_clojure_still_for_start_ups"></a>Clojure (still) for Start-ups</h2>
<div class="sectionbody">
<div class="paragraph">
<p>While more large companies are adopting Clojure than ever, the sweet spot is still the smaller companies of less than 100 employees.</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="/images/content/news/2021-03-15/lgvssmall.png" alt="Clojure is still a language of choice for small companies">
</div>
</div>
<div class="paragraph">
<p>The reasons that start-ups choose Clojure are many and variegated:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Leverage - small effort, big result</p>
</li>
<li>
<p>Ready access to large existing ecosystems - Java, JavaScript, .NET</p>
</li>
<li>
<p>Scalable base - grow from PoC, to MVP, to production systems at scale</p>
</li>
<li>
<p>Moving fast - discussed in the next section</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>One exciting start-up of note in the Clojure ecosystem is <a href="https://roamresearch.com">Roam Research</a>. Roam&#8217;s flagship product is an online note-taking tool that is designed to augment the human mind in building a set of notes that allow deep connectivity and discoverability. The <a href="https://www.theinformation.com/articles/a-200-million-seed-valuation-for-roam-shows-investor-frenzy-for-note-taking-apps">enthusiasm for Roam is palpable</a> and it’ll be fun to watch them grow.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_clojure_for_moving_fast"><a class="anchor" href="#_clojure_for_moving_fast"></a>Clojure for Moving Fast</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Most survey respondents reported that they came to Clojure from the Java programming language. The fact that both languages run on the same virtual machine certainly helps smooth the path from Java to Clojure. However, many other advantages allow Clojure programmers a greater flexibility and agility in their day to day work lives using Clojure.</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="/images/content/news/2021-03-15/features.png" alt="Functional Programming and Lispiness are great force-multipliers">
</div>
</div>
<div class="paragraph">
<p>First, Clojure programmers value a <strong>functional style of programming</strong> facilitating a separation of data and process. Coupled with its suite of immutable data structures, Clojure applications are often built as pipelines of data transformation functions that can be composed to implement higher-level business concepts in software. As a <strong>dialect of Lisp</strong>, Clojure provides an interactive programming environment called the REPL (Read, Eval, Print, Loop). The REPL fosters exploratory programming, allowing Clojure programmers to interactively develop solutions to sticky programming problems using a tight feedback loop. Indeed, the confluence of the REPL, immutable data structures, and functional programming allows for a development process light on ceremony, allowing programmers to focus on the problem at hand rather than the complexities foisted on them by their programming language.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_clojure_ecosystem"><a class="anchor" href="#_the_clojure_ecosystem"></a>The Clojure Ecosystem</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Finally, Clojure would have never grown to its current size without the help of countless developers, technical writers, and big thinkers along the way. The appreciation for the amazing Clojure community is palpable within Nubank and this appreciation is increasingly being expressed as <a href="https://github.com/orgs/nubank/sponsoring">open source project funding</a>. I&#8217;d like to close this year&#8217;s post by highlighting a number of the community leaders mentioned in the survey responses.</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/bbatsov">Bozhidar Batsov</a> <em>for continuing to improve Clojure tooling ecosystem.</em></p>
</li>
<li>
<p>Arne Brasseur - <em><a href="https://github.com/lambdaisland/kaocha">Kaocha</a> is superb and his educational skills fantastic.</em></p>
</li>
<li>
<p><em>Everything <a href="https://github.com/borkdude">Michiel Borkent</a> aka borkdude touches is awesome!</em></p>
</li>
<li>
<p><a href="https://github.com/seancorfield">Sean Corfield</a> <em>because he is always helpful and polite, and writes excellent documentation for important libraries.</em></p>
</li>
<li>
<p><a href="https://github.com/mfikes">Michael Fikes</a> <em>for being enthusiastic, engaging, and inspirational, and approachable.</em></p>
</li>
<li>
<p><a href="https://github.com/thheller">Thomas Heller</a> <em>has made an amazing tool in <a href="https://github.com/thheller/shadow-cljs">shadow-cljs</a>.</em></p>
</li>
<li>
<p>(Daniel) Higginbotham, <em>because he made me laugh hundreds of times while <a href="https://www.braveclojure.com">introducing me to Clojure</a>.</em></p>
</li>
<li>
<p><a href="https://github.com/awkay">Tony Kay</a> <em>and contributors of <a href="https://github.com/fulcrologic/fulcro">Fulcro</a> for providing a comprehensive solution to client-server state management.</em></p>
</li>
<li>
<p><a href="http://www.realgenekim.me">Gene Kim</a> <em>for … unabashed love of the language, and for helping spread the good word.</em></p>
</li>
<li>
<p><a href="https://www.londonclojurians.org">London Clojurians</a> - <em>the online talks in the past year have been amazing.</em></p>
</li>
<li>
<p>Tiago Luchini, <em><a href="https://github.com/hodur-org">Hodur</a> creator.</em></p>
</li>
<li>
<p><a href="https://github.com/gigasquid">Carin Meier</a> <em>for her progressiveness: for advancing the state of the art in machine learning, and her contributions to visibility and representation in the community.</em></p>
</li>
<li>
<p><a href="https://github.com/swannodette">David Nolen</a> <em>is generous with explanations, direct, genuine, and never condescending or judgmental.</em></p>
</li>
<li>
<p><a href="https://lispcast.com">Eric Normand</a>, <em>as he provides great content for beginners.</em></p>
</li>
<li>
<p><a href="https://www.michaelnygard.com">Michael Nygard</a> <em>for architecture insights.</em></p>
</li>
<li>
<p><a href="https://github.com/yogthos">Dmitri Sotnikov</a> <em>for making web dev in Clojure accessible to the masses.</em></p>
</li>
<li>
<p><a href="https://github.com/ptaoussanis">Peter Taoussanis</a> - <em>Nice, simple and complete libraries.</em></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>There are so many more who deserve praise and recognition so in the words of one of the survey respondents:</p>
</div>
<div class="quoteblock">
<blockquote>
Clojure literally changed my life for the better. I am eternally grateful for the humans behind it.
</blockquote>
<div class="attribution">
&#8212; anonymous respondent
</div>
</div>
<div class="paragraph">
<p>We too are grateful for everyone involved in the Clojure community and we hope to see a continuance and growth in support for those members of the community who work so hard and devote their valuable time to help Clojure and its ecosystem thrive.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_full_results"><a class="anchor" href="#_full_results"></a>Full Results</h2>
<div class="sectionbody">
<div class="paragraph">
<p>If you’d like to dig into the full results, you can find the complete set of data from this and former years here:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://www.surveymonkey.com/results/SM-S2L8NR6K9">2021</a></p>
</li>
<li>
<p><a href="https://www.surveymonkey.com/results/SM-CDBF7CYT7/">2020</a></p>
</li>
<li>
<p><a href="https://www.surveymonkey.com/results/SM-S9JVNXNQV/">2019</a></p>
</li>
<li>
<p><a href="https://www.surveymonkey.com/results/SM-9BC5FNJ68/">2018</a></p>
</li>
<li>
<p><a href="https://www.surveymonkey.com/results/SM-7K6NXJY3/">2016</a></p>
</li>
<li>
<p><a href="http://blog.cognitect.com/blog/2016/1/28/state-of-clojure-2015-survey-results">2015</a></p>
</li>
<li>
<p><a href="http://blog.cognitect.com/blog/2014/10/20/results-of-2014-state-of-clojure-and-clojurescript-survey">2014</a></p>
</li>
<li>
<p><a href="https://cemerick.com/blog/2013/11/18/results-of-the-2013-state-of-clojure-clojurescript-survey.html">2013</a></p>
</li>
<li>
<p><a href="https://cemerick.com/blog/2012/08/06/results-of-the-2012-state-of-clojure-survey.html">2012</a></p>
</li>
<li>
<p><a href="https://cemerick.com/blog/2011/07/11/results-of-the-2011-state-of-clojure-survey.html">2011</a></p>
</li>
<li>
<p><a href="https://cemerick.com/blog/2010/06/07/results-from-the-state-of-clojure-summer-2010-survey.html">2010</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Thanks again for using Clojure and ClojureScript and participating in the survey!</p>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2021/212-days.png" alt="Days">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Days</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">06 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2021/212-days.png" alt="Days" title="One of those days" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://cdn.evilmartians.com/front/blocks/common/images/social-5e5bfff.png" alt="Set up Tailwind CSS JIT in a Rails project to compile styles 20x faster">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Set up Tailwind CSS JIT in a Rails project to compile styles 20x faster</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Martian Chronicles, Evil Martians’ team blog</a> <span class="article__date">06 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Building an ultimate writing machine from Sublime Text</h1>
                            <h2 class="article__feed"><a target="_blank" href="">tonsky.me</a> <span class="article__date">06 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
          My setup for long-form writing in Sublime Text
        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Auto build and publish emacs org configuration as a website</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">04 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Having our emacs configuration in an org file is great, it allow us to have it more organized and easy to read, but org files have more features and one of them is the ability to be exported to different formats like HTML, PDF, markdown and so on. So what if we export our emacs configuration to HTML and then publish it in a website? 🤯
 It probably doesn&#39;t have any real utility but it would be nice to have a exclusive web page to show our emacs config to our friends :)
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://erick.navarro.io/images/blog/auto-build-and-publish-emacs-configuration-as-a-website/set-up-github-pages.png" alt="Auto build and publish emacs org configuration as a website">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Auto build and publish emacs org configuration as a website</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">04 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>
Having our emacs configuration in an <code class="verbatim">org</code> file is great, it allow us to have it more organized and easy to read, but <code class="verbatim">org</code> files have more features and one of them is the ability to be exported to different formats like HTML, PDF, markdown and so on. So what if we export our emacs configuration to HTML and then publish it in a website? 🤯</p>
<p>
It probably doesn&#39;t have any real utility but it would be nice to have a exclusive web page to show our emacs config to our friends :)</p>
<p>
We can do this in two ways:</p>
<ul>
<li>
<p>Manually, we can export the org file using the regular exportation feature of <code class="verbatim">org-mode</code> and then upload the resulting HTML somewhere</p>
</li>
<li>
<p>Automatically, our configuration will be rendered and published into a website every time we push some changes to our <code class="verbatim">dotfiles</code> repository</p>
</li>
</ul>
<p>Let&#39;s define what we need to do to have the automatic way:</p>
<ul>
<li>
<p>Have a script that render our org config file</p>
</li>
<li>
<p>Run this script in a CI so it can be run every time we push some changes</p>
</li>
<li>
<p>Push the rendered HTML to an extra repository</p>
</li>
<li>
<p>Activate Github Pages in the extra repository, so we can have an url where we can see the resulting website</p>
</li>
</ul>
<p>Let&#39;s assume we have this structure in our <code class="verbatim">dotfiles</code> repository:</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">├── emacs
│   ├── config.org
│   └── init.el
└── scripts</code></pre></div>
</div>
<p>
This is a &#34;regular&#34; structure for a <code class="verbatim">dotfiles</code> repository, the extra <code class="verbatim">scripts</code> folder will be used later. Now let&#39;s deep into how it will work.</p>
<div id="outline-container-headline-1" class="outline-2">
<h2 id="headline-1">
Automate the org file rendering
</h2>
<div id="outline-text-headline-1" class="outline-text-2">
<p>
We need to create to files and put them inside <code class="verbatim">scripts</code> folder:</p>
<ul>
<li>
<p><code class="verbatim">render-emacs-config-to-html.sh</code>, this will render our config file and place the resulting HTML file inside <code class="verbatim">scripts/output/index.html</code></p>
</li>
<li>
<p><code class="verbatim">org-render-html-minimal.el</code>, this is a minimal config file to be able to render org into html, it load the required packages and make some basic configuration</p>
</li>
</ul>
<p>Let&#39;s explore first <code class="verbatim">scripts/org-render-html-minimal.el</code></p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(require <span style="color:#e6db74">&#39;package</span>)

(setq package-archives <span style="color:#f92672">&#39;</span>((<span style="color:#e6db74">&#34;gnu&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;https://elpa.gnu.org/packages/&#34;</span>)
                         (<span style="color:#e6db74">&#34;melpa&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;https://melpa.org/packages/&#34;</span>)))

(package-initialize)

(package-refresh-contents)

<span style="color:#75715e">;; this is required to highlight code blocks properly</span>
(package-install <span style="color:#e6db74">&#39;htmlize</span>)

(require <span style="color:#e6db74">&#39;org</span>)

(require <span style="color:#e6db74">&#39;htmlize</span>)

<span style="color:#75715e">;; For some reason the default value `inline-css&#39; doesn&#39;t apply syntax highlighting correctly</span>
<span style="color:#75715e">;; in the resulting html file so we need to change the value to `css&#39;</span>
(setq org-html-htmlize-output-type <span style="color:#e6db74">&#39;css</span>)</code></pre></div>
</div>
<p>
To export code blocks correctly we need the package <code class="verbatim">htmlize</code>, this package is available in MELPA so we need to configure MELPA and then install it from there.</p>
<p>
Now let&#39;s check <code class="verbatim">scripts/render-emacs-config-to-html.sh</code></p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell"><span style="color:#75715e">#!/bin/sh
</span><span style="color:#75715e"></span>
<span style="color:#75715e"># read the docs based theme</span>
echo <span style="color:#e6db74">&#34;#+SETUPFILE: https://raw.githubusercontent.com/fniessen/org-html-themes/master/org/theme-readtheorg.setup&#34;</span> &gt; index.org
cat ../emacs/config.org &gt;&gt; index.org

emacs index.org --batch -Q --load org-render-html-minimal.el -f org-html-export-to-html --kill

<span style="color:#75715e"># output will be the directory uploaded to the render repository so we have to put all the resulting files inside that folder</span>
mkdir output
mv index.html output/</code></pre></div>
</div>
<p>
What are we doing here?</p>
<p>
We basically create a new org file called <code class="verbatim">index.org</code> and put a setup configuration file in it. You can avoid this step if you put this line directly in your config file, in this case we&#39;re using one of the themes available in this <a href="https://github.com/fniessen/org-html-themes">repository</a>, there is more themes available in this other <a href="https://olmon.gitlab.io/org-themes/">repository</a> so you can choose the one you like the most.</p>
<p>
Now we need to run emacs with our previously defined configuration <code class="verbatim">org-render-html-minimal.el</code> and tell it to render our <code class="verbatim">index.org</code>.</p>
<p>
And finally we put the resulting <code class="verbatim">index.html</code> inside <code class="verbatim">output</code> folder. This folder will be used later.</p>
</div>
</div>
<div id="outline-container-headline-2" class="outline-2">
<h2 id="headline-2">
Using Github actions to build and publish the rendered config
</h2>
<div id="outline-text-headline-2" class="outline-text-2">
<p>
We&#39;re going to use a Github action called <a href="https://github.com/marketplace/actions/push-directory-to-another-repository">push-directory-to-another-repository</a>, this action allow us to commit and push changes in another repository. Some configuration is required to use this action:</p>
<div id="outline-container-headline-3" class="outline-3">
<h3 id="headline-3">
Create a extra repository
</h3>
<div id="outline-text-headline-3" class="outline-text-3">
<p>
This extra repository will be used to host our rendered config file, in my case this repository is <code class="verbatim">erickgnavar/emacs-config</code>, we also need to activate Github Pages in this repository and set it up to use <code class="verbatim">master</code> branch</p>
<p>
<img src="https://erick.navarro.io/images/blog/auto-build-and-publish-emacs-configuration-as-a-website/set-up-github-pages.png" alt="/images/blog/auto-build-and-publish-emacs-configuration-as-a-website/set-up-github-pages.png" title="/images/blog/auto-build-and-publish-emacs-configuration-as-a-website/set-up-github-pages.png" /></p>
<p>
The url generated, <a href="https://erickgnavar.github.io/emacs-config/">erickgnavar.github.io/emacs-config</a> in my case, is where our rendered config file will be published.</p>
</div>
</div>
<div id="outline-container-headline-4" class="outline-3">
<h3 id="headline-4">
Create a personal token
</h3>
<div id="outline-text-headline-4" class="outline-text-3">
<p>
To be able to push changes into the new repository we have to create a personal access token, this can be made in <a href="https://github.com/settings/tokens/">account settings</a>, this token should have the <code class="verbatim">repo</code> scoped activated.</p>
<p>
<img src="https://erick.navarro.io/images/blog/auto-build-and-publish-emacs-configuration-as-a-website/generate-github-api-token.png" alt="/images/blog/auto-build-and-publish-emacs-configuration-as-a-website/generate-github-api-token.png" title="/images/blog/auto-build-and-publish-emacs-configuration-as-a-website/generate-github-api-token.png" /></p>
</div>
</div>
<div id="outline-container-headline-5" class="outline-3">
<h3 id="headline-5">
Configure a secret variable in our dotfiles repository
</h3>
<div id="outline-text-headline-5" class="outline-text-3">
<p>
The Github action needs a secret variable called <code class="verbatim">API_TOKEN_GITHUB</code>, this variable allow the action to push changes into the new repository, we can create it by going to <code class="verbatim">repository/settings/secrets/New repository secret</code></p>
<p>
<img src="https://erick.navarro.io/images/blog/auto-build-and-publish-emacs-configuration-as-a-website/create-api-token-secret.png" alt="/images/blog/auto-build-and-publish-emacs-configuration-as-a-website/create-api-token-secret.png" title="/images/blog/auto-build-and-publish-emacs-configuration-as-a-website/create-api-token-secret.png" /></p>
</div>
</div>
<div id="outline-container-headline-6" class="outline-3">
<h3 id="headline-6">
Configure Github action config file
</h3>
<div id="outline-text-headline-6" class="outline-text-3">
<p>
Finally we have to create a file <code class="verbatim">.github/workflows/ci.yml</code> with the following content:</p>
<div class="src src-yaml">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-yaml" data-lang="yaml"><span style="color:#f92672">name</span>: <span style="color:#ae81ff">CI</span>

<span style="color:#f92672">on</span>:
  <span style="color:#f92672">push</span>:
    <span style="color:#f92672">branches</span>: [ <span style="color:#ae81ff">master ]</span>

<span style="color:#f92672">jobs</span>:
  <span style="color:#f92672">build-emacs-config-page</span>:
    <span style="color:#f92672">runs-on</span>: <span style="color:#ae81ff">ubuntu-latest</span>
    <span style="color:#f92672">container</span>: <span style="color:#ae81ff">alpine:3.13.4</span>
    <span style="color:#f92672">steps</span>:
      - <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/checkout@v2</span>
      - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Install emacs</span>
        <span style="color:#f92672">run</span>: <span style="color:#ae81ff">apk --update add emacs</span>
      - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Render config into html</span>
        <span style="color:#f92672">run</span>: <span style="color:#ae81ff">cd scripts &amp;&amp; sh render-emacs-config-to-html.sh</span>
      - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Pushes to destination repository</span>
        <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">cpina/github-action-push-to-another-repository@cp_instead_of_deleting</span>
        <span style="color:#f92672">env</span>:
          <span style="color:#f92672">API_TOKEN_GITHUB</span>: <span style="color:#ae81ff">${{ secrets.API_TOKEN_GITHUB }}</span>
        <span style="color:#f92672">with</span>:
          <span style="color:#f92672">source-directory</span>: <span style="color:#e6db74">&#39;scripts/output&#39;</span>
          <span style="color:#f92672">destination-github-username</span>: <span style="color:#e6db74">&#39;YOUR_GITHUB_USERNAME&#39;</span>
          <span style="color:#f92672">destination-repository-name</span>: <span style="color:#e6db74">&#39;YOUR_NEW_REPOSITORY_NAME&#39;</span>
          <span style="color:#f92672">user-email</span>: <span style="color:#ae81ff">bot@emacs.bot</span></code></pre></div>
</div>
<p>
This action config file make some things:</p>
<ul>
<li>
<p>Install emacs so we can run it to render our config file</p>
</li>
<li>
<p>Render our config file using the script <code class="verbatim">render-emacs-config-to-html.sh</code> we previously defined</p>
</li>
<li>
<p>Take the content of <code class="verbatim">scripts/output</code>, commit and push it into our destination repository, this is why we need to move the resulting HTML file into <code class="verbatim">output</code> folder</p>
</li>
<li>
<p>And finally it calls <code class="verbatim">github-action-push-to-another-repository</code> action which will do all the <code class="verbatim">git</code> stuff required to push the changes</p>
</li>
</ul>
<p>Now every time we push changes to our <code class="verbatim">dotfiles</code> repository this action will push the rendered config file to our destination repository, the commits will look like this:</p>
<p>
<img src="https://erick.navarro.io/images/blog/auto-build-and-publish-emacs-configuration-as-a-website/destination-repo-commits-list.png" alt="/images/blog/auto-build-and-publish-emacs-configuration-as-a-website/destination-repo-commits-list.png" title="/images/blog/auto-build-and-publish-emacs-configuration-as-a-website/destination-repo-commits-list.png" /></p>
<p>
And when we enter to the url generated from Github pages, <a href="https://erickgnavar.github.io/emacs-config/">erickgnavar.github.io/emacs-config</a> in my case, we can see our configuration rendered:</p>
<p>
<img src="https://erick.navarro.io/images/blog/auto-build-and-publish-emacs-configuration-as-a-website/rendered-config-result-page.png" alt="/images/blog/auto-build-and-publish-emacs-configuration-as-a-website/rendered-config-result-page.png" title="/images/blog/auto-build-and-publish-emacs-configuration-as-a-website/rendered-config-result-page.png" /></p>
<p>
Enjoy 🎉</p>
</div>
</div>
</div>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Easy deploy of docker based projects</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">03 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I have a personal server where I run some projects, some of them written in python, elixir and other technologies so having to deal with specific installation of any of these technologies is not an ideal workflow, to fix this I use docker and all of them are deployed using docker-compose, they&#39;re connected to a single PostgreSQL server and they&#39;re behind the same web server.
 Running all of these projects in this way it&#39;s easier to maintain and in case something happens with the server I can re deploy everything in a easy way.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Easy deploy of docker based projects</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">03 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>
I have a personal server where I run some projects, some of them written in python, elixir and other technologies so having to deal with specific installation of any of these technologies is not an ideal workflow, to fix this I use docker and all of them are deployed using <code class="verbatim">docker-compose</code>, they&#39;re connected to a single PostgreSQL server and they&#39;re behind the same web server.</p>
<p>
Running all of these projects in this way it&#39;s easier to maintain and in case something happens with the server I can re deploy everything in a easy way. Let&#39;s take a look to these tools and how they work together.</p>
<p>
Let&#39;s assume we have the following requirements:</p>
<ul>
<li>
<p>Deploy a <a href="https://github.com/erickgnavar/demo-projects/tree/master/simple-django-project-with-docker">django application</a></p>
</li>
<li>
<p>Deploy a <a href="https://github.com/erickgnavar/demo-projects/tree/master/simple-phoenix-project-with-docker">phoenix application</a></p>
</li>
<li>
<p>Each application needs a PostgreSQL database</p>
</li>
<li>
<p>Both applications should be behind a web server and being accessed over HTTPS</p>
</li>
<li>
<p>All of these should run in the same server</p>
</li>
</ul>
<p>To solve this we&#39;re going to:</p>
<ul>
<li>
<p>Set up a linux server</p>
</li>
<li>
<p>Install PostgreSQL</p>
</li>
<li>
<p>Configure a web server which will handle incoming traffic and SSL termination</p>
</li>
<li>
<p>Run our applications inside Docker containers</p>
</li>
</ul>
<div id="outline-container-headline-1" class="outline-2">
<h2 id="headline-1">
Setting up a server
</h2>
<div id="outline-text-headline-1" class="outline-text-2">
<p>
If you already have a server you can skip this section.</p>
<p>
We first need a server which can run docker, most linux distros can be used for this but in this case we&#39;ll be using Ubuntu Server, if you don&#39;t have a server yet you can use any of these referral links to get some credit when you create your account:</p>
<ul>
<li>
<p><a href="https://m.do.co/c/330e2b815378">Digital Ocean</a> this will get you $100 on credits to be used in 2 months</p>
</li>
<li>
<p><a href="https://hetzner.cloud/?ref=om6r8Z9OZrQq">Hetzner</a> this will get you 20€ on credits, this provider has cheaper prices than Digital Ocean but it only have data centers in Europe</p>
</li>
<li>
<p><a href="https://www.linode.com/?r=f0455aac2f2cc4dd7f6f88ef517f59d994386a4c">Linode</a> this will get you $100 on credits to be used in 2 months</p>
</li>
</ul>
<p>Once you get a server it&#39;s recommended to make some basic configurations like updating packages, setup a firewall, etc. You can follow this Linode <a href="https://www.linode.com/docs/security/securing-your-server/">guide</a> to secure your server.</p>
<p>
After that you need to install docker, to do that you can follow the <a href="https://docs.docker.com/engine/install/">official documentation</a>, this have specific instructions for you linux distribution.</p>
<p>
Once we have <code class="verbatim">docker</code> and <code class="verbatim">docker-compose</code> installed we can follow this guide.</p>
</div>
</div>
<div id="outline-container-headline-2" class="outline-2">
<h2 id="headline-2">
Installing PostgreSQL in our host machine
</h2>
<div id="outline-text-headline-2" class="outline-text-2">
<p>
We&#39;re going to use a unique instance of PostgreSQL installed in the host machine, this way we can share the resources used by PostgreSQL with all the applications that we&#39;re going to deploy, we just need to create new users and databases for each one of the applications.</p>
<p>
First let&#39;s install PostgreSQL with:</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">sudo apt install postgresql-server</code></pre></div>
</div>
<p>
We need to login with <code class="verbatim">postgres</code> user so we can be able to enter to a <code class="verbatim">psql</code> session. We can do it with:</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">sudo su - postgres</code></pre></div>
</div>
<p>
Now we can open a <code class="verbatim">psql</code> session and create the databases and users for our applications:</p>
<div class="src src-sql">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sql" data-lang="sql">postgres<span style="color:#f92672">=#</span> <span style="color:#66d9ef">CREATE</span> <span style="color:#66d9ef">USER</span> django <span style="color:#66d9ef">WITH</span> <span style="color:#66d9ef">ENCRYPTED</span> PASSWORD <span style="color:#e6db74">&#39;secret&#39;</span>;

postgres<span style="color:#f92672">=#</span> <span style="color:#66d9ef">CREATE</span> <span style="color:#66d9ef">DATABASE</span> django <span style="color:#66d9ef">WITH</span> <span style="color:#66d9ef">OWNER</span> django;</code></pre></div>
</div>
<p>
And we do the same for our phoenix application:</p>
<div class="src src-sql">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sql" data-lang="sql">postgres<span style="color:#f92672">=#</span> <span style="color:#66d9ef">CREATE</span> <span style="color:#66d9ef">USER</span> phoenix <span style="color:#66d9ef">WITH</span> <span style="color:#66d9ef">ENCRYPTED</span> PASSWORD <span style="color:#e6db74">&#39;secret&#39;</span>;

postgres<span style="color:#f92672">=#</span> <span style="color:#66d9ef">CREATE</span> <span style="color:#66d9ef">DATABASE</span> phoenix <span style="color:#66d9ef">WITH</span> <span style="color:#66d9ef">OWNER</span> phoenix;</code></pre></div>
</div>
</div>
</div>
<div id="outline-container-headline-3" class="outline-2">
<h2 id="headline-3">
Configuring Caddy as a reverse proxy
</h2>
<div id="outline-text-headline-3" class="outline-text-2">
<p>
<a href="https://caddyserver.com">Caddy</a> is a &#34;new&#34; web server written in Go that have 2 main features that make it a good option for simpler deployments:</p>
<ul>
<li>
<p>Simpler configuration file</p>
</li>
<li>
<p>Free auto configured SSL certificates, using Let&#39;s Encrypt service, and automatic renewals</p>
</li>
</ul>
<p>If we were using for example Nginx we have to deal with HTTPS certificates by ourselves, installing <a href="https://certbot.eff.org">certbot</a>, and also have to configure some way to renew the certificates, Let&#39;s Encrypt issues certificates that expire after 3 months.</p>
<p>
Let&#39;s define our domains <code class="verbatim">django.domain.com</code> and <code class="verbatim">phoenix.domain.com</code> which will send traffic to their specific applications.</p>
<p>
Our django application needs that Caddy serves the static files so we define <code class="verbatim">file_server</code> option and tell caddy where are our static files, we also tell Caddy to send the traffic to port <code class="verbatim">8000</code> where our application is listening.</p>
<div class="src src-caddy">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-caddy" data-lang="caddy">django.domain.com {
    <span style="color:#66d9ef">root</span> <span style="color:#a6e22e">*</span> <span style="color:#e6db74">/opt/django</span>

    <span style="color:#a6e22e">@notStatic</span> {
        <span style="color:#66d9ef">not</span> <span style="color:#66d9ef">path</span> <span style="color:#e6db74">/static/*</span>
    }

    <span style="color:#66d9ef">reverse_proxy</span> <span style="color:#a6e22e">@notStatic</span> localhost:<span style="color:#ae81ff">8000</span>
    <span style="color:#66d9ef">file_server</span>
}</code></pre></div>
</div>
<p>
Our phoenix application will serve static files by itself so we just need to define the <code class="verbatim">reverse_proxy</code> directive to be able to send the traffic to port <code class="verbatim">4000</code></p>
<div class="src src-caddy">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-caddy" data-lang="caddy">phoenix.domain.com {
    <span style="color:#66d9ef">reverse_proxy</span> localhost:<span style="color:#ae81ff">4000</span>
}</code></pre></div>
</div>
<p>
Now when we reload our caddy server with <code class="verbatim">sudo systemctl reload caddy</code> it will get the SSL certificates and internally will check if they still valid, otherwise it will renew them.</p>
</div>
</div>
<div id="outline-container-headline-4" class="outline-2">
<h2 id="headline-4">
Running our projects with docker-compose
</h2>
<div id="outline-text-headline-4" class="outline-text-2">
<p>
<a href="https://docs.docker.com/compose/">Docker compose</a> is a tool that allow us to define different docker services in a easier way using a <code class="verbatim">yaml</code> file.</p>
<p>
We&#39;re going to configure our two projects using <code class="verbatim">docker-compose</code> but we first need their docker images so let&#39;s build them.</p>
<p>
Let&#39;s clone our projects(both are in the same repository, just in different folders), build the images and then publish them on a registry.</p>
<p>
This can be made in a separate machine because once the images are pushed to a remote registry they can be downloaded in our server.</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">cd simple-django-project-with-docker
docker build -t registry.mycompany.com/django:v1 .
docker push registry.mycompany.com/django:v1</code></pre></div>
</div>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">cd simple-phoenix-project-with-docker
docker build -t registry.mycompany.com/phoenix:v1 .
docker push registry.mycompany.com/phoenix:v1</code></pre></div>
</div>
<p>
You can use docker hub to push your images or use Gitlab registry in case you want free private images.</p>
<div id="outline-container-headline-5" class="outline-3">
<h3 id="headline-5">
Django application
</h3>
<div id="outline-text-headline-5" class="outline-text-3">
<p>
Let&#39;s create a folder in <code class="verbatim">/opt/django</code> and put the following code into a <code class="verbatim">docker-compose.yml</code> file.</p>
<div class="src src-yaml">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-yaml" data-lang="yaml"><span style="color:#f92672">version</span>: <span style="color:#e6db74">&#34;2&#34;</span>
<span style="color:#f92672">services</span>:
  <span style="color:#f92672">web</span>:
    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">registry.mycompany.com/django:v1</span>
    <span style="color:#f92672">restart</span>: <span style="color:#ae81ff">always</span>
    <span style="color:#f92672">network_mode</span>: <span style="color:#ae81ff">host</span>
    <span style="color:#f92672">environment</span>:
      <span style="color:#f92672">ALLOWED_HOSTS</span>: <span style="color:#e6db74">&#34;django.domain.com&#34;</span>
      <span style="color:#f92672">DEBUG</span>: <span style="color:#e6db74">&#34;0&#34;</span>
      <span style="color:#f92672">DATABASE_URL</span>: <span style="color:#e6db74">&#34;postgres://django:secret@localhost:5432/django&#34;</span>
      <span style="color:#f92672">DJANGO_SETTINGS_MODULE</span>: <span style="color:#e6db74">&#34;config.settings&#34;</span>
      <span style="color:#f92672">SECRET_KEY</span>: <span style="color:#e6db74">&#34;a 32 long secret key&#34;</span>
    <span style="color:#f92672">volumes</span>:
      - <span style="color:#ae81ff">./static:/app/static</span>
    <span style="color:#f92672">ports</span>:
      - <span style="color:#e6db74">&#34;127.0.0.1:8000:8000&#34;</span></code></pre></div>
</div>
<p>
The <code class="verbatim">static</code> folder will be used by Caddy to server static files.</p>
</div>
</div>
<div id="outline-container-headline-6" class="outline-3">
<h3 id="headline-6">
Phoenix application
</h3>
<div id="outline-text-headline-6" class="outline-text-3">
<p>
Now for our phoenix application let&#39;s create a folder <code class="verbatim">/opt/phoenix</code> and put the following code into a <code class="verbatim">docker-compose.yml</code> file.</p>
<div class="src src-yaml">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-yaml" data-lang="yaml"><span style="color:#f92672">version</span>: <span style="color:#e6db74">&#34;2&#34;</span>
<span style="color:#f92672">services</span>:
  <span style="color:#f92672">web</span>:
    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">registry.mycompany.com/phoenix:v1</span>
    <span style="color:#f92672">restart</span>: <span style="color:#ae81ff">always</span>
    <span style="color:#f92672">network_mode</span>: <span style="color:#ae81ff">host</span>
    <span style="color:#f92672">environment</span>:
      <span style="color:#f92672">DATABASE_URL</span>: <span style="color:#e6db74">&#34;postgres://phoenix:secret@localhost:5432/phoenix&#34;</span>
      <span style="color:#f92672">MIX_ENV</span>: <span style="color:#ae81ff">prod</span>
      <span style="color:#f92672">HOST</span>: <span style="color:#e6db74">&#34;phoenix.domain.com&#34;</span>
      <span style="color:#f92672">SECRET_KEY_BASE</span>: <span style="color:#e6db74">&#34;a 32 long secret key&#34;</span>
    <span style="color:#f92672">ports</span>:
      - <span style="color:#e6db74">&#34;127.0.0.1:4000:4000&#34;</span></code></pre></div>
</div>
<p>
Because we&#39;re running PostgreSQL in our host machine instead of a docker container we have to use <code class="verbatim">network_mode: host</code>, this allow us to access postgres just pointing to <code class="verbatim">localhost</code>.</p>
</div>
</div>
<div id="outline-container-headline-7" class="outline-3">
<h3 id="headline-7">
Deploying our projects
</h3>
<div id="outline-text-headline-7" class="outline-text-3">
<p>
Once we have the <code class="verbatim">docker-compose.yml</code> files configured we can go inside each project folder and run:</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">docker-compose up -d</code></pre></div>
</div>
<p>
For the django application we also have to run these commands, these are specific of django deployment process.</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell"><span style="color:#75715e"># Run database migrations</span>
docker-compose exec -T web python manage.py migrate

<span style="color:#75715e"># Collect all static files and place them in our STATIC_ROOT folder which will be served by Caddy</span>
docker-compose exec -T web python manage.py collectstatic --no-input</code></pre></div>
</div>
</div>
</div>
</div>
</div>
<div id="outline-container-headline-8" class="outline-2">
<h2 id="headline-8">
Deploying new changes
</h2>
<div id="outline-text-headline-8" class="outline-text-2">
<p>
Because we&#39;re using docker, when we need to update changes we just need to update their Docker images and restart their services. Some technologies can have differences in their deployment process but the basic idea is the same.</p>
<p>
Let&#39;s see how it could be for our two example applications.</p>
<div id="outline-container-headline-9" class="outline-3">
<h3 id="headline-9">
Django application
</h3>
<div id="outline-text-headline-9" class="outline-text-3">
<p>
When we update a django application we need to run some extra commands like <code class="verbatim">migrate</code>, <code class="verbatim">collectstatic</code>, etc. We can follow these steps to run them inside the docker container:</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">docker pull NEW_DJANGO_IMAGE

sed -i <span style="color:#e6db74">&#34;s/image.*/image:\ NEW_DJANGO_IMAGE/&#34;</span> docker-compose.yml

docker-compose up -d --force-recreate

docker-compose exec -T web python manage.py migrate

docker-compose exec -T web python manage.py collectstatic --no-input</code></pre></div>
</div>
<p>
We&#39;re pulling the new image from our registry, updating the image value in our <code class="verbatim">docker-compose.yml</code> file, restart the service (it will use the new image now) and then we can execute <code class="verbatim">migrate</code> and <code class="verbatim">collectstatic</code> commands</p>
</div>
</div>
<div id="outline-container-headline-10" class="outline-3">
<h3 id="headline-10">
Phoenix application
</h3>
<div id="outline-text-headline-10" class="outline-text-3">
<p>
For the phoenix application we&#39;re going to follow almost the same process with just one difference, we don&#39;t need to run migrations in a separate step because they will run when the application starts, this is defined in the phoenix docker image itself.</p>
<p>
So we just need to pull the new image, update it in <code class="verbatim">docker-compose.yml</code> file and then restart the service, the final script will be:</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">docker pull NEW_PHOENIX_IMAGE

sed -i <span style="color:#e6db74">&#34;s/image.*/image:\ NEW_PHOENIX_IMAGE/&#34;</span> docker-compose.yml

docker-compose up -d --force-recreate</code></pre></div>
</div>
</div>
</div>
</div>
</div>
<div id="outline-container-headline-11" class="outline-2">
<h2 id="headline-11">
Conclusion
</h2>
<div id="outline-text-headline-11" class="outline-text-2">
<p>
Having a central PostgreSQL instance and a central web server(Caddy), both in the host machine instead of inside a container allow us to manage them easily and also allow us to share these common services alongside the many applications that we are running in our server.</p>
</div>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Solving Advent of Code 2020 in under a second </h1>
                            <h2 class="article__feed"><a target="_blank" href="">Danny van Kooten</a> <span class="article__date">01 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><a href="https://adventofcode.com/">Advent of Code</a> is an annual event of small programming puzzles for a variety of skill sets and skill levels that can be solved in any programming language.</p>

<p>Last year (AoC 2019), I participated for the first time and used Rust as my language of choice.</p>

<p>This year, albeit a few months after the event actually occurred, I participated again and used C as my weapon of choice. (And yes, I did hurt myself in the process.)</p>

<p>I set out with two goals in mind:</p>

<ul>
  <li>To finish all challenges within a single month.</li>
  <li>To solve them all in under 1 second of runtime (on a single CPU core).</li>
</ul>

<p>For this last goal I was inspired by <a href="https://timvisee.com/blog/solving-aoc-2020-in-under-a-second/">Tim Visee</a> who did a really great write-up of some of the tricks he used to efficiently solve this year’s challenges. It sounded like a really fun thing to do and I was already well underway for such a thing anyway.</p>

<p>Two weeks later, iet ies done! Total runtime is 548 ms on my laptop, so I’m quite pleased with the results.</p>

<p>I could probably squeeze out a few more miliseconds here and there, but I see no options for making the 2 bottlenecks (<a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/15.c">day 15</a> and <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/23.c">day 23</a>) run any faster (except for throwing more hardware at it).</p>

<p>The code is on GitHub here: <a href="https://github.com/dannyvankooten/advent-of-code-2020">dannyvankooten/advent-of-code-2020</a></p>

<p>To be honest, finishing all challenges was harder than getting them all to run in under a second. I really enjoy optimising code for performance and trying out different algorithms.</p>

<p><strong>Things I learned:</strong></p>

<ul>
  <li>You can represent a <a href="https://www.redblobgames.com/grids/hexagons/">hexagonal grid</a> in a 2D array by simplify shifting every odd column or row (<a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/24.c">day 24</a>).</li>
  <li><a href="https://en.wikipedia.org/wiki/Linear_probing">Linear probing</a> is a much simpler way to deal with hash collissions than a linked list and results in less cache misses because the values can reside in contiguous memory locations.</li>
  <li>To check neighbors or directions in a 2D grid, it’s a lot more concise to keep an array of <code class="language-plaintext highlighter-rouge">Δx</code> and <code class="language-plaintext highlighter-rouge">Δy</code> values versus writing out all the various directions in a separate loop.</li>
  <li>You can’t brute force your way out of everything. Sometimes, math is required to get decent performance. Specifically, <a href="https://en.wikipedia.org/wiki/Chinese_remainder_theorem">Chinese Remainder Theorem</a> for <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/13.c">day 13</a> and any of the <a href="https://en.wikipedia.org/wiki/Baby-step_giant-step">algorithms for finding the discrete log</a> for <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/25.c">day 25</a>.</li>
  <li>Tooling! I wouldn’t want to write C without <a href="https://valgrind.org/">Valgrind</a> and <a href="https://sourceware.org/binutils/docs/gprof/index.html">Gprof</a>. <a href="https://valgrind.org/docs/manual/cg-manual.html">Cachegrind</a> can be useful too.</li>
  <li>When an array gets really sparse, it can be more efficient to use a hashmap despite the added overhead (<a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/15.c">day 15</a>).</li>
  <li>In loops, it can be really useful to add a call to <code class="language-plaintext highlighter-rouge">getc(stdin)</code> combined with <code class="language-plaintext highlighter-rouge">printf</code> debugging to allow stepping through the loop. Especially if you haven’t yet taken the time to learn <a href="https://www.gnu.org/software/gdb/">GDB</a> well enough, like me.</li>
</ul>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/1">Day 1</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/01.c">code</a> / runtime: 13 μs</p>

<p>The task was to find the product of the three entries in the puzzle input that sum to 2020. Since most numbers in the input were well over half that, it made sense to first sort the input in ascending order before starting our loops.</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/2">Day 2</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/02.c">code</a> / runtime: 12 μs</p>

<p>Day 2 was fairly straightforward, so I won’t go into any details on it.</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/3">Day 3</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/03.c">code</a> / runtime: 11 μs</p>

<p>The puzzle input is a 2D grid of tree positions. We’re then tasked with counting the number of trees for given slopes. I just looped over the 2D array multiple times, each time incrementing the row- and column indices with the given slopes.</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/4">Day 4</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/04.c">code</a> / runtime: 36 μs</p>

<p>The input consisted of several “passports” with their field names and values in a random order. Each field had restrictions on what a valid value for that field looked like.</p>

<p>My solution iterates over each passport in the input, marks each field (except the one that was to be ignored) as valid (1) or invalid (0) in an array and then uses <code class="language-plaintext highlighter-rouge">memcmp</code> to check whether the passport is valid or not.</p>

<p>There is a possible optimization by skipping forward to the next passport whenever any of the required fields is invalid, but since the runtime is already so low I did not find this worth the time.</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/5">Day 5</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/05.c">code</a> / runtime: 24 μs</p>

<p>My solution decodes each input line into a row and column, turns these into a seat ID and finds the highest seat ID. At the same tame it toggles a boolean value in a 2D array to keep track of all occupied seats.</p>

<p>It then iterates over this array while skipping the first few rows to find the first seat that is empty.</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/6">Day 6</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/06.c">code</a> / runtime: 32 μs</p>

<p>For day 6 I create two arrays of size 26 to keep track of user answers and group answers respectively. At the end of each line I <code class="language-plaintext highlighter-rouge">AND</code> the two arrays, so I have an array filled with <code class="language-plaintext highlighter-rouge">1</code>’s for the answers that were answered by every user in a group. Counting the <code class="language-plaintext highlighter-rouge">1</code> values in the group answers array gets us the number of questions answered by everyone in a group.</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/7">Day 7</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/07.c">code</a> / runtime: 4144 μs</p>

<p>Day 7 was the ideal candidate for a hashmap, since we have to do a ton of lookups by the name of a bag. Since I had just read Ben Hoyt’s post on <a href="https://benhoyt.com/writings/hash-table-in-c/">how to implement a hash table in C</a>, I decided to give his implementation a try.</p>

<p>Sadly I don’t have the linear search version in version control, as I would like to see what difference it made, but IIRC it was huge given that there are 594 bags in my input.</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/8">Day 8</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/08.c">code</a> / runtime: 105 μs</p>

<p>Day 8 reminded me of the <a href="https://github.com/dannyvankooten/monkey-c-monkey-do">bytecode interpreter I wrote last year</a>, so I really enjoyed this one. To detect the infinite loop I kept changing a single JUMP instruction to a NOOP until we reached the end of the program without repeating an instruction.</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/10">Day 10</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/10.c">code</a> / runtime: 8 μs</p>

<p>Dynamic programming! It took me a while to realise this though. For part 2 I go over a sorted array of adapter joltages and then count how many of the previous adapters it can connect to, adding the sum of options to get to that previous adapter to the one we’re looking at.</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/11">Day 11</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/11.c">code</a> / runtime: 2163 μs</p>

<p>A 2D square-grid problem where we have to look at all 8 neighbors for every point. I optimized this solution by keeping a list of neighbor indices for each seat, so these do not have to be recomputed on every transmutation.</p>

<p>Another optimization is to keep a list of seats to check and remove a seat from this list once it reached its permanent state:</p>

<ul>
  <li>If a seat is occupied and has less than 5 occupied neighbors, it is permanently occupied.</li>
  <li>If a seat has a permanently occupied neighboring seat, it is permanently empty.</li>
</ul>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/12">Day 12</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/12.c">code</a> / runtime: 61 μs</p>

<p>A ship that moves towards a waypoint positioned relative to the ship, according to directions  in the puzzle input. I didn’t optimize this solution that much since the straightforward approach was already plenty fast.</p>

<p>I used <code class="language-plaintext highlighter-rouge">sin()</code> and <code class="language-plaintext highlighter-rouge">cos()</code> for <a href="https://en.wikipedia.org/wiki/Rotation_matrix">rotating</a> the waypoint, but since the rotation amount is fixed to a multiple of <code class="language-plaintext highlighter-rouge">90</code> I could get rid of these.</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/13">Day 13</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/13.c">code</a> / runtime: 4 μs</p>

<p>This day required the <a href="https://en.wikipedia.org/wiki/Chinese_remainder_theorem">Chinese Remainder Theorem</a> to get done in a reasonable amount of time. Sadly I was not able to come up with this myself, but I saw a mention of it after getting stuck on my brute-force approach.</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/14">Day 14</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/14.c">code</a> / runtime: 1334 μs</p>

<p>Updating “memory addresses” with certain values from the puzzle input after applying a (changing) mask to the address. Since addresses were so large and wouldn’t fit in an array, I wrote a simple hashmap with integer keys and values.</p>

<p>To make sure the hashed key value is within the bounds of the backing array, I made sure capacity itself was a power of 2 and then used a bitwise <code class="language-plaintext highlighter-rouge">&amp;</code> on the <code class="language-plaintext highlighter-rouge">capacity - 1</code>. This is a lot faster than using the modulo operator.</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/15">Day 15</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/15.c">code</a> / runtime: 360147 μs (360 ms)</p>

<p>Today would have made the 1-second goal impossible without good enough hardware and a language that compiles to machine code. The solution is fairly straightforward and doesn’t leave much room for optimization.</p>

<p><del>For values lower than ~500K, I used an array to look-up the previous position of a number in constant time.</del></p>

<p><del>Since values larger than 500K were further apart (sparse), I used an optimized hashmap implementation for these values to store the previous positions. It uses a really limited amount (&lt; 10) of linear probing attempts to prevent spending too much time on values that have not been seen before.</del></p>

<p>I used a lookup array that stores the previous index of a number. The array was allocated using <code class="language-plaintext highlighter-rouge">mmap</code> with 2 MB “huge” page sizes in combination with a bitset that is checked before even indexing into the array. This shaved off another 100ms compared to the array + hashmap approach.</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/16">Day 16</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/16.c">code</a> / runtime: 183 μs</p>

<p>Today we had to parse a bunch of rules and find which values corresponded to which rule. We could deduce the position of each field by first creating a list of possible options and then picking the only available option and removing it from all other fields, repeating that latter part until we know the position for each field.</p>

<p>Today’s optimization was to simply ensure we’re breaking out of each loop or skipping to the next iteration as soon as possible.</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/17">Day 17</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/17.c">code</a> / runtime: 2136 μs</p>

<p>Day 17 was another game of life inspired challenge, but using a 4D grid.</p>

<p>The largest performance gain came from precomputing the neighbor count by looping over the active tiles and then adding 1 to each neighbor. This saves a ton of iterations versus doing it the other way around.</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/18">Day 18</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/18.c">code</a> / runtime: 449 μs</p>

<p>For day 18 we got to write a simple math parser with different operator precedence than what we’re used to in human math. I used what I learned from the <a href="https://interpreterbook.com/">interpreterbook.com</a> to implement an <a href="https://en.wikipedia.org/wiki/Operator-precedence_parser">operator precedence parser</a>.</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/19">Day 19</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/19.c">code</a> / runtime: 516 μs</p>

<p>I forgot the specifics of day 19. It was about implementing a form of regex and preventing infinite recursion. All I recall is that I did a simple recursion check on the two rules that caused the infinite recursion, and it worked…</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/20">Day 20</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/20.c">code</a> / runtime: 877 μs</p>

<p>Day 20 was about putting together an image from various tiles that had to be rotated and flipped into the correct orientation in order to fit together. This was the challenge that cost me the most time, but also probably the one I enjoyed the most.</p>

<p>My solution simply started with the first tile in the top-left corner in the image and then fitted any of the other tiles on any of its edges until all tiles were in the image. Instead of rotating the entire tile and then checking whether it fit, I only compared the edges of the tile and only rotated or flipped it when a match was found.</p>

<p>If another tile fitted on the northern or western edge of the starting tile, I shifted all the tile in the image. Another option was to first find a corner tile and then work from there, but this approach proved to be faster.</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/21">Day 21</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/21.c">code</a> / runtime: 276 μs</p>

<p>Day 21 resembled day 16 in that we could decude which ingredients contained an allergen by repeatedly picking the only available option until we were done.</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/22">Day 22</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/22.c">code</a> / runtime: 104 μs</p>

<p>Today was fun! A game of cards with recursion.</p>

<p>Pre-allocating enough memory for at most 50 games gave a slight performance increase. The biggest improvement came from not recursing into a sub-game (and all of its descedentants) when the sub-game started with player 1 holding the highest card.</p>

<p>Because of the special rule this meant that player 1 would eventually emerge as the winner, so we could declare him winner right away and save on an awful lot of recursion.</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/23">Day 23</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/23.c">code</a> / runtime: 172981 μs (173 ms)</p>

<p>A slow day today with not much room for making it run faster. I used an array where the value simply contained the next cup, thus resembling a singly linked list. This meant just changing  2 values on every iteration, 10 million times…</p>

<p>Like for day 15, I used 2 MB page sizes again. This resulted in a 22% performance improvement (51 ms faster) than using the default 4 kB page size.</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/24">Day 24</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/24.c">code</a> / runtime: 3102 μs</p>

<p>Another 2D grid problem but using a <a href="https://www.redblobgames.com/grids/hexagons/">hexagonal grid</a>, flipping to either black or white based on directions from the puzzle input. Part 2 introduced a form of game of life again. I re-used the same optimizations from before, pre-computing neighbor counts.</p>

<p>One more thing was to allocate a grid large enough to hold our entire “infinite” grid, but only iterating over the values neighboring any black tile.</p>

<p>Whenever a tile was flipped to black, I extended the grid bounds to iterate over and updated the neighbor count for each of that tile’s neighbors.</p>

<hr />

<p><strong><a href="https://adventofcode.com/2020/day/25">Day 25</a></strong> / <a href="https://github.com/dannyvankooten/advent-of-code-2020/blob/main/25.c">code</a> / runtime: 58 μs</p>

<p>Day 25 involved finding the discrete log, so I used the <a href="https://en.wikipedia.org/wiki/Baby-step_giant-step">Baby-Step-Giant-Step</a> algorithm while re-using my integer hashmap from an earlier day. This turned out to be really fast, clocking it at just 58 microseconds of runtime.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://programadorwebvalencia.com/img/blog/2021/04/scroll.png" alt="Cómo suavizar un scroll">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cómo suavizar un scroll</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Programador Web Valencia</a> <span class="article__date">01 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://programadorwebvalencia.com/img/blog/2021/04/scroll.png" alt="cookie" class="medium" /></p>

<p>Si queremos que al pulsar en un hipervínculo, o ancla, <strong>se desplace de manera suave</strong> y lenta, en lugar ser instantáneo, podemos optar por usar algunos de siguientes <strong>3 trucos</strong>. Pasando por <strong>CSS</strong>, <strong>JavaScript</strong> o <strong>JQuery</strong>. El artículo no cubre la forma de realizar un ancla, aunque puedes aprender en mi <a href="/cursos/html/hipervínculos/">curso gratuito de HTML</a>.</p>

<h2 id="demo">DEMO</h2>

<iframe frameborder="0" width="100%" height="300" src="https://programadorwebvalencia.com/demos/blog/como-suavizar-un-scroll/"></iframe>

<h2 id="versión-solo-con-css">Versión solo con CSS</h2>

<p>Al añadir el siguiente CSS conseguirás que los movimientos de tus anclas sean suaves en lugar de instantáneos.</p>

<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">body</span> <span class="p">{</span>
	<span class="py">scroll-behavior</span><span class="p">:</span> <span class="n">smooth</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>En el momento que se escribió este artículo no era compatible con Safari.</p>

<h2 id="versión-solo-con-javascript-vainilla">Versión solo con JavaScript Vainilla</h2>

<p>En caso contrario de que no funcione como esperas podrás usar un poco de JavaScript para conseguir el mismo efecto.</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;script&gt;</span>
	<span class="nb">document</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="dl">'</span><span class="s1">DOMContentLoaded</span><span class="dl">'</span><span class="p">,</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>	

	    	<span class="c1">//===</span>
		<span class="c1">// SCROLL SMOOTH</span>
		<span class="c1">//===</span>
		<span class="c1">// Variables</span>
		<span class="kd">const</span> <span class="nx">links</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelectorAll</span><span class="p">(</span><span class="dl">'</span><span class="s1">a[href *= "#"]:not([href = "#"])</span><span class="dl">'</span><span class="p">);</span>

		<span class="cm">/**
		 * Event scroll
		 */</span>
		<span class="kd">function</span> <span class="nx">clickHandler</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
		  <span class="nx">event</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
		  <span class="kd">const</span> <span class="nx">href</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">getAttribute</span><span class="p">(</span><span class="dl">"</span><span class="s2">href</span><span class="dl">"</span><span class="p">);</span>
		  <span class="kd">const</span> <span class="nx">offsetTop</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="nx">href</span><span class="p">).</span><span class="nx">offsetTop</span><span class="p">;</span>

		  <span class="nx">scroll</span><span class="p">({</span>
		    <span class="na">top</span><span class="p">:</span> <span class="nx">offsetTop</span><span class="p">,</span>
		    <span class="na">behavior</span><span class="p">:</span> <span class="dl">"</span><span class="s2">smooth</span><span class="dl">"</span>
		  <span class="p">});</span>
		<span class="p">}</span>

		<span class="c1">// Add event all links</span>
		<span class="nx">links</span><span class="p">.</span><span class="nx">forEach</span><span class="p">((</span><span class="nx">link</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">link</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="dl">"</span><span class="s2">click</span><span class="dl">"</span><span class="p">,</span> <span class="nx">clickHandler</span><span class="p">));</span>
	<span class="p">});</span>
<span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>

<h2 id="versión-solo-con-jquery">Versión solo con JQuery</h2>

<p>Y por último, en caso de que aún así no funcione; puedes recurrir a un clásico que nunca te va a fallar y ha sido utilizado durante muchos años.</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script&gt;</span>
	<span class="nx">$</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
	    <span class="nx">$</span><span class="p">(</span><span class="dl">'</span><span class="s1">a[href *= "#"]:not([href = "#"])</span><span class="dl">'</span><span class="p">).</span><span class="nx">click</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
				<span class="k">if</span> <span class="p">(</span><span class="nx">location</span><span class="p">.</span><span class="nx">pathname</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/^</span><span class="se">\/</span><span class="sr">/</span><span class="p">,</span> <span class="dl">''</span><span class="p">)</span> <span class="o">==</span> <span class="k">this</span><span class="p">.</span><span class="nx">pathname</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/^</span><span class="se">\/</span><span class="sr">/</span><span class="p">,</span> <span class="dl">''</span><span class="p">)</span> <span class="o">||</span> <span class="nx">location</span><span class="p">.</span><span class="nx">hostname</span> <span class="o">==</span> <span class="k">this</span><span class="p">.</span><span class="nx">hostname</span><span class="p">)</span> <span class="p">{</span>
					<span class="kd">let</span> <span class="nx">target</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">hash</span><span class="p">);</span>
		    <span class="nx">target</span> <span class="o">=</span> <span class="nx">target</span><span class="p">.</span><span class="nx">length</span> <span class="p">?</span> <span class="nx">target</span> <span class="p">:</span> <span class="nx">$</span><span class="p">(</span><span class="dl">'</span><span class="s1">[name = </span><span class="dl">'</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">hash</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">]</span><span class="dl">'</span><span class="p">);</span>
		    <span class="k">if</span> <span class="p">(</span><span class="nx">target</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="p">{</span>
			<span class="nx">$</span><span class="p">(</span><span class="dl">'</span><span class="s1">html, body</span><span class="dl">'</span><span class="p">).</span><span class="nx">animate</span><span class="p">({</span>
			    <span class="na">scrollTop</span><span class="p">:</span> <span class="nx">target</span><span class="p">.</span><span class="nx">offset</span><span class="p">().</span><span class="nx">top</span>
			<span class="p">},</span> <span class="mi">1000</span><span class="p">);</span>
			<span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
		    <span class="p">}</span>
		<span class="p">}</span>
	    <span class="p">});</span>
	<span class="p">});</span>
<span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>

<p>Obviamente necesitarás que esté presente JQuery en tu proyecto web.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Using compilation mode to run all the things</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">01 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Compilation mode is a major mode that allow us to run a command and see its output result in a special buffer, this resulting buffer show the errors and allow us to navigate through them, you can check the documentation for more details.
 It&#39;s a &#34;simple mode&#34; but it can be used for many things like compile and run a program, run tests, and so on.
Usage  Interactive   compile is an interactive function so we can call it with M-x compile and enter the command we want to execute.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://erick.navarro.io/images/blog/using-compilation-mode-to-run-all-the-things/run-mx-compile.gif" alt="Using compilation mode to run all the things">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Using compilation mode to run all the things</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">01 04 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>
Compilation mode is a major mode that allow us to run a command and see its output result in a special buffer, this resulting buffer show the errors and allow us to navigate through them, you can check the <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Compilation-Mode.html">documentation</a> for more details.</p>
<p>
It&#39;s a &#34;simple mode&#34; but it can be used for many things like compile and run a program, run tests, and so on.</p>
<div id="outline-container-headline-1" class="outline-2">
<h2 id="headline-1">
Usage
</h2>
<div id="outline-text-headline-1" class="outline-text-2">
<div id="outline-container-headline-2" class="outline-3">
<h3 id="headline-2">
Interactive
</h3>
<div id="outline-text-headline-2" class="outline-text-3">
<p>
<code class="verbatim">compile</code> is an interactive function so we can call it with <code class="verbatim">M-x compile</code> and enter the command we want to execute.</p>
<p>
In the following example we&#39;re compiling this blog using hugo binary:</p>
<p>
<img src="https://erick.navarro.io/images/blog/using-compilation-mode-to-run-all-the-things/run-mx-compile.gif" alt="/images/blog/using-compilation-mode-to-run-all-the-things/run-mx-compile.gif" title="/images/blog/using-compilation-mode-to-run-all-the-things/run-mx-compile.gif" /></p>
</div>
</div>
<div id="outline-container-headline-3" class="outline-3">
<h3 id="headline-3">
From code
</h3>
<div id="outline-text-headline-3" class="outline-text-3">
<p>
<code class="verbatim">compile</code> is a emacs-lisp function so we call it from our code, we just need to take care about the <code class="verbatim">default-directory</code> when we call it, for example if we call it from <code class="verbatim">lib/hello.ex</code> buffer, <code class="verbatim">default-directory</code> will be <code class="verbatim">lib</code> and in some cases we want to use our project root, or a different directory, to run our command.</p>
<p>
To fix this we need to setup <code class="verbatim">default-directory</code> before we call <code class="verbatim">compile</code>, for example let&#39;s build a custom function to run <code class="verbatim">hlint</code> in our entire project and then show its results in a <code class="verbatim">compilation</code> buffer:</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/run-hlint ()
  <span style="color:#e6db74">&#34;Run  hlint over the current project.&#34;</span>
  (interactive)
  (let ((default-directory (projectile-project-root)))
    (compile <span style="color:#e6db74">&#34;hlint .&#34;</span>)))</code></pre></div>
</div>
<p>
In this case we&#39;re setting up <code class="verbatim">default-directory</code> with our project root (using projectile to get the root) and then when we call <code class="verbatim">compile</code> it will take <code class="verbatim">default-directory</code> correctly.</p>
</div>
</div>
</div>
</div>
<div id="outline-container-headline-4" class="outline-2">
<h2 id="headline-4">
Some tweaks
</h2>
<div id="outline-text-headline-4" class="outline-text-2">
<p>
These modifications to default behaviour of <code class="verbatim">compilation-mode</code> should be made after the mode was loaded so we need to use <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Hooks-for-Loading.html">with-eval-after-load</a> otherwise these changes won&#39;t be applied correctly.</p>
<div id="outline-container-headline-5" class="outline-3">
<h3 id="headline-5">
Evil-mode
</h3>
<div id="outline-text-headline-5" class="outline-text-3">
<p>
The <code class="verbatim">compilation</code> buffer has some preset key bindings that conflict with <code class="verbatim">evil-mode</code>, for example when we press <code class="verbatim">g</code> in a compilation buffer this will re-run the command, but this key binding is also used by <code class="verbatim">evil-mode</code>, to fix this we can disable the default key binding with:</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(with-eval-after-load <span style="color:#e6db74">&#39;compile</span>
  (<span style="color:#a6e22e">define-key</span> compilation-mode-map (kbd <span style="color:#e6db74">&#34;g&#34;</span>) <span style="color:#66d9ef">nil</span>)
  (<span style="color:#a6e22e">define-key</span> compilation-mode-map (kbd <span style="color:#e6db74">&#34;r&#34;</span>) <span style="color:#e6db74">&#39;recompile</span>)
  (<span style="color:#a6e22e">define-key</span> compilation-mode-map (kbd <span style="color:#e6db74">&#34;h&#34;</span>) <span style="color:#66d9ef">nil</span>))</code></pre></div>
</div>
<p>
In this case <code class="verbatim">h</code> key binding is also disabled (also used by evil) and <code class="verbatim">r</code> is remapped to <code class="verbatim">recompile</code> for easy access now that we disabled <code class="verbatim">g</code> default key binding.</p>
</div>
</div>
<div id="outline-container-headline-6" class="outline-3">
<h3 id="headline-6">
Follow compilation output
</h3>
<div id="outline-text-headline-6" class="outline-text-3">
<p>
By default <code class="verbatim">compilation-mode</code> doesn&#39;t follow the output of the command so if our command result has a large output we&#39;ll need to scroll manually, to fix this we can change <code class="verbatim">compilation-scroll-output</code> to <code class="verbatim">t</code></p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(with-eval-after-load <span style="color:#e6db74">&#39;compile</span>
  <span style="color:#75715e">;; set cursor to follow compilation output</span>
  (setq compilation-scroll-output <span style="color:#66d9ef">t</span>))</code></pre></div>
</div>
</div>
</div>
<div id="outline-container-headline-7" class="outline-3">
<h3 id="headline-7">
Enable ANSI colors
</h3>
<div id="outline-text-headline-7" class="outline-text-3">
<p>
Some tools show results with colors for easy reading but <code class="verbatim">compilation-mode</code> won&#39;t show them by default, you can make them look better with:</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(require <span style="color:#e6db74">&#39;ansi-color</span>)

(defun colorize-compilation-buffer ()
  (let ((inhibit-read-only <span style="color:#66d9ef">t</span>))
    (ansi-color-apply-on-region (<span style="color:#a6e22e">point-min</span>) (<span style="color:#a6e22e">point-max</span>))))

(add-hook <span style="color:#e6db74">&#39;compilation-filter-hook</span> <span style="color:#e6db74">&#39;colorize-compilation-buffer</span>)</code></pre></div>
</div>
<p>
This was taken from this <a href="https://stackoverflow.com/questions/3072648/cucumbers-ansi-colors-messing-up-emacs-compilation-buffer/3072831#3072831">Stack Overflow answer</a></p>
</div>
</div>
<div id="outline-container-headline-8" class="outline-3">
<h3 id="headline-8">
Re run compilation from another buffer
</h3>
<div id="outline-text-headline-8" class="outline-text-3">
<p>
When we&#39;re making changes in our code we want to re-run our compilation process right after we save the changes but to do this we have to move to the compilation buffer to be able to re-run the compilation, a better approach to do this could be just call <code class="verbatim">recompile</code> by using a key binding, I use <code class="verbatim">evil-leader</code> to make this:</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(evil-leader/set-key <span style="color:#e6db74">&#34;R&#34;</span> <span style="color:#e6db74">&#39;recompile</span>)</code></pre></div>
</div>
<p>
<img src="https://erick.navarro.io/images/blog/using-compilation-mode-to-run-all-the-things/run-recompile.gif" alt="/images/blog/using-compilation-mode-to-run-all-the-things/run-recompile.gif" title="/images/blog/using-compilation-mode-to-run-all-the-things/run-recompile.gif" /></p>
<p>
But it can be attached to any key binding, for example:</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(global-set-key (kbd <span style="color:#e6db74">&#34;C-c C-r&#34;</span>) <span style="color:#e6db74">&#39;recompile</span>)</code></pre></div>
</div>
</div>
</div>
<div id="outline-container-headline-9" class="outline-3">
<h3 id="headline-9">
Bonus: run parrot mode animation when a compilation is successful
</h3>
<div id="outline-text-headline-9" class="outline-text-3">
<p>
I configured <a href="https://github.com/dp12/parrot">parrot-mode</a> to animate the little parrot every time the compilation process is a success, to make this we need a small function that check if it was a success and then we need to attach it to <code class="verbatim">&#39;compilation-finish-functions</code>, this is a variable defined in <code class="verbatim">compilation-mode</code>.</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/parrot-animate-when-compile-success (buffer result)
  (if (<span style="color:#a6e22e">string-match</span> <span style="color:#e6db74">&#34;^finished&#34;</span> result)
      (parrot-start-animation)))

(use-package parrot
  :ensure <span style="color:#66d9ef">t</span>
  :config
  (parrot-mode)
  (add-to-list <span style="color:#e6db74">&#39;compilation-finish-functions</span> <span style="color:#e6db74">&#39;my/parrot-animate-when-compile-success</span>))</code></pre></div>
</div>
</div>
</div>
</div>
</div>
<div id="outline-container-headline-10" class="outline-2">
<h2 id="headline-10">
Conclusion
</h2>
<div id="outline-text-headline-10" class="outline-text-2">
<p>
As we can see <code class="verbatim">compilation-mode</code> is a simple but powerful mode that allow us to build our own tools, we can create an automatic build system in case there is not something already existing for the technology we&#39;re using or if we just want to run some tasks in an easier way.</p>
</div>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="3 ejemplos básicos de Terraform sobre AWS">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">3 ejemplos básicos de Terraform sobre AWS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">30 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Para este episodio de Informe Nube, David y Antony vuelven con Terraform sobre AWS para explicar tres ejemplos básicos. Este episodio continúa <a href="https://republicaweb.es/podcast/terraform-en-amazon-web-services/" data-type="URL" data-id="https://republicaweb.es/podcast/terraform-en-amazon-web-services/">el anterior sobre Terraform en AWS</a> y se puede seguir también <a href="https://www.youtube.com/watch?v=5zpGuRjuVz8" data-type="URL" data-id="https://www.youtube.com/watch?v=5zpGuRjuVz8">desde el canal de YouTube de Cursos de Desarrollo.</a></p>



<ol>
<li>Cómo crear las credenciales y configurar el cli de AWS</li>
<li>Cómo crear una máquina virtual en AWS EC2 con acceso SSH y Clave SSH</li>
<li>Cómo crear un servidor Web Nginx en EC2 con soporte de Elastic IP y Volumen de Datos asociad</li>
<li>ómo crear un Cluster de Kubernetes EKS en AWS</li>

</ol>







<p>No dudes en conectar con David y con Antony para sugerirles nuevos episodios sobre cloud y tecnologías de servidor.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Introducing TestParameterInjector: A JUnit4 parameterized test runner</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">30 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Statement from the FSF board of directors meeting on March 29, 2021</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FSF News</a> <span class="article__date">30 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Acelerando los desarrollos con contenedores : SonarQube</h1>
                            <h2 class="article__feed"><a target="_blank" href="">En Mi Local Funciona</a> <span class="article__date">30 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        En este artículo se va a mostrar cómo poder disponer de un contenedor de SonarQube de forma rápida para utilizarlo durante el desarrollo
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2021/211-task-description-effort.png" alt="Task Description vs Effort">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Task Description vs Effort</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">30 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2021/211-task-description-effort.png" alt="Task Description vs Effort" title="Assumption is the mother of all f ups" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Student applications for Google Summer of Code 2021 are now open!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">29 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://thehistoryoftheweb.com/wp-content/uploads/2017/09/cropped-thotw-logo-square-1-32x32.jpg" alt="March 2021 Weblog: Trusting in the Standard">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">March 2021 Weblog: Trusting in the Standard</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The History of the Web</a> <span class="article__date">29 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>A look at the work that standards makes possible, and the kinds of hypertext that were never fully realized</p>
<p>The post <a rel="nofollow" href="https://thehistoryoftheweb.com/postscript/march-2021-weblog-trusting-in-the-standard/">March 2021 Weblog: Trusting in the Standard</a> appeared first on <a rel="nofollow" href="https://thehistoryoftheweb.com">The History of the Web</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Welcoming Ian Kelling to staff seat on FSF&#39;s board of directors</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FSF News</a> <span class="article__date">29 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Font size is useless; let’s fix it</h1>
                            <h2 class="article__feed"><a target="_blank" href="">tonsky.me</a> <span class="article__date">29 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
          What happens when you set fontSize: 32 in your favorite editor
        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Updated Debian 10: 10.9 released</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Debian News</a> <span class="article__date">27 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
    The Debian project is pleased to announce the ninth update of its
stable distribution Debian 10 (codename <q>buster</q>).
This point release mainly adds corrections for security issues,
along with a few adjustments for serious problems. Security advisories
have already been published separately and are referenced where available.
  
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">JavaScript: saber si la tecla «Bloq Mayus» está activada</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Bufa</a> <span class="article__date">26 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Código js para averiguar si tenemos activada la tecla «Bloq Mayus» en nuestro teclado, la cual activa el uso continuo de las letras mayúsculas, y puede que en algunos casos eso no nos interese. Un ejemplo en un input password: [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Instalando Istio en Windows 10</h1>
                            <h2 class="article__feed"><a target="_blank" href="">En Mi Local Funciona</a> <span class="article__date">26 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        El objetivo de este artículo está pensado para entornos locales de formación, desarrollo y pruebas, donde veremos cómo instalar Istio en Windows 10.

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Update on work to improve governance at the FSF</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FSF News</a> <span class="article__date">26 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://diarioestoico.com/wp-content/uploads/2020/03/cropped-logo-estoico-footer-150x150-1-32x32.png" alt="MARCO AURELIO Y LA ADVERSIDAD">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">MARCO AURELIO Y LA ADVERSIDAD</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Diario Estoico</a> <span class="article__date">25 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Si una disciplina ética ha caracterizado al estoicismo esta es, sin duda, la de combatir la adversidad. Desde que Zenón de Citio tuviera que recomenzar su vida sin posesiones&#160; tras haberlo perdido todo en el naufragio de su navío, se sucedieron una tradición de filósofos estoicos que, pudiendo representar más o menos con su experiencia [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Preliminary board statement on FSF governance</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FSF News</a> <span class="article__date">25 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/lem1.png" alt="Lem can now be started as a full featured Lisp REPL">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Lem can now be started as a full featured Lisp REPL</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">24 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>The <a href="https://github.com/lem-project/lem/">Lem editor</a>, which supports
Common Lisp as well as other languages, works by default in the
terminal with a ncurses frontend (it also has an experimental Electron
frontend). It ships a nice Lisp REPL: it has good fuzzy completion,
enough keyboard shortcuts, an interactive debugger, a completion menu,
etc.</p>

<p>It is now possible to run Lem straight in its Lisp REPL. Run it with:</p>

<pre><code>lem --eval &quot;(lem-lisp-mode:start-lisp-repl t)&quot;
</code></pre>

<p>The optional argument (<code>t</code>) was added recently (thanks, @cxxxr) and allows to start the REPL in fullscreen.</p>

<p>Here is it in action:</p>

<p><img src="/lem1.png" alt="" /></p>

<p><img src="/lem2.png" alt="" /></p>

<p><img src="/lem3.png" alt="" /></p>

<p><img src="/lem4.png" alt="" /></p>

<p>The other terminal-based REPL alternatives are:</p>

<ul>
<li><a href="https://github.com/koji-kojiro/cl-repl/">cl-repl</a> (wants to be full-featured, à la ipython)</li>
<li><a href="https://github.com/hellerve/sbcli">sbcli</a> (handy, but minimalistic)</li>
</ul>

<p>but IMO, they now fall short compared to Lem&rsquo;s features.</p>

<h2 id="installation">Installation</h2>

<p>To install it, see its <a href="https://github.com/lem-project/lem/wiki">wiki</a>. In short, do</p>

<pre><code> ros install cxxxr/lem
</code></pre>

<p>or use <a href="https://github.com/40ants/lem-docker">lem-docker</a>.</p>

<p>To install Roswell, do one of</p>

<pre><code>brew install roswell  # macos or linuxbrew
yay -S roswell
scoop install roswell  # windows

# Debian package:
curl -sOL `curl -s https://api.github.com/repos/roswell/roswell/releases/latest | jq -r '.assets | .[] | select(.name|test(&quot;deb$&quot;)) | .browser_download_url'`
sudo dpkg -i roswell.deb
</code></pre>

<p>See its <a href="https://github.com/roswell/roswell/releases">releases</a>.</p>

<h2 id="usage-quickref">Usage (quickref)</h2>

<p>Lem has Emacs-like keybindings, as well as a vi emulation (<code>M-x vi-mode</code>). Unfortunately, that is not documented much.</p>

<p>So, to open a file, press <code>C-x C-f</code> (you get the file selection dialog shown above). To save it, it&rsquo;s <code>C-x C-s</code>.</p>

<p>To switch to the REPL: <code>C-c C-z</code>.</p>

<p>To compile and load a buffer: <code>C-c C-k</code>. To compile a function: <code>C-c C-c</code>.</p>

<p>To switch windows: <code>C-x o</code>. To make a window fullscreen: <code>C-x 1</code>. To split it vertically: <code>C-x 3</code> and horizontally: <code>C-x 2</code>.</p>

<p>To switch buffers: <code>C-x b</code>.</p>

<p>To run an interactive command: <code>M-x</code> (<code>alt-x</code>).</p>

<p>See this Emacs &amp; Slime cheatsheet to find more: <a href="https://lispcookbook.github.io/cl-cookbook/emacs-ide.html#appendix">https://lispcookbook.github.io/cl-cookbook/emacs-ide.html#appendix</a></p>

<p>Lem works out of the box for several programming languages (Python, Rust, Scala…). It also has an HTML mode, a directory mode… Lem needs to be discovered!</p>

<ul>
<li>chat: <a href="https://gitter.im/lem-developers/community">https://gitter.im/lem-developers/community</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Listening to maintainers for the next phase of Clojurists Together</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">24 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Help us understand the best way we can fund the Clojure community.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Emoji under the hood</h1>
                            <h2 class="article__feed"><a target="_blank" href="">tonsky.me</a> <span class="article__date">24 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
          Detailed look into all the machinery involved in rendering Emoji
        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Handling Text Over Images in CSS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Ahmad Shadeed Blog</a> <span class="article__date">23 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2021/210-denvercoder9.png" alt="DENVERCODER9">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">DENVERCODER9</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">23 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2021/210-denvercoder9.png" alt="DENVERCODER9" title="979" /></p>

<p><img src="https://www.monkeyuser.com/assets/images/2021/210-denvercoder9-1.png" style="margin-top: -30px;" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://blogs.windows.com/wp-content/uploads/prod/sites/33/2021/06/cropped-browser-icon-logo-32x32.jpg" alt="Joining forces on better browser compatibility in 2021">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Joining forces on better browser compatibility in 2021</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Microsoft Edge Blog</a> <span class="article__date">22 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Over the past few years, Microsoft has partnered with a group of browser vendors and other industry stakeholders to identify and address the top sources of web developer pain through initiatives like the <a href="https://insights.developer.mozilla.or
</p>
<p>The post <a rel="nofollow" href="https://blogs.windows.com/msedgedev/2021/03/22/better-compatibility-compat2021/">Joining forces on better browser compatibility in 2021</a> appeared first on <a rel="nofollow" href="https://blogs.windows.com/msedgedev">Microsoft Edge Blog</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Free Software Foundation lending aid to support local free software groups</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FSF News</a> <span class="article__date">22 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        BOSTON, Massachusetts, USA -- Sunday, March 21, 2021 -- As part of its
annual LibrePlanet conference, the Free Software Foundation (FSF)
announced its plan to provide small grants to local free software
groups around the world.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hyperreals *R: Ejemplo pr&amp;#225;ctico. Potencias de Fermi-Dirac - Evaluaci&amp;#243;n perezosa en python - Parte&amp;#160;6</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">21 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Se llaman <strong>potencias de Fermi-Dirac</strong> a los n&#250;meros de la forma <span class="math">\(p^{2^k}\)</span>,
ordenados de menor a mayor, donde <code>p</code> es un n&#250;mero primo y <code>k</code> es un n&#250;mero&nbsp;natural.</p>
<p>Vamos a ver c&#243;mo crear la sucesi&#243;n de <code>potencias</code> Fermi-Dirac. Realizaremos las
siguientes&nbsp;comprobaciones:</p>
<div class="highlight"><pre><span></span><code><span class="n">potencias</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span>

<span class="n">potencias</span><span class="p">[:</span><span class="mi">14</span><span class="p">]</span>    <span class="o">==</span>  <span class="p">[</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">7</span><span class="p">,</span><span class="mi">9</span><span class="p">,</span><span class="mi">11</span><span class="p">,</span><span class="mi">13</span><span class="p">,</span><span class="mi">16</span><span class="p">,</span><span class="mi">17</span><span class="p">,</span><span class="mi">19</span><span class="p">,</span><span class="mi">23</span><span class="p">,</span><span class="mi">25</span><span class="p">,</span><span class="mi">29</span><span class="p">]</span>
<span class="n">potencias</span><span class="p">[</span><span class="mi">60</span><span class="p">]</span>     <span class="o">==</span>  <span class="mi">241</span>
<span class="n">potencias</span><span class="p">[</span><span class="mi">10</span><span class="o">**</span><span class="mi">6</span><span class="p">]</span>  <span class="o">==</span>  <span class="mi">15476303</span>
</code></pre></div>

<h2>Estudio&nbsp;previo</h2>
<p>Si sacamos la lista de potencias en funci&#243;n del exponente <code>k</code> tendr&#237;amos las
siguientes&nbsp;sucesiones:</p>
<div class="math">$$
\begin{align*}
P_0 &amp;= 2,3,5,7,11,...\\
P_1 &amp;= 4,9,25,49,121,..\\
P_2 &amp;= 16,81,625,2401,14641,...\\
P_3 &amp;= 256,6561,390625,5764801,214358881,815730721,...
\end{align*}
$$</div>
<p>Necesitamos combinar estas sucesiones en una sola. A priori, no sabemos cu&#225;ntos
elementos vamos a necesitar de cada sucesi&#243;n. Como m&#225;ximo, para sacar las
primeras 14 potencias nos basta con los primeros 14 n&#250;meros primos y crear 14
secuencias, de <span class="math">\(P_0\)</span> a <span class="math">\(P_{13}\)</span>, ordenarlos sus elementos en una &#250;nica lista y
escoger los primeros 14 elementos. Con este proceso habremos calculado 196
potencias para s&#243;lo 14 elementos que necesitamos al&nbsp;final.</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">primes</span> <span class="kn">import</span> <span class="n">primes</span>

<span class="n">potencias</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">p</span><span class="o">**</span><span class="mi">2</span><span class="o">**</span><span class="n">k</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">primes</span><span class="p">[:</span><span class="mi">14</span><span class="p">]</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">14</span><span class="p">))</span>
<span class="nb">print</span><span class="p">(</span><span class="n">potencias</span><span class="p">[:</span><span class="mi">14</span><span class="p">])</span>

<span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">13</span><span class="p">,</span> <span class="mi">16</span><span class="p">,</span> <span class="mi">17</span><span class="p">,</span> <span class="mi">19</span><span class="p">,</span> <span class="mi">23</span><span class="p">,</span> <span class="mi">25</span><span class="p">,</span> <span class="mi">29</span><span class="p">]</span>
</code></pre></div>

<p>A&#250;n en el caso de que tuvi&#233;ramos alg&#250;n medio de reducir el n&#250;mero de elementos a
usar de cada secuencia, seguimos sin saber cu&#225;ntos n&#250;meros primos ser&#225;n
necesarios. Para sacar los 14 primeros elementos de las potencias de Fermi-Dirac
s&#243;lo se necesitaban los 10 primeros n&#250;meros&nbsp;primos.</p>
<p>Es evidente que una estrategia por <em>fuerza bruta</em> es complicada y termina por
hacer muchos c&#225;lculos innecesarios, una complejidad del <span class="math">\(O({n^2})\)</span> no resoluble
con un ordenador normal. Veamos c&#243;mo nos puede ayudar la <em>evaluaci&#243;n perezosa</em>.</p>
<h2>Modelos</h2>
<p>Por intentar crear un modelo, intentemos ver las sucesiones como un iterador de&nbsp;iteradores:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">count</span>

<span class="kn">from</span> <span class="nn">primes</span> <span class="kn">import</span> <span class="n">primes</span>

<span class="n">potencias</span> <span class="o">=</span> <span class="p">((</span><span class="n">p</span><span class="o">**</span><span class="mi">2</span><span class="o">**</span><span class="n">k</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">primes</span><span class="p">)</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">count</span><span class="p">())</span>
</code></pre></div>

<p>Pero el problema con las <em>expresiones generadora</em> es similar al que tienen las
expresiones lambda: carecen de su propia clausura y cualquier <em>variable libre</em>
queda alterada por el entorno donde se&nbsp;eval&#250;an.</p>
<p>Se puede comprobar el fallo si intentamos extraer dos&nbsp;iteradores:</p>
<div class="highlight"><pre><span></span><code><span class="n">p0</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">potencias</span><span class="p">)</span>
<span class="n">p1</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">potencias</span><span class="p">)</span>
<span class="nb">next</span><span class="p">(</span><span class="n">p1</span><span class="p">)</span>  <span class="c1"># --&gt; 4</span>
<span class="nb">next</span><span class="p">(</span><span class="n">p0</span><span class="p">)</span>  <span class="c1"># --&gt; 4</span>
<span class="nb">next</span><span class="p">(</span><span class="n">p0</span><span class="p">)</span>  <span class="c1"># --&gt; 9</span>
</code></pre></div>

<p>El exponente <code>k</code> ha cambiado de valor con el segundo iterador, lo que afecta a
las potencias del primero. Tenemos que dotar a los iteradores de su propia&nbsp;clausura:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Iterator</span>
<span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">count</span>

<span class="kn">from</span> <span class="nn">primes</span> <span class="kn">import</span> <span class="n">primes</span>

<span class="k">def</span> <span class="nf">potencias_gen</span><span class="p">(</span><span class="n">k</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Iterator</span><span class="p">[</span><span class="nb">int</span><span class="p">]:</span>
    <span class="k">yield from</span> <span class="p">(</span><span class="n">p</span><span class="o">**</span><span class="mi">2</span><span class="o">**</span><span class="n">k</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">primes</span><span class="p">)</span>

<span class="n">potencias</span> <span class="o">=</span> <span class="p">(</span><span class="n">potencias_gen</span><span class="p">(</span><span class="n">k</span><span class="p">)</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">count</span><span class="p">())</span>
</code></pre></div>

<p>Para obtener una &#250;nica secuencia a partir de este <em>iterador de iteradores</em> en un
&#250;nico iterador, operaci&#243;n que se conoce como <em>&#8220;aplanar la secuencia&#8221;</em>.</p>
<p>Definimos la siguiente funci&#243;n para mezclar dos listas&nbsp;ordenadas:</p>
<div class="highlight"><pre><span></span><code><span class="c1"># tipo para secuencias ordenadas</span>
<span class="n">SortedIterator</span> <span class="o">=</span> <span class="n">Iterator</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span>

<span class="k">def</span> <span class="nf">zipsort</span><span class="p">(</span><span class="n">s1</span><span class="p">:</span> <span class="n">SortedIterator</span><span class="p">,</span> <span class="n">s2</span><span class="p">:</span> <span class="n">SortedIterator</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">SortedIterator</span><span class="p">:</span>
    <span class="n">x</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">s1</span><span class="p">)</span>
    <span class="n">y</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">s2</span><span class="p">)</span>
    <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">x</span> <span class="o">&lt;=</span> <span class="n">y</span><span class="p">:</span>
            <span class="k">yield</span> <span class="n">x</span>
            <span class="n">x</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">s1</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">yield</span> <span class="n">y</span>
            <span class="n">y</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">s2</span><span class="p">)</span>
</code></pre></div>

<p>La funci&#243;n <code>zipsort</code> combina dos listas ordenadas <code>SortedIterator</code> para devolver
otra lista ordenada <code>SortedIterator</code>. Si quisi&#233;ramos combinar tres listas,
bastar&#237;a con volver repetir con <code>zipsort</code>:</p>
<div class="highlight"><pre><span></span><code><span class="n">zipsort</span><span class="p">(</span><span class="n">zipsort</span><span class="p">(</span><span class="n">s1</span><span class="p">,</span> <span class="n">s2</span><span class="p">),</span> <span class="n">s3</span><span class="p">)</span>
</code></pre></div>

<p>En general, podr&#237;amos combinar todas las listas de esta&nbsp;manera:</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">flat</span><span class="p">(</span><span class="n">iterators</span><span class="p">:</span> <span class="n">Iterator</span><span class="p">[</span><span class="n">SortedIterator</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">SortedIterator</span><span class="p">:</span>
    <span class="n">it1</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">iterators</span><span class="p">)</span>
    <span class="n">it2</span> <span class="o">=</span> <span class="n">flat</span><span class="p">(</span><span class="n">iterators</span><span class="p">)</span>
    <span class="k">yield from</span> <span class="n">zipsort</span><span class="p">(</span><span class="n">it1</span><span class="p">,</span> <span class="n">it2</span><span class="p">)</span>

<span class="n">potencias</span> <span class="o">=</span> <span class="n">flat</span><span class="p">(</span><span class="n">potencias_gen</span><span class="p">(</span><span class="n">k</span><span class="p">)</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">count</span><span class="p">())</span>
</code></pre></div>

<p>El problema es que se entra en un bucle infinito de llamadas recursivas a <code>flat</code>
que habr&#225; que&nbsp;evitar.</p>
<p>Si observamos las sucesiones <span class="math">\(P_0\)</span>, <span class="math">\(P_1\)</span>, <span class="math">\(P_2\)</span>,&#8230;, el primer elemento de una
sucesi&#243;n es siempre inferior a cualquier elemento de sucesiones posteriores.
Usando esta propiedad, podemos redefinir nuestra funci&#243;n&nbsp;aplanadora:</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">flat</span><span class="p">(</span><span class="n">iterators</span><span class="p">:</span> <span class="n">Iterator</span><span class="p">[</span><span class="n">SortedIterator</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">SortedIterator</span><span class="p">:</span>
    <span class="n">it1</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">iterators</span><span class="p">)</span>
    <span class="k">yield</span> <span class="nb">next</span><span class="p">(</span><span class="n">it1</span><span class="p">)</span>
    <span class="k">yield from</span> <span class="n">zipsort</span><span class="p">(</span><span class="n">it1</span><span class="p">,</span> <span class="n">flat</span><span class="p">(</span><span class="n">iterators</span><span class="p">))</span>

<span class="n">potencias</span> <span class="o">=</span> <span class="n">flat</span><span class="p">(</span><span class="n">potencias_gen</span><span class="p">(</span><span class="n">k</span><span class="p">)</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">count</span><span class="p">())</span>
</code></pre></div>

<p>La funci&#243;n <code>flat</code> devuelve siempre un elemento antes de invocarse por
recursividad, suficiente para frenar la cadena de llamadas recursivas. Visto de
otro modo, se ha convertido la funci&#243;n en <em>perezosa</em>, devolviendo elementos a
medida que sean necesarios. De todos modos, seguimos limitados por el nivel de
recursividad en python (~3000 niveles en CPython), aunque no vamos a superar
este l&#237;mite en las pruebas<sup id="fnref:1"><a class="footnote-ref" href="https://blog.ch3m4.org/feeds/python.atom.xml#fn:1">1</a></sup>.</p>
<h2>C&#243;digo&nbsp;final</h2>
<p>Descarga: <a href="https://blog.ch3m4.org/2021/03/07/evaluacion-perezosa-en-python-parte-6/potencias.py" title="Potencias de Fermi-Dirac">potencias.py</a></p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Iterator</span>
<span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">count</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TypeVar</span>

<span class="kn">from</span> <span class="nn">lazyseq</span> <span class="kn">import</span> <span class="n">LazySortedSequence</span>
<span class="kn">from</span> <span class="nn">primes</span> <span class="kn">import</span> <span class="n">primes</span>


<span class="n">SortedIterator</span> <span class="o">=</span> <span class="n">Iterator</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span>


<span class="k">def</span> <span class="nf">join</span><span class="p">(</span><span class="n">s1</span><span class="p">:</span> <span class="n">SortedIterator</span><span class="p">,</span> <span class="n">s2</span><span class="p">:</span> <span class="n">SortedIterator</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">SortedIterator</span><span class="p">:</span>
    <span class="n">x</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">s1</span><span class="p">)</span>
    <span class="n">y</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">s2</span><span class="p">)</span>
    <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">x</span> <span class="o">&lt;=</span> <span class="n">y</span><span class="p">:</span>
            <span class="k">yield</span> <span class="n">x</span>
            <span class="n">x</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">s1</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">yield</span> <span class="n">y</span>
            <span class="n">y</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">s2</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">flat</span><span class="p">(</span><span class="n">it</span><span class="p">:</span> <span class="n">Iterator</span><span class="p">[</span><span class="n">SortedIterator</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">SortedIterator</span><span class="p">:</span>
    <span class="n">s1</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">it</span><span class="p">)</span>
    <span class="k">yield</span> <span class="nb">next</span><span class="p">(</span><span class="n">s1</span><span class="p">)</span>
    <span class="k">yield from</span> <span class="n">join</span><span class="p">(</span><span class="n">s1</span><span class="p">,</span> <span class="n">flat</span><span class="p">(</span><span class="n">it</span><span class="p">))</span>


<span class="k">def</span> <span class="nf">mkiter</span><span class="p">(</span><span class="n">k</span><span class="p">):</span>
    <span class="k">yield from</span> <span class="p">(</span><span class="n">p</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">**</span> <span class="n">k</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">primes</span><span class="p">)</span>

<span class="n">potencias</span> <span class="o">=</span> <span class="n">LazySortedSequence</span><span class="p">(</span><span class="n">flat</span><span class="p">(</span><span class="n">mkiter</span><span class="p">(</span><span class="n">k</span><span class="p">)</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">count</span><span class="p">()))</span>
</code></pre></div>

<p>Para las&nbsp;comprobaciones:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">potencias</span><span class="p">[:</span><span class="mi">14</span><span class="p">]</span>
<span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">13</span><span class="p">,</span> <span class="mi">16</span><span class="p">,</span> <span class="mi">17</span><span class="p">,</span> <span class="mi">19</span><span class="p">,</span> <span class="mi">23</span><span class="p">,</span> <span class="mi">25</span><span class="p">,</span> <span class="mi">29</span><span class="p">]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">potencias</span><span class="p">[</span><span class="mi">60</span><span class="p">]</span>
<span class="mi">241</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">potencias</span><span class="p">[</span><span class="mi">10</span> <span class="o">**</span> <span class="mi">6</span><span class="p">]</span>
<span class="mi">15476303</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">primes</span><span class="o">.</span><span class="n">size</span>
<span class="mi">999432</span>
</code></pre></div>

<p>Para obtener el elemento <span class="math">\(10^6\)</span> tarda bastante al necesitar obtener casi un
mill&#243;n de n&#250;meros primos. Una vez obtenidos, el c&#225;lculo es bastante&nbsp;r&#225;pido.</p>
<hr />
<h2>Serie <em>Evaluaci&#243;n Perezosa en&nbsp;Python</em></h2>
<ul>
<li><a href="https://blog.ch3m4.org/2021/02/08/evaluacion-perezosa-en-python-parte-1/" title="Introducci&#243;n a la _evaluaci&#243;n perezosa_">Parte 1 - Introducci&#243;n a la <em>evaluaci&#243;n&nbsp;perezosa</em></a></li>
<li><a href="https://blog.ch3m4.org/2021/02/09/evaluacion-perezosa-en-python-parte-2/" title="Secuencias infinitas">Parte 2 - Secuencias&nbsp;infinitas</a></li>
<li><a href="https://blog.ch3m4.org/2021/02/14/evaluacion-perezosa-en-python-parte-3/" title="Parte 3 - _Memoizaci&#243;n_">Parte 3 - <em>Memoizaci&#243;n</em></a></li>
<li><a href="https://blog.ch3m4.org/2021/02/15/evaluacion-perezosa-en-python-parte-4/" title="Parte 4 - _Evaluaci&#243;n perezosa_ avanzada">Parte 4 - <em>Evaluaci&#243;n perezosa</em>&nbsp;avanzada</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/07/evaluacion-perezosa-en-python-parte-5/" title="Parte 5 - Formalizaci&#243;n de la Secuencia Perezosa">Parte 5 - Formalizaci&#243;n de la Secuencia&nbsp;Perezosa</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/07/evaluacion-perezosa-en-python-parte-6/" title="Parte 6 - Ejemplo pr&#225;ctico: Potencias de Fermi-Dirac">Parte 6 - Ejemplo pr&#225;ctico: Potencias de&nbsp;Fermi-Dirac</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/10/evaluacion-perezosa-en-python-apendice/" title="Ap&#233;ndice: sobre el tipado de datos utilizado">Ap&#233;ndice: sobre el tipado de datos&nbsp;utilizado</a></li>
</ul>
<div class="admonition danger">
<p class="admonition-title">La serie unificada como <em>Jupyter Notebook</em>&nbsp;en:</p>
<ul>
<li><a href="https://blog.ch3m4.org/2021/notebook-serie-evaluacion-perezosa-en-python.sync.ipynb" title="Notebook - Evaluaci&#243;n perezosa en python">formato notebook&nbsp;(.ipynb)</a></li>
<li><a href="https://blog.ch3m4.org/2021/notebook-serie-evaluacion-perezosa-en-python.sync.md" title="Jupytext - Evaluaci&#243;n perezosa en python">formato jupytext&nbsp;(.md)</a></li>
</ul>
</div>
<hr />
<p><span class="caps">ANOTACIONES</span>:</p>
<div class="footnote">
<hr />
<ol>
<li id="fn:1">
<p>Es posible que en posteriores art&#237;culos veamos t&#233;cnicas para superar las
limitaciones de la recursivad en python.&#160;<a class="footnote-backref" href="https://blog.ch3m4.org/feeds/python.atom.xml#fnref:1" title="Jump back to footnote 1 in the text">&#8617;</a></p>
</li>
</ol>
</div>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hyperreals *R: Introducci&amp;#243;n a la &amp;#8220;Evaluaci&amp;#243;n Perezosa&amp;#8221; - Evaluaci&amp;#243;n perezosa en python - Parte&amp;#160;1</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">21 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <h2>Introducci&#243;n a la <em>Evaluaci&#243;n&nbsp;Perezosa</em></h2>
<p>Podemos definir <em>&#8220;Evaluaci&#243;n Perezosa&#8221;</em> como aquella evaluaci&#243;n que realiza los
m&#237;nimos c&#225;lculos imprecindibles para obtener el resultado&nbsp;final.</p>
<p>La evaluaci&#243;n perezosa es una de las caracter&#237;stica del languaje haskell, aunque
vamos a ver que tambi&#233;n se puede hacer en otros lenguajes como&nbsp;python.</p>
<p>Por ejemplo, imaginemos que queremos obtener todos los n&#250;mero cuadrados menores
de&nbsp;100:</p>
<div class="highlight"><pre><span></span><code><span class="n">cuadrados</span> <span class="o">=</span> <span class="p">[</span><span class="n">x</span><span class="o">**</span><span class="mi">2</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">100</span><span class="p">)]</span>
<span class="n">resultado</span> <span class="o">=</span> <span class="p">[</span><span class="n">y</span> <span class="k">for</span> <span class="n">y</span> <span class="ow">in</span> <span class="n">cuadrados</span> <span class="k">if</span> <span class="n">y</span> <span class="o">&lt;</span> <span class="mi">100</span><span class="p">]</span>
</code></pre></div>

<p>Para obtener el <code>resultado</code>, antes hemos calculado la lista completa
<code>cuadrados</code>, a pesar de que s&#243;lo necesit&#225;bamos unos 10&nbsp;elementos.</p>
<p>Una posible mejora ser&#237;a usar una expresi&#243;n&nbsp;generadora:</p>
<div class="highlight"><pre><span></span><code><span class="n">cuadrados</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span><span class="o">**</span><span class="mi">2</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">100</span><span class="p">))</span>
<span class="n">resultado</span> <span class="o">=</span> <span class="p">[</span><span class="n">y</span> <span class="k">for</span> <span class="n">y</span> <span class="ow">in</span> <span class="n">cuadrados</span> <span class="k">if</span> <span class="n">y</span> <span class="o">&lt;</span> <span class="mi">100</span><span class="p">]</span>
</code></pre></div>

<p>Aqu&#237; los elementos de la lista <code>cuadrados</code> se calculan a medida que son
necesarios, sin gastar memoria para almacenar la secuencia a medida que se
obtiene, algo que pasaba con el ejemplo anterior. A&#250;n as&#237;, se vuelven a calcular
los 100 cuadrados, ya que no se corta la iteraci&#243;n en ning&#250;n momento.
Necesitamos un modo de limitarnos &#250;nicamente a los elementos que vamos a&nbsp;utilizar.</p>
<p>Para quedarnos s&#243;lo con los primeros elementos vamos a usar la funci&#243;n
<code>itertools.takewhile</code>:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">takewhile</span>

<span class="n">cuadrados</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span><span class="o">**</span><span class="mi">2</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">100</span><span class="p">))</span>
<span class="n">resultado</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">takewhile</span><span class="p">(</span><span class="k">lambda</span> <span class="n">y</span><span class="p">:</span> <span class="n">y</span><span class="o">&lt;</span><span class="mi">100</span><span class="p">,</span> <span class="n">cuadrados</span><span class="p">))</span>
</code></pre></div>

<p>En este caso, obtenemos &#250;nicamente los cuadrados necesarios, lo que supone un
importante ahorro de tiempo de&nbsp;c&#225;lculo.</p>
<p>Si no se tiene cuidado, es muy f&#225;cil hacer m&#225;s c&#225;lculos de la cuenta, e incluso
acabar en bucles infinitos o agotando los recursos de la m&#225;quina. Como veremos
en esta serie de art&#237;culos, en python se puede tener evaluaci&#243;n perezosa usando
correctamente iteradores y&nbsp;generadores.</p>
<h2>Tipo&nbsp;Range</h2>
<p>Veamos el siguiente&nbsp;c&#243;digo:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">r</span> <span class="o">=</span> <span class="nb">range</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">100</span><span class="p">,</span><span class="mi">3</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">r</span><span class="p">[</span><span class="mi">10</span><span class="p">]</span>
<span class="mi">32</span>
</code></pre></div>

<p>Normalmente, se usa la funci&#243;n <code>range</code> para crear bucles sin tener en cuenta que
realmente es un constructor de objetos de tipo <code>Range</code>. Estos objetos responden
a los mismos m&#233;todos que una lista, permitiendo obtener un elemento de cualquier
posici&#243;n de la secuencia sin necesidad de generar la secuencia completa. Tambi&#233;n
se pueden hacer otras operaciones habituales con&nbsp;listas:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">r</span><span class="p">)</span>  <span class="c1"># obtener el tama&#241;o</span>
<span class="mi">33</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">r</span><span class="p">[</span><span class="mi">20</span><span class="p">:</span><span class="mi">30</span><span class="p">]</span>  <span class="c1"># obtener un rango</span>
<span class="nb">range</span><span class="p">(</span><span class="mi">62</span><span class="p">,</span> <span class="mi">92</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">r</span><span class="p">[</span><span class="mi">30</span><span class="p">:</span><span class="mi">20</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>  <span class="c1"># obtener un rango inverso</span>
<span class="nb">range</span><span class="p">(</span><span class="mi">92</span><span class="p">,</span> <span class="mi">62</span><span class="p">,</span> <span class="o">-</span><span class="mi">3</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">r</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>  <span class="c1"># la misma secuencia invertida</span>
<span class="nb">range</span><span class="p">(</span><span class="mi">98</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">3</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">r</span><span class="p">[</span><span class="mi">20</span><span class="p">:</span><span class="mi">30</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>  <span class="c1"># umm, secuencia vac&#237;a???</span>
<span class="nb">range</span><span class="p">(</span><span class="mi">62</span><span class="p">,</span> <span class="mi">92</span><span class="p">,</span> <span class="o">-</span><span class="mi">3</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">r</span><span class="p">[::</span><span class="mi">2</span><span class="p">]</span>  <span class="c1"># una nueva secuencia con distinto paso</span>
<span class="nb">range</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">101</span><span class="p">,</span> <span class="mi">6</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="mi">3</span> <span class="ow">in</span> <span class="n">r</span>  <span class="c1"># comprobar si contiene un elemento</span>
<span class="kc">False</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">r</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="mi">65</span><span class="p">)</span>  <span class="c1"># buscar la posici&#243;n de un elemento</span>
<span class="mi">21</span>
</code></pre></div>

<p>Como vemos, de alg&#250;n modo calcula los nuevos rangos y los pasos seg&#250;n
necesitemos. Es suficientemente inteligente para cambiar el elemento final por
otro que considere m&#225;s&nbsp;apropiado.</p>
<p>Digamos que un objeto de tipo <code>Range</code> conoce c&#243;mo operar con secuencias
aritm&#233;ticas, pudiendo obtener un elemento cualquiera de la secuencia sin tener
que calcular el&nbsp;resto.</p>
<h2>Secuencias con elemento gen&#233;rico&nbsp;conocido</h2>
<p>Probemos a crear algo similar a <code>Range</code> para la secuencia de cuadrados. Derivar&#225;
de la clase abstracta <code>Sequence</code>, por lo que tenemos que definir, por lo menos,
los m&#233;todos <code>__len__</code> y  <code>_getitem__</code>. Nos apoyaremos en un objeto <em>range</em> para
esta labor (patr&#243;n <em>Delegate</em>):</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Sequence</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Union</span>


<span class="k">class</span> <span class="nc">SquaresRange</span><span class="p">(</span><span class="n">Sequence</span><span class="p">):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">start</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">stop</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">step</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">stop</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
            <span class="n">start</span><span class="p">,</span> <span class="n">stop</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">start</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_range</span> <span class="o">=</span> <span class="nb">range</span><span class="p">(</span><span class="n">start</span><span class="p">,</span> <span class="n">stop</span><span class="p">,</span> <span class="n">step</span><span class="p">)</span>

    <span class="nd">@staticmethod</span>
    <span class="k">def</span> <span class="nf">from_range</span><span class="p">(</span><span class="n">rng</span><span class="p">:</span> <span class="nb">range</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="s2">&quot;SquaresRange&quot;</span><span class="p">:</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Constructor de SquaresRange a partir de un rango</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">instance</span> <span class="o">=</span> <span class="n">SquaresRange</span><span class="p">()</span>
        <span class="n">instance</span><span class="o">.</span><span class="n">_range</span> <span class="o">=</span> <span class="n">rng</span>
        <span class="k">return</span> <span class="n">instance</span>

    <span class="k">def</span> <span class="fm">__len__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
        <span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_range</span><span class="p">)</span>

    <span class="k">def</span> <span class="fm">__getitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">idx</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">slice</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">Union</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="s2">&quot;SquaresRange&quot;</span><span class="p">]:</span>
        <span class="n">i</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_range</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span>
        <span class="k">return</span> <span class="n">i</span> <span class="o">**</span> <span class="mi">2</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="nb">int</span><span class="p">)</span> <span class="k">else</span> <span class="n">SquaresRange</span><span class="o">.</span><span class="n">from_range</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>

    <span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
        <span class="n">r</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_range</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;SquaresRange(</span><span class="si">{</span><span class="n">r</span><span class="o">.</span><span class="n">start</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">r</span><span class="o">.</span><span class="n">stop</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">r</span><span class="o">.</span><span class="n">step</span><span class="si">}</span><span class="s2">)&quot;</span>
</code></pre></div>

<p>Podemos probar su&nbsp;funcionamiento:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">SquaresRange</span><span class="p">(</span><span class="o">-</span><span class="mi">10</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">):</span>
<span class="o">...</span>     <span class="nb">print</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
<span class="o">...</span>
<span class="mi">100</span>
<span class="mi">49</span>
<span class="mi">16</span>
<span class="mi">1</span>
<span class="o">&gt;&gt;&gt;</span> <span class="nb">list</span><span class="p">(</span><span class="n">SquaresRange</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">50</span><span class="p">,</span> <span class="mi">4</span><span class="p">)[:</span><span class="mi">30</span><span class="p">:</span><span class="mi">2</span><span class="p">])</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">49</span><span class="p">,</span> <span class="mi">225</span><span class="p">,</span> <span class="mi">529</span><span class="p">,</span> <span class="mi">961</span><span class="p">,</span> <span class="mi">1521</span><span class="p">,</span> <span class="mi">2209</span><span class="p">]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">SquaresRange</span><span class="p">(</span><span class="mi">100</span><span class="p">)[::</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="n">SquaresRange</span><span class="p">(</span><span class="mi">99</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="mi">16</span> <span class="ow">in</span> <span class="n">SquaresRange</span><span class="p">(</span><span class="o">-</span><span class="mi">10</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="kc">True</span>
</code></pre></div>

<p>Hay que tener en cuenta que, a diferencia de un iterador, este rango no se
<em>&#8220;agota&#8221;</em> por lo que se puede usar repetidas veces sin ning&#250;n&nbsp;problema.</p>
<p>Siguiendo m&#225;s all&#225;, podemos generalizar esta secuencia para se usar cualquier
funci&#243;n. Creamos la siguiente <em>clase abstracta</em>:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">abc</span> <span class="kn">import</span> <span class="n">abstractmethod</span>
<span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Sequence</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Type</span><span class="p">,</span> <span class="n">Union</span>


<span class="k">class</span> <span class="nc">GenericRange</span><span class="p">(</span><span class="n">Sequence</span><span class="p">):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">start</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">stop</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">step</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">stop</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
            <span class="n">start</span><span class="p">,</span> <span class="n">stop</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">start</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_range</span> <span class="o">=</span> <span class="nb">range</span><span class="p">(</span><span class="n">start</span><span class="p">,</span> <span class="n">stop</span><span class="p">,</span> <span class="n">step</span><span class="p">)</span>

    <span class="nd">@abstractmethod</span>
    <span class="k">def</span> <span class="nf">getitem</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">pos</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        M&#233;todo abstracto.</span>
<span class="sd">          Funci&#243;n para calcular un elemento a partir de la posici&#243;n</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">pos</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">from_range</span><span class="p">(</span><span class="bp">cls</span><span class="p">:</span> <span class="n">Type</span><span class="p">[</span><span class="s2">&quot;GenericRange&quot;</span><span class="p">],</span> <span class="n">rng</span><span class="p">:</span> <span class="nb">range</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="s2">&quot;GenericRange&quot;</span><span class="p">:</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Constructor de un GenericRange a partir de un rango</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">instance</span> <span class="o">=</span> <span class="bp">cls</span><span class="p">()</span>
        <span class="n">instance</span><span class="o">.</span><span class="n">_range</span> <span class="o">=</span> <span class="n">rng</span>
        <span class="k">return</span> <span class="n">instance</span>

    <span class="k">def</span> <span class="fm">__len__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
        <span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_range</span><span class="p">)</span>

    <span class="k">def</span> <span class="fm">__getitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">idx</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">slice</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">Union</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="s2">&quot;GenericRange&quot;</span><span class="p">]:</span>
        <span class="n">i</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_range</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">getitem</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="nb">int</span><span class="p">)</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">from_range</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>

    <span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
        <span class="n">classname</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span>
        <span class="n">r</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_range</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">classname</span><span class="si">}</span><span class="s2">(</span><span class="si">{</span><span class="n">r</span><span class="o">.</span><span class="n">start</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">r</span><span class="o">.</span><span class="n">stop</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">r</span><span class="o">.</span><span class="n">step</span><span class="si">}</span><span class="s2">)&quot;</span>
</code></pre></div>

<p>Con esta clase abstracta creamos dos clases concretas, definiendo el m&#233;todo
abstracto <code>.getitem()</code> con la funci&#243;n&nbsp;gen&#233;rica:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">SquaresRange</span><span class="p">(</span><span class="n">GenericRange</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">getitem</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">i</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">i</span> <span class="o">**</span> <span class="mi">2</span>

<span class="k">class</span> <span class="nc">CubicsRange</span><span class="p">(</span><span class="n">GenericRange</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">getitem</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">i</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">i</span> <span class="o">**</span> <span class="mi">3</span>
</code></pre></div>

<p>Que podemos emplear de este&nbsp;modo:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">SquaresRange</span><span class="p">(</span><span class="o">-</span><span class="mi">10</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">):</span>
<span class="o">...</span>     <span class="nb">print</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
<span class="o">...</span>
<span class="mi">100</span>
<span class="mi">49</span>
<span class="mi">16</span>
<span class="mi">1</span>
<span class="o">&gt;&gt;&gt;</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">CubicsRange</span><span class="p">(</span><span class="o">-</span><span class="mi">10</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">):</span>
<span class="o">...</span>     <span class="nb">print</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
<span class="o">...</span>
<span class="o">-</span><span class="mi">1000</span>
<span class="o">-</span><span class="mi">343</span>
<span class="o">-</span><span class="mi">64</span>
<span class="o">-</span><span class="mi">1</span>
<span class="o">&gt;&gt;&gt;</span> <span class="nb">list</span><span class="p">(</span><span class="n">CubicsRange</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">50</span><span class="p">,</span> <span class="mi">4</span><span class="p">)[:</span><span class="mi">30</span><span class="p">:</span><span class="mi">2</span><span class="p">])</span>
<span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">343</span><span class="p">,</span> <span class="mi">3375</span><span class="p">,</span> <span class="mi">12167</span><span class="p">,</span> <span class="mi">29791</span><span class="p">,</span> <span class="mi">59319</span><span class="p">,</span> <span class="mi">103823</span><span class="p">]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">SquaresRange</span><span class="p">(</span><span class="mi">100</span><span class="p">)[::</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="n">SquaresRange</span><span class="p">(</span><span class="mi">99</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">SquaresRange</span><span class="p">(</span><span class="mi">100</span><span class="p">)</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="mi">81</span><span class="p">)</span>
<span class="mi">9</span>
</code></pre></div>

<h2>Resumen</h2>
<p>La <em>Evaluaci&#243;n Perezosa</em> realiza &#250;nicamente aquellos c&#225;lculos que son necesarios
para obtener el resultado final, evitando as&#237; malgastar tiempo y recursos en
resultados intermedios que no se van a&nbsp;usar.</p>
<p>El tipo <em>Range</em> es algo m&#225;s que una facilidad para realizar iteraciones. A
partir de un objeto <em>range</em> se pueden crear nuevos rangos sin necesidad de
generar ning&#250;n elementos de la&nbsp;secuencia.</p>
<p>Si conocemos el modo de obtener cualquier elemento de una secuencia a partir de
su posici&#243;n, entonces podemos crear secuencias para operar con ellas igual que
har&#237;amos con un <em>rango</em>, sin necesidad de generar sus&nbsp;elementos.</p>
<p>En el pr&#243;ximo art&#237;culo veremos c&#243;mo podemos ir m&#225;s lejos para crear y trabajar
con <em>secuencias infinitas</em> de&nbsp;elementos.</p>
<hr />
<h2>Serie <em>Evaluaci&#243;n Perezosa en&nbsp;Python</em></h2>
<ul>
<li><a href="https://blog.ch3m4.org/2021/02/08/evaluacion-perezosa-en-python-parte-1/" title="Introducci&#243;n a la _evaluaci&#243;n perezosa_">Parte 1 - Introducci&#243;n a la <em>evaluaci&#243;n&nbsp;perezosa</em></a></li>
<li><a href="https://blog.ch3m4.org/2021/02/09/evaluacion-perezosa-en-python-parte-2/" title="Secuencias infinitas">Parte 2 - Secuencias&nbsp;infinitas</a></li>
<li><a href="https://blog.ch3m4.org/2021/02/14/evaluacion-perezosa-en-python-parte-3/" title="Parte 3 - _Memoizaci&#243;n_">Parte 3 - <em>Memoizaci&#243;n</em></a></li>
<li><a href="https://blog.ch3m4.org/2021/02/15/evaluacion-perezosa-en-python-parte-4/" title="Parte 4 - _Evaluaci&#243;n perezosa_ avanzada">Parte 4 - <em>Evaluaci&#243;n perezosa</em>&nbsp;avanzada</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/07/evaluacion-perezosa-en-python-parte-5/" title="Parte 5 - Formalizaci&#243;n de la Secuencia Perezosa">Parte 5 - Formalizaci&#243;n de la Secuencia&nbsp;Perezosa</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/07/evaluacion-perezosa-en-python-parte-6/" title="Parte 6 - Ejemplo pr&#225;ctico: Potencias de Fermi-Dirac">Parte 6 - Ejemplo pr&#225;ctico: Potencias de&nbsp;Fermi-Dirac</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/10/evaluacion-perezosa-en-python-apendice/" title="Ap&#233;ndice: sobre el tipado de datos utilizado">Ap&#233;ndice: sobre el tipado de datos&nbsp;utilizado</a></li>
</ul>
<div class="admonition danger">
<p class="admonition-title">La serie unificada como <em>Jupyter Notebook</em>&nbsp;en:</p>
<ul>
<li><a href="https://blog.ch3m4.org/2021/notebook-serie-evaluacion-perezosa-en-python.sync.ipynb" title="Notebook - Evaluaci&#243;n perezosa en python">formato notebook&nbsp;(.ipynb)</a></li>
<li><a href="https://blog.ch3m4.org/2021/notebook-serie-evaluacion-perezosa-en-python.sync.md" title="Jupytext - Evaluaci&#243;n perezosa en python">formato jupytext&nbsp;(.md)</a></li>
</ul>
</div>
<hr />
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="HTML sobre WebSockets, una nueva esperanza">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">HTML sobre WebSockets, una nueva esperanza</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">21 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>En este episodio partimos del interesante artículo de Matt E. Patterson llamado <a href="https://alistapart.com/article/the-future-of-web-software-is-html-over-websockets/" data-type="URL" data-id="https://alistapart.com/article/the-future-of-web-software-is-html-over-websockets/">«The Future of Web Software Is HTML-over-WebSockets»</a> En el artículo se explica con detalle la evolución de la arquitectura de las aplicaciones web y la aparición de un nuevo enfoque basado en usar WebSockets. Según el autor <em>«este nuevo enfoque basado en WebSockets está llamando la atención de los desarrolladores web. Es un enfoque que reafirma las promesas de los frameworks clásicos de server-rendering (creación rápida de prototipos, gestión del estado del lado servidor, sólido rendimiento de renderizado) y que  permite la colaboración multiusuario y los diseños reactivos, sin tener que construir dos aplicaciones separadas». </em></p>



<p>Este nuevo enfoque de HTML sobre WebSockets es complicado de asimilar cuando venimos de un arquitectura que separa claramente el lado cliente y servidor. Una gran preocupación de muchos desarrolladores es evitar soluciones complejas de lado cliente, evitando esos cientos de KB que se acumulan en el navegador.  La solución es sustituir JSON por HTML, en un ciclo donde el encargado de renderizar sea siempre el servidor y envíe de forma inmediata por WebSockets el nuevo HTML a mostrar.</p>







<p>Este episodio surge principalmente <a href="https://programadorwebvalencia.com/html-sobre-websockets/" data-type="URL" data-id="https://programadorwebvalencia.com/html-sobre-websockets/">de un artículo de Andros Fenollosa</a> acompañado de vídeo, donde explica este concepto de WebSockets. Aquí hablamos sobre la información compartida con Andros sobre HTML sobre WebSockets y al mismo tiempo exploramos ventajas, inconvenientes, conceptos de seguridad y frameworks. También vemos <a href="http://[https://github.com/tanrax/demo-HTML-over-WebSockets-in-Django](https://github.com/tanrax/demo-HTML-over-WebSockets-in-Django)" data-type="URL" data-id="[https://github.com/tanrax/demo-HTML-over-WebSockets-in-Django](https://github.com/tanrax/demo-HTML-over-WebSockets-in-Django)">la demo creada por Andros en Django </a>para ver el ejemplo de funcionamiento en un blog de 100 entradas.</p>



<p></p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Free Software Awards winners announced: CiviCRM, Bradley Kuhn, and Alyssa Rosenzweig</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FSF News</a> <span class="article__date">20 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        BOSTON, Massachusetts, USA -- Saturday, March 20, 2021 -- The Free
Software Foundation (FSF) today announced the recipients of the 2020
Free Software Awards, which are given annually at the FSF's
LibrePlanet conference to groups and individuals in the free software
community who have made significant contributions to the cause for
software freedom. This year's recipients of the awards are CiviCRM,
Alyssa Rosenzweig, and Bradley Kuhn. As the ceremony was conducted
virtually this year, each winner selected the person they wished to
present them the award.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cómo usar Pam_Tally2 para gestionar los intentos fallidos de acceso en SSH</h1>
                            <h2 class="article__feed"><a target="_blank" href="">ochobitshacenunbyte</a> <span class="article__date">18 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Recientemente he tenido que gestionar en un cliente el bloqueo de ciertos usuarios, cuando querían acceder a diferentes servidores de un entorno vía SSH. Esto era debido a que, seguramente, habían puesto de forma&#46;&#46;&#46;</p>
<p>La entrada <a rel="nofollow" href="https://www.ochobitshacenunbyte.com/2021/03/18/como-usar-pam_tally2-para-gestionar-los-intentos-fallidos-de-acceso-en-ssh/">Cómo usar Pam_Tally2 para gestionar los intentos fallidos de acceso en SSH</a> se publicó primero en <a rel="nofollow" href="https://www.ochobitshacenunbyte.com">ochobitshacenunbyte</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Season of Docs announces the successful 2020 long-running projects </h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">18 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Keyword argument functions now also accept maps</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">18 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div class="paragraph">
<p>To date, Clojure’s support for keyword arguments forces programmers to choose between creating APIs that better support people (accepting keyword args) or APIs that better support programs (by taking a map of those args).</p>
</div>
<div class="paragraph">
<p>Introduced in Clojure 1.11, a function specified to take keyword arguments may be passed a single map instead of or in addition to (and following) the key/value pairs. When a lone map is passed, it is used outright for destructuring, else a trailing map is added to the map built from the preceding key/values via <code>conj</code>. For example, a function that takes a sequence of optional keyword arguments and returns a vector containing the values is defined as:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">(defn destr [&amp; {:keys [a b] :as opts}]
  [a b opts])

(destr :a 1)
-&gt;[1 nil {:a 1}]

(destr {:a 1 :b 2})
-&gt;[1 2 {:a 1 :b 2}]</code></pre>
</div>
</div>
<div class="paragraph">
<p>In Clojure 1.11 the call to <code>destr</code> accepts a mixture of key/value pairs and/or a lone (or trailing) map benefitting both programmer and program.</p>
</div>
<div class="paragraph">
<p>This enhancement is available now in <code>org.clojure/clojure "1.11.0-alpha1"</code>.</p>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Ready for QA</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">18 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://diarioestoico.com/wp-content/uploads/2020/03/cropped-logo-estoico-footer-150x150-1-32x32.png" alt="LIDERAZGO Y LA MAYÉUTICA DE SÓCRATES">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">LIDERAZGO Y LA MAYÉUTICA DE SÓCRATES</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Diario Estoico</a> <span class="article__date">17 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ¿Te consideras un buen líder? ¿Te parece que una definición de líder podría ser: acompañar al otro para que saque lo mejor de sí mismo? ¿Crees que tú lo haces en tu día a día? Estas tres preguntas permiten dos tipos de respuesta: una negativa y otra positiva. Si tu respuesta en la primera pregunta [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://thehistoryoftheweb.com/wp-content/uploads/2017/09/cropped-thotw-logo-square-1-32x32.jpg" alt="Content Management Made Simple">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Content Management Made Simple</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The History of the Web</a> <span class="article__date">16 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Content Management Systems — software that helps people author and publish websites — likely dates back farther than you think. The problem is, it wasn't quite called that yet.</p>
<p>The post <a rel="nofollow" href="https://thehistoryoftheweb.com/history-of-content-management-systems/">Content Management Made Simple</a> appeared first on <a rel="nofollow" href="https://thehistoryoftheweb.com">The History of the Web</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Errores convertidos en calidad de producto con Firebase Crashlytics</h1>
                            <h2 class="article__feed"><a target="_blank" href="">En Mi Local Funciona</a> <span class="article__date">16 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Desde hace unos años Crashlytics es imprescindible en cualquier desarrollo móvil profesional. En este post te hablamos sobre esta herramienta gratuita.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2021/209-trolley-conundrum.png" alt="Trolley Conundrum">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Trolley Conundrum</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">16 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2021/209-trolley-conundrum.png" alt="Trolley Conundrum" title="Or the illusion of choice" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hyperreals *R: Formalizaci&amp;#243;n de la Secuencia Perezosa - Evaluaci&amp;#243;n perezosa en python - Parte&amp;#160;5</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">15 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <h2>Refactorizaci&#243;n</h2>
<p>Hasta ahora hemos visto c&#243;mo crear una <em>secuencia perezosa</em> que va guardando en
una cach&#233; los resultados de una operaci&#243;n (proceso de <em>memoizaci&#243;n</em>). As&#237; mismo,
cuando la secuencia es una <em>secuencia ordenada</em> podemos optimizar algunas
b&#250;squedas, tal como vimos con la secuencia de n&#250;meros&nbsp;primos.</p>
<p>Vamos a intentar darle una forma a todo esto creando las clases <code>LazySequence</code> y
<code>LazySortedSequence</code>.</p>
<p>El c&#243;digo refactorizado final se puede descargar a&nbsp;continuaci&#243;n:</p>
<ul>
<li><a href="https://blog.ch3m4.org/2021/03/07/evaluacion-perezosa-en-python-parte-5/genericrange.py" title="GenericRange class">genericrange.py</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/07/evaluacion-perezosa-en-python-parte-5/lazyseq.py" title="LazySequence class">lazyseq.py</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/07/evaluacion-perezosa-en-python-parte-5/primes.py" title="Primes class">primes.py</a></li>
</ul>
<h3>LazySequence</h3>
<p>La clase <code>LazySequence</code> crea una <em>secuencia perezosa</em> a partir de un iterador.
A medida que obtenga elementos del iterador, los va almacenando en una&nbsp;cach&#233;:</p>
<div class="highlight"><pre><span></span><code><span class="n">T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;T&quot;</span><span class="p">,</span> <span class="n">covariant</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">LazySequence</span><span class="p">(</span><span class="n">Iterator</span><span class="p">[</span><span class="n">T</span><span class="p">]):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">iterator</span><span class="p">:</span> <span class="n">Iterator</span><span class="p">[</span><span class="n">T</span><span class="p">]):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_cache</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">T</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">iterator</span> <span class="o">=</span> <span class="n">iterator</span>

    <span class="k">def</span> <span class="fm">__next__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">T</span><span class="p">:</span>
        <span class="n">x</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">iterator</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_cache</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">x</span>
</code></pre></div>

<p>Cada vez que se calcule un nuevo elemento a trav&#233;s de <code>next()</code>, &#233;ste se a&#241;adir&#225;
a la&nbsp;cach&#233;.</p>
<p>Para que funcione como secuencia, se implementan los m&#233;todos <code>__getitem__</code>:</p>
<div class="highlight"><pre><span></span><code>    <span class="nd">@singledispatchmethod</span>
    <span class="k">def</span> <span class="fm">__getitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">idx</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">NotImplemented</span>

    <span class="nd">@__getitem__</span><span class="o">.</span><span class="n">register</span>
    <span class="k">def</span> <span class="nf">__getitem_int__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">idx</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">T</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">idx</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">OverflowError</span>
        <span class="k">elif</span> <span class="n">idx</span> <span class="o">&gt;=</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_cache</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">islice</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">iterator</span><span class="p">,</span> <span class="n">idx</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="o">+</span> <span class="mi">1</span><span class="p">))</span>

        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_cache</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span>

    <span class="nd">@__getitem__</span><span class="o">.</span><span class="n">register</span>
    <span class="k">def</span> <span class="nf">__getitem_slice__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sl</span><span class="p">:</span> <span class="nb">slice</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="n">T</span><span class="p">]:</span>
        <span class="n">rng</span> <span class="o">=</span> <span class="nb">range</span><span class="p">(</span><span class="n">INFINITE</span><span class="p">)[</span><span class="n">sl</span><span class="p">]</span>
        <span class="k">return</span> <span class="p">[</span><span class="bp">self</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">rng</span><span class="p">]</span>
</code></pre></div>

<p>Y a&#241;adimos el m&#233;todo <code>__iter__</code> para cumplir con el protocolo <em>iterator</em>:</p>
<div class="highlight"><pre><span></span><code>    <span class="k">def</span> <span class="fm">__iter__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Iterator</span><span class="p">[</span><span class="n">T</span><span class="p">]:</span>
        <span class="k">yield from</span> <span class="bp">self</span><span class="o">.</span><span class="n">_cache</span>
        <span class="k">yield from</span> <span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_cache</span><span class="p">),</span> <span class="n">INFINITE</span><span class="p">))</span>
</code></pre></div>

<h3>LazySortedSequence</h3>
<p>Derivando de <code>LazySequence</code>, se crea la clase <code>LazySortedSequence</code> para cuando
el iterador produzca una secuencia ordenada. Tal como hemos visto, cuando la
secuencia est&#225; ordenada podemos realizar b&#250;squedas por <em>bisecciones</em> que
resultan bastante&nbsp;eficiente.</p>
<p>La operaci&#243;n principal ser&#225; el m&#233;todo <code>insertpos()</code> que nos indica la posici&#243;n
en la que se insertar&#237;a un elemento en la secuencia, manteniendo el orden de los
elementos. Si no son suficientes con los elementos de la cach&#233;, se extraer&#225;n m&#225;s
del iterador mediante <code>next()</code>, que ir&#225;n a&#241;adi&#233;ndose progresivamente a la&nbsp;cach&#233;:</p>
<div class="highlight"><pre><span></span><code><span class="n">Ord</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;Ord&quot;</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span> <span class="n">covariant</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">LazySortedSequence</span><span class="p">(</span><span class="n">LazySequence</span><span class="p">[</span><span class="n">Ord</span><span class="p">]):</span>
    <span class="k">def</span> <span class="nf">insertpos</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">x</span> <span class="o">&lt;=</span> <span class="bp">self</span><span class="o">.</span><span class="n">last</span><span class="p">:</span>
            <span class="n">idx</span> <span class="o">=</span> <span class="n">bisect_left</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_cache</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">while</span> <span class="n">x</span> <span class="o">&gt;</span> <span class="nb">next</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
                <span class="k">pass</span>
            <span class="n">idx</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="o">-</span> <span class="mi">1</span>

        <span class="k">return</span> <span class="n">idx</span>
</code></pre></div>

<p>Con el m&#233;todo <code>insertpos()</code> ya podemos definir los m&#233;todos <code>__contains__()</code> e
<code>index()</code> t&#237;picos de la&nbsp;secuencias:</p>
<div class="highlight"><pre><span></span><code>    <span class="k">def</span> <span class="fm">__contains__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
        <span class="n">idx</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">insertpos</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">x</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">_cache</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span>

    <span class="k">def</span> <span class="nf">index</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
        <span class="n">idx</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">insertpos</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">x</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">_cache</span><span class="p">[</span><span class="n">idx</span><span class="p">]:</span>
            <span class="k">return</span> <span class="n">idx</span>
        <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">x</span><span class="si">}</span><span class="s2"> is not in </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</code></pre></div>

<p>No existe un protocolo para elementos <em>ordenables</em> (<code>Sortable</code>, <code>Ordered</code>). Para
ordenar elementos se usan los m&#233;todos de comparaci&#243;n <code>__eq__</code>, <code>__ne__</code>,
<code>__lt__</code>, <code>__le__</code>, <code>__gt__</code> y <code>__ge__</code>. Pero se suele considerar estos m&#233;todos
redundantes ya que basta con definir s&#243;lo dos (eg: <code>__eq__</code> y <code>__lt__</code>) para
establecer una&nbsp;ordenaci&#243;n.</p>
<p>Como no hay una forma mejor, hemos creado el tipo gen&#233;rico <code>Ord</code> enlazado con
<code>int</code> para que al menos el chequeador de tipos no se queje en la comparaci&#243;nes,
aunque no tiene porqu&#233; limitarse su aplicaci&#243;n a n&#250;meros&nbsp;enteros.</p>
<h3>N&#250;meros&nbsp;primos</h3>
<p>Como caso pr&#225;ctico, veamos c&#243;mo se puede redefinir la clase <code>Primes</code>:</p>
<div class="highlight"><pre><span></span><code><span class="nd">@final</span>
<span class="k">class</span> <span class="nc">Primes</span><span class="p">(</span><span class="n">LazySortedSequence</span><span class="p">[</span><span class="n">Prime</span><span class="p">]):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">__genprimes</span><span class="p">())</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_cache</span><span class="o">.</span><span class="n">extend</span><span class="p">([</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">])</span>

    <span class="k">def</span> <span class="nf">__genprimes</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Iterator</span><span class="p">[</span><span class="n">Prime</span><span class="p">]:</span>
        <span class="n">_primes</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_cache</span>
        <span class="n">start</span> <span class="o">=</span> <span class="mi">5</span>
        <span class="n">top</span> <span class="o">=</span> <span class="mi">1</span>
        <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
            <span class="n">stop</span> <span class="o">=</span> <span class="n">_primes</span><span class="p">[</span><span class="n">top</span><span class="p">]</span> <span class="o">**</span> <span class="mi">2</span>
            <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">start</span><span class="p">,</span> <span class="n">stop</span><span class="p">,</span> <span class="mi">2</span><span class="p">):</span>
                <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">islice</span><span class="p">(</span><span class="n">_primes</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">top</span><span class="p">):</span>
                    <span class="k">if</span> <span class="n">n</span> <span class="o">%</span> <span class="n">p</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                        <span class="k">break</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="k">yield</span> <span class="n">n</span>

            <span class="n">start</span> <span class="o">=</span> <span class="n">stop</span> <span class="o">+</span> <span class="mi">2</span>
            <span class="n">top</span> <span class="o">+=</span> <span class="mi">1</span>
</code></pre></div>

<p>Si dejamos as&#237; la codificaci&#243;n, la clase <code>Primes</code> usar&#225; el m&#233;todo <code>__contains__</code>
de <code>LazySortedSequence</code>. Este m&#233;todo a&#241;adir&#225; primos a la cach&#233; hasta alcanzar el
argumento&nbsp;solicitado.</p>
<p>Si recordamos de la implementaci&#243;n anterior que ten&#237;amos de la clase <code>Primes</code>,
el m&#233;todo <code>__contains__()</code> estaba optimizado para comprobar la pertencia de un
n&#250;mero, sin a&#241;adir m&#225;s elementos a la cach&#233;. Vamos a recuperar esta&nbsp;codificaci&#243;n:</p>
<div class="highlight"><pre><span></span><code>    <span class="k">def</span> <span class="fm">__contains__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">n</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>

        <span class="k">if</span> <span class="n">n</span> <span class="o">&lt;=</span> <span class="bp">self</span><span class="o">.</span><span class="n">last</span><span class="p">:</span>
            <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__contains__</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>

        <span class="n">root</span> <span class="o">=</span> <span class="n">isqrt</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
        <span class="n">_primes</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_cache</span>

        <span class="n">top</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="k">if</span> <span class="n">root</span> <span class="o">&gt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">last</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">insertpos</span><span class="p">(</span><span class="n">root</span><span class="p">)</span>

        <span class="k">if</span> <span class="nb">any</span><span class="p">(</span><span class="n">n</span> <span class="o">%</span> <span class="n">prime</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">for</span> <span class="n">prime</span> <span class="ow">in</span> <span class="n">islice</span><span class="p">(</span><span class="n">_primes</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">top</span><span class="p">)):</span>
            <span class="k">return</span> <span class="kc">False</span>

        <span class="c1"># &quot;one-shot&quot; check</span>
        <span class="k">if</span> <span class="nb">any</span><span class="p">(</span><span class="n">n</span> <span class="o">%</span> <span class="n">i</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">last</span> <span class="o">+</span> <span class="mi">2</span><span class="p">,</span> <span class="n">root</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)):</span>
            <span class="k">return</span> <span class="kc">False</span>

        <span class="k">return</span> <span class="kc">True</span>
</code></pre></div>

<hr />
<h2>Serie <em>Evaluaci&#243;n Perezosa en&nbsp;Python</em></h2>
<ul>
<li><a href="https://blog.ch3m4.org/2021/02/08/evaluacion-perezosa-en-python-parte-1/" title="Introducci&#243;n a la _evaluaci&#243;n perezosa_">Parte 1 - Introducci&#243;n a la <em>evaluaci&#243;n&nbsp;perezosa</em></a></li>
<li><a href="https://blog.ch3m4.org/2021/02/09/evaluacion-perezosa-en-python-parte-2/" title="Secuencias infinitas">Parte 2 - Secuencias&nbsp;infinitas</a></li>
<li><a href="https://blog.ch3m4.org/2021/02/14/evaluacion-perezosa-en-python-parte-3/" title="Parte 3 - _Memoizaci&#243;n_">Parte 3 - <em>Memoizaci&#243;n</em></a></li>
<li><a href="https://blog.ch3m4.org/2021/02/15/evaluacion-perezosa-en-python-parte-4/" title="Parte 4 - _Evaluaci&#243;n perezosa_ avanzada">Parte 4 - <em>Evaluaci&#243;n perezosa</em>&nbsp;avanzada</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/07/evaluacion-perezosa-en-python-parte-5/" title="Parte 5 - Formalizaci&#243;n de la Secuencia Perezosa">Parte 5 - Formalizaci&#243;n de la Secuencia&nbsp;Perezosa</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/07/evaluacion-perezosa-en-python-parte-6/" title="Parte 6 - Ejemplo pr&#225;ctico: Potencias de Fermi-Dirac">Parte 6 - Ejemplo pr&#225;ctico: Potencias de&nbsp;Fermi-Dirac</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/10/evaluacion-perezosa-en-python-apendice/" title="Ap&#233;ndice: sobre el tipado de datos utilizado">Ap&#233;ndice: sobre el tipado de datos&nbsp;utilizado</a></li>
</ul>
<div class="admonition danger">
<p class="admonition-title">La serie unificada como <em>Jupyter Notebook</em>&nbsp;en:</p>
<ul>
<li><a href="https://blog.ch3m4.org/2021/notebook-serie-evaluacion-perezosa-en-python.sync.ipynb" title="Notebook - Evaluaci&#243;n perezosa en python">formato notebook&nbsp;(.ipynb)</a></li>
<li><a href="https://blog.ch3m4.org/2021/notebook-serie-evaluacion-perezosa-en-python.sync.md" title="Jupytext - Evaluaci&#243;n perezosa en python">formato jupytext&nbsp;(.md)</a></li>
</ul>
</div>
<hr />
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hyperreals *R: Evaluaci&amp;#243;n perezosa en python -&amp;#160;Ap&amp;#233;ndice</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">15 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <h2>Ap&#233;ndice: sobre el tipado de datos&nbsp;utilizado</h2>
<p>Durante esta serie de art&#237;culos he procurado usar el <em>tipado gradual</em> de python,
no s&#243;lo para mejorar la compresi&#243;n, sino porque lo considero buena pr&#225;ctica para
detectar algunos problemas en el momento de escribir el c&#243;digo. El int&#233;rprete de
python realmente no realiza ning&#250;n chequeo de estas <em>anotaciones</em> de tipos,
dejando por completo su comprobaci&#243;n a alguna otra herramienta que pueda estar
usando el&nbsp;desarrollador.</p>
<p>He utilizado las clases abstractas del m&#243;dulo <code>collections.abc</code> como base para
definir los <em>iterables</em>, <em>secuencias</em> e <em>iteradores</em>. He cre&#237;do que as&#237; quedaba
mejor documentado, adem&#225;s de ser el modo m&#225;s conocido por programadores de otros
lenguajes. Por derivar de la clase abstracta <code>Sequence</code>, sabemos que
<code>GenericRange</code> implementa varios m&#233;todos abstractos como son <code>__len__</code> y
<code>__getitem__</code>.</p>
<p>Sin embargo, en python se considera sup&#233;rfluo y poco recomendable este uso de
clases abstractas. El modo <em>pyth&#243;nico</em> consiste en implementar esos m&#233;todos sin
m&#225;s indicaci&#243;n. S&#243;lo por el hecho de contar con estos m&#233;todos, nuestra clase ya
ser&#225; considerada como <em>secuencia</em>, se podr&#225; usar donde haga falta una
<em>secuencia</em> y, en definitiva, se comportar&#225; como si fuera una secuencia. Son los
llamados <em>duck types</em> o <em>tipos estructurales</em> que tanto caracterizan a python y
que, a partir de ahora, nos vamos a tener que acostumbrar a denominar
<strong><em>Protocolos</em></strong>.</p>
<p>Por ejemplo, pod&#237;amos haber declarado la clase <code>GenericRange</code> sin indicar
ninguna&nbsp;superclase:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">GenericRange</span><span class="p">:</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">start</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">stop</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">step</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
        <span class="o">...</span>

    <span class="k">def</span> <span class="fm">__len__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
        <span class="o">...</span>

    <span class="k">def</span> <span class="fm">__getitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">idx</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">slice</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">Union</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="s2">&quot;GenericRange&quot;</span><span class="p">]:</span>
        <span class="o">...</span>
</code></pre></div>

<p>Al tener el m&#233;todo <code>__len__()</code> se dice que cumple con el <em>protocolo <code>Sized</code></em>,
algo que se puede comprobar del mismo modo que si fuera una&nbsp;subclase:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Sized</span>
<span class="o">&gt;&gt;&gt;</span> <span class="nb">issubclass</span><span class="p">(</span><span class="n">GenericRange</span><span class="p">,</span> <span class="n">Sized</span><span class="p">)</span>
<span class="kc">True</span>
</code></pre></div>

<p>En cambio, nos puede sorprender que no cumpla con el <em>protocolo <code>Sequence</code></em>, a
pesar de que se comportaba como&nbsp;tal:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Sequence</span>
<span class="o">&gt;&gt;&gt;</span> <span class="nb">issubclass</span><span class="p">(</span><span class="n">GenericRange</span><span class="p">,</span> <span class="n">Sequence</span><span class="p">)</span>
<span class="kc">False</span>
</code></pre></div>

<p>Resulta que para cumplir con el protocolo <code>Sequence</code>, adem&#225;s de <code>__getitem__()</code>,
debe tener implementados los m&#233;todos  <code>__iter__()</code>, <code>__reversed__()</code> e
<code>index()</code>.</p>
<p>Cuando <code>GenericRange</code> derivaba de <code>Sequence</code>, estos m&#233;todos se heredaban de la
superclase como <em>m&#233;todos mixin</em>, para cuya implementaci&#243;n b&#225;sica utiliza
&#250;nicamente el m&#233;todo <code>__getitem__()</code>. Tambi&#233;n implementa otros m&#233;todos como
<code>__contains__()</code> (<em>Container</em>) y <code>count()</code> (<em>Countable</em>). &#201;se era el motivo por
el que s&#243;lo hac&#237;a falta definir <code>__getitem__()</code> para que funcionara como&nbsp;secuencia.</p>
<p>Como <em>protocolo</em>, estos m&#233;todos no se adquieren por herencia y necesitan una implementaci&#243;n para cumplir con el protocolo <code>Sequence</code>. No obstante, algunas funciones, como <code>reversed</code>, admiten objetos con implementaciones parciales del protocolo <code>Sequence</code>, algo que &#250;nicamente sabremos si recurrimos a la documentaci&#243;n de la&nbsp;funci&#243;n.</p>
<h2>Secuencia de&nbsp;enteros</h2>
<p>He empleado el tipo <code>Sequence</code> sin indicar de qu&#233; tipo son los elementos. Un
chequeador de tipos asume que se trata de un iterable de elementos de tipo
<code>Any</code>, por lo que no deber&#237;a dar problemas. Pero siempre podemos ser m&#225;s
precisos y usar <code>Sequence[int]</code> como tipo de datos para nuestras secuencias de
n&#250;meros&nbsp;enteros.</p>
<h2>Referencia <em>forward</em></h2>
<p>En la anotaciones de tipos, a veces necesitamos referenciar una clase antes de
que est&#233; definida, las conocidas como <em>referencias forward</em> de tipos. El modo
normal de hacer este tipo de referencias es escribir el nombre de la clase entre
comillas, como una <em>string</em>.</p>
<p>A partir de python 3.10 no har&#225; falta acudir a este remedio pudiendo usar
referencias <em>forward</em> sin mayor problema. Para las versiones anteriores, se
puede obtener esta funcionalidad del m&#243;dulo <code>__future__</code>:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">annotations</span>
</code></pre></div>

<h2>Uni&#243;n de&nbsp;tipos</h2>
<p>En el m&#233;todo <code>__getitem__()</code> de <code>GenericRange</code> he utilizado dos uniones de&nbsp;tipos:</p>
<div class="highlight"><pre><span></span><code>    <span class="k">def</span> <span class="fm">__getitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">idx</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">slice</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">Union</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="s2">&quot;GenericRange&quot;</span><span class="p">]:</span>
        <span class="n">i</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_range</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">getitem</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="nb">int</span><span class="p">)</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">from_range</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
</code></pre></div>

<p>La uni&#243;n <code>idx: Union[int, slice]</code> se puede interpretar como que <code>idx</code> puede ser
de tipo <code>int</code> o de tipo <code>slice</code>. La notaci&#243;n com&#250;n de expresar esta uni&#243;n de
tipos en varios lenguajes ser&#237;a <code>idx: int | slice</code>, nomenclatura que tambi&#233;n
ser&#225; aceptada en python&nbsp;3.10.</p>
<p>La otra uni&#243;n, <code>Union[int, "GenericRange"]</code> indica que el resultado ser&#225; de tipo
<code>int</code> o de tipo <code>GenericRange</code>.</p>
<p>De todos modos, en estas anotaciones no se est&#225; reflejando la dependencia que
hay entre tipos. Si <code>idx</code> es entero, el resultado siempre ser&#225; un entero. Si
<code>idx</code> es <code>slice</code>, el resultado siempre ser&#225; <code>GenericRange</code>. En lenguajes con
tipado est&#225;tico, es normal disponer de varias definiciones del mismo m&#233;todos,
con diferentes signaturas, que se seleccionan seg&#250;n sean los tipos de los
argumentos y resultados que&nbsp;tengamos.</p>
<p>Python tiene una facilidad para hacer algo similar. Con
<code>functools.singledispathmethod</code> podemos definir varios m&#233;todos que se invocar&#225;n
seg&#250;n el tipo de dato del primer argumento. De este modo, el m&#233;todo
<code>__getitem__()</code> lo podr&#237;amos expresar&nbsp;as&#237;:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">functools</span> <span class="kn">import</span> <span class="n">singledispatchmethod</span>

<span class="k">class</span> <span class="nc">GenericRange</span><span class="p">(</span><span class="n">Sequence</span><span class="p">):</span>
    <span class="o">...</span>

    <span class="nd">@singledispatchmethod</span>
    <span class="k">def</span> <span class="fm">__getitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">idx</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">NotImplemented</span>

    <span class="nd">@__getitem__</span><span class="o">.</span><span class="n">register</span>
    <span class="k">def</span> <span class="nf">_</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">idx</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
        <span class="n">i</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_range</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">getitem</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>

    <span class="nd">@__getitem__</span><span class="o">.</span><span class="n">register</span>
    <span class="k">def</span> <span class="nf">_</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">idx</span><span class="p">:</span> <span class="nb">slice</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="s2">&quot;GenericRange&quot;</span><span class="p">:</span>
        <span class="n">i</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_range</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">from_range</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
</code></pre></div>

<p>Lamentablemente nos saldr&#225; un error ya que no existe a&#250;n la clase <code>GenericRange</code>
cuando es aplicado el decorador <code>singledispatchmethod</code>. Una soluci&#243;n es sacar el
&#250;ltimo registro fuera, una vez que ya se ha definido la&nbsp;clase:</p>
<div class="highlight"><pre><span></span><code><span class="nd">@GenericRange</span><span class="o">.</span><span class="fm">__getitem__</span><span class="o">.</span><span class="n">register</span>
<span class="k">def</span> <span class="nf">_</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">idx</span><span class="p">:</span> <span class="nb">slice</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">GenericRange</span><span class="p">:</span>
    <span class="n">i</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_range</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span>
    <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">from_range</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
</code></pre></div>

<h2>C&#243;digo&nbsp;final</h2>
<p>Con estos cambios, tendr&#237;amos nuestro c&#243;digo corregido de esta&nbsp;manera:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">abc</span> <span class="kn">import</span> <span class="n">abstractmethod</span>
<span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Sequence</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Type</span><span class="p">,</span> <span class="n">Union</span>
<span class="kn">from</span> <span class="nn">functools</span> <span class="kn">import</span> <span class="n">singledispatchmethod</span>
<span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">annotations</span>

<span class="k">class</span> <span class="nc">GenericRange</span><span class="p">(</span><span class="n">Sequence</span><span class="p">[</span><span class="nb">int</span><span class="p">]):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">start</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">stop</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">step</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">stop</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
            <span class="n">start</span><span class="p">,</span> <span class="n">stop</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">start</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_range</span> <span class="o">=</span> <span class="nb">range</span><span class="p">(</span><span class="n">start</span><span class="p">,</span> <span class="n">stop</span><span class="p">,</span> <span class="n">step</span><span class="p">)</span>

    <span class="nd">@abstractmethod</span>
    <span class="k">def</span> <span class="nf">getitem</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">pos</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        M&#233;todo abstracto.</span>
<span class="sd">          Funci&#243;n para calcular un elemento a partir de la posici&#243;n</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">pos</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">from_range</span><span class="p">(</span><span class="bp">cls</span><span class="p">:</span> <span class="n">Type</span><span class="p">[</span><span class="n">GenericRange</span><span class="p">],</span> <span class="n">rng</span><span class="p">:</span> <span class="nb">range</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">GenericRange</span><span class="p">:</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Constructor de un GenericRange a partir de un rango</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">instance</span> <span class="o">=</span> <span class="bp">cls</span><span class="p">()</span>
        <span class="n">instance</span><span class="o">.</span><span class="n">_range</span> <span class="o">=</span> <span class="n">rng</span>
        <span class="k">return</span> <span class="n">instance</span>

    <span class="k">def</span> <span class="fm">__len__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
        <span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_range</span><span class="p">)</span>

    <span class="nd">@singledispatchmethod</span>
    <span class="k">def</span> <span class="fm">__getitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">idx</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">NotImplemented</span>

    <span class="nd">@__getitem__</span><span class="o">.</span><span class="n">register</span>
    <span class="k">def</span> <span class="nf">_</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">idx</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
        <span class="n">i</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_range</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">getitem</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>

    <span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
        <span class="n">classname</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span>
        <span class="n">r</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_range</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">classname</span><span class="si">}</span><span class="s2">(</span><span class="si">{</span><span class="n">r</span><span class="o">.</span><span class="n">start</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">r</span><span class="o">.</span><span class="n">stop</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">r</span><span class="o">.</span><span class="n">step</span><span class="si">}</span><span class="s2">)&quot;</span>


<span class="nd">@GenericRange</span><span class="o">.</span><span class="fm">__getitem__</span><span class="o">.</span><span class="n">register</span>
<span class="k">def</span> <span class="nf">_</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">idx</span><span class="p">:</span> <span class="nb">slice</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">GenericRange</span><span class="p">:</span>
    <span class="n">i</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_range</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span>
    <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">from_range</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
</code></pre></div>

<h2>Conclusi&#243;n</h2>
<p>Python est&#225; realizando un gran esfuerzo en incorporar <em>anotaciones de tipo</em> sin
perder con ello sus caracter&#237;sticos tipos <em>ducking</em>. De igual modo, vamos a ver
c&#243;mo se incorporan m&#225;s elementos de otros lenguajes como las <em>dataclasses</em>,
<em>programaci&#243;n as&#237;ncrona</em> o los <em>patrones estructurales</em>, aunque tardar&#225;n en ser
adoptados por la mayor parte de programadores&nbsp;python.</p>
<p>Si algo tiene python es no tener demasiada prisa en que se apliquen sus cambios.
Como dec&#237;a un gran sabio: <em>&#8220;Vamos a cambiarlo todo para que todo siga igual&#8221;</em>.</p>
<hr />
<h2>Serie <em>Evaluaci&#243;n Perezosa en&nbsp;Python</em></h2>
<ul>
<li><a href="https://blog.ch3m4.org/2021/02/08/evaluacion-perezosa-en-python-parte-1/" title="Introducci&#243;n a la _evaluaci&#243;n perezosa_">Parte 1 - Introducci&#243;n a la <em>evaluaci&#243;n&nbsp;perezosa</em></a></li>
<li><a href="https://blog.ch3m4.org/2021/02/09/evaluacion-perezosa-en-python-parte-2/" title="Secuencias infinitas">Parte 2 - Secuencias&nbsp;infinitas</a></li>
<li><a href="https://blog.ch3m4.org/2021/02/14/evaluacion-perezosa-en-python-parte-3/" title="Parte 3 - _Memoizaci&#243;n_">Parte 3 - <em>Memoizaci&#243;n</em></a></li>
<li><a href="https://blog.ch3m4.org/2021/02/15/evaluacion-perezosa-en-python-parte-4/" title="Parte 4 - _Evaluaci&#243;n perezosa_ avanzada">Parte 4 - <em>Evaluaci&#243;n perezosa</em>&nbsp;avanzada</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/07/evaluacion-perezosa-en-python-parte-5/" title="Parte 5 - Formalizaci&#243;n de la Secuencia Perezosa">Parte 5 - Formalizaci&#243;n de la Secuencia&nbsp;Perezosa</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/07/evaluacion-perezosa-en-python-parte-6/" title="Parte 6 - Ejemplo pr&#225;ctico: Potencias de Fermi-Dirac">Parte 6 - Ejemplo pr&#225;ctico: Potencias de&nbsp;Fermi-Dirac</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/10/evaluacion-perezosa-en-python-apendice/" title="Ap&#233;ndice: sobre el tipado de datos utilizado">Ap&#233;ndice: sobre el tipado de datos&nbsp;utilizado</a></li>
</ul>
<div class="admonition danger">
<p class="admonition-title">La serie unificada como <em>Jupyter Notebook</em>&nbsp;en:</p>
<ul>
<li><a href="https://blog.ch3m4.org/2021/notebook-serie-evaluacion-perezosa-en-python.sync.ipynb" title="Notebook - Evaluaci&#243;n perezosa en python">formato notebook&nbsp;(.ipynb)</a></li>
<li><a href="https://blog.ch3m4.org/2021/notebook-serie-evaluacion-perezosa-en-python.sync.md" title="Jupytext - Evaluaci&#243;n perezosa en python">formato jupytext&nbsp;(.md)</a></li>
</ul>
</div>
<hr />
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hyperreals *R: Evaluaci&amp;#243;n perezosa avanzada - Evaluaci&amp;#243;n perezosa en python - Parte&amp;#160;4</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">15 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <h2><em>Evaluaci&#243;n perezosa</em>&nbsp;avanzada</h2>
<p>Haskell tiene una librer&#237;a, <code>Data.Numbers.Primes</code>, que ofrece tanto una
secuencia con todos los n&#250;meros primos, <code>primes</code>, como la funci&#243;n <code>isprime</code> con
la que chequear si un n&#250;mero es primo. Gracias a la <em>evaluaci&#243;n perezosa</em>,
haskell s&#243;lo calcula los elementos de <code>primes</code> que&nbsp;necesite.</p>
<p>Vamos a intentar hacer en python lo que hace sencillo&nbsp;haskell:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;</span> <span class="n">take</span> <span class="mi">100</span> <span class="n">primes</span>
<span class="p">[</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">7</span><span class="p">,</span><span class="mi">11</span><span class="p">,</span><span class="mi">13</span><span class="p">,</span><span class="mi">17</span><span class="p">,</span><span class="mi">19</span><span class="p">,</span><span class="mi">23</span><span class="p">,</span><span class="mi">29</span><span class="p">,</span><span class="mi">31</span><span class="p">,</span><span class="mi">37</span><span class="p">,</span><span class="mi">41</span><span class="p">,</span><span class="mi">43</span><span class="p">,</span><span class="mi">47</span><span class="p">,</span><span class="mi">53</span><span class="p">,</span><span class="mi">59</span><span class="p">,</span><span class="mi">61</span><span class="p">,</span><span class="mi">67</span><span class="p">,</span><span class="mi">71</span><span class="p">,</span><span class="mi">73</span><span class="p">,</span><span class="mi">79</span><span class="p">,</span><span class="mi">83</span><span class="p">,</span><span class="mi">89</span><span class="p">,</span><span class="mi">97</span><span class="p">,</span><span class="mi">101</span><span class="p">,</span><span class="mi">103</span><span class="p">,</span>
<span class="mi">107</span><span class="p">,</span><span class="mi">109</span><span class="p">,</span><span class="mi">113</span><span class="p">,</span><span class="mi">127</span><span class="p">,</span><span class="mi">131</span><span class="p">,</span><span class="mi">137</span><span class="p">,</span><span class="mi">139</span><span class="p">,</span><span class="mi">149</span><span class="p">,</span><span class="mi">151</span><span class="p">,</span><span class="mi">157</span><span class="p">,</span><span class="mi">163</span><span class="p">,</span><span class="mi">167</span><span class="p">,</span><span class="mi">173</span><span class="p">,</span><span class="mi">179</span><span class="p">,</span><span class="mi">181</span><span class="p">,</span><span class="mi">191</span><span class="p">,</span><span class="mi">193</span><span class="p">,</span><span class="mi">197</span><span class="p">,</span><span class="mi">199</span><span class="p">,</span><span class="mi">211</span><span class="p">,</span>
<span class="mi">223</span><span class="p">,</span><span class="mi">227</span><span class="p">,</span><span class="mi">229</span><span class="p">,</span><span class="mi">233</span><span class="p">,</span><span class="mi">239</span><span class="p">,</span><span class="mi">241</span><span class="p">,</span><span class="mi">251</span><span class="p">,</span><span class="mi">257</span><span class="p">,</span><span class="mi">263</span><span class="p">,</span><span class="mi">269</span><span class="p">,</span><span class="mi">271</span><span class="p">,</span><span class="mi">277</span><span class="p">,</span><span class="mi">281</span><span class="p">,</span><span class="mi">283</span><span class="p">,</span><span class="mi">293</span><span class="p">,</span><span class="mi">307</span><span class="p">,</span><span class="mi">311</span><span class="p">,</span><span class="mi">313</span><span class="p">,</span><span class="mi">317</span><span class="p">,</span><span class="mi">331</span><span class="p">,</span>
<span class="mi">337</span><span class="p">,</span><span class="mi">347</span><span class="p">,</span><span class="mi">349</span><span class="p">,</span><span class="mi">353</span><span class="p">,</span><span class="mi">359</span><span class="p">,</span><span class="mi">367</span><span class="p">,</span><span class="mi">373</span><span class="p">,</span><span class="mi">379</span><span class="p">,</span><span class="mi">383</span><span class="p">,</span><span class="mi">389</span><span class="p">,</span><span class="mi">397</span><span class="p">,</span><span class="mi">401</span><span class="p">,</span><span class="mi">409</span><span class="p">,</span><span class="mi">419</span><span class="p">,</span><span class="mi">421</span><span class="p">,</span><span class="mi">431</span><span class="p">,</span><span class="mi">433</span><span class="p">,</span><span class="mi">439</span><span class="p">,</span><span class="mi">443</span><span class="p">,</span><span class="mi">449</span><span class="p">,</span>
<span class="mi">457</span><span class="p">,</span><span class="mi">461</span><span class="p">,</span><span class="mi">463</span><span class="p">,</span><span class="mi">467</span><span class="p">,</span><span class="mi">479</span><span class="p">,</span><span class="mi">487</span><span class="p">,</span><span class="mi">491</span><span class="p">,</span><span class="mi">499</span><span class="p">,</span><span class="mi">503</span><span class="p">,</span><span class="mi">509</span><span class="p">,</span><span class="mi">521</span><span class="p">,</span><span class="mi">523</span><span class="p">,</span><span class="mi">541</span><span class="p">]</span>

<span class="o">&gt;</span> <span class="n">primes</span><span class="o">!!</span><span class="mi">90000</span>
<span class="mi">1159531</span>

<span class="o">&gt;</span> <span class="n">isPrime</span> <span class="p">(</span><span class="mi">2</span><span class="o">^</span><span class="mi">31</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
<span class="kt">True</span>
</code></pre></div>

<h2>Calculo de n&#250;meros&nbsp;primos</h2>
<p>Por definici&#243;n, un n&#250;mero primo s&#243;lo es divisible por <code>1</code> y por s&#237;&nbsp;mismo:</p>
<div class="highlight"><pre><span></span><code><span class="n">Prime</span> <span class="o">=</span> <span class="nb">int</span>  <span class="c1"># un alias para n&#250;meros primos</span>

<span class="k">def</span> <span class="nf">isprime</span><span class="p">(</span><span class="n">n</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
    <span class="k">return</span> <span class="ow">not</span> <span class="nb">any</span><span class="p">(</span><span class="n">n</span> <span class="o">%</span> <span class="n">i</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">n</span><span class="p">))</span>

<span class="k">def</span> <span class="nf">primes</span><span class="p">(</span><span class="n">to</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="n">Prime</span><span class="p">]:</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">to</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span> <span class="k">if</span> <span class="n">isprime</span><span class="p">(</span><span class="n">i</span><span class="p">)]</span>
</code></pre></div>

<p>Podemos aplicar algunas optimizaciones a estos&nbsp;c&#225;lculos:</p>
<ul>
<li>Excepto el 2, podemos descartar como primos todos los n&#250;meros&nbsp;pares</li>
<li>Al comprobar divisores de <span class="math">\(n\)</span>, basta con probar hasta <span class="math">\(\sqrt{n}\)</span>, y &#250;nicamente
  con aquellos que sean&nbsp;primos</li>
</ul>
<p>Con estas premisas, podemos ir ya dise&#241;ando una estrategia para obtener una
secuencia de primos por evaluaci&#243;n&nbsp;perezosa:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Generator</span><span class="p">,</span> <span class="n">Iterable</span>
<span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">islice</span>

<span class="n">INFINITE</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">maxsize</span>  <span class="c1"># una aproximaci&#243;n 'mala' para infinito</span>
<span class="n">Prime</span> <span class="o">=</span> <span class="nb">int</span>  <span class="c1"># un alias para n&#250;meros primos</span>

<span class="c1"># lista de n&#250;meros primos que vayamos obteniendo</span>
<span class="n">primes</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">Prime</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>


<span class="k">def</span> <span class="nf">isdivisible</span><span class="p">(</span><span class="n">n</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">divisors</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">[</span><span class="nb">int</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Comprobar si 'n' es divisible por</span>
<span class="sd">    los elementos de un iterable ordenado</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="n">divisible</span> <span class="o">=</span> <span class="kc">False</span>
    <span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">divisors</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">n</span> <span class="o">%</span> <span class="n">d</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
            <span class="n">divisible</span> <span class="o">=</span> <span class="kc">True</span>
            <span class="k">break</span>
        <span class="k">if</span> <span class="n">d</span> <span class="o">*</span> <span class="n">d</span> <span class="o">&gt;</span> <span class="n">n</span><span class="p">:</span>
            <span class="k">break</span>
    <span class="k">return</span> <span class="n">divisible</span>


<span class="k">def</span> <span class="nf">isprime</span><span class="p">(</span><span class="n">n</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
    <span class="sd">&quot;&quot;&quot;Comprobar si 'n' es un n&#250;mero primo&quot;&quot;&quot;</span>

    <span class="k">if</span> <span class="n">n</span> <span class="o">&lt;=</span> <span class="n">primes</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span>
        <span class="k">return</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">primes</span>

    <span class="c1"># probando primos como divisores</span>
    <span class="k">if</span> <span class="n">isdivisible</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">primes</span><span class="p">):</span>
        <span class="k">return</span> <span class="kc">False</span>

    <span class="c1"># seguir con el resto de n&#250;meros impares</span>
    <span class="n">start</span> <span class="o">=</span> <span class="n">primes</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="mi">2</span>
    <span class="k">return</span> <span class="ow">not</span> <span class="n">isdivisible</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">range</span><span class="p">(</span><span class="n">start</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>


<span class="k">def</span> <span class="nf">genprimes</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="n">Generator</span><span class="p">[</span><span class="n">Prime</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">]:</span>
    <span class="sd">&quot;&quot;&quot;Generador de n&#250;meros primos&quot;&quot;&quot;</span>

    <span class="n">start</span> <span class="o">=</span> <span class="n">primes</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="mi">2</span>
    <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">start</span><span class="p">,</span> <span class="n">INFINITE</span><span class="p">,</span> <span class="mi">2</span><span class="p">):</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">isdivisible</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">primes</span><span class="p">):</span>
            <span class="n">primes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
            <span class="k">yield</span> <span class="n">n</span>
</code></pre></div>

<p>El generador <code>genprimes</code> nos dar&#225; un iterador con el que ir obteniendo los
n&#250;meros primos siguientes al &#250;ltimo de la lista. A medida que obtiene un primo,
se a&#241;ade a la lista <code>primes</code>.</p>
<p>La lista <code>primes</code> actua como <em>cach&#233;</em> de los n&#250;meros primos obtenidos y la
emplear&#225; <code>isprime</code> para sus comprobaciones. Si <code>isprime</code> se queda sin primos,
continua con los siguientes n&#250;meros impares hasta obtener un resultado, sin
pararse a calcular los primos&nbsp;intermedios.</p>
<h2>Secuencia de n&#250;meros&nbsp;primos</h2>
<p>Vistas estas funciones vamos a armar con ellas la estructura de una clase
<em>secuencia</em>. <code>isprime</code> pasar&#225; a ser el m&#233;todo <code>__contains__</code> y el generador
<code>genprimes</code> lo usaremos para ampliar autom&#225;ticamente la lista de n&#250;meros primos
seg&#250;n sea&nbsp;necesario:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Generator</span><span class="p">,</span> <span class="n">Iterable</span>
<span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">islice</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Union</span>

<span class="n">INFINITE</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">maxsize</span>  <span class="c1"># una mala aproximaci&#243;n de infinito</span>
<span class="n">Prime</span> <span class="o">=</span> <span class="nb">int</span>  <span class="c1"># un alias para los primos</span>


<span class="k">def</span> <span class="nf">isdivisible</span><span class="p">(</span><span class="n">n</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">divisors</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">[</span><span class="nb">int</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Comprobar si 'n' es divisible por</span>
<span class="sd">    los elementos de un iterable ordenado</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="n">divisible</span> <span class="o">=</span> <span class="kc">False</span>
    <span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">divisors</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">n</span> <span class="o">%</span> <span class="n">d</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
            <span class="n">divisible</span> <span class="o">=</span> <span class="kc">True</span>
            <span class="k">break</span>
        <span class="k">if</span> <span class="n">d</span> <span class="o">*</span> <span class="n">d</span> <span class="o">&gt;</span> <span class="n">n</span><span class="p">:</span>
            <span class="k">break</span>
    <span class="k">return</span> <span class="n">divisible</span>


<span class="k">def</span> <span class="nf">nth</span><span class="p">(</span><span class="n">it</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">,</span> <span class="n">n</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;Obtener de un iterable el elemento en la posici&#243;n 'n'&quot;&quot;&quot;</span>
    <span class="k">return</span> <span class="nb">next</span><span class="p">(</span><span class="n">islice</span><span class="p">(</span><span class="n">it</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="kc">None</span><span class="p">))</span>


<span class="k">class</span> <span class="nc">Primes</span><span class="p">:</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Collection of primes numbers</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_primes</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">Prime</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span> <span class="nf">last</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Prime</span><span class="p">:</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_primes</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span> <span class="nf">size</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
        <span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_primes</span><span class="p">)</span>

    <span class="k">def</span> <span class="fm">__len__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">INFINITE</span>

    <span class="k">def</span> <span class="fm">__contains__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">n</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
        <span class="sd">&quot;&quot;&quot;Comprobar si 'n' es un n&#250;mero primo&quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="n">n</span> <span class="o">&lt;=</span> <span class="bp">self</span><span class="o">.</span><span class="n">last</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">n</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_primes</span>

        <span class="c1"># probando primos como divisores</span>
        <span class="k">if</span> <span class="n">isdivisible</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_primes</span><span class="p">):</span>
            <span class="k">return</span> <span class="kc">False</span>

        <span class="c1"># seguir con el resto de n&#250;meros impares</span>
        <span class="n">start</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">last</span> <span class="o">+</span> <span class="mi">2</span>
        <span class="k">return</span> <span class="ow">not</span> <span class="n">isdivisible</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="nb">range</span><span class="p">(</span><span class="n">start</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>

    <span class="k">def</span> <span class="nf">genprimes</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Generator</span><span class="p">[</span><span class="n">Prime</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">]:</span>
        <span class="sd">&quot;&quot;&quot;Generador de n&#250;meros primos&quot;&quot;&quot;</span>

        <span class="n">start</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">last</span> <span class="o">+</span> <span class="mi">2</span>
        <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">start</span><span class="p">,</span> <span class="n">INFINITE</span><span class="p">,</span> <span class="mi">2</span><span class="p">):</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">isdivisible</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_primes</span><span class="p">):</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_primes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
                <span class="k">yield</span> <span class="n">n</span>

    <span class="k">def</span> <span class="fm">__getitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">idx</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">slice</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">Prime</span><span class="p">:</span>
        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">idx</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
            <span class="k">if</span> <span class="n">idx</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">:</span>
                <span class="k">raise</span> <span class="ne">OverflowError</span>

            <span class="k">return</span> <span class="p">(</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_primes</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span>
                <span class="k">if</span> <span class="n">idx</span> <span class="o">&lt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span>
                <span class="k">else</span> <span class="n">nth</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">genprimes</span><span class="p">(),</span> <span class="n">idx</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span><span class="p">)</span>
            <span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">rng</span> <span class="o">=</span> <span class="nb">range</span><span class="p">(</span><span class="n">INFINITE</span><span class="p">)[</span><span class="n">idx</span><span class="p">]</span>
            <span class="k">return</span> <span class="p">[</span><span class="bp">self</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">rng</span><span class="p">]</span>

<span class="c1"># Secuencia de los n&#250;meros primos</span>
<span class="n">primes</span> <span class="o">=</span> <span class="n">Primes</span><span class="p">()</span>
<span class="n">isprime</span> <span class="o">=</span> <span class="n">primes</span><span class="o">.</span><span class="fm">__contains__</span>
</code></pre></div>

<p>Como <em>infinito</em> se usa <code>sys.maxsize</code> que es el mayor tama&#241;o que puede tener una
lista para la versi&#243;n <code>CPython</code>. Si tratamos de usar &#237;ndices mayores para una
lista nos dar&#225;&nbsp;error.</p>
<p>Cuando se solicita un n&#250;mero primo que no est&#225; en la lista, el m&#233;todo
<code>__getitem__</code> invoca autom&#225;ticamente al iterador que devuelve <code>genprimes</code> hasta
alcanzarlo. A medida que se descubren n&#250;meros primos, se val almacenando para su
posterior&nbsp;uso.</p>
<p>Pruebas de&nbsp;uso:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">primes</span> <span class="kn">import</span> <span class="n">primes</span><span class="p">,</span> <span class="n">isprime</span>
<span class="o">&gt;&gt;&gt;</span> <span class="nb">print</span><span class="p">(</span><span class="n">primes</span><span class="p">[:</span><span class="mi">100</span><span class="p">])</span>
<span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">13</span><span class="p">,</span> <span class="mi">17</span><span class="p">,</span> <span class="mi">19</span><span class="p">,</span> <span class="mi">23</span><span class="p">,</span> <span class="mi">29</span><span class="p">,</span> <span class="mi">31</span><span class="p">,</span> <span class="mi">37</span><span class="p">,</span> <span class="mi">41</span><span class="p">,</span> <span class="mi">43</span><span class="p">,</span> <span class="mi">47</span><span class="p">,</span> <span class="mi">53</span><span class="p">,</span> <span class="mi">59</span><span class="p">,</span> <span class="mi">61</span><span class="p">,</span> <span class="mi">67</span><span class="p">,</span> <span class="mi">71</span><span class="p">,</span> <span class="mi">73</span><span class="p">,</span>
 <span class="mi">79</span><span class="p">,</span> <span class="mi">83</span><span class="p">,</span> <span class="mi">89</span><span class="p">,</span> <span class="mi">97</span><span class="p">,</span> <span class="mi">101</span><span class="p">,</span> <span class="mi">103</span><span class="p">,</span> <span class="mi">107</span><span class="p">,</span> <span class="mi">109</span><span class="p">,</span> <span class="mi">113</span><span class="p">,</span> <span class="mi">127</span><span class="p">,</span> <span class="mi">131</span><span class="p">,</span> <span class="mi">137</span><span class="p">,</span> <span class="mi">139</span><span class="p">,</span> <span class="mi">149</span><span class="p">,</span> <span class="mi">151</span><span class="p">,</span> <span class="mi">157</span><span class="p">,</span>
 <span class="mi">163</span><span class="p">,</span> <span class="mi">167</span><span class="p">,</span> <span class="mi">173</span><span class="p">,</span> <span class="mi">179</span><span class="p">,</span> <span class="mi">181</span><span class="p">,</span> <span class="mi">191</span><span class="p">,</span> <span class="mi">193</span><span class="p">,</span> <span class="mi">197</span><span class="p">,</span> <span class="mi">199</span><span class="p">,</span> <span class="mi">211</span><span class="p">,</span> <span class="mi">223</span><span class="p">,</span> <span class="mi">227</span><span class="p">,</span> <span class="mi">229</span><span class="p">,</span> <span class="mi">233</span><span class="p">,</span> <span class="mi">239</span><span class="p">,</span> <span class="mi">241</span><span class="p">,</span>
 <span class="mi">251</span><span class="p">,</span> <span class="mi">257</span><span class="p">,</span> <span class="mi">263</span><span class="p">,</span> <span class="mi">269</span><span class="p">,</span> <span class="mi">271</span><span class="p">,</span> <span class="mi">277</span><span class="p">,</span> <span class="mi">281</span><span class="p">,</span> <span class="mi">283</span><span class="p">,</span> <span class="mi">293</span><span class="p">,</span> <span class="mi">307</span><span class="p">,</span> <span class="mi">311</span><span class="p">,</span> <span class="mi">313</span><span class="p">,</span> <span class="mi">317</span><span class="p">,</span> <span class="mi">331</span><span class="p">,</span> <span class="mi">337</span><span class="p">,</span> <span class="mi">347</span><span class="p">,</span>
 <span class="mi">349</span><span class="p">,</span> <span class="mi">353</span><span class="p">,</span> <span class="mi">359</span><span class="p">,</span> <span class="mi">367</span><span class="p">,</span> <span class="mi">373</span><span class="p">,</span> <span class="mi">379</span><span class="p">,</span> <span class="mi">383</span><span class="p">,</span> <span class="mi">389</span><span class="p">,</span> <span class="mi">397</span><span class="p">,</span> <span class="mi">401</span><span class="p">,</span> <span class="mi">409</span><span class="p">,</span> <span class="mi">419</span><span class="p">,</span> <span class="mi">421</span><span class="p">,</span> <span class="mi">431</span><span class="p">,</span> <span class="mi">433</span><span class="p">,</span> <span class="mi">439</span><span class="p">,</span>
 <span class="mi">443</span><span class="p">,</span> <span class="mi">449</span><span class="p">,</span> <span class="mi">457</span><span class="p">,</span> <span class="mi">461</span><span class="p">,</span> <span class="mi">463</span><span class="p">,</span> <span class="mi">467</span><span class="p">,</span> <span class="mi">479</span><span class="p">,</span> <span class="mi">487</span><span class="p">,</span> <span class="mi">491</span><span class="p">,</span> <span class="mi">499</span><span class="p">,</span> <span class="mi">503</span><span class="p">,</span> <span class="mi">509</span><span class="p">,</span> <span class="mi">521</span><span class="p">,</span> <span class="mi">523</span><span class="p">,</span> <span class="mi">541</span><span class="p">]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">primes</span><span class="p">[</span><span class="mi">90000</span><span class="p">]</span>
<span class="mi">1159531</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">isprime</span><span class="p">(</span><span class="mi">2</span><span class="o">**</span><span class="mi">31</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
<span class="kc">True</span>
<span class="o">&gt;&gt;&gt;</span> <span class="p">(</span><span class="mi">2</span><span class="o">**</span><span class="mi">31</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="ow">in</span> <span class="n">primes</span><span class="o">.</span><span class="n">_primes</span>
<span class="kc">False</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">primes</span><span class="o">.</span><span class="n">last</span>
<span class="mi">1159531</span>
</code></pre></div>

<p>Para cumplir con el protocolo <code>Sequence</code> podemos a&#241;adir los m&#233;todos que nos
faltan, cosa que animo hacer al lector. El m&#233;todo <code>count()</code> es trivial: si es
primo, habr&#225; 1 ocurrencia; si no es primo, 0 ocurrencias. El m&#233;todo <code>index()</code> es
algo m&#225;s complicado. En cambio el <code>_reversed__()</code> es imposible ya que no se
puede invertir una secuencia infinta. A pesar de ello, la clase <code>Prime</code> se
comportar&#225; casi como una secuencia siempre y cuando no itentemos acceder a la
secuencia por el&nbsp;final.</p>
<h2>M&#225;s&nbsp;optimizaciones</h2>
<h3>Bisecciones</h3>
<p>La lista de primos que vamos generando siempre ser&#225; una <em>lista ordenada</em>, por lo
que se pueden optimizar mucho las b&#250;squedas usando <em>bisecciones</em>, para lo que
tenemos el m&#243;dulo <code>bisect</code> (<span class="math">\(O(\log{n})\)</span> en lugar de <span class="math">\(O(n)\)</span>).</p>
<p>Por ejemplo, para comprobar si un elemento est&#225; en una lista&nbsp;ordenada:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">bisect</span> <span class="kn">import</span> <span class="n">bisect_left</span>

<span class="k">def</span> <span class="nf">bs_contains</span><span class="p">(</span><span class="n">lst</span><span class="p">:</span> <span class="nb">list</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
    <span class="n">idx</span> <span class="o">=</span> <span class="n">bisect_left</span><span class="p">(</span><span class="n">lst</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">idx</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">lst</span><span class="p">)</span> <span class="ow">and</span> <span class="n">lst</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span> <span class="o">==</span> <span class="n">x</span>
</code></pre></div>

<h3>Programaci&#243;n&nbsp;din&#225;mica</h3>
<p>En el generador de n&#250;meros primos podemos observar que se est&#225;n comprobando los
cuadrados de los divisores m&#225;s veces de las necesarias. Podemos delimitar rangos
en los que se van a usar los mismos divisores. Por ejemplo, si tenemos la
secuencia <code>[2, 3]</code> como divisores podemos chequear n&#250;meros hasta el <code>23</code>. Para
seguir con el <code>25</code> tenemos que a&#241;adir un primo m&#225;s, <code>[2, 3, 5]</code> con los que ya
podemos chequear hasta el <code>47</code>. Y as&#237; sucesivamente. El rango <code>range(start,
INFINITE, 2)</code> lo podemos fraccionar seg&#250;n el grupo de primos que emplearemos
como&nbsp;divisores.</p>
<p>La <em>programaci&#243;n din&#225;mica</em> tiene sus riesgos y es bastante f&#225;cil que no funcione
bien a la primera, pero mejoran mucho la eficiencia de un&nbsp;algoritmo.</p>
<h3>Multiproceso</h3>
<p>Como opci&#243;n de mejora est&#225; el uso de t&#233;cnicas de concurrencia y multiproceso.
Como primera medida que podemos pensar ser&#237;a crear varios <em>workers</em> que chequeen
en paralelo la divisibilidad para chequear varios n&#250;meros a la vez. El problema
es que estos workers tendr&#237;an que tener su copia de la lista de primos y
actualizarla conforme se obtenien, algo que es sumamente costoso y poco&nbsp;eficiente.</p>
<p>Una estrategia mejor ser&#237;a especializar cada <em>worker</em> en un subconjunto de
n&#250;meros primos de modo que todos los <em>workers</em> intervengan colaborativamente en
el chequeo del mismo&nbsp;n&#250;mero.</p>
<p>En concurrencia, hay muchas estrategias posibles y ninguna mejor. Al final, cada
problema tiene su soluci&#243;n particular que no sirve como soluci&#243;n&nbsp;general.</p>
<h3>C&#243;digo final&nbsp;optimizado</h3>
<p>El c&#243;digo final optimizado, sin usar concurrencia, se puede obtener del
siguiente&nbsp;enlace:</p>
<div class="admonition descarga">
<p class="admonition-title">Descarga</p>
<p><a href="https://blog.ch3m4.org/2021/02/15/evaluacion-perezosa-en-python-parte-4/primes.py">primes.py</a></p>
</div>
<p>Por hacernos una idea, esta ser&#237;a la comparativa de tiempos de la versiones haskell y&nbsp;python:</p>




<table>
<thead>
<tr>
<th align="left">operaci&#243;n</th>
<th align="right">haskell</th>
<th align="right">python</th>
<th align="right">python opt</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">primo 90000</td>
<td align="right">310ms</td>
<td align="right">1450ms</td>
<td align="right">860ms</td>
</tr>
<tr>
<td align="left">es primo <span class="math">\(2^{31}-1\)</span></td>
<td align="right">20ms</td>
<td align="right">10ms</td>
<td align="right">3ms</td>
</tr>
<tr>
<td align="left">index 1159531</td>
<td align="right">240ms</td>
<td align="right">N/A</td>
<td align="right">820ms</td>
</tr>
</tbody>
</table>
<hr />
<h2>Serie <em>Evaluaci&#243;n Perezosa en&nbsp;Python</em></h2>
<ul>
<li><a href="https://blog.ch3m4.org/2021/02/08/evaluacion-perezosa-en-python-parte-1/" title="Introducci&#243;n a la _evaluaci&#243;n perezosa_">Parte 1 - Introducci&#243;n a la <em>evaluaci&#243;n&nbsp;perezosa</em></a></li>
<li><a href="https://blog.ch3m4.org/2021/02/09/evaluacion-perezosa-en-python-parte-2/" title="Secuencias infinitas">Parte 2 - Secuencias&nbsp;infinitas</a></li>
<li><a href="https://blog.ch3m4.org/2021/02/14/evaluacion-perezosa-en-python-parte-3/" title="Parte 3 - _Memoizaci&#243;n_">Parte 3 - <em>Memoizaci&#243;n</em></a></li>
<li><a href="https://blog.ch3m4.org/2021/02/15/evaluacion-perezosa-en-python-parte-4/" title="Parte 4 - _Evaluaci&#243;n perezosa_ avanzada">Parte 4 - <em>Evaluaci&#243;n perezosa</em>&nbsp;avanzada</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/07/evaluacion-perezosa-en-python-parte-5/" title="Parte 5 - Formalizaci&#243;n de la Secuencia Perezosa">Parte 5 - Formalizaci&#243;n de la Secuencia&nbsp;Perezosa</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/07/evaluacion-perezosa-en-python-parte-6/" title="Parte 6 - Ejemplo pr&#225;ctico: Potencias de Fermi-Dirac">Parte 6 - Ejemplo pr&#225;ctico: Potencias de&nbsp;Fermi-Dirac</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/10/evaluacion-perezosa-en-python-apendice/" title="Ap&#233;ndice: sobre el tipado de datos utilizado">Ap&#233;ndice: sobre el tipado de datos&nbsp;utilizado</a></li>
</ul>
<div class="admonition danger">
<p class="admonition-title">La serie unificada como <em>Jupyter Notebook</em>&nbsp;en:</p>
<ul>
<li><a href="https://blog.ch3m4.org/2021/notebook-serie-evaluacion-perezosa-en-python.sync.ipynb" title="Notebook - Evaluaci&#243;n perezosa en python">formato notebook&nbsp;(.ipynb)</a></li>
<li><a href="https://blog.ch3m4.org/2021/notebook-serie-evaluacion-perezosa-en-python.sync.md" title="Jupytext - Evaluaci&#243;n perezosa en python">formato jupytext&nbsp;(.md)</a></li>
</ul>
</div>
<hr />
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hyperreals *R: Memoizaci&amp;#243;n - Evaluaci&amp;#243;n perezosa en python - Parte&amp;#160;3</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">15 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <h2>Cach&#233;s y&nbsp;Memoizaci&#243;n</h2>
<p>En el pasado art&#237;culo vimos que para obtener un elemento de la sucesi&#243;n
fibonacci necesit&#225;bamos calcular los anteriores. Ve&#225;moslo con m&#225;s&nbsp;detalle.</p>
<p>Podemos definir la siguiente funci&#243;n para obtener un elemento de esta&nbsp;sucesi&#243;n:</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">fib</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">n</span>
    <span class="k">return</span> <span class="n">fib</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">fib</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span>
</code></pre></div>

<p>Esta funci&#243;n tiene un terrible problema de eficacia, puesto que se llama a s&#237;
misma demasiadas veces para calcular el mismo elemento. Por ejemplo, para
calcular <code>fib(10)</code> llama una vez a <code>fib(9)</code> y a <code>fib(8)</code>, pero para calcular
<code>fib(9)</code> tambi&#233;n llama a <code>fib(8)</code>. Si sumamos todas las llamadas, habr&#225;
necesitado&nbsp;llamar:</p>
<ul>
<li><code>fib(9)</code> 1&nbsp;vez</li>
<li><code>fib(8)</code> 2&nbsp;veces</li>
<li><code>fib(7)</code> 3&nbsp;veces</li>
<li><code>fib(6)</code> 5&nbsp;veces</li>
<li><code>fib(5)</code> 8&nbsp;veces</li>
<li><code>fib(4)</code> 13&nbsp;veces</li>
<li><code>fib(3)</code> 21&nbsp;veces</li>
<li><code>fib(2)</code> 34&nbsp;veces</li>
<li><code>fib(1)</code> 55&nbsp;veces</li>
<li><code>fib(0)</code> 34&nbsp;veces</li>
</ul>
<p>Para elementos mayores, todav&#237;a ser&#225;n m&#225;s las llamadas que se habr&#225;n&nbsp;repetido.</p>
<p>Un mejora nos la da la propia documentaci&#243;n de python como aplicaci&#243;n de la
funci&#243;n <a href="https://docs.python.org/3.9/library/functools.html#functools.lru_cache"><code>functools.lru_cache</code></a>:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">functools</span> <span class="kn">import</span> <span class="n">lru_cache</span>

<span class="nd">@lru_cache</span><span class="p">(</span><span class="n">maxsize</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">fib</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">n</span>
    <span class="k">return</span> <span class="n">fib</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">fib</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span>
</code></pre></div>

<p>B&#225;sicamente, <code>lru_cache</code> es un <em>decorador</em> que detecta los argumentos que se
pasa a una funci&#243;n y guarda en un cach&#233; el resultado que devuelve. Un <strong>cach&#233;
<span class="caps">LRU</span></strong> (<em>Least Recently Used</em> ) tiene la estrategia de eliminar de la cach&#233; los
elementos que hayan sido menos utilizados recientemente. En este caso, con
<code>maxsize=None</code> no se impone ning&#250;n l&#237;mite de tama&#241;o, por lo que guardar&#225; todos
los elementos de la cach&#233; <sup id="fnref:1"><a class="footnote-ref" href="https://blog.ch3m4.org/feeds/python.atom.xml#fn:1">1</a></sup>.</p>
<p>A este proceso de guardar los resultados de una evaluaci&#243;n en funci&#243;n de los
argumentos de entrada se conoce por <strong>&#8220;memoize&#8221;</strong> o <strong>&#8220;memoizaci&#243;n&#8221;</strong>, y es
fundamental para la <em>evaluaci&#243;n perezosa</em>.</p>
<p>Podemos obtener informaci&#243;n de la&nbsp;cach&#233;:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">fib</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">fib</span><span class="o">.</span><span class="n">cache_info</span><span class="p">()</span>
<span class="n">CacheInfo</span><span class="p">(</span><span class="n">hits</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span> <span class="n">misses</span><span class="o">=</span><span class="mi">11</span><span class="p">,</span> <span class="n">maxsize</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">currsize</span><span class="o">=</span><span class="mi">11</span><span class="p">)</span>
</code></pre></div>

<p>Nos dice que la cach&#233; tiene 11 elementos (la serie de <code>fib(0)</code> a <code>fib(10)</code>), que
ha fallado 11 veces, una por elemento de la sucesi&#243;n, pero s&#237; que ha acertado 8.
Una importante mejora de como lo ten&#237;amos&nbsp;antes.</p>
<p>A&#250;n as&#237;, en python tenemos limitado el n&#250;mero de llamadas recursivas que se
pueden hacer, que suele estar en torno a unas 3000 llamadas recursivas <sup id="fnref:2"><a class="footnote-ref" href="https://blog.ch3m4.org/feeds/python.atom.xml#fn:2">2</a></sup>:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">fib</span><span class="p">(</span><span class="mi">10000</span><span class="p">)</span>
<span class="o">...</span>
<span class="ne">RecursionError</span><span class="p">:</span> <span class="n">maximum</span> <span class="n">recursion</span> <span class="n">depth</span> <span class="n">exceeded</span> <span class="ow">in</span> <span class="n">comparison</span>
</code></pre></div>

<p>Para no tener este problema, en la documentaci&#243;n hacen el truco de ir visitando
en orden todos los elementos de la sucesi&#243;n hasta llegar al que&nbsp;queremos.</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="p">[</span><span class="n">fib</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">16</span><span class="p">)]</span>
<span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">13</span><span class="p">,</span> <span class="mi">21</span><span class="p">,</span> <span class="mi">34</span><span class="p">,</span> <span class="mi">55</span><span class="p">,</span> <span class="mi">89</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">233</span><span class="p">,</span> <span class="mi">377</span><span class="p">,</span> <span class="mi">610</span><span class="p">]</span>
</code></pre></div>

<p>Con este truco se instruye a la cach&#233; con todos los elementos de la sucesi&#243;n
hasta llegar al que queremos. Para el c&#225;lculo de un elemento s&#243;lo se necesitar&#225;n
los dos elementos anteriores de la sucesi&#243;n, que ya tendremos en la cach&#233;, lo
que evita m&#250;ltiples llamadas&nbsp;recursivas.</p>
<p>Con este mismo prop&#243;sito, podemos probar a calcular el elemento 10000 aplicando
las t&#233;cnicas ya aprendidas hasta&nbsp;ahora:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">count</span><span class="p">,</span> <span class="n">islice</span>
<span class="kn">from</span> <span class="nn">functools</span> <span class="kn">import</span> <span class="n">lru_cache</span>

<span class="n">&#8469;</span> <span class="o">=</span> <span class="n">count</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">suc_fib</span> <span class="o">=</span> <span class="p">(</span><span class="n">fib</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">&#8469;</span><span class="p">)</span>
<span class="n">fib10k</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">islice</span><span class="p">(</span><span class="n">suc_fib</span><span class="p">,</span> <span class="mi">10000</span><span class="p">,</span> <span class="kc">None</span><span class="p">))</span>
</code></pre></div>

<p>Esta gesti&#243;n de la cach&#233; es totalmente opaca para nosotros. Si pudi&#233;ramos
acceder a ella ser&#237;a un modo de obtener la sucesi&#243;n de fibonacci hasta el mayor
elemento que se haya&nbsp;calculado.</p>
<p>Vamos a itentar crear una cach&#233; similar capaz de generar autom&#225;ticamente los
elementos de la&nbsp;sucesi&#243;n:</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">fibcache</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
    <span class="n">cache</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">def</span> <span class="nf">wrap</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
        <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">cache</span><span class="p">),</span> <span class="n">n</span> <span class="o">+</span> <span class="mi">1</span><span class="p">):</span>
            <span class="n">cache</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">f</span><span class="p">(</span><span class="n">i</span><span class="p">))</span>
        <span class="k">return</span> <span class="n">cache</span><span class="p">[</span><span class="n">n</span><span class="p">]</span>

    <span class="n">wrap</span><span class="o">.</span><span class="n">cache</span> <span class="o">=</span> <span class="n">cache</span>

    <span class="k">return</span> <span class="n">wrap</span>

<span class="nd">@fibcache</span>
<span class="k">def</span> <span class="nf">fib</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">n</span>
    <span class="k">return</span> <span class="n">fib</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">fib</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span>
</code></pre></div>

<p>Hemos creado el decorador, <code>fibcache</code> que a&#241;ade una cach&#233; a la funci&#243;n que
decora. Al hacer la llamada <code>fib(n)</code>, este decorador se asegura que todos los
elementos anteriores de la sucesi&#243;n est&#233;n en la cach&#233;. La cach&#233; es accesible
mediante el atributo <code>fib.cache</code>, que no ser&#225; otra cosa que la sucesi&#243;n de&nbsp;fibonacci.</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">fib</span><span class="p">(</span><span class="mi">10000</span><span class="p">)</span>
<span class="mf">3364476487643178326662161200510754331030214846068006390656476997468008144216.</span><span class="o">...</span>
<span class="o">...</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">fib</span><span class="o">.</span><span class="n">cache</span><span class="p">[</span><span class="mi">10000</span><span class="p">]</span>
<span class="mf">3364476487643178326662161200510754331030214846068006390656476997468008144216.</span><span class="o">...</span>
<span class="o">...</span>
</code></pre></div>

<p>Lo genial de esta estrategia es que s&#243;lo calculamos los m&#237;nimos elementos
necesarios para obtener el resultado buscado, algo que es el fundamento de lo
que conocemos por <em>evaluaci&#243;n perezosa</em>.</p>
<h2>Resumen</h2>
<p>Aplicando t&#233;cnicas de <em>memoizaci&#243;n</em>, hemos conseguido que una funci&#243;n recursiva
almacene los c&#225;lculos que hace para as&#237; evitar repetirlos, con lo que es posible
reducir los niveles de&nbsp;recursividad.</p>
<p>Con un decorador, hemos asociado una cach&#233; a una funci&#243;n que se rellena
autom&#225;ticamente, y en orden, con los resultados intermedios hasta llegar al
resultado solicitado. Esta cach&#233; ser&#225; una sucesi&#243;n ordenada de resultados, que
crece a medida que se&nbsp;necesite.</p>
<p>A este proceso de realizar c&#225;lculos seg&#250;n sea necesario es lo que conocemos por
<em>Evaluaci&#243;n Perezosa</em>.</p>
<hr />
<h2>Serie <em>Evaluaci&#243;n Perezosa en&nbsp;Python</em></h2>
<ul>
<li><a href="https://blog.ch3m4.org/2021/02/08/evaluacion-perezosa-en-python-parte-1/" title="Introducci&#243;n a la _evaluaci&#243;n perezosa_">Parte 1 - Introducci&#243;n a la <em>evaluaci&#243;n&nbsp;perezosa</em></a></li>
<li><a href="https://blog.ch3m4.org/2021/02/09/evaluacion-perezosa-en-python-parte-2/" title="Secuencias infinitas">Parte 2 - Secuencias&nbsp;infinitas</a></li>
<li><a href="https://blog.ch3m4.org/2021/02/14/evaluacion-perezosa-en-python-parte-3/" title="Parte 3 - _Memoizaci&#243;n_">Parte 3 - <em>Memoizaci&#243;n</em></a></li>
<li><a href="https://blog.ch3m4.org/2021/02/15/evaluacion-perezosa-en-python-parte-4/" title="Parte 4 - _Evaluaci&#243;n perezosa_ avanzada">Parte 4 - <em>Evaluaci&#243;n perezosa</em>&nbsp;avanzada</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/07/evaluacion-perezosa-en-python-parte-5/" title="Parte 5 - Formalizaci&#243;n de la Secuencia Perezosa">Parte 5 - Formalizaci&#243;n de la Secuencia&nbsp;Perezosa</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/07/evaluacion-perezosa-en-python-parte-6/" title="Parte 6 - Ejemplo pr&#225;ctico: Potencias de Fermi-Dirac">Parte 6 - Ejemplo pr&#225;ctico: Potencias de&nbsp;Fermi-Dirac</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/10/evaluacion-perezosa-en-python-apendice/" title="Ap&#233;ndice: sobre el tipado de datos utilizado">Ap&#233;ndice: sobre el tipado de datos&nbsp;utilizado</a></li>
</ul>
<div class="admonition danger">
<p class="admonition-title">La serie unificada como <em>Jupyter Notebook</em>&nbsp;en:</p>
<ul>
<li><a href="https://blog.ch3m4.org/2021/notebook-serie-evaluacion-perezosa-en-python.sync.ipynb" title="Notebook - Evaluaci&#243;n perezosa en python">formato notebook&nbsp;(.ipynb)</a></li>
<li><a href="https://blog.ch3m4.org/2021/notebook-serie-evaluacion-perezosa-en-python.sync.md" title="Jupytext - Evaluaci&#243;n perezosa en python">formato jupytext&nbsp;(.md)</a></li>
</ul>
</div>
<hr />
<p><span class="caps">ANOTACIONES</span>:</p>
<div class="footnote">
<hr />
<ol>
<li id="fn:1">
<p>Existe un decorador equivalente, <code>functools.cache</code>, que tambi&#233;n sirve para
crear cach&#233;s sin l&#237;mite, pero no contabiliza el n&#250;mero de aciertos.&#160;<a class="footnote-backref" href="https://blog.ch3m4.org/feeds/python.atom.xml#fnref:1" title="Jump back to footnote 1 in the text">&#8617;</a></p>
</li>
<li id="fn:2">
<p>El l&#237;mite de llamadas recursivas se obtiene con la funci&#243;n
<code>sys.getrecursionlimit()</code> y se podr&#237;a alterar con <code>sys.setrecursionlimit</code>,
aunque no es recomendable.&#160;<a class="footnote-backref" href="https://blog.ch3m4.org/feeds/python.atom.xml#fnref:2" title="Jump back to footnote 2 in the text">&#8617;</a></p>
</li>
</ol>
</div>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hyperreals *R: Secuencias infinitas - Evaluaci&amp;#243;n perezosa en python - Parte&amp;#160;2</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">15 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <h2>Algunas&nbsp;definiciones</h2>
<p>Puede ser interesante dejar claras algunas definiciones para distinguir entre
iteradores e iterables (se pueden ver las definiciones completas en el
<a href="https://docs.python.org/3.9/glossary.html">glosario</a> de&nbsp;python):</p>
<dl>
<dt><strong>Iterable</strong></dt>
<dd>cualquier objeto capaz de devolver sus miembros de uno en&nbsp;uno</dd>
<dt><strong>Iterador</strong></dt>
<dd><em>iterable</em> que representa un flujo de datos, cuyos elementos&nbsp;se</dd>
<dd>obtienen uno detr&#225;s de&nbsp;otro</dd>
<dt><strong>Secuencia</strong></dt>
<dd><em>iterable</em> con acceso eficiente a sus elementos mediante un &#237;ndice&nbsp;entero</dd>
<dt><strong>Generador</strong></dt>
<dd>funci&#243;n que devuelve un <em>iterador</em></dd>
<dt><strong>Expresi&#243;n&nbsp;generadora</strong></dt>
<dd>expresi&#243;n que devuelve un <em>iterador</em></dd>
</dl>
<p>Lo importante a tener en cuenta es que tenemos dos grandes <em>grupos de
iterables</em>: los <em>iteradores</em> y las <em>secuencias</em>.</p>
<p>Los elementos de una <em>secuencia</em> son accesibles por su posici&#243;n, mientras que
los elementos de un <em>iterador</em> s&#243;lo se pueden acceder en serie. <em>Iterable</em> ser&#237;a
el concepto m&#225;s general que englobar&#237;a ambos&nbsp;t&#233;rminos.</p>
<p>En el resto del art&#237;culo hablaremos de <em>&#8220;secuencias&#8221;</em> como t&#233;rmino matem&#225;tico,
aunque su implementaci&#243;n podr&#237;a corresponder con cualquier iterable de los&nbsp;mencionados.</p>
<h2>Secuencias&nbsp;infinitas</h2>
<p>En python, para crear secuencias infinitas se suelen usar <em>generadores</em>. Por
ejemplo, para obtener la secuencia de <em>N&#250;meros Naturales</em> se podr&#237;a hacer&nbsp;as&#237;:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Iterable</span>

<span class="k">def</span> <span class="nf">&#8469;</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="n">Iterable</span><span class="p">[</span><span class="nb">int</span><span class="p">]:</span>
    <span class="n">n</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="k">while</span> <span class="mi">1</span><span class="p">:</span>
        <span class="k">yield</span> <span class="n">n</span>
        <span class="n">n</span> <span class="o">+=</span> <span class="mi">1</span>
</code></pre></div>

<p>No podemos tratar las secuencias infinitas del mismo modo que con una lista.
Necesitamos las funciones del m&#243;dulo <a href="https://docs.python.org/3.9/library/itertools.html">itertools</a> capaces de operar con
iteradores para pasar a una lista en el momento que realmente la necesitemos. Al
final de la documentaci&#243;n del m&#243;dulo se incluyen algunas
<a href="https://docs.python.org/3.9/library/itertools.html#itertools-recipes">recetas</a> que dan idea de lo que pueden&nbsp;hacer.</p>
<p>Por ejemplo, podr&#237;amos redefinir la secuencia de n&#250;mero naturales con
<code>itertools.count</code>:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">count</span>

<span class="n">&#8469;</span> <span class="o">=</span> <span class="n">count</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</code></pre></div>

<p>Para obtener los primeros 100 n&#250;meros&nbsp;naturales</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">islice</span>

<span class="nb">print</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">islice</span><span class="p">(</span><span class="n">&#8469;</span><span class="p">,</span> <span class="mi">100</span><span class="p">)))</span>

<span class="p">[</span><span class="mi">100</span><span class="p">,</span> <span class="mi">101</span><span class="p">,</span> <span class="mi">102</span><span class="p">,</span> <span class="mi">103</span><span class="p">,</span> <span class="mi">104</span><span class="p">,</span> <span class="mi">105</span><span class="p">,</span> <span class="mi">106</span><span class="p">,</span> <span class="mi">107</span><span class="p">,</span> <span class="mi">108</span><span class="p">,</span> <span class="mi">109</span><span class="p">,</span> <span class="mi">110</span><span class="p">,</span> <span class="mi">111</span><span class="p">,</span> <span class="mi">112</span><span class="p">,</span> <span class="mi">113</span><span class="p">,</span> <span class="mi">114</span><span class="p">,</span> <span class="mi">115</span><span class="p">,</span> <span class="mi">116</span><span class="p">,</span> <span class="mi">117</span><span class="p">,</span> <span class="mi">118</span><span class="p">,</span> <span class="mi">119</span><span class="p">,</span> <span class="mi">120</span><span class="p">,</span> <span class="mi">121</span><span class="p">,</span> <span class="mi">122</span><span class="p">,</span> <span class="mi">123</span><span class="p">,</span> <span class="mi">124</span><span class="p">,</span> <span class="mi">125</span><span class="p">,</span> <span class="mi">126</span><span class="p">,</span> <span class="mi">127</span><span class="p">,</span> <span class="mi">128</span><span class="p">,</span> <span class="mi">129</span><span class="p">,</span> <span class="mi">130</span><span class="p">,</span> <span class="mi">131</span><span class="p">,</span> <span class="mi">132</span><span class="p">,</span> <span class="mi">133</span><span class="p">,</span> <span class="mi">134</span><span class="p">,</span> <span class="mi">135</span><span class="p">,</span> <span class="mi">136</span><span class="p">,</span> <span class="mi">137</span><span class="p">,</span> <span class="mi">138</span><span class="p">,</span> <span class="mi">139</span><span class="p">,</span> <span class="mi">140</span><span class="p">,</span> <span class="mi">141</span><span class="p">,</span> <span class="mi">142</span><span class="p">,</span> <span class="mi">143</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">145</span><span class="p">,</span> <span class="mi">146</span><span class="p">,</span> <span class="mi">147</span><span class="p">,</span> <span class="mi">148</span><span class="p">,</span> <span class="mi">149</span><span class="p">,</span> <span class="mi">150</span><span class="p">,</span> <span class="mi">151</span><span class="p">,</span> <span class="mi">152</span><span class="p">,</span> <span class="mi">153</span><span class="p">,</span> <span class="mi">154</span><span class="p">,</span> <span class="mi">155</span><span class="p">,</span> <span class="mi">156</span><span class="p">,</span> <span class="mi">157</span><span class="p">,</span> <span class="mi">158</span><span class="p">,</span> <span class="mi">159</span><span class="p">,</span> <span class="mi">160</span><span class="p">,</span> <span class="mi">161</span><span class="p">,</span> <span class="mi">162</span><span class="p">,</span> <span class="mi">163</span><span class="p">,</span> <span class="mi">164</span><span class="p">,</span> <span class="mi">165</span><span class="p">,</span> <span class="mi">166</span><span class="p">,</span> <span class="mi">167</span><span class="p">,</span> <span class="mi">168</span><span class="p">,</span> <span class="mi">169</span><span class="p">,</span> <span class="mi">170</span><span class="p">,</span> <span class="mi">171</span><span class="p">,</span> <span class="mi">172</span><span class="p">,</span> <span class="mi">173</span><span class="p">,</span> <span class="mi">174</span><span class="p">,</span> <span class="mi">175</span><span class="p">,</span> <span class="mi">176</span><span class="p">,</span> <span class="mi">177</span><span class="p">,</span> <span class="mi">178</span><span class="p">,</span> <span class="mi">179</span><span class="p">,</span> <span class="mi">180</span><span class="p">,</span> <span class="mi">181</span><span class="p">,</span> <span class="mi">182</span><span class="p">,</span> <span class="mi">183</span><span class="p">,</span> <span class="mi">184</span><span class="p">,</span> <span class="mi">185</span><span class="p">,</span> <span class="mi">186</span><span class="p">,</span> <span class="mi">187</span><span class="p">,</span> <span class="mi">188</span><span class="p">,</span> <span class="mi">189</span><span class="p">,</span> <span class="mi">190</span><span class="p">,</span> <span class="mi">191</span><span class="p">,</span> <span class="mi">192</span><span class="p">,</span> <span class="mi">193</span><span class="p">,</span> <span class="mi">194</span><span class="p">,</span> <span class="mi">195</span><span class="p">,</span> <span class="mi">196</span><span class="p">,</span> <span class="mi">197</span><span class="p">,</span> <span class="mi">198</span><span class="p">,</span> <span class="mi">199</span><span class="p">]</span>
</code></pre></div>

<p>Emular la funci&#243;n <code>enumerate</code>:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Iterable</span><span class="p">,</span> <span class="n">Iterator</span>

<span class="k">def</span> <span class="nf">enumerate</span><span class="p">(</span><span class="n">it</span><span class="p">:</span> <span class="n">Iterable</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Iterator</span><span class="p">:</span>
    <span class="n">&#8469;</span> <span class="o">=</span> <span class="n">count</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
    <span class="k">return</span> <span class="nb">zip</span><span class="p">(</span><span class="n">&#8469;</span><span class="p">,</span> <span class="n">it</span><span class="p">)</span>
</code></pre></div>

<p>&#191;Y si quisi&#233;ramos obtener la lista de cuadrados en el int&#233;rvalo <code>[100, 200)</code>.
Veamos (<span class="caps">NO</span> <span class="caps">PROBAR</span>):</p>
<div class="highlight"><pre><span></span><code><span class="n">&#8469;</span> <span class="o">=</span> <span class="n">count</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">cuadrados</span> <span class="o">=</span> <span class="p">(</span><span class="n">n</span><span class="o">**</span><span class="mi">2</span> <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">&#8469;</span><span class="p">)</span>
<span class="n">res</span> <span class="o">=</span> <span class="p">[</span><span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">cuadrados</span> <span class="k">if</span> <span class="mi">100</span><span class="o">&lt;=</span><span class="n">x</span><span class="o">&lt;</span><span class="mi">200</span><span class="p">]</span>
</code></pre></div>

<p>Si probabos es posible que se quede en un bucle infinito. Necesita comprobar
todos los elementos, por lo que se pondr&#225; a calcular todos lo elementos de la
sucesi&#243;n para ver si cumplen la&nbsp;condici&#243;n.</p>
<p>Como sabemos que la sucesi&#243;n de cuadrados es creciente, podemos pararla en el
momento que se salga de&nbsp;l&#237;mites:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">dropwhile</span><span class="p">,</span> <span class="n">takewhile</span>

<span class="n">&#8469;</span> <span class="o">=</span> <span class="n">count</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">cuadrados</span> <span class="o">=</span> <span class="p">(</span><span class="n">n</span> <span class="o">**</span> <span class="mi">2</span> <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">&#8469;</span><span class="p">)</span>
<span class="n">mayores_100</span> <span class="o">=</span> <span class="n">dropwhile</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="mi">100</span><span class="p">,</span> <span class="n">cuadrados</span><span class="p">)</span>
<span class="n">menores_200</span> <span class="o">=</span> <span class="n">takewhile</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span> <span class="o">&lt;=</span> <span class="mi">200</span><span class="p">,</span> <span class="n">mayores_100</span><span class="p">)</span>
<span class="n">res</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">menores_200</span><span class="p">)</span>
</code></pre></div>

<p>En definitiva, hemos encadenado varias funciones hasta conseguir el iterador que
necesit&#225;bamos. En <em>programaci&#243;n funcional</em>, a este encadenado de funciones se
denomina como <em>composici&#243;n de funciones</em> y es bastante utilizado.
Lamentablemente, en python no existe este tipo de&nbsp;operaciones.</p>
<h2>Ejemplo: sucesi&#243;n de&nbsp;Fibonacci</h2>
<p>La sucesi&#243;n de <em>Fibonacci</em> se define de la siguiente&nbsp;manera:</p>
<div class="math">$$f_0=1$$</div>
<div class="math">$$f_1=1$$</div>
<div class="math">$$f_n = f_{n-1} + f_{n-2}$$</div>
<p>Operando, podemos obtener la&nbsp;sencuencia:</p>
<div class="highlight"><pre><span></span><code><span class="mi">1</span>
<span class="mi">1</span>
<span class="mi">1</span><span class="o">+</span><span class="mi">1</span> <span class="ow">-&gt;</span> <span class="mi">2</span>
<span class="mi">1</span><span class="o">+</span><span class="mi">2</span> <span class="ow">-&gt;</span> <span class="mi">3</span>
<span class="mi">2</span><span class="o">+</span><span class="mi">3</span> <span class="ow">-&gt;</span> <span class="mi">5</span>
<span class="o">...</span>
</code></pre></div>

<p>La lista de los 20&nbsp;primeros:</p>
<div class="highlight"><pre><span></span><code><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">13</span><span class="p">,</span> <span class="mi">21</span><span class="p">,</span> <span class="mi">34</span><span class="p">,</span> <span class="mi">55</span><span class="p">,</span> <span class="mi">89</span><span class="p">,</span> <span class="mi">144</span><span class="p">,</span> <span class="mi">233</span><span class="p">,</span> <span class="mi">377</span><span class="p">,</span> <span class="mi">610</span><span class="p">,</span> <span class="mi">987</span><span class="p">,</span> <span class="mi">1597</span><span class="p">,</span> <span class="mi">2584</span><span class="p">,</span> <span class="mi">4181</span><span class="p">,</span> <span class="mi">6765</span><span class="p">]</span>
</code></pre></div>

<p>Un modo simple de construir la serie es usar un&nbsp;generador:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">collections.abc</span> <span class="kn">import</span> <span class="n">Iterator</span>
<span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">islice</span>

<span class="k">def</span> <span class="nf">fib</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="n">Iterator</span><span class="p">[</span><span class="nb">int</span><span class="p">]:</span>
    <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span>
    <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
        <span class="k">yield</span> <span class="n">a</span>
        <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">b</span><span class="p">,</span> <span class="n">a</span><span class="o">+</span><span class="n">b</span>

<span class="c1"># primeros 20 elementos</span>
<span class="nb">print</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">islice</span><span class="p">(</span><span class="n">fib</span><span class="p">(),</span> <span class="mi">20</span><span class="p">)))</span>
</code></pre></div>

<p>Para obtener un elemento en una posici&#243;n dada tenemos que <em>consumir</em> el
iterador, elemento a elemento, hasta llegar a la posici&#243;n que&nbsp;queremos.</p>
<p>Por ejemplo, para obtener el elemento de la posici&#243;n&nbsp;1000:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="nb">next</span><span class="p">(</span><span class="n">islice</span><span class="p">(</span><span class="n">fib</span><span class="p">(),</span> <span class="mi">1000</span><span class="p">,</span> <span class="kc">None</span><span class="p">))</span>
<span class="mi">70330367711422815821835254877183549770181269836358732742604905087154537118196933</span>
<span class="mi">57974224949456261173348775044924176599108818636326545022364710601205337412127386</span>
<span class="mi">7339111198139373125598767690091902245245323403501</span>
</code></pre></div>

<p>Ha sido necesario calcular todos los elementos anteriores hasta llegar al que
deseamos, algo que hay que repetir para cada uno de los elementos que queramos&nbsp;extraer.</p>
<p>Afortunadamente, la sucesi&#243;n de fibonacci tiene elemento gen&#233;rico que se expresa
en funci&#243;n de el <em>n&#250;mero &#225;ureo</em> <span class="math">\(\varphi\)</span> y que tiene la siguiente&nbsp;formulaci&#243;n:</p>
<div class="math">$$\varphi ={\frac {1+{\sqrt {5}}}{2}}$$</div>
<p>Usando el <em>n&#250;mero &#225;ureo</em>, un elemento de la serie fibonacci se puede calcular
con la siguiente f&#243;rmula de &#201;douard&nbsp;Lucas,:</p>
<div class="math">$$f_n=\frac{\varphi^n-\left(1-\varphi\right)^{n}}{\sqrt5}$$</div>
<p>Que podemos ajustar el redondeo y expresar&nbsp;como:</p>
<div class="math">$$f_{n}=\operatorname {int} \left({\frac {\varphi ^{n}}{\sqrt {5}}}+{\frac {1}{2}}\right)$$</div>
<p>As&#237; pues, podemos echar mano de la secuencia <code>GenericRange</code> que vimos en el
art&#237;culo anterior para definir una secuencia para&nbsp;fibonacci:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">FibRange</span><span class="p">(</span><span class="n">GenericRange</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">getitem</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">n</span><span class="p">):</span>
        <span class="n">sqrt5</span> <span class="o">=</span> <span class="mi">5</span><span class="o">**</span><span class="p">(</span><span class="mi">1</span><span class="o">/</span><span class="mi">2</span><span class="p">)</span>
        <span class="n">&#966;</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span> <span class="o">+</span> <span class="n">sqrt5</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span>
        <span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">&#966;</span><span class="o">**</span><span class="n">n</span><span class="o">/</span><span class="n">sqrt5</span> <span class="o">+</span> <span class="mi">1</span><span class="o">/</span><span class="mi">2</span><span class="p">)</span>


<span class="o">&gt;&gt;&gt;</span> <span class="nb">list</span><span class="p">(</span><span class="n">FibRange</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span><span class="mi">110</span><span class="p">))</span>
<span class="p">[</span><span class="mi">354224848179263111168</span><span class="p">,</span>
 <span class="mi">573147844013818970112</span><span class="p">,</span>
 <span class="mi">927372692193082081280</span><span class="p">,</span>
 <span class="mi">1500520536206901248000</span><span class="p">,</span>
 <span class="mi">2427893228399983329280</span><span class="p">,</span>
 <span class="mi">3928413764606884839424</span><span class="p">,</span>
 <span class="mi">6356306993006868692992</span><span class="p">,</span>
 <span class="mi">10284720757613753532416</span><span class="p">,</span>
 <span class="mi">16641027750620622225408</span><span class="p">,</span>
 <span class="mi">26925748508234379952128</span><span class="p">]</span>
</code></pre></div>

<p>Lamentablemente, aunque al final se obtenga un n&#250;mero entero, para hacer el
c&#225;lculo hemos recurrido al c&#225;lculo num&#233;rico de coma flotante, lo que produce
desbordamiento cuando trabajamos con n&#250;meros grandes. Tenemos que buscar otros
m&#233;todos para mantenernos en el dominio de los n&#250;mero enteros. Pero lo dejaremos
ya para el pr&#243;ximo art&#237;culo, donde veremos las <em>memoizaciones</em> o el modo de
guardar los resultados de un funci&#243;n para evitar repetir el mismo c&#225;lculo cuando
se vuelva a&nbsp;necesitar.</p>
<h2>Resumen</h2>
<p>Las secuencias num&#233;ricas se pueden expresar en forma de <em>iterables</em>, de las que
tenemos dos tipos: <code>iteradores</code> y <code>secuencias</code>.</p>
<p>Normalmente en python, para trabajar con secuencias infinitas se usan
iteradores. Para poder manejar estos iteradores se usan las funciones del m&#243;dulo
<code>itertools</code> que podemos combinar para obtener como resultado un iterable  que ya
podemos manejar&nbsp;mejor.</p>
<p>Si la secuencia tiene definido un elemento gen&#233;rico, entonces podemos utilizar
los rangos que ya hab&#237;amos visto anteriormente para crear la secuencia&nbsp;infinita.</p>
<hr />
<h2>Serie <em>Evaluaci&#243;n Perezosa en&nbsp;Python</em></h2>
<ul>
<li><a href="https://blog.ch3m4.org/2021/02/08/evaluacion-perezosa-en-python-parte-1/" title="Introducci&#243;n a la _evaluaci&#243;n perezosa_">Parte 1 - Introducci&#243;n a la <em>evaluaci&#243;n&nbsp;perezosa</em></a></li>
<li><a href="https://blog.ch3m4.org/2021/02/09/evaluacion-perezosa-en-python-parte-2/" title="Secuencias infinitas">Parte 2 - Secuencias&nbsp;infinitas</a></li>
<li><a href="https://blog.ch3m4.org/2021/02/14/evaluacion-perezosa-en-python-parte-3/" title="Parte 3 - _Memoizaci&#243;n_">Parte 3 - <em>Memoizaci&#243;n</em></a></li>
<li><a href="https://blog.ch3m4.org/2021/02/15/evaluacion-perezosa-en-python-parte-4/" title="Parte 4 - _Evaluaci&#243;n perezosa_ avanzada">Parte 4 - <em>Evaluaci&#243;n perezosa</em>&nbsp;avanzada</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/07/evaluacion-perezosa-en-python-parte-5/" title="Parte 5 - Formalizaci&#243;n de la Secuencia Perezosa">Parte 5 - Formalizaci&#243;n de la Secuencia&nbsp;Perezosa</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/07/evaluacion-perezosa-en-python-parte-6/" title="Parte 6 - Ejemplo pr&#225;ctico: Potencias de Fermi-Dirac">Parte 6 - Ejemplo pr&#225;ctico: Potencias de&nbsp;Fermi-Dirac</a></li>
<li><a href="https://blog.ch3m4.org/2021/03/10/evaluacion-perezosa-en-python-apendice/" title="Ap&#233;ndice: sobre el tipado de datos utilizado">Ap&#233;ndice: sobre el tipado de datos&nbsp;utilizado</a></li>
</ul>
<div class="admonition danger">
<p class="admonition-title">La serie unificada como <em>Jupyter Notebook</em>&nbsp;en:</p>
<ul>
<li><a href="https://blog.ch3m4.org/2021/notebook-serie-evaluacion-perezosa-en-python.sync.ipynb" title="Notebook - Evaluaci&#243;n perezosa en python">formato notebook&nbsp;(.ipynb)</a></li>
<li><a href="https://blog.ch3m4.org/2021/notebook-serie-evaluacion-perezosa-en-python.sync.md" title="Jupytext - Evaluaci&#243;n perezosa en python">formato jupytext&nbsp;(.md)</a></li>
</ul>
</div>
<hr />
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Rethinking the JavaScript ternary operator</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">15 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Lots of people treat the ternary operator with suspicion. At first glance, ternaries appear unnecessary. Nothing more than a tool for the overly clever to trim some characters from their code. A favourite hack for coders who don’t care about readability. And sure, it’s all too easy to turn ternaries into an indecipherable mess. But what if we’re missing something? What if there's more to ternaries than meets the eye?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Rethinking the JavaScript ternary operator</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">15 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Lots of people treat the ternary operator with suspicion. At first glance, ternaries appear unnecessary. Nothing more than a tool for the overly clever to trim some characters from their code. A favourite hack for coders who don’t care about readability. And sure, it’s all too easy to turn ternaries into an indecipherable mess. But what if we’re missing something? What if there's more to ternaries than meets the eye?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://programadorwebvalencia.com/img/blog/2021/03/websockets-sobre-html.png" alt="HTML sobre WebSockets">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">HTML sobre WebSockets</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Programador Web Valencia</a> <span class="article__date">14 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://programadorwebvalencia.com/img/blog/2021/03/websockets-sobre-html.png" alt="WebSockets sobre HTML" /></p>

<p>La forma tradicional de <strong>conseguir una SPA (Single-page Application) es dividir las responsabilidades</strong>, el Back-End sirve la información y el Front-End la dibuja dinámicamente. Tristemente implica un <strong>doble esfuerzo</strong> en el desarrollo siendo necesario la creación de 2 aplicaciones con tecnologías diferentes aumentando costes e involucrando a dos perfiles especializados. Aunque, por supuesto, es el precio que debemos pagar si queremos una web en tiempo real y que se renderice en un pestañeo. ¿O hay una alternativa? ¿Con incluso <strong>mejor rendimiento</strong>? Así es, y además es <strong>más fácil</strong> de desarrollar al trabajar con <strong>un solo lenguaje</strong>. Esta arquitectura se denomina: <strong>HTML sobre WebSockets</strong>.</p>

<p><strong>Chris McCord</strong>, creador de Phoenix (el Framework más popular dentro del ecosistema Elixir), presentó en <strong>ElixirConf 2019</strong> una tecnología llamada <a href="https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html">LiveView</a>. En apenas <a href="https://www.youtube.com/watch?v=MZvmYaFkNJI">15 minutos creó un clon de Twitter que funcionaba en tiempo real</a> <strong>sin necesidad de incorporar JavaScript renderizador</strong> o un framework popular (React, Angular, Vue…) que gestione la Vista, demostrando que era posible quedarse en el Back-End y lograr productividad con una dulce aroma a buen rendimiento. Desde entonces se ha popularizado esta solución, <strong>inspirado a otros desarrolladores</strong> para crear implementaciones de HTML sobre WebSockets en <strong>otros lenguajes</strong>. Se puede volver al <strong>Back-End pero sin renunciar a lo bueno del Front-End</strong>.</p>

<h2 id="cómo-funciona">¿Cómo funciona?</h2>

<p><strong>Disclamer: ¡si se usa JavaScript!</strong> Su labor no es renderizar sino crear un canal de comunicación con WebSockets y situar el HTML recibido en el lugar adecuado. Además de otras tareas secundarias como animaciones, gestión de eventos, etc.</p>

<p>La solución de McCord es <strong>no enviar al Front-End un JSON, sino HTML</strong> que no necesite ser preprocesado. De ese modo trasladamos la carga del dibujado, y toda su lógica, al Back-End. Ya pero… ¿Cómo hacemos que el servidor nos envíe nuevo contenido de forma inmediata y sin realizar una petición? Sencillo: con WebSockets.</p>

<p>Repasemos el sistema <strong>tradicional</strong> de la introducción. Desde la Web hago una petición HTTP, el navegador inicia la acción, obteniendo en la respuesta un JSON con toda la información en crudo. Lo siguiente es interpretar y crear el HTML correspondiente.</p>

<p><img src="https://programadorwebvalencia.com/img/blog/2021/03/websockets-sobre-html-tradicional.jpg" alt="Tradicional" class="medium" /></p>

<p>Mientras que HTML sobre WebSockets puede ser el <strong>envío de un JSON donde se devuelve HTML/CSS/JS</strong>. O incluso puede quitar el propio envío quedando a la escucha.</p>

<p><img src="https://programadorwebvalencia.com/img/blog/2021/03/websockets-sobre-html-protocolo.jpg" alt="Protocolo WebSockets sobre HTML" class="medium" /></p>

<p>Veamos el <strong>ejemplo</strong> donde se renderiza el artículo número 2 de un blog.</p>

<h3 id="1-conectamos">1. Conectamos</h3>

<p>Partimos con una conexión. Ya hay un tubo de comunicación entre cliente y servidor.</p>

<p><img src="https://programadorwebvalencia.com/img/blog/2021/03/websockets-sobre-html-conectar.jpg" alt="Conectar con WebSockets" class="medium" /></p>

<h3 id="2-petición-de-componente">2. Petición de componente</h3>

<p>El cliente pide el contenido de la ruta “/articulo/2/” a través del canal.</p>

<p><img src="https://programadorwebvalencia.com/img/blog/2021/03/websockets-sobre-html-pedir.jpg" alt="Pedir WebSockets sobre HTML" class="medium" /></p>

<h3 id="3-recepción-de-htmlcssjs">3. Recepción de HTML/CSS/JS</h3>

<p>El servidor genera el HTML/CSS/JS, usando el sistema de plantillas del Back-End, y lo devuelve por el canal.</p>

<p><img src="https://programadorwebvalencia.com/img/blog/2021/03/websockets-sobre-html-recibir.jpg" alt="Recibir WebSockets sobre HTML" class="medium" /></p>

<h3 id="4-impresión">4. Impresión</h3>

<p>Por último, el Front-End lo sitúa en el lugar adecuado o asignado.</p>

<h2 id="dónde-puedo-ver-una-demostración">¿Dónde puedo ver una demostración?</h2>

<p>He creado un <strong>prototipo en Django</strong> de un Blog con 100 entradas, cada artículo esta relacionado con sus respectivos comentarios. Además existe un apartado para visualizar el artículo completo, un paginador y una sección estática con algunos párrafos.</p>

<video src="https://programadorwebvalencia.com/videos/blog/2021/03/demo-websockets-sobre-html.mp4" autoplay="" muted="" loop=""></video>

<p>Aquí puedes ver como los cambios son reflejados en todos los clientes.</p>

<video src="https://programadorwebvalencia.com/videos/blog/2021/03/demo-websockets-sobre-html-broadcast.mp4" autoplay="" muted="" loop=""></video>

<p>Si observáis la url, nunca se cambia de página, y… ¡aun así funciona! ¿Quieres <strong>probarlo por ti mismo</strong>? Tienes la posibilidad de levantarlo a partir del <a href="https://github.com/tanrax/demo-HTML-over-WebSockets-in-Django">código fuente en GitHub</a>, esta Docketizado a un comando de distancia para arrancarlo.</p>

<h2 id="cuáles-son-sus-ventajas">¿Cuáles son sus ventajas?</h2>

<ul>
  <li>Solo hay <strong>un motor de renderizado</strong>, simplificando la tarea.</li>
  <li><strong>Real-time</strong>, los clientes reciben los cambios tan rápido como sea posible.</li>
  <li>El protocolo <strong>WebSockets es más rápido que HTTP</strong>. Fuente: <a href="https://stackoverflow.com/questions/14703627/websockets-protocol-vs-http:">starkoveflow</a></li>
  <li>Apropiado para <strong>conexiones lentas</strong>. Fuente: <a href="https://browsee.io/blog/websocket-vs-http-calls-performance-study/">browsee</a>.</li>
  <li>Crear un <strong>SPA sin apenas JavaScript</strong>.</li>
  <li><strong>Excelente SEO</strong>, los motores de búsqueda adorarán la página al encontrarse solo HTML.</li>
</ul>

<h2 id="cuáles-son-sus-inconvenientes">¿Cuáles son sus inconvenientes?</h2>

<ul>
  <li>El servidor necesitará <strong>más recursos</strong> al tener que dejar un WebSocket abierto por cliente.</li>
  <li><strong>Poca documentación</strong> al respecto.</li>
  <li><strong>Pocos frameworks</strong>.</li>
</ul>

<h2 id="qué-frameworks-existen">¿Qué Frameworks existen?</h2>

<p>Puedes empezar por los siguientes recursos.</p>

<ul>
  <li><strong>Elixir/Phoenix</strong>: LiveView.</li>
  <li><strong>Python/Django</strong>: Sockpuppet y Reactor.</li>
  <li><strong>C#/.NET</strong>: Blazor Server.</li>
  <li><strong>JavaScript</strong>: <a href="https://turbo.hotwire.dev/">Turbo</a> con <a href="https://stimulus.hotwire.dev/">Stimulus</a></li>
</ul>

<h2 id="apuntes-finales">Apuntes finales</h2>

<p>No creo que sea la solución definitiva, pero merece ser escuchada. Es llamativo su <strong>creciendo adopción</strong> y herramientas que están apareciendo. A nivel personal se sorprendió <strong>lo poco conocido que es</strong>, posiblemente a causa del <strong>poderoso ecosistema de JavaScript</strong>. Sin embargo es todo un placer no estar en la carrera de fondo que supone el Front-End para no quedarte desactualizado, y centrarte en el lenguaje de servidor.</p>

<p>En serio, ¿qué puedes perder por probarlo?</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="freeCodeCamp ya habla español con Rafael Hernandez">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">freeCodeCamp ya habla español con Rafael Hernandez</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">14 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Recientemente freeCodeCamp, una de las comunidades de aprendizaje tecnológico más importantes en internet,  anunció las versiones en español y en chino de sus contenidos. Este <a href="https://www.freecodecamp.org/news/world-language-translation-effort/" data-type="URL" data-id="https://www.freecodecamp.org/news/world-language-translation-effort/">anuncio</a> fue recibido con entusiasmo entre el público hispanohablante, ya que <a href="https://www.freecodecamp.org/espanol/news/" data-type="URL" data-id="https://www.freecodecamp.org/espanol/news/">freeCodeCamp </a>es un recurso imprescindible para aprender desarrollo web. Gracias a sus contenidos cada día <em>miles de personas en todo el mundo</em> pueden aprender de manera abierta y sin coste, habilidades relacionadas con las tecnologías de internet y conocimientos técnicos. </p>



<p>Para hablar sobre esta iniciativa de freeCodeCamp, por indicación del propio fundador <a href="https://twitter.com/ossia" data-type="URL" data-id="https://twitter.com/ossia">Quincy Larson,</a> invitamos al podcast a <a href="https://twitter.com/RafaelDavisH" data-type="URL" data-id="https://twitter.com/RafaelDavisH">Rafael Hernández,</a> coordinador desde Los Ángeles, del equipo encargado de la comunidad hispanohablante. Con Rafael discutimos entre otras cosas:</p>



<ul>
<li>El origen de freeCodeCamp y sus principales objetivos.</li>
<li>Las perspectivas con respecto al idioma español y a otros idiomas en la comunidad de freeCodeCamp.</li>
<li>Requisitos y solicitudes para participar como voluntario.</li>
<li>El trabajo de los voluntarios y su coordinación.</li>
<li>Financiación de freeCodeCamp y formas de donación.</li>
<li>Certificaciones de freeCodeCamp y valoraciones a nivel profesional.</li>
<li>Colaboraciones con empresas tecnológicas y acuerdos de colaboración.</li>
<li>Edición y gestión de contenidos.</li>
<li>Futuro y acciones próximas de freeCodeCamp.</li>


</ul>



<p>En esta charla Rafael Hernández nos cuenta cosas muy relevantes sobre la organización de esta comunidad. Desde su propia historia y la de Quincy Larson, además también de todo lo relacionado con los contenidos y la dirección estratégica de freeCodeCamp en la parte de idiomas.</p>







<p>Agradecer la atención y la disponibilidad de Rafael y Quincy para realizar esta entrevista. Os animamos a visitar los enlaces que nos deja Rafael y a participar en la comunidad de aprendizaje en línea de freeCodeCamp. Por último, animar a todo el mundo a crear contenidos en español o a colaborar con el proyecto con alguna aportación económica.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://blogs.windows.com/wp-content/uploads/prod/sites/33/2021/06/cropped-browser-icon-logo-32x32.jpg" alt="Serving our customers more effectively with new release cycles for Microsoft Edge">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Serving our customers more effectively with new release cycles for Microsoft Edge</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Microsoft Edge Blog</a> <span class="article__date">12 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Innovation has been part of Microsoft Edge since day one, whether you’re seamlessly accessing corporate apps online for work or saving money shopping with built-in coupons. As contributors to the Chromium project, we look forward to <a href="https:
</p>
<p>The post <a rel="nofollow" href="https://blogs.windows.com/msedgedev/2021/03/12/new-release-cycles-microsoft-edge-extended-stable/">Serving our customers more effectively with new release cycles for Microsoft Edge</a> appeared first on <a rel="nofollow" href="https://blogs.windows.com/msedgedev">Microsoft Edge Blog</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://evercade.co.uk/wp-content/uploads/2021/04/cropped-heart-32x32-1.png" alt="Evercade and The Oliver Twins raise over £11.000 for the National Videogame Museum">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Evercade and The Oliver Twins raise over £11.000 for the National Videogame Museum</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Evercade</a> <span class="article__date">12 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Evercade, Codemasters and The Oliver Twins are delighted to share the news of the first donation to the National Videogame Museum. Following the launch of The Oliver Twins Collection cartridge, exclusively for the Evercade Retro Gaming console, it was announced that all profits from this would be donated to the National Videogame Museum in Sheffield.... <a class="view-article" href="https://evercade.co.uk/evercade-and-the-oliver-twins-raise-over-11-000-for-the-national-videogame-museum/">View Article</a></p>
<p>The post <a rel="nofollow" href="https://evercade.co.uk/evercade-and-the-oliver-twins-raise-over-11-000-for-the-national-videogame-museum/">Evercade and The Oliver Twins raise over £11.000 for the National Videogame Museum</a> appeared first on <a rel="nofollow" href="https://evercade.co.uk">Evercade</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://diarioestoico.com/wp-content/uploads/2020/03/cropped-logo-estoico-footer-150x150-1-32x32.png" alt="EL VALOR DE LA AMISTAD EN EL ESTOICISMO">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">EL VALOR DE LA AMISTAD EN EL ESTOICISMO</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Diario Estoico</a> <span class="article__date">12 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        La amistad verdadera es un aspecto clave para el estoicismo. El ser humano es, por naturaleza, un ser sociable, por tanto, los amigos que elegimos influyen en nuestras vidas de forma muy profunda. En este artículo vamos a tratar el concepto de amistad según “El arte de cultivar la verdadera amistad” del estoico Cicerón. ¿TIENEN [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://cdn.evilmartians.com/front/blocks/common/images/social-5e5bfff.png" alt="Build images on GitHub Actions with Docker layer caching">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Build images on GitHub Actions with Docker layer caching</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Martian Chronicles, Evil Martians’ team blog</a> <span class="article__date">11 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Google Cloud pierde mucha pasta y más noticias sobre hardware y sistemas">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Google Cloud pierde mucha pasta y más noticias sobre hardware y sistemas</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">10 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Nueva edición de Informe Nube con David Vaquero y Antony Goetzschel. Un episodio dedicado a repasar una colección de noticias recientes sobre las tecnologías cloud, hardware y sistemas.</p>



<p>Entre las noticias:</p>



<ul>
<li>00:03:28​ Google Cloud pierde mucha pasta</li>
<li>00:13:38​ Filtración masiva de contraseñas</li>
<li>00:29:12​ Precios de los Threadripper Pro y placas base</li>
<li>00:52:08​ Hackean el dominio de Perl</li>
<li>00:57:42​ RoadMap de Rocky Linux</li>
<li>01:09:53​ Almalinux 8.3 beta 1</li>
<li>01:13:29​ Liberado Longhorn 1.1</li>
<li>01:17:43​ Comparativa Backups en la nube</li>
<li>01:20:07​ Rapid API</li>
<li>01:22:52​ Remotive.io</li>
<li>01:31:11​ Despedida</li>
</ul>



<p>Os recordamos que los episodios de Informe Nube también están disponibles en su formato original de vídeo, en el canal de YouTube de Cursos de desarrollo.</p>



<p></p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Digging Into CSS Logical Properties</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Ahmad Shadeed Blog</a> <span class="article__date">10 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Google Summer of Code 2021 Mentoring Orgs announced!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">09 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://blogs.windows.com/wp-content/uploads/prod/sites/33/2021/06/cropped-browser-icon-logo-32x32.jpg" alt="Microsoft Edge Legacy desktop application support ends today">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Microsoft Edge Legacy desktop application support ends today</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Microsoft Edge Blog</a> <span class="article__date">09 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Our new modern browser, Microsoft Edge, debuted over a year ago and today can be found on hundreds of millions of devices. Last August, <a href="https://techcommunity.microsoft.com/t5/microsoft-365-blog/microsoft-365-apps-say-farewell-to-internet-exp
</p>
<p>The post <a rel="nofollow" href="https://blogs.windows.com/msedgedev/2021/03/09/microsoft-edge-legacy-end-of-support/">Microsoft Edge Legacy desktop application support ends today</a> appeared first on <a rel="nofollow" href="https://blogs.windows.com/msedgedev">Microsoft Edge Blog</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2021/208-masochism.png" alt="Masochism">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Masochism</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">09 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2021/208-masochism.png" alt="Masochism" title="It's all about making the wrong choice at the wrong time." /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Phil Libin: Find a new way to ski</h1>
                            <h2 class="article__feed"><a target="_blank" href="">tonsky.me</a> <span class="article__date">09 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
          Brief transcript of What I Know podcast with Phil Libin on entrepreneurship
        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Quick starting is a bendy road</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Manuel Uberti</a> <span class="article__date">08 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>After more than a year with <a href="https://www.manueluberti.eu/emacs/2019/10/04/straight/">straight</a> as my package manager, recently I have
decided to sit down and look closely at how I handle my Emacs packages.</p>

<p>For all the interesting design choices and splendid documentation <code class="language-plaintext highlighter-rouge">straight</code>
offers, I have never used neither its version freezing capabilities nor the
chances to edit the source code of a package to try possible fixes before
sending patches upstream. Two reasons, mainly:</p>

<ul>
  <li>I update my packages on a daily basis, accepting the risk of breakages in
order to signal them to the maintainers and offer some help;</li>
  <li>when I want to send a patch, I have the source code of the package I am
working on outside of my Emacs configuration to avoid leaving something messy
around.</li>
</ul>

<p>These are not issues with <code class="language-plaintext highlighter-rouge">straight</code>, of course. It all depends on what one needs
from their package manager.</p>

<p>One of the major benefits that <code class="language-plaintext highlighter-rouge">straight</code> brought to my setup is a boost in
startup speed. However, why don’t give <code class="language-plaintext highlighter-rouge">package-quickstart</code> a try? Setting
<code class="language-plaintext highlighter-rouge">package-quickstart</code> to <code class="language-plaintext highlighter-rouge">t</code> instructs <code class="language-plaintext highlighter-rouge">package.el</code> to pre-compute an autoload
file so that the activation of packages can be done much faster, resulting in a
faster startup<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>. And indeed it does, resulting in more or less the same 0.4
seconds that I was getting with <code class="language-plaintext highlighter-rouge">straight</code>.</p>

<p>One thing to be aware of is that, as the documention of <code class="language-plaintext highlighter-rouge">package-quickstart</code>
suggests, “the use of ‘package-quickstart-refresh’ every time the activation
need to be changed, such as when ‘package-load-list’ is modified” is required.
Hence, I added an <code class="language-plaintext highlighter-rouge">:after-while</code> advice to <code class="language-plaintext highlighter-rouge">package-menu-execute</code> (bound to
<kbd>x</kbd> in <code class="language-plaintext highlighter-rouge">Package Menu</code>) to make sure <code class="language-plaintext highlighter-rouge">package-quickstart-refresh</code> is run
after every upgrade.</p>

<p>Again, mine is not an argument against <code class="language-plaintext highlighter-rouge">straight</code>. It’s still a great package
manager and a fantastic alternative to the built-in <code class="language-plaintext highlighter-rouge">package.el</code>. However, these
days my Emacs interactions do not need the fine-grained control <code class="language-plaintext highlighter-rouge">straight</code>
provides.</p>

<h2 id="notes">Notes</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>See the <a href="https://git.savannah.gnu.org/cgit/emacs.git/commit/etc/NEWS?id=6dfdf0c9e8e4aca77b148db8d009c862389c64d3">relevant commit</a>. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Quick starting is a bendy road</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Manuel Uberti</a> <span class="article__date">08 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>After more than a year with <a href="https://www.manueluberti.eu/emacs/2019/10/04/straight/">straight</a> as my package manager, recently I have
decided to sit down and look closely at how I handle my Emacs packages.</p>

<p>For all the interesting design choices and splendid documentation <code class="language-plaintext highlighter-rouge">straight</code>
offers, I have never used neither its version freezing capabilities nor the
chances to edit the source code of a package to try possible fixes before
sending patches upstream. Two reasons, mainly:</p>

<ul>
  <li>I update my packages on a daily basis, accepting the risk of breakages in
order to signal them to the maintainers and offer some help;</li>
  <li>when I want to send a patch, I have the source code of the package I am
working on outside of my Emacs configuration to avoid leaving something messy
around.</li>
</ul>

<p>These are not issues with <code class="language-plaintext highlighter-rouge">straight</code>, of course. It all depends on what one needs
from their package manager.</p>

<p>One of the major benefits that <code class="language-plaintext highlighter-rouge">straight</code> brought to my setup is a boost in
startup speed. However, why don’t give <code class="language-plaintext highlighter-rouge">package-quickstart</code> a try? Setting
<code class="language-plaintext highlighter-rouge">package-quickstart</code> to <code class="language-plaintext highlighter-rouge">t</code> instructs <code class="language-plaintext highlighter-rouge">package.el</code> to pre-compute an autoload
file so that the activation of packages can be done much faster, resulting in a
faster startup<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>. And indeed it does, resulting in more or less the same 0.4
seconds that I was getting with <code class="language-plaintext highlighter-rouge">straight</code>.</p>

<p>One thing to be aware of is that, as the documention of <code class="language-plaintext highlighter-rouge">package-quickstart</code>
suggests, “the use of ‘package-quickstart-refresh’ every time the activation
need to be changed, such as when ‘package-load-list’ is modified” is required.
Hence, I added an <code class="language-plaintext highlighter-rouge">:after-while</code> advice to <code class="language-plaintext highlighter-rouge">package-menu-execute</code> (bound to
<kbd>x</kbd> in <code class="language-plaintext highlighter-rouge">Package Menu</code>) to make sure <code class="language-plaintext highlighter-rouge">package-quickstart-refresh</code> is run
after every upgrade.</p>

<p>Again, mine is not an argument against <code class="language-plaintext highlighter-rouge">straight</code>. It’s still a great package
manager and a fantastic alternative to the built-in <code class="language-plaintext highlighter-rouge">package.el</code>. However, these
days my Emacs interactions do not need the fine-grained control <code class="language-plaintext highlighter-rouge">straight</code>
provides.</p>

<h2 id="notes">Notes</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>See the <a href="https://git.savannah.gnu.org/cgit/emacs.git/commit/etc/NEWS?id=6dfdf0c9e8e4aca77b148db8d009c862389c64d3">relevant commit</a>. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How the ARPANET Protocols Worked</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Two-Bit History</a> <span class="article__date">08 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The ARPANET changed computing forever by proving that computers of wildly different manufacture could be connected using standardized protocols. In my post on the historical significance of the ARPANET, I mentioned a few of those protocols, but didn't describe them in any detail. So I wanted to take a closer look at them. I also wanted to see how much of the design of those early protocols survives in the protocols we use today.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://javierarcheni.com/wp-content/uploads/2021/04/cropped-favicon-javierarcheni-32x32.png" alt="Conseguir un sencillo efecto de desplazamiento (scroll) para cualquier navegador con polyfill">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Conseguir un sencillo efecto de desplazamiento (scroll) para cualquier navegador con polyfill</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Javier Archeni</a> <span class="article__date">07 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Uno de los efectos más comunes es una página web es la capacidad de desplazarse hacia un sección, normalmente tras hacer clic en algún elemento de menú o navegación. Lo más común es el típico ejemplo de «one-page» con un menú superior donde el usuario va directamente hacia la sección correspondiente. Sí, los enlaces hacia &#8230; <a href="https://javierarcheni.com/blog/conseguir-un-sencillo-efecto-de-desplazamiento-scroll-para-cualquier-navegador-con-polyfill/">Ver más</a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Llamen al de seguridad con Néstor Angulo de Ugarte">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Llamen al de seguridad con Néstor Angulo de Ugarte</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">06 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Justo después de un año desde su participación en otro episodio del podcast, volvemos a hablar con <a href="https://twitter.com/pharar" data-type="URL" data-id="https://twitter.com/pharar">Néstor Angulo de Ugarte.</a> En esta ocasión aprovechamos la sección de seguridad del informe de O&#8217;Reilly Media para tratar  sobre las amenazas de seguridad en internet, hablamos también de WAF (Web Application Firewall), de educación sobre ciberseguridad y también sobre su trabajo diario en GoDaddy defendiendo aplicaciones y sitios web.</p>



<p>Néstor Angulo es un profesional de la seguridad muy interesado en todo lo relativo a la tecnología. Ofrece charlas con frecuencia sobre seguridad informática y trabaja de manera diaria solucionando problemas de seguridad en sitios web. </p>



<p>Con Néstor hablamos también de certificación en seguridad, discutimos sobre privacidad en internet y sobre hacking ético. Como siempre un auténtico gusto poder compartir con él un rato en este podcast.</p>



<p></p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">February 2021 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">05 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Read more updates from Clj-kondo/babashka/sci, ClojisR, O’Doyle Rules, and Calva
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://blogs.windows.com/wp-content/uploads/prod/sites/33/2021/06/cropped-browser-icon-logo-32x32.jpg" alt="Microsoft Edge 89: Delivering improved browser performance to get the job done">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Microsoft Edge 89: Delivering improved browser performance to get the job done</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Microsoft Edge Blog</a> <span class="article__date">04 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><strong>Note: We’re in the process of deploying features mentioned in this post, starting with Stable 89, so it might be a little while before you see them in your channel and build</strong><strong><em>.</em></strong></p>
<p>Nowadays, it’s not unusual </p>
<p>The post <a rel="nofollow" href="https://blogs.windows.com/msedgedev/2021/03/04/edge-89-performance/">Microsoft Edge 89: Delivering improved browser performance to get the job done</a> appeared first on <a rel="nofollow" href="https://blogs.windows.com/msedgedev">Microsoft Edge Blog</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure 1.10.3 release</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">04 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Clojure 1.10.3 is a small release with the following changes:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Reverted the case error message change from 1.10.2 due to backwards compatibility concerns</p>
</li>
<li>
<p>Added prepl support for reader conditionals</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_detailed_changelog"><a class="anchor" href="#_detailed_changelog"></a>Detailed changelog</h2>
<div class="sectionbody">
<div class="paragraph">
<p>See the <a href="https://github.com/clojure/clojure/blob/master/changes.md#changes-to-clojure-in-version-1103">change log</a> for a complete list of all changes in Clojure 1.10.3.</p>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Terraform en Amazon Web Services">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Terraform en Amazon Web Services</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">03 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>David Vaquero y Antony Goetzschel vuelven con su Informe Nube, con una sesión completa sobre Terraform en Amazon Web Services. En este extenso episodio nos cuentan todo lo que debes tener en cuenta para gestionar Terraform en AWS. Explican conceptos básicos como son la gestión de credenciales, la creación de buckets S3, conocer las VPC (redes privadas virtuales en la nube) y el servicio de gestión DNS de AWS Route 53.</p>



<p>Esta primera parte ofrece una buena base para tratar Terraform sobre la tecnología de Amazon Web Services. Recuerda que este episodio es una versión en audio de los vídeos disponibles en el <a href="https://www.youtube.com/channel/UChE59MSKV-eEFyS-0_wqrFg" data-type="URL" data-id="https://www.youtube.com/channel/UChE59MSKV-eEFyS-0_wqrFg">canal de YouTube de Cursos de Desarrollo.</a></p>



<p>Contenidos del episodio:</p>



<p>00:00:00 Intro<br>00:00:11 Sumario<br>00:03:06 Credencias IAM a AWS<br>00:16:57 Creación de un Bucket S3<br>00:19:08 Explicación VPC en AWS<br>00:25:24 Route 53<br>00:27:49 Seguimos con Bucket S3<br>00:42:07 Terraform con AWS y S3<br>00:59:30 Creación de la VPC<br>01:24:18 Security Groups y Reglas de red<br>01:29:33 Definición máquina EC2<br>01:42:07 Manejo de user_data<br>01:48:11 Alta disponibilidad<br>01:54:34 Volumen compartido EFS<br>02:09:14 Fe de Erratas<br>02:11:08 Despedida y novedades</p>



<p></p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Season of Docs 2020: 5 Technical communication learnings as an open source contributor</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">03 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Exciting New Features in Django 3.2</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">02 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Django 3.2 is just around the corner and it's packed with new features. Django versions are usually not that exciting (it's a good thing!), but this time many features were added to the ORM, so I find it especially interesting!</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">PRESS: Hardware hacker and academic Nadya Peek to keynote LibrePlanet 2021</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FSF News</a> <span class="article__date">02 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        BOSTON, Massachusetts, USA -- Tuesday, March 2, 2021 -- The Free Software Foundation (FSF) today announced digital fabrication expert and University of Washington assistant professor Nadya Peek as a keynote speaker for LibrePlanet 2021. The annual technology and social justice conference will be held online on March 20 and 21, 2021, with the theme "Empowering Users."
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojurists Together board nominations and annual members meeting</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">02 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Stand for the upcoming Clojurists Together board elections
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">SoD and technical documentation in an open source organization</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">02 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://nosinmiscookies.com/wp-content/uploads/2019/03/cropped-favicon-32x32.png" alt="La importancia de elegir una herramienta SEO adecuada">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">La importancia de elegir una herramienta SEO adecuada</h1>
                            <h2 class="article__feed"><a target="_blank" href="">No sin mis cookies</a> <span class="article__date">02 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Una cosa que está clara y es que para hacer SEO necesitas hacerte con herramientas que te ayuden en la tarea de recopilar datos para analizar y medir resultados, entre otras funciones.</p>
<p>The post <a rel="nofollow" href="https://nosinmiscookies.com/elegir-herramienta-seo/">La importancia de elegir una herramienta SEO adecuada</a> appeared first on <a rel="nofollow" href="https://nosinmiscookies.com">No sin mis cookies</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://thehistoryoftheweb.com/wp-content/uploads/2017/09/cropped-thotw-logo-square-1-32x32.jpg" alt="The Most Ill-Timed Website in History">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Most Ill-Timed Website in History</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The History of the Web</a> <span class="article__date">02 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>There are a near infinite number of sites that have launched that you've never heard about. This is likely one of them. But if not for poor timing, it may have been primed for success.</p>
<p>The post <a rel="nofollow" href="https://thehistoryoftheweb.com/postscript/the-most-ill-timed-website-in-history/">The Most Ill-Timed Website in History</a> appeared first on <a rel="nofollow" href="https://thehistoryoftheweb.com">The History of the Web</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2021/207-promotion.png" alt="Promotion">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Promotion</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">02 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2021/207-promotion.png" alt="Promotion" title="Don't let power be your master." /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Things I wish I knew when I started in elixir development</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">01 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        These are some things I commonly use in my elixir development workflow that might be interesting for someone.
Managing multiple versions of elixir and erlang   When you have to work in more than one project at time that could probably means you have to handle different elixir and erlang versions so installing the default version that your OS provides won&#39;t be helpful. Here is where asdf shines to solves this problem, asdf allow us to have different versions of elixir, erlang and other languages in the same machine so we can easily switch between them.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Things I wish I knew when I started in elixir development</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">01 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>
These are some things I commonly use in my elixir development workflow that might be interesting for someone.</p>
<div id="outline-container-headline-1" class="outline-2">
<h2 id="headline-1">
Managing multiple versions of elixir and erlang
</h2>
<div id="outline-text-headline-1" class="outline-text-2">
<p>
When you have to work in more than one project at time that could probably means you have to handle different elixir and erlang versions so installing the default version that your OS provides won&#39;t be helpful. Here is where <code class="verbatim">asdf</code> shines to solves this problem, <code class="verbatim">asdf</code> allow us to have different versions of elixir, erlang and other languages in the same machine so we can easily switch between them.</p>
<p>
In macOS you can install it with <code class="verbatim">brew install asdf</code> and then follow the instructions that the installer prints out to set up the <code class="verbatim">PATH</code>, more info in its Github page <a href="https://github.com/asdf-vm/asdf">https://github.com/asdf-vm/asdf</a></p>
<p>
Now we have <code class="verbatim">asdf</code> installed we need to install the plugins to handle <code class="verbatim">erlang</code> and <code class="verbatim">elixir</code>, we can install them with:</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">asdf plugin add erlang
asdf plugin add elixir</code></pre></div>
</div>
<p>
Once we have those installed we need to define which versions we&#39;re going to use in our project, there is more than one way to do that:</p>
<div id="outline-container-headline-2" class="outline-3">
<h3 id="headline-2">
Using environment variables
</h3>
<div id="outline-text-headline-2" class="outline-text-3">
<p>
We can set up the required versions by defining environment variables with the <code class="verbatim">ASDF_</code> prefix so if we need version elixir <code class="verbatim">1.10</code> we need to define the variable <code class="verbatim">ASDF_ELIXIR_VERSION</code> with the value <code class="verbatim">1.10</code> the same applies for erlang or other programming languages as well.</p>
<p>
For example we can define variables for elixir and erlang as the example below:</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">export ASDF_ELIXIR_VERSION<span style="color:#f92672">=</span>1.10.3-otp-22
export ASDF_ERLANG_VERSION<span style="color:#f92672">=</span>22.3</code></pre></div>
</div>
<blockquote>
<p>To handle environment variables in a easy way we can use <a href="https://direnv.net">direnv</a>, it allows to define environment variables in a file <code class="verbatim">.envrc</code> and it will loaded automatically as soon as we enter to out project folder.</p>
</blockquote>
</div>
</div>
<div id="outline-container-headline-3" class="outline-3">
<h3 id="headline-3">
File based config file
</h3>
<div id="outline-text-headline-3" class="outline-text-3">
<p>
<code class="verbatim">asdf</code> allow us to define a <code class="verbatim">.tool-versions</code> file where we can put all the versions needed for our project, we can define one as the example below:</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">erlang 23.0.2
elixir 1.10.4-otp-23</code></pre></div>
</div>
</div>
</div>
<div id="outline-container-headline-4" class="outline-3">
<h3 id="headline-4">
Creating a new project
</h3>
<div id="outline-text-headline-4" class="outline-text-3">
<p>
Because we have first to define the versions used in a project we can&#39;t just run <code class="verbatim">mix new my_app</code> because <code class="verbatim">asdf</code> doesn&#39;t know yet which versions we want. To do this we have 2 options:</p>
<ul>
<li>
<p>Define global versions of elixir and erlang using for example <code class="verbatim">asdf global elixir 1.9.0</code> and the same for erlang <code class="verbatim">asdf global erlang 22.3</code> and then we can execute <code class="verbatim">mix new my_app</code> normally</p>
</li>
<li>
<p>Define the versions just for the <code class="verbatim">mix new</code> command execution, for example <code class="verbatim">ASDF_ELIXIR_VERSION=1.9.0 ASDF_ERLANG_VERSION=22.3 mix new my_app</code>, this way we don&#39;t affect the global scope and then we can define these same versions inside the created project.</p>
</li>
</ul>
<p>I like the second one because I don&#39;t have to change the global version each time I want to create a new project and I can easily access to that command from bash history.</p>
</div>
</div>
<div id="outline-container-headline-5" class="outline-3">
<h3 id="headline-5">
Notes about erlang compilation
</h3>
<div id="outline-text-headline-5" class="outline-text-3">
<p>
<code class="verbatim">asdf</code> uses <code class="verbatim">kerl</code> under the hood to handle erlang compilation and when we are installing a new version it will ask for a java installation 😕, to avoid this behaviour we can define the following environment variable:</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">export KERL_CONFIGURE_OPTIONS<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;--disable-debug --without-javac&#34;</span></code></pre></div>
</div>
</div>
</div>
</div>
</div>
<div id="outline-container-headline-6" class="outline-2">
<h2 id="headline-6">
Ecto database url
</h2>
<div id="outline-text-headline-6" class="outline-text-2">
<p>
If we are dealing with databases in our project we will probably be using Ecto. And Ecto allow us to define database credentials in two ways, the first one is define them separately as the example below:</p>
<div class="src src-elixir">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-elixir" data-lang="elixir">config <span style="color:#e6db74">:my_app</span>, <span style="color:#a6e22e">Repo</span>,
  <span style="color:#e6db74">database</span>: <span style="color:#e6db74">&#34;ecto_simple&#34;</span>,
  <span style="color:#e6db74">username</span>: <span style="color:#e6db74">&#34;postgres&#34;</span>,
  <span style="color:#e6db74">password</span>: <span style="color:#e6db74">&#34;postgres&#34;</span>,
  <span style="color:#e6db74">hostname</span>: <span style="color:#e6db74">&#34;localhost&#34;</span></code></pre></div>
</div>
<p>
And the second one is using a unique parameter:</p>
<div class="src src-elixir">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-elixir" data-lang="elixir">config <span style="color:#e6db74">:my_app</span>, <span style="color:#a6e22e">Repo</span>,
  <span style="color:#e6db74">url</span>: <span style="color:#e6db74">&#34;postgres://postgres:postgres@localhost/ecto_simple&#34;</span></code></pre></div>
</div>
<p>
This is my favorite option for these reasons:</p>
<ul>
<li>
<p>Just one value to maintain</p>
</li>
<li>
<p>This format is also accepted in <code class="verbatim">psql</code>, for example we can execute <code class="verbatim">psql postgres://postgres:postgres@localhost/ecto_simple</code> and we&#39;re connected to the database. I just discovered this a few weeks ago 😅</p>
</li>
<li>
<p>We can change credentials for example when we&#39;re running a mix command just prepending the value <code class="verbatim">DATABASE_URL=postgres://postgres:postgres@localhost/test_db mix something</code> in the case we&#39;re loading it from an environment variable</p>
</li>
</ul>
<p>Then if you have the connection url in a variable called <code class="verbatim">DATABASE_URL</code>, using <code class="verbatim">direnv</code> of course 😉, you can just execute <code class="verbatim">psql $DATABASE_URL</code> to database session.</p>
</div>
</div>
<div id="outline-container-headline-7" class="outline-2">
<h2 id="headline-7">
Using iex
</h2>
<div id="outline-text-headline-7" class="outline-text-2">
<div id="outline-container-headline-8" class="outline-3">
<h3 id="headline-8">
Enable shell history
</h3>
<div id="outline-text-headline-8" class="outline-text-3">
<p>
A cool feature of elixir is <code class="verbatim">iex</code>, you can load modules, recompile them and so on, but when sometimes we execute &#34;large&#34; pieces of code or some cases that we&#39;re trying out to understand the code or something else and when we have to restart the session we lost all the history 😢, we can avoid this by adding a flag <code class="verbatim">-kernel shell_history enabled</code> in the environment variable <code class="verbatim">ERL_AFLAGS</code> before we start our <code class="verbatim">iex</code> session. I just put following code in my <code class="verbatim">.zshrc</code> to have it enabled for all my projects:</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">export ERL_AFLAGS<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;-kernel shell_history enabled&#34;</span></code></pre></div>
</div>
</div>
</div>
<div id="outline-container-headline-9" class="outline-3">
<h3 id="headline-9">
Preload aliases
</h3>
<div id="outline-text-headline-9" class="outline-text-3">
<p>
Another thing than could be annoying to deal with is aliasing a large module name, for example if we have <code class="verbatim">MyApp.Contexts.Authentication.User</code> and we are using this module pretty often it could be easier to have it already loaded when we start a iex session, we can make this by defining a <code class="verbatim">.iex.exs</code> file in the project root with the desired aliases, for example:</p>
<div class="src src-elixir">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-elixir" data-lang="elixir"><span style="color:#f92672">alias</span> <span style="color:#a6e22e">MyApp.Contexts.Authentication.User</span></code></pre></div>
</div>
<p>
And now when we start a new <code class="verbatim">iex</code> session we will have that module aliased from the beginning so we can use <code class="verbatim">User.whatever</code> without a problem.</p>
<blockquote>
<p>Keep in mind that even if we can make an alias(a module name is just an atom) when we starting a session using just <code class="verbatim">iex</code> we cannot access to its functions. We need to start our <code class="verbatim">iex</code> session using <code class="verbatim">iex -S mix</code></p>
</blockquote>
</div>
</div>
<div id="outline-container-headline-10" class="outline-3">
<h3 id="headline-10">
Recompiling modules
</h3>
<div id="outline-text-headline-10" class="outline-text-3">
<p>
Within a <code class="verbatim">iex</code> sessions we can recompile a module just writing <code class="verbatim">r module_name</code> and if the want to recompile the whole project we can execute <code class="verbatim">recompile</code>, this is useful when we are making some changes in the code and we need to test it right away with all the values that we already had defined. It&#39;s also called &#34;REPL based development&#34; and it&#39;s most used with lisp based programming languages but having <code class="verbatim">iex</code> in elixir we can use those nice features as well.</p>
</div>
</div>
</div>
</div>
<div id="outline-container-headline-11" class="outline-2">
<h2 id="headline-11">
Mix tasks
</h2>
<div id="outline-text-headline-11" class="outline-text-2">
<p>
These are tasks that <code class="verbatim">mix</code> can run, duhh.. But we can create them and use them in our projects. For example maybe we are debugging some code and we don&#39;t want to execute a long process(business process) instead of that we can just extract some function calls and execute them from a mix task using existing data. We can create a mix task with the following code:</p>
<div class="src src-elixir">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-elixir" data-lang="elixir"><span style="color:#66d9ef">defmodule</span> <span style="color:#a6e22e">Mix.Tasks.Foo</span> <span style="color:#66d9ef">do</span>
  <span style="color:#a6e22e">@moduledoc</span> <span style="color:#66d9ef">false</span>
  <span style="color:#f92672">use</span> <span style="color:#a6e22e">Mix.Task</span>

  <span style="color:#66d9ef">def</span> run(_args) <span style="color:#66d9ef">do</span>
    <span style="color:#a6e22e">Application</span><span style="color:#f92672">.</span>ensure_all_started(<span style="color:#e6db74">:my_app</span>)
    <span style="color:#a6e22e">IO</span><span style="color:#f92672">.</span>puts(<span style="color:#e6db74">&#34;runnning...&#34;</span>)
  <span style="color:#66d9ef">end</span>
<span style="color:#66d9ef">end</span></code></pre></div>
</div>
<p>
We have to name this file <code class="verbatim">foo.ex</code> and place it inside <code class="verbatim">lib</code> folder and now we can run <code class="verbatim">mix foo</code> and we&#39;ll get a <code class="verbatim">running...</code> message.</p>
<p>
I use this many times, actually I have some defined tasks in many projects than I reuse to debug some workflows.</p>
<blockquote>
<p>I know that we &#34;should&#34; be defining the cases that we are debugging in a test, run it and then try to fix the code and then run the tests again but this way works for me so I&#39;m OK with that 🙃</p>
</blockquote>
</div>
</div>
<div id="outline-container-headline-12" class="outline-2">
<h2 id="headline-12">
Working with local third party libraries
</h2>
<div id="outline-text-headline-12" class="outline-text-2">
<p>
In some cases we could found some weird behaviour, a bug of just want to know a little more deep about how a third party library works. In that case it could be difficult to setup a local version of a library that we use in our project.</p>
<p>
I remember using just <code class="verbatim">pip install -e path_to_library</code> in python and just starting to changing the library code.</p>
<p>
In elixir when we want to install a local version of a library we can specify the path of it in the <code class="verbatim">mix.exs</code> file, for example:</p>
<div class="src src-elixir">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-elixir" data-lang="elixir"><span style="color:#66d9ef">defmodule</span> <span style="color:#a6e22e">MyApp.MixProject</span> <span style="color:#66d9ef">do</span>
  <span style="color:#f92672">use</span> <span style="color:#a6e22e">Mix.Project</span>

  <span style="color:#66d9ef">def</span> project() <span style="color:#66d9ef">do</span>
    [
      <span style="color:#e6db74">app</span>: <span style="color:#e6db74">:my_app</span>,
      <span style="color:#e6db74">version</span>: <span style="color:#e6db74">&#34;0.0.1&#34;</span>,
      <span style="color:#e6db74">elixir</span>: <span style="color:#e6db74">&#34;~&gt; 1.0&#34;</span>,
      <span style="color:#e6db74">deps</span>: deps(),
    ]
  <span style="color:#66d9ef">end</span>

  <span style="color:#66d9ef">def</span> application() <span style="color:#66d9ef">do</span>
    []
  <span style="color:#66d9ef">end</span>

  <span style="color:#66d9ef">defp</span> deps() <span style="color:#66d9ef">do</span>
    [
      {<span style="color:#e6db74">:ecto</span>, <span style="color:#e6db74">&#34;~&gt; 2.0&#34;</span>},
      {<span style="color:#e6db74">:postgrex</span>, <span style="color:#e6db74">&#34;~&gt; 0.8.1&#34;</span>},
      {<span style="color:#e6db74">:ecto_sql</span>, <span style="color:#e6db74">path</span>: <span style="color:#e6db74">&#34;ecto_sql_local_path&#34;</span>}
    ]
  <span style="color:#66d9ef">end</span>
<span style="color:#66d9ef">end</span></code></pre></div>
</div>
<p>
In this case we&#39;re telling our project to install <code class="verbatim">ecto_sql</code> from the given <code class="verbatim">path</code>, this will work but just the first time because it will load and compile <code class="verbatim">ecto_sql</code> at the beginning and then when we&#39;re making some changes in the code placed in <code class="verbatim">ecto_sql_local_path</code> these changes won&#39;t be recompiled automatically because <code class="verbatim">mix</code> is only watching for changes inside our project. In this case we can force to recompile some modules by using for example <code class="verbatim">r Ecto.Migrator</code> from within an <code class="verbatim">iex</code> session but if we are modifying more modules it would be tedious to recompile manually every one of them, for this case we can define a <code class="verbatim">Recompiler</code> module that make this work for us, name it as you want, this will contains:</p>
<div class="src src-elixir">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-elixir" data-lang="elixir"><span style="color:#66d9ef">defmodule</span> <span style="color:#a6e22e">Recompiler</span> <span style="color:#66d9ef">do</span>
  <span style="color:#66d9ef">def</span> run <span style="color:#66d9ef">do</span>
    modules_to_recompile <span style="color:#f92672">=</span> [
      <span style="color:#a6e22e">Ecto.Migrator</span>,
      <span style="color:#a6e22e">Ecto.SomeOtherModule</span>
    ]

    <span style="color:#66d9ef">for</span> module <span style="color:#f92672">&lt;-</span> modules_to_recompile <span style="color:#66d9ef">do</span>
      <span style="color:#a6e22e">IEx.Helpers</span><span style="color:#f92672">.</span>r(module)
    <span style="color:#66d9ef">end</span>
  <span style="color:#66d9ef">end</span>
<span style="color:#66d9ef">end</span></code></pre></div>
</div>
<p>
We can place this module somewhere inside our <code class="verbatim">lib</code> folder and when we call <code class="verbatim">Recompiler.run</code> from within a <code class="verbatim">iex</code> session it will recompile all the defined modules.</p>
</div>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Activate python virtualenv automatically with direnv</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">01 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        direnv is a tool to set up automatically environment variables as soon as we enter in a directory that contains a .envrc file. We can use this feature to activate our virtualenvs as well.
 Let&#39;s see what happens when we activate manually a virtualenv with source ./env/bin/activate:
  A new new environment variable called VIRTUAL_ENV is exported.
  The path is updated to include the bin directory inside our virtualenv this is made to allow us to point to the correct python installation and run cli interfaces exposed by the dependencies we have installed.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Activate python virtualenv automatically with direnv</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">01 03 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>
<a href="https://direnv.net">direnv</a> is a tool to set up automatically environment variables as soon as we enter in a directory that contains a <code class="verbatim">.envrc</code> file. We can use this feature to activate our virtualenvs as well.</p>
<p>
Let&#39;s see what happens when we activate manually a virtualenv with <code class="verbatim">source ./env/bin/activate</code>:</p>
<ul>
<li>
<p>A new new environment variable called <code class="verbatim">VIRTUAL_ENV</code> is exported.</p>
</li>
<li>
<p>The path is updated to include the <code class="verbatim">bin</code> directory inside our <code class="verbatim">virtualenv</code> this is made to allow us to point to the correct python installation and run cli interfaces exposed by the dependencies we have installed.</p>
</li>
</ul>
<p>Because all the &#34;magic&#34; about activating a <code class="verbatim">virtualenv</code> is basically configuring some environment variables we can do it automatically using <code class="verbatim">direnv</code>.</p>
<p>
Let&#39;s assume we have a <code class="verbatim">virtualenv</code> installed in the path <code class="verbatim">/Users/erick/.virtualenvs/demo</code>, the <code class="verbatim">virtualenv</code> is located inside <code class="verbatim">~/.environments</code> because I&#39;m using <code class="verbatim">virtualenvwrapper</code> but it can be in any other location. Now we can use this location to configure our <code class="verbatim">.envrc</code> file as the following:</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">export VIRTUAL_ENV<span style="color:#f92672">=</span>/Users/erick/.virtualenvs/demo
export PATH<span style="color:#f92672">=</span>/Users/erick/.virtualenvs/demo/bin:$PATH</code></pre></div>
</div>
<p>
Now when we enter our project folder the virtualenv will be &#34;activated&#34; automatically and when we leave the project folder it will be &#34;deactivated&#34;.</p>
<p>
Also when we use this method is easiest for our editor(emacs in my case) to recognize the current python installation and be able to run tests, execute files, etc.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">January 2021 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">28 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Read more updates from Clj-kondo/babashka/sci, ClojisR, O’Doyle Rules, and Calva
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">December 2020 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">28 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Read more updates from Clj-kondo/babashka/sci, ClojisR, O’Doyle Rules, and Calva
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Find file under cursor in emacs</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">27 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        #TIL you can use gf to open a file under the current cursor position in VIM, I was reading this post I found in Hacker News and I was wondering if evil-mode has this functionality as well
 evil-mode has this key binding defined and it uses (find-file-at-point), it works well for absolute paths but not for relative paths and I wanted to use it for a path like this templates/home.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Front-end insatisfecho es mi profesión">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Front-end insatisfecho es mi profesión</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">27 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>La velocidad de los cambios en el ámbito del front-end, ha generado una sensación de hastío o insatisfacción entre los profesionales del diseño web. No son pocos los profesionales que<strong> expresan su descontento con la complejidad o la sobre ingeniería </strong>que ha sufrido la capa de presentación de los sitios web. En este episodio nos hacemos eco de este sentimiento, a través de otro acertado <a href="https://css-tricks.com/front-end-dissatisfaction-and-backing-off/" data-type="URL" data-id="https://css-tricks.com/front-end-dissatisfaction-and-backing-off/">artículo de Chris Coyier titulado Front-End Dissatisfaction (and Backing&#160;Off),</a> que a su vez hace referencia a otros artículos similares.</p>



<p>Muchos profesionales ven con escepticismo las ventajas de aplicar las últimas tecnologías a su stack de herramientas. A fin de cuentas, como se explica <strong>la web sigue funcionando con HTML y CSS,</strong> y la progresiva incorporación de frameworks y otras herramientas, diluye la sencillez del medio.  Existe una presión en ocasiones infundada, por estar al día en las últimas tendencias, a menudo también <strong>debido al temor de no quedarse atrás en la carrera o mercado profesional.</strong> En el episodio comentamos este artículo sobre la evolución del front-end y nuestra opinión acerca de cómo afrontar tanto cambio.</p>



<p>En la segunda parte del episodio volvemos (min 36:30) con la <strong>sección Backlog,</strong> donde contamos recientes experiencias relacionadas con nuestro trabajo. Hablamos sobre una aplicación de citas que le solicitaron desarrollar a Andros y también de lo poco profesional que resulta dejar textos «lorem ipsum» en una web publicada.</p>



<p>Por último vuelve también (min 50:43) la <strong>sección Radar</strong> al podcast con algunos enlaces de recursos y herramientas  de interés, relacionadas con el desarrollo web.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">My Home Office</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">27 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The COVID-19 pandemic transformed the workplace for many people during 2020, closing offices and forcing millions to work from home. The figures don&rsquo;t lie: in April 2020, almost half of the workforce in the UK worked from home.
Personally, I have been enjoying the benefits of home working since 2014, although I am fortunate to have a separate room in which to call my &lsquo;office&rsquo;, and so it is easier to maintain a healthy work/life balance, and I can shut the door to drown out the noise from the rest of the household.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">My Home Office</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">27 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The COVID-19 pandemic transformed the workplace for many people during 2020, closing offices and forcing millions to work from home. The figures don&rsquo;t lie: in April 2020, almost half of the workforce in the UK worked from home.
Personally, I have been enjoying the benefits of home working since 2014, although I am fortunate to have a separate room in which to call my &lsquo;office&rsquo;, and so it is easier to maintain a healthy work/life balance, and I can shut the door to drown out the noise from the rest of the household.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">DuckDuckGo logo redesign</h1>
                            <h2 class="article__feed"><a target="_blank" href="">tonsky.me</a> <span class="article__date">26 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">CSS: @media para detectar dispositivo táctil</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Bufa</a> <span class="article__date">24 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Podemos usar la regla @media con pointer: coarse de css para detectar dispositivos con pantallas táctiles como pueden ser tablets o smartphones y en ese caso aplicar los estilos que necesitemos dentro. Un ejemplo: @media (pointer: coarse) { /* tus [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Embracing modern image formats</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">24 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        While the weight of our JS bundles is super important, it's not the only factor when it comes to page load time! Images are often several times bigger than our bundles, and they can have a horrible impact on the experience. In this article, we'll see how to use next-gen image formats like Webp in a friendly, backwards-compatible way.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Macs and 4K 120Hz displays compatibility list</h1>
                            <h2 class="article__feed"><a target="_blank" href="">tonsky.me</a> <span class="article__date">24 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
          Macs/4K 120Hz displays compatibility list
        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2021/206-time-to-merge.png" alt="Time To Merge">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Time To Merge</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">23 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2021/206-time-to-merge.png" alt="Time To Merge" title="At least there is a branch where the bug is fixed" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://javierarcheni.com/wp-content/uploads/2021/04/cropped-favicon-javierarcheni-32x32.png" alt="Eleventy es mucho más que un generador de sitios web estáticos">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Eleventy es mucho más que un generador de sitios web estáticos</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Javier Archeni</a> <span class="article__date">22 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Para algunas personas los generadores de sitios estáticos son la forma natural de crear un sitio web. La idea principal es la simplicidad y la escasez de mantenimiento. Si tienes un sitio web que va a cambiar poco o va a seguir una estructura muy básica en su contenido, son una solución ideal. Admitamos que &#8230; <a href="https://javierarcheni.com/blog/eleventy-mucho-mas-generador-estatico/">Ver más</a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Aprendiendo Rust con Lorenzo Carbonell (Atareao)">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Aprendiendo Rust con Lorenzo Carbonell (Atareao)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">21 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Rust es un lenguaje de programación de sistemas orientado a crear aplicaciones de alto rendimiento. Las principales ventajas de Rust <strong>son su enfoque en la velocidad, su entorno seguro de ejecución en memoria y la concurrencia. </strong>Usado por las principales empresas de tecnología como Google, Mozilla, Dropbox o Microsoft, Rust sigue apareciendo año tras año entre los lenguajes más apreciados por la comunidad de desarrollo.</p>



<p>Rust ha dado origen a un montón de proyectos innovadores que van desde sistemas operativos, motores para juegos, controladores y bases de datos. Rust soporta WebAssembly, un entorno de ejecución que permite desplegar aplicaciones nativas en el navegador sin necesidad de JavaScript, por cierto creado también en Mozilla. WebAssembly permite compilar y desplegar tus proyectos Rust a servidores, dispositivos IoT, móviles y al navegador.</p>



<p>Aunque Rust sea visto como un lenguaje de sistemas más situado en reemplazar a C y C++, en ámbitos como sistemas operativos o librerías nativas, muchos desarrolladores de Rust están trabajando en gran medida en backends para la <strong>creación de aplicaciones web. </strong>No es por tanto extraño que frameworks web como <a href="https://hyper.rs/" data-type="URL" data-id="https://hyper.rs/">Hyper,</a> <a href="https://actix.rs/" data-type="URL" data-id="https://actix.rs/">Actix </a>y <a href="https://rocket.rs/" data-type="URL" data-id="https://rocket.rs/">Rocket </a>se encuentren entre los proyectos más populares entre los desarrolladores de Rust.</p>



<p>Para este episodio invitamos a <strong>Lorenzo Carbonell,</strong> más conocido por la comunidad como Atareao. Lorenzo es un gran divulgador de las tecnologías de código abierto y especialista en GNU/Linux y Android. A través de su web <a href="http://atareao.es/">atareao.es</a> y su podcast, Lorenzo comparte valiosa información sobre infinidad de tecnología y también sus proyectos. Precisamente no hace mucho, <a href="https://www.atareao.es/podcast/objetivo-rust/" data-type="URL" data-id="https://www.atareao.es/podcast/objetivo-rust/">Lorenzo contaba que había decidido aprender Rust,</a> así que nos ofrece una gran excusa para invitarlo al programa para hablar sobre este lenguaje.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The styled-components Happy Path</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">21 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        styled-components is a wonderfully powerful styling library for React, and over the years I've learned a lot about how to use it effectively. This article shares my personal “best practices”.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Basis Universal Textures - Khronos Ratification and &lt;model-viewer&gt; Support</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">18 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://i.ytimg.com/vi/9TLw4Ri2lK8/hqdefault.jpg" alt="Fractals in WebAssembly, Async Iteration for Node.js Streams, TDD, Scroll to Text Fragment, and Immutable code 🥺  — Pony Foo Weekly">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Fractals in WebAssembly, Async Iteration for Node.js Streams, TDD, Scroll to Text Fragment, and Immutable code 🥺  — Pony Foo Weekly</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Pony Foo Weekly</a> <span class="article__date">18 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="f-core"><div class="md-markdown"></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://2ality.com/2019/11/nodejs-streams-async-iteration.html?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-195" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Node.js streams via Async Iteration</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/deep-dive" style="color:#f7f0f5;background-color:#900070" class="wy-link-tag">Deep Dive</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Working with Node.js streams is much more pleasant if we use asynchronous iteration. Axel shows how to do just that.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/rauschma?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-195" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Axel Rauschmayer</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://www.youtube.com/watch?v=9TLw4Ri2lK8&#38;utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-195" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>A WebAssembly tutorial with fractals</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/webassembly" class="wy-link-tag">webassembly</a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Learn how to port an interactive fractals app to the web by compiling it from C to WebAssembly.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/RobAboukhalil?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-195" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Robert Aboukhalil</p> </a></div></td><td class="wy-td wy-link-cell-image"><a href="https://www.youtube.com/watch?v=9TLw4Ri2lK8&#38;utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-195" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://i.ytimg.com/vi/9TLw4Ri2lK8/hqdefault.jpg" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-primary"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://tinyurl.com/yxcbnnvw?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-195" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>How to measure and improve Node.js performance</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/node.js" class="wy-link-tag">node.js</a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>If JavaScript is so fast, why are so many Node.js applications slow? I&#x2019;ll show how we can profile a Node app using both the built-in profiler and Raygun.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/raygunio?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-195" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Raygun</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/sponsored" class="wy-link-tag wy-link-sponsor">Sponsored</a></div></td><td class="wy-td wy-link-cell-image"><a href="https://tinyurl.com/yxcbnnvw?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-195" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://raygun.com/blog/images/measure-node-performance/feature.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://blog.sapegin.me/all/avoid-mutation/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-195" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Washing your code: avoid mutation</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/best-practices" style="color:#900070;background-color:#ffe270" class="wy-link-tag">Best Practices</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Mutations happen when we change a JavaScript object or array without creating a new variable or reassigning an existing one. Mutations make code harder to understand and can lead to hard-to-find bugs.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/iamsapegin?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-195" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Artem Sapegin</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://mgearon.com/html/text-fragments/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-195" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Scroll to text fragment</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/news" style="color:#1bc211;background-color:#e4f9e3" class="wy-link-tag">News</a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>How to use text fragments to highlight part of a web page when you link to it without using the ID HTML tag. A quick way to grab the users attention.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/michaelgearon?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-195" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Michael Gearon</p> </a></div></td><td class="wy-td wy-link-cell-image"><a href="https://mgearon.com/html/text-fragments/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-195" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://mgearon.com/wp-content/uploads/2020/07/text-fragments-start-and-end.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://frosinastamatoska.medium.com/10-rules-of-front-end-tdd-to-abide-by-f48987dc2ffc?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-195" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Front-end TDD rules to abide by</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/deep-dive" style="color:#f7f0f5;background-color:#900070" class="wy-link-tag">Deep Dive</a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>It has been one year since I&#x2019;ve joined my current team. It is a team consisting of three members, me and two other backend developers.</p> </div></div><div class="wy-link-source-section"><a href="https://github.com/FrosinaS?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-195" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Frosina Stamatoska</p> </a></div></td><td class="wy-td wy-link-cell-image"><a href="https://frosinastamatoska.medium.com/10-rules-of-front-end-tdd-to-abide-by-f48987dc2ffc?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-195" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://miro.medium.com/max/789/1*vZcY9vv64smudvYVDhKwmQ.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div></div><style>html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;position:relative;vertical-align:baseline}sup{top:-.5em}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto;resize:vertical;min-height:280px;max-height:900px}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item;margin:-10px -20px;padding:10px;background-color:#f6f6f6;cursor:pointer;border-bottom:2px solid #ddd}[hidden],template{display:none}body,body:after,body:before,html,html:after,html:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*,:after,:before{-webkit-box-sizing:inherit;-moz-box-sizing:inherit;box-sizing:inherit}@-moz-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-webkit-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-o-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-moz-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@-webkit-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@-o-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}.f-core{font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}.f-mono{font-family:Consolas,Menlo,Monaco,'Lucida Console','Liberation Mono','DejaVu Sans Mono','Bitstream Vera Sans Mono','Courier New',monospace,serif}.ly-custom-heading .f-heading,.ly-custom-heading h1,.ly-custom-heading h2,.ly-custom-heading h3,.ly-custom-heading h4,.ly-custom-heading h5,.ly-custom-heading h6,.ly-lean .f-heading,.ly-lean h1,.ly-lean h2,.ly-lean h3,.ly-lean h4,.ly-lean h5,.ly-lean h6{font-family:Neuton,'Hoefler Text',Palatino,Baskerville,Georgia,'Times New Roman',serif}.ly-custom-subheading .f-subheading,.ly-lean .f-subheading{font-family:Merriweather,Georgia,serif}body{margin:0;font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif;background:#fcfcfc;color:#333}img{max-width:100%;border:none}.md-markdown figure:not(.twitter-tweet-figure){background-color:#f6f6f6}.md-markdown figure:not(.twitter-tweet-figure)>a{display:block}.md-markdown figure:not(.twitter-tweet-figure)>a>img,.md-markdown figure:not(.twitter-tweet-figure)>img{display:block;margin-left:auto;margin-right:auto}.md-markdown figcaption{padding:10px;font-style:italic;font-size:14px;background:-webkit-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-moz-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-o-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-ms-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:linear-gradient(to right,#fff9e2 33%,#fcf9ee 100%);color:#555}.md-markdown .figure-has-loaded{background:-webkit-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-moz-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-o-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-ms-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:linear-gradient(to bottom,rgba(255,255,255,0) 0,#fcf9ee 100%)}b,em,font-style italic,font-weight bold,i,ins,strong{text-decoration:none}del{text-decoration:line-through}sub,sup{bottom:0;line-height:18px}button,input{overflow:visible;border-radius:0}button{border:none;padding:6px 8px;font-size:1.2em;background:0 0}button[disabled]{color:#cbccbc!important}input,select,textarea{display:block;width:100%;padding:10px 8px;line-height:18px;border:none;font:inherit}select{height:38px}ol,ul{padding:0;margin:0;list-style-position:inside}li>ol,li>ul{margin-left:20px}hr{border:none;border-top:5px solid rgba(0,0,0,.05);margin:20px 0}kbd{display:inline-block;border:1px solid #ccc;margin:0 .1em;padding:.1em .6em;line-height:1.4;font-size:11px;background-color:#f7f7f7;-webkit-box-shadow:0 1px 0 #bbb,0 0 0 2px #fff inset;box-shadow:0 1px 0 #bbb,0 0 0 2px #fff inset;border-radius:3px;color:#333;text-shadow:0 1px 0 #fff;white-space:nowrap}iframe{display:inline-block;border:none;max-width:100%}summary:hover{opacity:.8}details{padding:10px 20px 20px;border-bottom:2px dashed #ddd}details[open] summary{margin-bottom:20px}blockquote{border:none;margin:0!important}ol,p,ul{line-height:35px}p{margin:35px 0}@media only screen and (min-width:768px){ol,p,ul{line-height:30px}}a,button,input[type=submit]{cursor:pointer;text-decoration:none}.lk-link{color:#e92c6c;border-bottom:1px solid transparent;background-color:rgba(255,255,255,.04)}.lk-link .md-code-inline{position:relative}.lk-link .md-code-inline:only-child{display:inline-block;line-height:17px}.lk-link .md-code-inline:before{content:'';position:absolute;background-color:#f1e05a;top:0;left:0;right:0;bottom:0;opacity:.04}.lk-link:visited{background-color:rgba(233,44,108,.04)}.lk-link:visited .md-code-inline:before{background-color:#e92c6c}.lk-link:hover{border-bottom:1px solid #e92c6c}.lk-rainbows{position:relative;color:#333;margin-bottom:5px}.lk-rainbows:hover:before{position:absolute;content:'';left:0;right:0;bottom:-8px;height:3px;opacity:.8;-webkit-transition:.1s ease-in-out;-moz-transition:.1s ease-in-out;-o-transition:.1s ease-in-out;-ms-transition:all .1s ease-in-out;transition:.1s ease-in-out;-webkit-animation:.5s infinite bg-rainbow;-moz-animation:.5s infinite bg-rainbow;-o-animation:.5s infinite bg-rainbow;-ms-animation:bg-rainbow .5s infinite;animation:.5s infinite bg-rainbow}.lk-icon{color:#333}.lk-icon:hover{color:#e92c6c}.lk-visitor{color:#333}.lk-visitor:after{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-left:5px}.lk-visitor.lk-visitor-large:after{font-size:1em}.lk-visitor:hover:after{color:#333;border-bottom-style:solid}.lk-visitor:visited:after{color:#7d5cff}.lk-visitor-inside{color:#333}.lk-visitor-inside .lk-visitor-target:before{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-right:5px}.lk-visitor-inside.lk-visitor-large .lk-visitor-target:before{font-size:1em}.lk-visitor-inside:hover .lk-visitor-target:before{color:#333;border-bottom-style:solid}.lk-visitor-inside:visited .lk-visitor-target:before{color:#7d5cff}.lk-visitor-before{color:#333}.lk-visitor-before:before{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-right:5px}.lk-visitor-before.lk-visitor-large:before{font-size:1em}.lk-visitor-before:hover:before{color:#333;border-bottom-style:solid}.lk-visitor-before:visited:before{color:#7d5cff}.lk-visitor-before-no-underline:before{border-bottom-width:0}.lk-link-to-green{color:#cbccbc}.lk-link-to-green:visited,.lk-link-to-green:visited:before{color:#1bc211;background-color:#1bc211}.lk-link-to-green:active{outline-color:#1bc211}.lk-link-to-green:hover,.lk-link-to-green:hover:before{color:#8be186;border-bottom-color:#1bc211}.lk-green .lk-link,a.lk-green{color:#1bc211}.lk-green .lk-link:visited,a.lk-green:visited{background-color:rgba(27,194,17,.04)}.lk-green .lk-link:visited .md-code-inline:before,a.lk-green:visited .md-code-inline:before{background-color:#1bc211}.lk-green .lk-link:active,a.lk-green:active{outline-color:#1bc211}.lk-green .lk-link:hover,a.lk-green:hover{border-bottom-color:#1bc211}.lk-green.lk-icon:hover{color:#1bc211}.lk-pink-light .lk-link,a.lk-pink-light{color:#ea6c93}.lk-pink-light .lk-link:visited,a.lk-pink-light:visited{background-color:rgba(234,108,147,.04)}.lk-pink-light .lk-link:visited .md-code-inline:before,a.lk-pink-light:visited .md-code-inline:before{background-color:#ea6c93}.lk-pink-light .lk-link:active,a.lk-pink-light:active{outline-color:#ea6c93}.lk-pink-light .lk-link:hover,a.lk-pink-light:hover{border-bottom-color:#ea6c93}.lk-pink-light.lk-icon:hover{color:#ea6c93}.lk-black .lk-link,a.lk-black{color:#333}.lk-black .lk-link:visited,a.lk-black:visited{background-color:rgba(51,51,51,.04)}.lk-black .lk-link:visited .md-code-inline:before,a.lk-black:visited .md-code-inline:before{background-color:#333}.lk-black .lk-link:active,a.lk-black:active{outline-color:#333}.lk-black .lk-link:hover,a.lk-black:hover{border-bottom-color:#333}.lk-black.lk-icon:hover{color:#333}.lk-gray .lk-link,a.lk-gray{color:#999}.lk-gray .lk-link:visited,a.lk-gray:visited{background-color:rgba(153,153,153,.04)}.lk-gray .lk-link:visited .md-code-inline:before,a.lk-gray:visited .md-code-inline:before{background-color:#999}.lk-gray .lk-link:active,a.lk-gray:active{outline-color:#999}.lk-gray .lk-link:hover,a.lk-gray:hover{border-bottom-color:#999}.lk-gray.lk-icon:hover{color:#999}.lk-white .lk-link,a.lk-white{color:#fcfcfc}.lk-white .lk-link:visited,a.lk-white:visited{background-color:rgba(252,252,252,.04)}.lk-white .lk-link:visited .md-code-inline:before,a.lk-white:visited .md-code-inline:before{background-color:#fcfcfc}.lk-white .lk-link:active,a.lk-white:active{outline-color:#fcfcfc}.lk-white .lk-link:hover,a.lk-white:hover{border-bottom-color:#fcfcfc}.lk-white.lk-icon:hover{color:#fcfcfc}.lk-orange .lk-link,a.lk-orange{color:#f3720d}.lk-orange .lk-link:visited,a.lk-orange:visited{background-color:rgba(243,114,13,.04)}.lk-orange .lk-link:visited .md-code-inline:before,a.lk-orange:visited .md-code-inline:before{background-color:#f3720d}.lk-orange .lk-link:active,a.lk-orange:active{outline-color:#f3720d}.lk-orange .lk-link:hover,a.lk-orange:hover{border-bottom-color:#f3720d}.lk-orange.lk-icon:hover{color:#f3720d}.lk-lilly .lk-link,a.lk-lilly{color:#7d5cff}.lk-lilly .lk-link:visited,a.lk-lilly:visited{background-color:rgba(125,92,255,.04)}.lk-lilly .lk-link:visited .md-code-inline:before,a.lk-lilly:visited .md-code-inline:before{background-color:#7d5cff}.lk-lilly .lk-link:active,a.lk-lilly:active{outline-color:#7d5cff}.lk-lilly .lk-link:hover,a.lk-lilly:hover{border-bottom-color:#7d5cff}.lk-lilly.lk-icon:hover{color:#7d5cff}.lk-blue .lk-link,a.lk-blue{color:#1a4d7f}.lk-blue .lk-link:visited,a.lk-blue:visited{background-color:rgba(26,77,127,.04)}.lk-blue .lk-link:visited .md-code-inline:before,a.lk-blue:visited .md-code-inline:before{background-color:#1a4d7f}.lk-blue .lk-link:active,a.lk-blue:active{outline-color:#1a4d7f}.lk-blue .lk-link:hover,a.lk-blue:hover{border-bottom-color:#1a4d7f}.lk-blue.lk-icon:hover{color:#1a4d7f}.lk-inherited .lk-link,a.lk-inherited{color:inherit}.lk-inherited .lk-link:active,a.lk-inherited:active{outline-color:inherit}.lk-inherited .lk-link:hover,a.lk-inherited:hover{border-bottom-color:inherit}.lk-inherited.lk-icon:hover{color:inherit}.lk-twitter .lk-link,a.lk-twitter{color:#55acee}.lk-twitter .lk-link:visited,a.lk-twitter:visited{background-color:rgba(85,172,238,.04)}.lk-twitter .lk-link:visited .md-code-inline:before,a.lk-twitter:visited .md-code-inline:before{background-color:#55acee}.lk-twitter .lk-link:active,a.lk-twitter:active{outline-color:#55acee}.lk-twitter .lk-link:hover,a.lk-twitter:hover{border-bottom-color:#55acee}.lk-twitter.lk-icon:hover{color:#55acee}.lk-facebook .lk-link,a.lk-facebook{color:#3b5998}.lk-facebook .lk-link:visited,a.lk-facebook:visited{background-color:rgba(59,89,152,.04)}.lk-facebook .lk-link:visited .md-code-inline:before,a.lk-facebook:visited .md-code-inline:before{background-color:#3b5998}.lk-facebook .lk-link:active,a.lk-facebook:active{outline-color:#3b5998}.lk-facebook .lk-link:hover,a.lk-facebook:hover{border-bottom-color:#3b5998}.lk-facebook.lk-icon:hover{color:#3b5998}.lk-clean{background-color:transparent}.lk-chrome:hover{color:#4989f4}.lk-teal .lk-link,a.lk-teal{color:#00a19c}.lk-teal .lk-link:visited,a.lk-teal:visited{background-color:rgba(0,161,156,.04)}.lk-teal .lk-link:visited .md-code-inline:before,a.lk-teal:visited .md-code-inline:before{background-color:#00a19c}.lk-teal .lk-link:active,a.lk-teal:active{outline-color:#00a19c}.lk-teal .lk-link:hover,a.lk-teal:hover{border-bottom-color:#00a19c}.lk-teal.lk-icon:hover{color:#00a19c}table{width:100%;border-spacing:0;border-collapse:separate}td,th{padding:8px}@media only screen and (max-width:950px){.table-responsive{display:block}.table-responsive>thead{display:none}.table-responsive>tbody,.table-responsive>tfoot{display:block}.table-responsive>tbody>tr,.table-responsive>tfoot>tr{display:block;background-color:rgba(203,204,188,.1);margin-bottom:30px}.table-responsive>tbody>tr:nth-child(even),.table-responsive>tfoot>tr:nth-child(even){background-color:rgba(203,204,188,.15)}.table-responsive>tbody>tr:last-child,.table-responsive>tfoot>tr:last-child{margin-bottom:0}.table-responsive>tbody>tr>td,.table-responsive>tfoot>tr>td{display:block;text-align:left}.table-responsive>tbody>tr>td:before,.table-responsive>tfoot>tr>td:before{display:block;content:attr(data-label);color:#555;font-size:13px;margin:0 0 5px}.table-responsive .table-responsive-hide{display:none}}.c-oreilly-teal{color:#00a19c}.c-yellow-highlight{color:#ffe270}.c-dark-orange{color:#f3720d}.c-pink{color:#e92c6c}.c-purple{color:#900070}.c-blue{color:#1a4d7f}.c-dark-turquoise{color:#1686a2}.c-dark-green{color:#1bc211}.c-white{color:#fcfcfc}.c-gray{color:#b7b7b7}.c-lilly{color:#7d5cff}.c-teal{color:#3aca96}.c-bg-oreilly-teal{background-color:#00a19c}.c-bg-yellow-highlight{background-color:#ffe270}.c-bg-dark-orange{background-color:#f3720d}.c-bg-pink{background-color:#e92c6c}.c-bg-purple{background-color:#900070}.c-bg-blue{background-color:#1a4d7f}.c-bg-dark-turquoise{background-color:#1686a2}.c-bg-dark-green{background-color:#1bc211}.c-bg-white{background-color:#fcfcfc}.c-bg-gray{background-color:#b7b7b7}.c-bg-lilly{background-color:#7d5cff}.c-bg-teal{background-color:#3aca96}.tj-emoji{width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em}.dc-header{margin-bottom:60px}.dc-heading{text-align:center;font-size:4em;padding:0 10px;margin-top:0;margin-bottom:10px}.dc-role{line-height:26px;padding:0 20px;margin-top:10px;text-align:center;font-style:italic;color:#cbccbc}.dc-colored{background:#f6f6f6;border-top:9px solid rgba(125,92,255,.5)}.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:800px}.md-markdown blockquote:not(.twitter-tweet){margin:0;padding:20px 0;border:none;border-top:5px solid rgba(0,0,0,.05);border-bottom:5px solid rgba(0,0,0,.05)}.md-markdown blockquote:not(.twitter-tweet) h1,.md-markdown blockquote:not(.twitter-tweet) h2,.md-markdown blockquote:not(.twitter-tweet) h3,.md-markdown blockquote:not(.twitter-tweet) h4,.md-markdown blockquote:not(.twitter-tweet) h5,.md-markdown blockquote:not(.twitter-tweet) h6{margin:-20px 0;padding:20px 0}.md-markdown blockquote:not(.twitter-tweet) .md-code-block{margin:0}.md-markdown blockquote:not(.twitter-tweet) .md-code-block:last-child{margin-bottom:-20px}.md-markdown img:first-child{margin-top:0}.md-markdown img:last-child{margin-bottom:0}.md-markdown p:first-child{margin-top:0}.md-markdown p:last-child{margin-bottom:0}.md-markdown .md-code-block+ol,.md-markdown .md-code-block+ul,.md-markdown ol+.md-code-block,.md-markdown ul+.md-code-block{margin-top:35px}.md-markdown a:not(.md-heading){color:#e92c6c;border-bottom:1px solid transparent;background-color:rgba(255,255,255,.04)}.md-markdown a:not(.md-heading) .md-code-inline{position:relative}.md-markdown a:not(.md-heading) .md-code-inline:only-child{display:inline-block;line-height:17px}.md-markdown a:not(.md-heading) .md-code-inline:before{content:'';position:absolute;background-color:#f1e05a;top:0;left:0;right:0;bottom:0;opacity:.04}.md-markdown a:not(.md-heading):visited{background-color:rgba(233,44,108,.04)}.md-markdown a:not(.md-heading):visited .md-code-inline:before{background-color:#e92c6c}.md-markdown a:not(.md-heading):hover{border-bottom:1px solid #e92c6c}.md-markdown thead{background-color:#e0e0e0}.md-markdown tbody{background-color:#f6f6f6}.md-markdown tbody tr:nth-child(even){background-color:#f9f9f9}.md-markdown h1,.md-markdown h2,.md-markdown h3,.md-markdown h4,.md-markdown h5,.md-markdown h6{padding:10px 0}.md-markdown h1:first-child,.md-markdown h2:first-child,.md-markdown h3:first-child,.md-markdown h4:first-child,.md-markdown h5:first-child,.md-markdown h6:first-child{margin-top:0}.md-markdown h1:last-child,.md-markdown h2:last-child,.md-markdown h3:last-child,.md-markdown h4:last-child,.md-markdown h5:last-child,.md-markdown h6:last-child{margin-bottom:0}.md-markdown iframe{display:block;margin:35px auto}.md-markdown iframe:first-child{margin-top:0}.md-markdown iframe:last-child{margin-bottom:0}.md-markdown li>p:only-child{display:inline}.md-markdown ul{list-style-type:none}.md-markdown ul>li:before{content:'◯';margin-right:5px}.md-heading{color:inherit}.md-markdown-inline{display:inline}.md-markdown-inline p{display:inline;line-height:initial}.md-code-block,.ocha-highlighted{margin:0 -20px}.ocha-code-block{padding:18px 50px}.md-markdown:not(.mm-content-html) .md-code-block+blockquote{max-width:inherit!important;margin:0 -20px;padding-left:20px;padding-right:20px}.md-code-block .md-code{display:block}.md-markdown-summary p{margin:10px 0}@media only screen and (min-width:768px){.md-markdown h1,.md-markdown h2,.md-markdown h3,.md-markdown h4,.md-markdown h5,.md-markdown h6{margin-left:-40px;margin-right:-40px;padding:10px 40px}.md-code-block,.ocha-highlighted{margin:0 -40px}.md-markdown:not(.mm-content-html) .md-code-block+blockquote{margin:0 -40px;padding-left:40px;padding-right:40px}}@media only screen and (min-width:1300px){.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:900px}}@media only screen and (min-width:1400px){.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:1000px}.md-code-block,.md-markdown:not(.mm-content-html) .md-code-block+blockquote,.ocha-highlighted{margin:0 -400px 0 -40px}}.md-markdown-large blockquote,.md-markdown-large code,.md-markdown-large ol,.md-markdown-large p,.md-markdown-large table,.md-markdown-large ul{max-width:inherit}.md-footnotes{margin-top:80px;padding:20px 0;border-top:1px dashed #cbccbc}.md-footnote{margin:0;padding:8px 0;font-size:14px;display:-webkit-box;display:-moz-box;display:-webkit-flex;display:-ms-flexbox;display:box;display:flex;-webkit-box-align:center;-moz-box-align:center;-o-box-align:center;-ms-flex-align:center;-webkit-align-items:center;align-items:center}.md-footnote p{line-height:16px}.md-footnote-anchor{padding:2px 6px;margin-right:10px;text-align:center;font-weight:700;color:#e92c6c}.ly-custom-subheading .md-footnote-anchor,.ly-lean .md-footnote-anchor{font-family:Merriweather,Georgia,serif}.md-markdown a.md-footnote-anchor{border:1px solid #e92c6c}.md-markdown a.md-footnote-anchor:hover{background-color:#e92c6c;color:#fcfcfc}.md-footnote-ref{margin-left:1px;margin-right:3px}.md-markdown a.md-footnote-ref{border-bottom:1px dotted}.md-code-block,.md-code-inline{-webkit-text-size-adjust:none;-ms-text-size-adjust:none;text-size-adjust:none;background:#fcfcf5;color:#4d4d4c}.md-code-block{line-height:24px}.md-code{padding:8px 10px}.md-code-inline{padding:0 6px}a .md-code{color:inherit}.md-code-comment{color:#8e908c}.md-code-attribute,.md-code-built_in,.md-code-constant,.md-code-literal,.md-code-number,.md-code-params,.md-code-pragma,.md-code-preprocessor,.md-code-regexp,.md-code-tag,.md-code-variable,.md-lang-css .md-code-class,.md-lang-css .md-code-id,.md-lang-css .md-code-pseudo,.md-lang-html .md-code-doctype,.md-lang-ruby .md-code-constant,.md-lang-xml .md-code-doctype,.md-lang-xml .md-code-pi,.md-lang-xml .md-code-tag .md-code-title,color #c82829{color:#f5871f}.md-lang-css .md-code-rule .md-code-attribute,.md-lang-ruby .md-code-class .md-code-title{color:#eab700}.md-code-header,.md-code-inheritance,.md-code-name,.md-code-string,.md-code-value,.md-lang-ruby .md-code-symbol,.md-lang-xml .md-code-cdata{color:#718c00}.md-code-title,.md-lang-css .md-code-hexcolor{color:#3e999f}.md-code-function,.md-lang-coffeescript .md-code-title,.md-lang-javascript .md-code-title,.md-lang-perl .md-code-sub,.md-lang-python .md-code-decorator,.md-lang-python .md-code-title,.md-lang-ruby .md-code-function .md-code-title,.md-lang-ruby .md-code-title .md-code-keyword{color:#4271ae}.md-code-keyword,.md-lang-javascript .md-code-function{color:#8959a8}.md-lang-coffeescript .md-lang-javascript,.md-lang-javascript .md-lang-xml,.md-lang-tex .md-code-formula,.md-lang-xml .md-code-cdata,.md-lang-xml .md-lang-css,.md-lang-xml .md-lang-javascript,.md-lang-xml .vbscript{opacity:.5}.md-code-deletion{background-color:rgba(244,0,30,.05);color:#f4001e}.md-code-addition{background-color:rgba(27,194,17,.05);color:#1bc211}.md-mark{background-color:rgba(255,226,112,.5);color:inherit}.md-mark span{color:inherit}.md-heading-hover{cursor:pointer;background-color:rgba(22,134,162,.1)}.mde-text-left{text-align:left}.mde-text-center{text-align:center}.mde-text-right{text-align:right}.mde-size-small{font-size:12px}.mde-size-small,.mde-size-small p{line-height:12px}.mde-size-large{font-size:36px}.mde-size-large,.mde-size-large p{line-height:36px}.mde-size-giant{font-size:72px}.mde-size-giant,.mde-size-giant p{line-height:72px}.mde-clearfix:after{content:' ';display:block;visibility:hidden;clear:both;font-size:0;height:0}.mde-quote{margin:0;padding:20px 0;border:none;border-top:5px solid rgba(0,0,0,.05);border-bottom:5px solid rgba(0,0,0,.05)}.mde-core{font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}.mde-mono{font-family:Consolas,Menlo,Monaco,'Lucida Console','Liberation Mono','DejaVu Sans Mono','Bitstream Vera Sans Mono','Courier New',monospace,serif}.ly-custom-heading .mde-heading,.ly-lean .mde-heading{font-family:Neuton,'Hoefler Text',Palatino,Baskerville,Georgia,'Times New Roman',serif}.ly-custom-subheading .mde-subheading,.ly-lean .mde-subheading{font-family:Merriweather,Georgia,serif}.mde-pad-0{padding:0}.mde-pad-5{padding:5px}.mde-pad-10{padding:10px}.mde-pad-15{padding:15px}.mde-pad-20{padding:20px}.mde-pad-25{padding:25px}.mde-pad-30{padding:30px}.mde-pad-50{padding:50px}.mde-mar-0{margin:0}.mde-mar-5{margin:5px}.mde-mar-10{margin:10px}.mde-mar-15{margin:15px}.mde-mar-20{margin:20px}.mde-mar-25{margin:25px}.mde-mar-30{margin:30px}.mde-mar-50{margin:50px}@media only screen and (min-width:900px){.mde-left{float:left}.mde-right{float:right}.mde-inline{display:inline-block;vertical-align:top}.mde-20{max-width:20%}.mde-25{max-width:25%}.mde-33{max-width:33.3333333333%}.mde-50{max-width:50%}.mde-66{max-width:66.6666666666%}.mde-75{max-width:75%}}.twitter-tweet-figure{background:0 0;padding:0}.twitter-tweet-figure:before{content:none}.twitter-tweet-figure .twitter-tweet{margin:0 auto}blockquote.twitter-tweet{overflow:hidden;color:#1c2022;background-color:#fff;border:1px solid #e1e8ed;border-radius:4px;width:500px;max-width:100%;min-width:220px;padding:1.25rem 1.25rem .725rem}blockquote.twitter-tweet:before{content:none}blockquote.twitter-tweet p{white-space:pre-wrap;font:16px/1.4 Helvetica,Roboto,'Segoe UI',Calibri,'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}blockquote.twitter-tweet a,blockquote.twitter-tweet a:visited{color:#2b7bb9}.wy-container{margin:0 auto;padding:20px 0;max-width:800px}.wy-container .md-markdown p{line-height:22px;margin:10px 0}.wy-container .md-markdown p:first-child{margin-top:0}.wy-container .md-markdown p:last-child{margin-bottom:0}.wy-container .md-markdown blockquote:not(.twitter-tweet){padding:10px 0}.wy-container .md-code-block{margin:0;padding:10px;white-space:pre-wrap}.wy-table{width:100%;padding:0}.wy-td{padding:0}.wy-section-link,.wy-section-markdown,.wy-section-poll,.wy-section-summary{padding-top:25px}.wy-section-thanks{margin-top:25px;padding:10px;font-size:15px;background-color:#f2fcf2}.wy-header-text,.wy-issue{display:inline-block;margin:10px 0;line-height:24px}.wy-issue{float:right;font-size:12px}.wy-issue-content{display:block;padding:0 5px;background-color:#fcfcfc}.wy-section-header{padding-top:40px}.wy-section-header h1,.wy-section-header h2,.wy-section-header h3,.wy-section-header h4,.wy-section-header h5,.wy-section-header h6{margin:0}.wy-section-header p{line-height:inherit}.wy-header-td{padding:0}.wy-header-content{margin:0 10px}.wy-header-text{color:#fcfcfc;text-shadow:1px 1px 0 #1a4d7f;font-weight:700;font-size:24px}.wy-content{padding-bottom:25px}.wy-link-addendum,.wy-link-tag,.wy-link-title{display:inline-block;vertical-align:bottom;margin-bottom:10px}.wy-link-title{border-bottom:1px solid;font-size:20px;margin-right:10px}.wy-link-tag{background-color:#1a4d7f;color:#fcfcfc;text-transform:uppercase;font-size:13px;margin-right:5px;padding:2px 4px}.wy-link-tag:last-child{margin-right:0}.wy-link-addendum{color:#999;margin-left:5px}.wy-link-addendum:hover{border-bottom-color:transparent}.wy-link-title-section{position:relative}.wy-link-stats{position:absolute;right:0;background-color:#3aca96;color:#fcfcfc;border-bottom:1px solid #299a71}.wy-link-stats-logo{background-color:rgba(0,0,0,.1);color:#299a71}.wy-link-stat{margin:3px}.wy-link-description{font-size:14px;color:#666}.wy-link-source-section{margin-top:10px}.wy-link-source{margin-right:10px;margin-bottom:10px;display:inline-block;vertical-align:middle;color:#55acee}.wy-link-source-plain{color:#333}.wy-link-source.wy-link-source-plain a{color:#55acee}.wy-link-source.wy-link-source-plain a:visited{background-color:rgba(85,172,238,.04)}.wy-link-source.wy-link-source-plain a:visited .md-code-inline:before{background-color:#55acee}.wy-link-source.wy-link-source-plain a:active{outline-color:#55acee}.wy-link-source.wy-link-source-plain a:hover{border-bottom-color:#55acee}.wy-link-sponsor{background-color:transparent;color:#999;outline:#999 solid 1px}.wy-link-cell-before-image{vertical-align:middle;width:70%}.wy-link-cell-image{padding-left:10px}.wy-link-image-anchor{display:block;overflow:hidden;max-height:300px}.wy-link-image{display:block;margin:0 auto}.wy-footer-table{margin:20px 0}.wy-footer-cell{text-align:center}.wy-read-online{font-size:13px}.wy-section-link-job .wy-link-source,.wy-section-link-job .wy-link-title{font-size:14px}.wy-section-link-job .wy-link-description{font-size:12px}.wy-link-pixel{float:right}@media only screen and (max-width:500px){.wy-issue-publication,.wy-issue-separator{display:none}}.md-code-block{margin:0!important;padding:10px}</style>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A new resource for coordinated vulnerability disclosure in open source projects</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">17 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://nosinmiscookies.com/wp-content/uploads/2019/03/cropped-favicon-32x32.png" alt="Qué es la afinidad en los enlaces y para qué nos sirve en SEO">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Qué es la afinidad en los enlaces y para qué nos sirve en SEO</h1>
                            <h2 class="article__feed"><a target="_blank" href="">No sin mis cookies</a> <span class="article__date">17 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Ante todo, agradecer a Carlos de No sin mis cookies el poder escribir en este blog. Para quien no me conozca, mi nombre es David Ayala y llevo trabajando en el mundo del SEO desde el año 2003. Soy un amante del link building y de los enlaces y por ello hoy he venido a ... <a title="Qué es la afinidad en los enlaces y para qué nos sirve en SEO" class="read-more" href="https://nosinmiscookies.com/afinidad-enlaces-seo/" aria-label="Más en Qué es la afinidad en los enlaces y para qué nos sirve en SEO">Read more</a></p>
<p>The post <a rel="nofollow" href="https://nosinmiscookies.com/afinidad-enlaces-seo/">Qué es la afinidad en los enlaces y para qué nos sirve en SEO</a> appeared first on <a rel="nofollow" href="https://nosinmiscookies.com">No sin mis cookies</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://cdn.evilmartians.com/front/blocks/common/images/social-5e5bfff.png" alt="Serverless TypeScript: A complete setup for AWS SAM Lambdas">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Serverless TypeScript: A complete setup for AWS SAM Lambdas</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Martian Chronicles, Evil Martians’ team blog</a> <span class="article__date">17 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://diarioestoico.com/wp-content/uploads/2020/03/cropped-logo-estoico-footer-150x150-1-32x32.png" alt="IRA, ENFADO Y ESTOICISMO: DOMA EL DRAGÓN">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">IRA, ENFADO Y ESTOICISMO: DOMA EL DRAGÓN</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Diario Estoico</a> <span class="article__date">16 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Entiende el enfado y aprender a gestionar la ira desde la psicología y el estoicismo. En este artículo profundizaremos desde el estoicismo en el por qué somos víctimas de la ira y el enfado, pues es desde la sabiduría que podremos comprender y desde la comprensión que podremos cambiar. Además, la psicología y el estoicismo [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Riding the Struggle Bus that was the Table of Contents</h1>
                            <h2 class="article__feed"><a target="_blank" href="">blog.karenying.com</a> <span class="article__date">16 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        All aboard 🚌 + life update
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2021/205-adoption.png" alt="Adoption">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Adoption</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">16 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2021/205-adoption.png" alt="Adoption" title="from __future__ import braces" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="La salud de internet en el 2020 según Mozilla">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">La salud de internet en el 2020 según Mozilla</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">13 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Vuelve el<a href="https://2020.internethealthreport.org/" data-type="URL" data-id="https://2020.internethealthreport.org/"> Internet Health Report de Mozilla</a> al podcast en su edición 2020. En este episodio hablamos de los puntos principales que se tratan en este último informe de la Fundación Mozilla.  El informe anual compila investigaciones e historias que <strong>buscan sugerir cómo internet podría ser más saludable en todo el mundo.</strong> En su última edición el informe Mozilla apunta como es ineludible, a la pandemia como uno de los factores que ha influido en el uso de internet. En otros puntos, sigue centrado en la necesidad de garantizar un acceso libre y universal a la red, el poder las grandes tecnológicas, los movimientos sociales y la búsqueda de un equilibrio que ayude&#160;a explorar<strong> la doble naturaleza de internet, la saludable y la no saludable.</strong></p>



<p>Como en otras ediciones, se trata de un informe largo, con diferentes fuentes y <a href="https://2020.internethealthreport.org/slideshow-internet-health/#1" data-type="URL" data-id="https://2020.internethealthreport.org/slideshow-internet-health/#1">apoyado con ilustrativos gráficos. </a>En el episodio nos limitamos a contar lo que nos ha parecido más destacable, con especial mención a cuestiones educativas, la desinformación y el poder las grandes compañías de internet.</p>



<p>Os animamos a visitar la web de la Fundación Mozilla, donde poder consultar toda la información disponible y explorar los vínculos a las noticias y estudios que complementan este informe 2020. También se puede descargar en formato PDF o ePub.</p>



<blockquote class="twitter-tweet"><p lang="es" dir="ltr">SORTEO Libro Python ? La editorial <a href="https://twitter.com/EdicionesENI?ref_src=twsrc%5Etfw">@EdicionesENI</a> colabora con el podcast ofreciendo algunos de sus títulos Consigue el libro online Python 3 haciendo RT de esta publicación <a href="https://twitter.com/hashtag/sorteoLibroPythonRW?src=hash&#38;ref_src=twsrc%5Etfw">#sorteoLibroPythonRW</a> y siguiendo a <a href="https://twitter.com/EdicionesENI?ref_src=twsrc%5Etfw">@EdicionesENI</a> <a href="https://twitter.com/republicawebes?ref_src=twsrc%5Etfw">@republicawebes</a> Hasta 20/02 12pm <a href="https://t.co/gBhCzb3EoN">https://t.co/gBhCzb3EoN</a> <a href="https://t.co/fpB6EehX4w">pic.twitter.com/fpB6EehX4w</a></p>— Podcast República Web (@republicawebes) <a href="https://twitter.com/republicawebes/status/1360554000542752777?ref_src=twsrc%5Etfw">February 13, 2021</a></blockquote> <script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>



<p>En este episodio también damos la bienvenida a la <a href="https://www.ediciones-eni.com" data-type="URL" data-id="https://www.ediciones-eni.com">editorial de libros informáticos Ediciones ENI,</a> que como colaboración con el podcast ofrece el acceso a algunos de sus libros. Este acceso se brindará a las personas que vayan ganando los concursos que periódicamente realizaremos en el podcast.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://miro.medium.com/max/759/1*OChqO9y1iP2XddAGOLY8tA.png" alt="React Performance, Effortless Web Security, TypeScript Unions, WebAssembly, and MORE! 🤪  — Pony Foo Weekly">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">React Performance, Effortless Web Security, TypeScript Unions, WebAssembly, and MORE! 🤪  — Pony Foo Weekly</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Pony Foo Weekly</a> <span class="article__date">12 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="f-core"><div class="md-markdown"></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://nosleepjavascript.com/react-performance/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-194" style="color:#555;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>React is slow, what now?</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/performance" class="wy-link-tag">performance</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Grab a cup of coffee and enjoy the ride as we study React applications performance from the ground up, the processes involved, the tools to measure and identify slow parts, the important metrics to take in account, how these impact the UX and the various ways there are available to make applications super fast and smooth.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/franleplant?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-194" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>franleplant</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://engineering.q42.nl/passwordless-authentication?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-194" style="color:#555;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Effortless security on the web</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/best-practices" style="color:#900070;background-color:#ffe270" class="wy-link-tag">Best Practices</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>How to implement multi-device passwordless authentication on the web with the Web Authentication API.</p> </div></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-job"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://tinyurl.com/y56jwhqr?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-194" style="color:#555;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>The widest selection of tech remote jobs (powered by AI)</p> </a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Tired of looking for remote roles on multiple websites? Try <a href="http://bergamot.io/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-194" target="_blank" rel="noopener noreferrer">Bergamot.io</a>, a brand new website that aggregates vacancies from over 150,000 companies&#x2019; career pages. Select your stack or just past URL to Linkedin profile and you&#x2019;ll get relevant and up-to-date job selection.</p> </div></div><div class="wy-link-source-section"><span class="wy-link-source wy-link-source-plain md-markdown md-markdown-inline"><p><a href="http://bergamot.io/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-194" target="_blank" rel="noopener noreferrer">Bergamot.io</a></p> </span><a href="https://ponyfoo.com/weekly/links/tagged/sponsored" class="wy-link-tag wy-link-sponsor">Sponsored</a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://vasilyev-maksim.medium.com/discriminated-unions-in-typescript-why-is-it-so-good-6325681b2c3e?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-194" style="color:#555;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Discriminated unions in TypeScript</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/article" style="color:#e4f9e3;background-color:#1bc211" class="wy-link-tag">Article</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Discriminated unions allow us to precisely describe the structure of variadic models, instead of mixing all the fields into a single &#x201C;Frankenstein&#x201D; model.</p> </div></div><div class="wy-link-source-section"><span class="wy-link-source wy-link-source-plain md-markdown md-markdown-inline"><p>Vasilyev Maksim</p> </span></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://medium.com/@robaboukhalil/7a7daa4f2ecd?source=friends_link&#38;sk=9029f95ccadfbf82a026f282a4df6b2c&#38;utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-194" style="color:#555;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>WebAssembly and SIMD: A match made in the browser</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/webassembly" class="wy-link-tag">webassembly</a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>How WebAssembly and SIMD enables running compute-intensive apps on the web</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/RobAboukhalil?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-194" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Robert Aboukhalil</p> </a></div></td><td class="wy-td wy-link-cell-image"><a href="https://medium.com/@robaboukhalil/7a7daa4f2ecd?source=friends_link&#38;sk=9029f95ccadfbf82a026f282a4df6b2c&#38;utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-194" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://miro.medium.com/max/759/1*OChqO9y1iP2XddAGOLY8tA.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://www.rainforestqa.com/blog/2020-03-09-replacing-recompose-with-react-hooks?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-194" style="color:#555;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Replacing Recompose with React Hooks</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/article" style="color:#e4f9e3;background-color:#1bc211" class="wy-link-tag">Article</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>AJ explains how their team recently made the decision to remove Recompose entirely &#x2013; which was a large endeavor. It touched over 200 files, and in some places was deeply coupled to core functionality of our app.This post covers why we decided to replace Recompose.</p> </div></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://tomekdev.com/posts/input-and-form/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-194" style="color:#555;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>If there is an input, there should be a form</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/best-practices" style="color:#900070;background-color:#ffe270" class="wy-link-tag">Best Practices</a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Make every input on your page a bit happier and wrap it with a form. That&#x2019;s going to pay off in better UX, argues Tomek.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/tomekdev_?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-194" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Tomek Nie&#x17C;urawski</p> </a></div></td><td class="wy-td wy-link-cell-image"><a href="https://tomekdev.com/posts/input-and-form/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-194" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://tomekdev.com/static/a74ea3b3d44f7a89f8bdc6a17d971a41/003-form-is-there.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div></div><style>html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;position:relative;vertical-align:baseline}sup{top:-.5em}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto;resize:vertical;min-height:280px;max-height:900px}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item;margin:-10px -20px;padding:10px;background-color:#f6f6f6;cursor:pointer;border-bottom:2px solid #ddd}[hidden],template{display:none}body,body:after,body:before,html,html:after,html:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*,:after,:before{-webkit-box-sizing:inherit;-moz-box-sizing:inherit;box-sizing:inherit}@-moz-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-webkit-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-o-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-moz-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@-webkit-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@-o-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}.f-core{font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}.f-mono{font-family:Consolas,Menlo,Monaco,'Lucida Console','Liberation Mono','DejaVu Sans Mono','Bitstream Vera Sans Mono','Courier New',monospace,serif}.ly-custom-heading .f-heading,.ly-custom-heading h1,.ly-custom-heading h2,.ly-custom-heading h3,.ly-custom-heading h4,.ly-custom-heading h5,.ly-custom-heading h6,.ly-lean .f-heading,.ly-lean h1,.ly-lean h2,.ly-lean h3,.ly-lean h4,.ly-lean h5,.ly-lean h6{font-family:Neuton,'Hoefler Text',Palatino,Baskerville,Georgia,'Times New Roman',serif}.ly-custom-subheading .f-subheading,.ly-lean .f-subheading{font-family:Merriweather,Georgia,serif}body{margin:0;font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif;background:#fcfcfc;color:#333}img{max-width:100%;border:none}.md-markdown figure:not(.twitter-tweet-figure){background-color:#f6f6f6}.md-markdown figure:not(.twitter-tweet-figure)>a{display:block}.md-markdown figure:not(.twitter-tweet-figure)>a>img,.md-markdown figure:not(.twitter-tweet-figure)>img{display:block;margin-left:auto;margin-right:auto}.md-markdown figcaption{padding:10px;font-style:italic;font-size:14px;background:-webkit-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-moz-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-o-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-ms-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:linear-gradient(to right,#fff9e2 33%,#fcf9ee 100%);color:#555}.md-markdown .figure-has-loaded{background:-webkit-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-moz-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-o-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-ms-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:linear-gradient(to bottom,rgba(255,255,255,0) 0,#fcf9ee 100%)}b,em,font-style italic,font-weight bold,i,ins,strong{text-decoration:none}del{text-decoration:line-through}sub,sup{bottom:0;line-height:18px}button,input{overflow:visible;border-radius:0}button{border:none;padding:6px 8px;font-size:1.2em;background:0 0}button[disabled]{color:#cbccbc!important}input,select,textarea{display:block;width:100%;padding:10px 8px;line-height:18px;border:none;font:inherit}select{height:38px}ol,ul{padding:0;margin:0;list-style-position:inside}li>ol,li>ul{margin-left:20px}hr{border:none;border-top:5px solid rgba(0,0,0,.05);margin:20px 0}kbd{display:inline-block;border:1px solid #ccc;margin:0 .1em;padding:.1em .6em;line-height:1.4;font-size:11px;background-color:#f7f7f7;-webkit-box-shadow:0 1px 0 #bbb,0 0 0 2px #fff inset;box-shadow:0 1px 0 #bbb,0 0 0 2px #fff inset;border-radius:3px;color:#333;text-shadow:0 1px 0 #fff;white-space:nowrap}iframe{display:inline-block;border:none;max-width:100%}summary:hover{opacity:.8}details{padding:10px 20px 20px;border-bottom:2px dashed #ddd}details[open] summary{margin-bottom:20px}blockquote{border:none;margin:0!important}ol,p,ul{line-height:35px}p{margin:35px 0}@media only screen and (min-width:768px){ol,p,ul{line-height:30px}}a,button,input[type=submit]{cursor:pointer;text-decoration:none}.lk-link{color:#e92c6c;border-bottom:1px solid transparent;background-color:rgba(255,255,255,.04)}.lk-link .md-code-inline{position:relative}.lk-link .md-code-inline:only-child{display:inline-block;line-height:17px}.lk-link .md-code-inline:before{content:'';position:absolute;background-color:#f1e05a;top:0;left:0;right:0;bottom:0;opacity:.04}.lk-link:visited{background-color:rgba(233,44,108,.04)}.lk-link:visited .md-code-inline:before{background-color:#e92c6c}.lk-link:hover{border-bottom:1px solid #e92c6c}.lk-rainbows{position:relative;color:#333;margin-bottom:5px}.lk-rainbows:hover:before{position:absolute;content:'';left:0;right:0;bottom:-8px;height:3px;opacity:.8;-webkit-transition:.1s ease-in-out;-moz-transition:.1s ease-in-out;-o-transition:.1s ease-in-out;-ms-transition:all .1s ease-in-out;transition:.1s ease-in-out;-webkit-animation:.5s infinite bg-rainbow;-moz-animation:.5s infinite bg-rainbow;-o-animation:.5s infinite bg-rainbow;-ms-animation:bg-rainbow .5s infinite;animation:.5s infinite bg-rainbow}.lk-icon{color:#333}.lk-icon:hover{color:#e92c6c}.lk-visitor{color:#333}.lk-visitor:after{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-left:5px}.lk-visitor.lk-visitor-large:after{font-size:1em}.lk-visitor:hover:after{color:#333;border-bottom-style:solid}.lk-visitor:visited:after{color:#7d5cff}.lk-visitor-inside{color:#333}.lk-visitor-inside .lk-visitor-target:before{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-right:5px}.lk-visitor-inside.lk-visitor-large .lk-visitor-target:before{font-size:1em}.lk-visitor-inside:hover .lk-visitor-target:before{color:#333;border-bottom-style:solid}.lk-visitor-inside:visited .lk-visitor-target:before{color:#7d5cff}.lk-visitor-before{color:#333}.lk-visitor-before:before{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-right:5px}.lk-visitor-before.lk-visitor-large:before{font-size:1em}.lk-visitor-before:hover:before{color:#333;border-bottom-style:solid}.lk-visitor-before:visited:before{color:#7d5cff}.lk-visitor-before-no-underline:before{border-bottom-width:0}.lk-link-to-green{color:#cbccbc}.lk-link-to-green:visited,.lk-link-to-green:visited:before{color:#1bc211;background-color:#1bc211}.lk-link-to-green:active{outline-color:#1bc211}.lk-link-to-green:hover,.lk-link-to-green:hover:before{color:#8be186;border-bottom-color:#1bc211}.lk-green .lk-link,a.lk-green{color:#1bc211}.lk-green .lk-link:visited,a.lk-green:visited{background-color:rgba(27,194,17,.04)}.lk-green .lk-link:visited .md-code-inline:before,a.lk-green:visited .md-code-inline:before{background-color:#1bc211}.lk-green .lk-link:active,a.lk-green:active{outline-color:#1bc211}.lk-green .lk-link:hover,a.lk-green:hover{border-bottom-color:#1bc211}.lk-green.lk-icon:hover{color:#1bc211}.lk-pink-light .lk-link,a.lk-pink-light{color:#ea6c93}.lk-pink-light .lk-link:visited,a.lk-pink-light:visited{background-color:rgba(234,108,147,.04)}.lk-pink-light .lk-link:visited .md-code-inline:before,a.lk-pink-light:visited .md-code-inline:before{background-color:#ea6c93}.lk-pink-light .lk-link:active,a.lk-pink-light:active{outline-color:#ea6c93}.lk-pink-light .lk-link:hover,a.lk-pink-light:hover{border-bottom-color:#ea6c93}.lk-pink-light.lk-icon:hover{color:#ea6c93}.lk-black .lk-link,a.lk-black{color:#333}.lk-black .lk-link:visited,a.lk-black:visited{background-color:rgba(51,51,51,.04)}.lk-black .lk-link:visited .md-code-inline:before,a.lk-black:visited .md-code-inline:before{background-color:#333}.lk-black .lk-link:active,a.lk-black:active{outline-color:#333}.lk-black .lk-link:hover,a.lk-black:hover{border-bottom-color:#333}.lk-black.lk-icon:hover{color:#333}.lk-gray .lk-link,a.lk-gray{color:#999}.lk-gray .lk-link:visited,a.lk-gray:visited{background-color:rgba(153,153,153,.04)}.lk-gray .lk-link:visited .md-code-inline:before,a.lk-gray:visited .md-code-inline:before{background-color:#999}.lk-gray .lk-link:active,a.lk-gray:active{outline-color:#999}.lk-gray .lk-link:hover,a.lk-gray:hover{border-bottom-color:#999}.lk-gray.lk-icon:hover{color:#999}.lk-white .lk-link,a.lk-white{color:#fcfcfc}.lk-white .lk-link:visited,a.lk-white:visited{background-color:rgba(252,252,252,.04)}.lk-white .lk-link:visited .md-code-inline:before,a.lk-white:visited .md-code-inline:before{background-color:#fcfcfc}.lk-white .lk-link:active,a.lk-white:active{outline-color:#fcfcfc}.lk-white .lk-link:hover,a.lk-white:hover{border-bottom-color:#fcfcfc}.lk-white.lk-icon:hover{color:#fcfcfc}.lk-orange .lk-link,a.lk-orange{color:#f3720d}.lk-orange .lk-link:visited,a.lk-orange:visited{background-color:rgba(243,114,13,.04)}.lk-orange .lk-link:visited .md-code-inline:before,a.lk-orange:visited .md-code-inline:before{background-color:#f3720d}.lk-orange .lk-link:active,a.lk-orange:active{outline-color:#f3720d}.lk-orange .lk-link:hover,a.lk-orange:hover{border-bottom-color:#f3720d}.lk-orange.lk-icon:hover{color:#f3720d}.lk-lilly .lk-link,a.lk-lilly{color:#7d5cff}.lk-lilly .lk-link:visited,a.lk-lilly:visited{background-color:rgba(125,92,255,.04)}.lk-lilly .lk-link:visited .md-code-inline:before,a.lk-lilly:visited .md-code-inline:before{background-color:#7d5cff}.lk-lilly .lk-link:active,a.lk-lilly:active{outline-color:#7d5cff}.lk-lilly .lk-link:hover,a.lk-lilly:hover{border-bottom-color:#7d5cff}.lk-lilly.lk-icon:hover{color:#7d5cff}.lk-blue .lk-link,a.lk-blue{color:#1a4d7f}.lk-blue .lk-link:visited,a.lk-blue:visited{background-color:rgba(26,77,127,.04)}.lk-blue .lk-link:visited .md-code-inline:before,a.lk-blue:visited .md-code-inline:before{background-color:#1a4d7f}.lk-blue .lk-link:active,a.lk-blue:active{outline-color:#1a4d7f}.lk-blue .lk-link:hover,a.lk-blue:hover{border-bottom-color:#1a4d7f}.lk-blue.lk-icon:hover{color:#1a4d7f}.lk-inherited .lk-link,a.lk-inherited{color:inherit}.lk-inherited .lk-link:active,a.lk-inherited:active{outline-color:inherit}.lk-inherited .lk-link:hover,a.lk-inherited:hover{border-bottom-color:inherit}.lk-inherited.lk-icon:hover{color:inherit}.lk-twitter .lk-link,a.lk-twitter{color:#55acee}.lk-twitter .lk-link:visited,a.lk-twitter:visited{background-color:rgba(85,172,238,.04)}.lk-twitter .lk-link:visited .md-code-inline:before,a.lk-twitter:visited .md-code-inline:before{background-color:#55acee}.lk-twitter .lk-link:active,a.lk-twitter:active{outline-color:#55acee}.lk-twitter .lk-link:hover,a.lk-twitter:hover{border-bottom-color:#55acee}.lk-twitter.lk-icon:hover{color:#55acee}.lk-facebook .lk-link,a.lk-facebook{color:#3b5998}.lk-facebook .lk-link:visited,a.lk-facebook:visited{background-color:rgba(59,89,152,.04)}.lk-facebook .lk-link:visited .md-code-inline:before,a.lk-facebook:visited .md-code-inline:before{background-color:#3b5998}.lk-facebook .lk-link:active,a.lk-facebook:active{outline-color:#3b5998}.lk-facebook .lk-link:hover,a.lk-facebook:hover{border-bottom-color:#3b5998}.lk-facebook.lk-icon:hover{color:#3b5998}.lk-clean{background-color:transparent}.lk-chrome:hover{color:#4989f4}.lk-teal .lk-link,a.lk-teal{color:#00a19c}.lk-teal .lk-link:visited,a.lk-teal:visited{background-color:rgba(0,161,156,.04)}.lk-teal .lk-link:visited .md-code-inline:before,a.lk-teal:visited .md-code-inline:before{background-color:#00a19c}.lk-teal .lk-link:active,a.lk-teal:active{outline-color:#00a19c}.lk-teal .lk-link:hover,a.lk-teal:hover{border-bottom-color:#00a19c}.lk-teal.lk-icon:hover{color:#00a19c}table{width:100%;border-spacing:0;border-collapse:separate}td,th{padding:8px}@media only screen and (max-width:950px){.table-responsive{display:block}.table-responsive>thead{display:none}.table-responsive>tbody,.table-responsive>tfoot{display:block}.table-responsive>tbody>tr,.table-responsive>tfoot>tr{display:block;background-color:rgba(203,204,188,.1);margin-bottom:30px}.table-responsive>tbody>tr:nth-child(even),.table-responsive>tfoot>tr:nth-child(even){background-color:rgba(203,204,188,.15)}.table-responsive>tbody>tr:last-child,.table-responsive>tfoot>tr:last-child{margin-bottom:0}.table-responsive>tbody>tr>td,.table-responsive>tfoot>tr>td{display:block;text-align:left}.table-responsive>tbody>tr>td:before,.table-responsive>tfoot>tr>td:before{display:block;content:attr(data-label);color:#555;font-size:13px;margin:0 0 5px}.table-responsive .table-responsive-hide{display:none}}.c-oreilly-teal{color:#00a19c}.c-yellow-highlight{color:#ffe270}.c-dark-orange{color:#f3720d}.c-pink{color:#e92c6c}.c-purple{color:#900070}.c-blue{color:#1a4d7f}.c-dark-turquoise{color:#1686a2}.c-dark-green{color:#1bc211}.c-white{color:#fcfcfc}.c-gray{color:#b7b7b7}.c-lilly{color:#7d5cff}.c-teal{color:#3aca96}.c-bg-oreilly-teal{background-color:#00a19c}.c-bg-yellow-highlight{background-color:#ffe270}.c-bg-dark-orange{background-color:#f3720d}.c-bg-pink{background-color:#e92c6c}.c-bg-purple{background-color:#900070}.c-bg-blue{background-color:#1a4d7f}.c-bg-dark-turquoise{background-color:#1686a2}.c-bg-dark-green{background-color:#1bc211}.c-bg-white{background-color:#fcfcfc}.c-bg-gray{background-color:#b7b7b7}.c-bg-lilly{background-color:#7d5cff}.c-bg-teal{background-color:#3aca96}.tj-emoji{width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em}.dc-header{margin-bottom:60px}.dc-heading{text-align:center;font-size:4em;padding:0 10px;margin-top:0;margin-bottom:10px}.dc-role{line-height:26px;padding:0 20px;margin-top:10px;text-align:center;font-style:italic;color:#cbccbc}.dc-colored{background:#f6f6f6;border-top:9px solid rgba(125,92,255,.5)}.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:800px}.md-markdown blockquote:not(.twitter-tweet){margin:0;padding:20px 0;border:none;border-top:5px solid rgba(0,0,0,.05);border-bottom:5px solid rgba(0,0,0,.05)}.md-markdown blockquote:not(.twitter-tweet) h1,.md-markdown blockquote:not(.twitter-tweet) h2,.md-markdown blockquote:not(.twitter-tweet) h3,.md-markdown blockquote:not(.twitter-tweet) h4,.md-markdown blockquote:not(.twitter-tweet) h5,.md-markdown blockquote:not(.twitter-tweet) h6{margin:-20px 0;padding:20px 0}.md-markdown blockquote:not(.twitter-tweet) .md-code-block{margin:0}.md-markdown blockquote:not(.twitter-tweet) .md-code-block:last-child{margin-bottom:-20px}.md-markdown img:first-child{margin-top:0}.md-markdown img:last-child{margin-bottom:0}.md-markdown p:first-child{margin-top:0}.md-markdown p:last-child{margin-bottom:0}.md-markdown .md-code-block+ol,.md-markdown .md-code-block+ul,.md-markdown ol+.md-code-block,.md-markdown ul+.md-code-block{margin-top:35px}.md-markdown a:not(.md-heading){color:#e92c6c;border-bottom:1px solid transparent;background-color:rgba(255,255,255,.04)}.md-markdown a:not(.md-heading) .md-code-inline{position:relative}.md-markdown a:not(.md-heading) .md-code-inline:only-child{display:inline-block;line-height:17px}.md-markdown a:not(.md-heading) .md-code-inline:before{content:'';position:absolute;background-color:#f1e05a;top:0;left:0;right:0;bottom:0;opacity:.04}.md-markdown a:not(.md-heading):visited{background-color:rgba(233,44,108,.04)}.md-markdown a:not(.md-heading):visited .md-code-inline:before{background-color:#e92c6c}.md-markdown a:not(.md-heading):hover{border-bottom:1px solid #e92c6c}.md-markdown thead{background-color:#e0e0e0}.md-markdown tbody{background-color:#f6f6f6}.md-markdown tbody tr:nth-child(even){background-color:#f9f9f9}.md-markdown h1,.md-markdown h2,.md-markdown h3,.md-markdown h4,.md-markdown h5,.md-markdown h6{padding:10px 0}.md-markdown h1:first-child,.md-markdown h2:first-child,.md-markdown h3:first-child,.md-markdown h4:first-child,.md-markdown h5:first-child,.md-markdown h6:first-child{margin-top:0}.md-markdown h1:last-child,.md-markdown h2:last-child,.md-markdown h3:last-child,.md-markdown h4:last-child,.md-markdown h5:last-child,.md-markdown h6:last-child{margin-bottom:0}.md-markdown iframe{display:block;margin:35px auto}.md-markdown iframe:first-child{margin-top:0}.md-markdown iframe:last-child{margin-bottom:0}.md-markdown li>p:only-child{display:inline}.md-markdown ul{list-style-type:none}.md-markdown ul>li:before{content:'◯';margin-right:5px}.md-heading{color:inherit}.md-markdown-inline{display:inline}.md-markdown-inline p{display:inline;line-height:initial}.md-code-block,.ocha-highlighted{margin:0 -20px}.ocha-code-block{padding:18px 50px}.md-markdown:not(.mm-content-html) .md-code-block+blockquote{max-width:inherit!important;margin:0 -20px;padding-left:20px;padding-right:20px}.md-code-block .md-code{display:block}.md-markdown-summary p{margin:10px 0}@media only screen and (min-width:768px){.md-markdown h1,.md-markdown h2,.md-markdown h3,.md-markdown h4,.md-markdown h5,.md-markdown h6{margin-left:-40px;margin-right:-40px;padding:10px 40px}.md-code-block,.ocha-highlighted{margin:0 -40px}.md-markdown:not(.mm-content-html) .md-code-block+blockquote{margin:0 -40px;padding-left:40px;padding-right:40px}}@media only screen and (min-width:1300px){.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:900px}}@media only screen and (min-width:1400px){.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:1000px}.md-code-block,.md-markdown:not(.mm-content-html) .md-code-block+blockquote,.ocha-highlighted{margin:0 -400px 0 -40px}}.md-markdown-large blockquote,.md-markdown-large code,.md-markdown-large ol,.md-markdown-large p,.md-markdown-large table,.md-markdown-large ul{max-width:inherit}.md-footnotes{margin-top:80px;padding:20px 0;border-top:1px dashed #cbccbc}.md-footnote{margin:0;padding:8px 0;font-size:14px;display:-webkit-box;display:-moz-box;display:-webkit-flex;display:-ms-flexbox;display:box;display:flex;-webkit-box-align:center;-moz-box-align:center;-o-box-align:center;-ms-flex-align:center;-webkit-align-items:center;align-items:center}.md-footnote p{line-height:16px}.md-footnote-anchor{padding:2px 6px;margin-right:10px;text-align:center;font-weight:700;color:#e92c6c}.ly-custom-subheading .md-footnote-anchor,.ly-lean .md-footnote-anchor{font-family:Merriweather,Georgia,serif}.md-markdown a.md-footnote-anchor{border:1px solid #e92c6c}.md-markdown a.md-footnote-anchor:hover{background-color:#e92c6c;color:#fcfcfc}.md-footnote-ref{margin-left:1px;margin-right:3px}.md-markdown a.md-footnote-ref{border-bottom:1px dotted}.md-code-block,.md-code-inline{-webkit-text-size-adjust:none;-ms-text-size-adjust:none;text-size-adjust:none;background:#fcfcf5;color:#4d4d4c}.md-code-block{line-height:24px}.md-code{padding:8px 10px}.md-code-inline{padding:0 6px}a .md-code{color:inherit}.md-code-comment{color:#8e908c}.md-code-attribute,.md-code-built_in,.md-code-constant,.md-code-literal,.md-code-number,.md-code-params,.md-code-pragma,.md-code-preprocessor,.md-code-regexp,.md-code-tag,.md-code-variable,.md-lang-css .md-code-class,.md-lang-css .md-code-id,.md-lang-css .md-code-pseudo,.md-lang-html .md-code-doctype,.md-lang-ruby .md-code-constant,.md-lang-xml .md-code-doctype,.md-lang-xml .md-code-pi,.md-lang-xml .md-code-tag .md-code-title,color #c82829{color:#f5871f}.md-lang-css .md-code-rule .md-code-attribute,.md-lang-ruby .md-code-class .md-code-title{color:#eab700}.md-code-header,.md-code-inheritance,.md-code-name,.md-code-string,.md-code-value,.md-lang-ruby .md-code-symbol,.md-lang-xml .md-code-cdata{color:#718c00}.md-code-title,.md-lang-css .md-code-hexcolor{color:#3e999f}.md-code-function,.md-lang-coffeescript .md-code-title,.md-lang-javascript .md-code-title,.md-lang-perl .md-code-sub,.md-lang-python .md-code-decorator,.md-lang-python .md-code-title,.md-lang-ruby .md-code-function .md-code-title,.md-lang-ruby .md-code-title .md-code-keyword{color:#4271ae}.md-code-keyword,.md-lang-javascript .md-code-function{color:#8959a8}.md-lang-coffeescript .md-lang-javascript,.md-lang-javascript .md-lang-xml,.md-lang-tex .md-code-formula,.md-lang-xml .md-code-cdata,.md-lang-xml .md-lang-css,.md-lang-xml .md-lang-javascript,.md-lang-xml .vbscript{opacity:.5}.md-code-deletion{background-color:rgba(244,0,30,.05);color:#f4001e}.md-code-addition{background-color:rgba(27,194,17,.05);color:#1bc211}.md-mark{background-color:rgba(255,226,112,.5);color:inherit}.md-mark span{color:inherit}.md-heading-hover{cursor:pointer;background-color:rgba(22,134,162,.1)}.mde-text-left{text-align:left}.mde-text-center{text-align:center}.mde-text-right{text-align:right}.mde-size-small{font-size:12px}.mde-size-small,.mde-size-small p{line-height:12px}.mde-size-large{font-size:36px}.mde-size-large,.mde-size-large p{line-height:36px}.mde-size-giant{font-size:72px}.mde-size-giant,.mde-size-giant p{line-height:72px}.mde-clearfix:after{content:' ';display:block;visibility:hidden;clear:both;font-size:0;height:0}.mde-quote{margin:0;padding:20px 0;border:none;border-top:5px solid rgba(0,0,0,.05);border-bottom:5px solid rgba(0,0,0,.05)}.mde-core{font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}.mde-mono{font-family:Consolas,Menlo,Monaco,'Lucida Console','Liberation Mono','DejaVu Sans Mono','Bitstream Vera Sans Mono','Courier New',monospace,serif}.ly-custom-heading .mde-heading,.ly-lean .mde-heading{font-family:Neuton,'Hoefler Text',Palatino,Baskerville,Georgia,'Times New Roman',serif}.ly-custom-subheading .mde-subheading,.ly-lean .mde-subheading{font-family:Merriweather,Georgia,serif}.mde-pad-0{padding:0}.mde-pad-5{padding:5px}.mde-pad-10{padding:10px}.mde-pad-15{padding:15px}.mde-pad-20{padding:20px}.mde-pad-25{padding:25px}.mde-pad-30{padding:30px}.mde-pad-50{padding:50px}.mde-mar-0{margin:0}.mde-mar-5{margin:5px}.mde-mar-10{margin:10px}.mde-mar-15{margin:15px}.mde-mar-20{margin:20px}.mde-mar-25{margin:25px}.mde-mar-30{margin:30px}.mde-mar-50{margin:50px}@media only screen and (min-width:900px){.mde-left{float:left}.mde-right{float:right}.mde-inline{display:inline-block;vertical-align:top}.mde-20{max-width:20%}.mde-25{max-width:25%}.mde-33{max-width:33.3333333333%}.mde-50{max-width:50%}.mde-66{max-width:66.6666666666%}.mde-75{max-width:75%}}.twitter-tweet-figure{background:0 0;padding:0}.twitter-tweet-figure:before{content:none}.twitter-tweet-figure .twitter-tweet{margin:0 auto}blockquote.twitter-tweet{overflow:hidden;color:#1c2022;background-color:#fff;border:1px solid #e1e8ed;border-radius:4px;width:500px;max-width:100%;min-width:220px;padding:1.25rem 1.25rem .725rem}blockquote.twitter-tweet:before{content:none}blockquote.twitter-tweet p{white-space:pre-wrap;font:16px/1.4 Helvetica,Roboto,'Segoe UI',Calibri,'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}blockquote.twitter-tweet a,blockquote.twitter-tweet a:visited{color:#2b7bb9}.wy-container{margin:0 auto;padding:20px 0;max-width:800px}.wy-container .md-markdown p{line-height:22px;margin:10px 0}.wy-container .md-markdown p:first-child{margin-top:0}.wy-container .md-markdown p:last-child{margin-bottom:0}.wy-container .md-markdown blockquote:not(.twitter-tweet){padding:10px 0}.wy-container .md-code-block{margin:0;padding:10px;white-space:pre-wrap}.wy-table{width:100%;padding:0}.wy-td{padding:0}.wy-section-link,.wy-section-markdown,.wy-section-poll,.wy-section-summary{padding-top:25px}.wy-section-thanks{margin-top:25px;padding:10px;font-size:15px;background-color:#f2fcf2}.wy-header-text,.wy-issue{display:inline-block;margin:10px 0;line-height:24px}.wy-issue{float:right;font-size:12px}.wy-issue-content{display:block;padding:0 5px;background-color:#fcfcfc}.wy-section-header{padding-top:40px}.wy-section-header h1,.wy-section-header h2,.wy-section-header h3,.wy-section-header h4,.wy-section-header h5,.wy-section-header h6{margin:0}.wy-section-header p{line-height:inherit}.wy-header-td{padding:0}.wy-header-content{margin:0 10px}.wy-header-text{color:#fcfcfc;text-shadow:1px 1px 0 #1a4d7f;font-weight:700;font-size:24px}.wy-content{padding-bottom:25px}.wy-link-addendum,.wy-link-tag,.wy-link-title{display:inline-block;vertical-align:bottom;margin-bottom:10px}.wy-link-title{border-bottom:1px solid;font-size:20px;margin-right:10px}.wy-link-tag{background-color:#1a4d7f;color:#fcfcfc;text-transform:uppercase;font-size:13px;margin-right:5px;padding:2px 4px}.wy-link-tag:last-child{margin-right:0}.wy-link-addendum{color:#999;margin-left:5px}.wy-link-addendum:hover{border-bottom-color:transparent}.wy-link-title-section{position:relative}.wy-link-stats{position:absolute;right:0;background-color:#3aca96;color:#fcfcfc;border-bottom:1px solid #299a71}.wy-link-stats-logo{background-color:rgba(0,0,0,.1);color:#299a71}.wy-link-stat{margin:3px}.wy-link-description{font-size:14px;color:#666}.wy-link-source-section{margin-top:10px}.wy-link-source{margin-right:10px;margin-bottom:10px;display:inline-block;vertical-align:middle;color:#55acee}.wy-link-source-plain{color:#333}.wy-link-source.wy-link-source-plain a{color:#55acee}.wy-link-source.wy-link-source-plain a:visited{background-color:rgba(85,172,238,.04)}.wy-link-source.wy-link-source-plain a:visited .md-code-inline:before{background-color:#55acee}.wy-link-source.wy-link-source-plain a:active{outline-color:#55acee}.wy-link-source.wy-link-source-plain a:hover{border-bottom-color:#55acee}.wy-link-sponsor{background-color:transparent;color:#999;outline:#999 solid 1px}.wy-link-cell-before-image{vertical-align:middle;width:70%}.wy-link-cell-image{padding-left:10px}.wy-link-image-anchor{display:block;overflow:hidden;max-height:300px}.wy-link-image{display:block;margin:0 auto}.wy-footer-table{margin:20px 0}.wy-footer-cell{text-align:center}.wy-read-online{font-size:13px}.wy-section-link-job .wy-link-source,.wy-section-link-job .wy-link-title{font-size:14px}.wy-section-link-job .wy-link-description{font-size:12px}.wy-link-pixel{float:right}@media only screen and (max-width:500px){.wy-issue-publication,.wy-issue-separator{display:none}}.md-code-block{margin:0!important;padding:10px}</style>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Updates on the Tsunami Security Scanning Engine</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">10 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The 2021 Season of Docs application for organizations is open!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">09 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">CSS: múltiples :not()</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Bufa</a> <span class="article__date">09 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Ejemplo CSS si quieres usar varias veces la pseudoclase :not() para un único selector que tiene diferentes atributos. input:not([type=&#34;radio&#34;]):not([type=&#34;checkbox&#34;]){ background: red; } div:not(.inner):not(.wrapper){ background: blue; }
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://javierarcheni.com/wp-content/uploads/2021/04/cropped-favicon-javierarcheni-32x32.png" alt="El «no code» cambiará la industria del software pero necesitará programadores">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">El «no code» cambiará la industria del software pero necesitará programadores</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Javier Archeni</a> <span class="article__date">08 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Cuando pensamos en los efectos que produce la tecnología, es habitual subestimar los efectos a largo plazo, y al mismo tiempo sobrevalorar los efectos a corto. Los cambios tecnológicos rara vez son radicales y suelen venir precedidos por la combinación de varios factores. Tomemos por ejemplo la Inteligencia Artificial, que aunque sus principios tengan décadas, &#8230; <a href="https://javierarcheni.com/blog/el-no-code-cambiara-la-industria-del-software-pero-necesitara-programadores/">Ver más</a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Google joins the Rust Foundation</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">08 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Writing fuzz tests with ease using Bazel</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">08 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/sotu-downloads-2020.png" alt="State of the Common Lisp ecosystem, 2020  🎉">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">State of the Common Lisp ecosystem, 2020  🎉</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">08 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>This is a description of the Common Lisp ecosystem, as of January, 2021,
from the perspective of a user and contributor.</p>

<p>The purpose of this article is both to give an overview of the
ecosystem, and to help drive consolidation in each domain.</p>

<p>Each application domain has recommendations for consolidating that
part of the ecosystem, and pointers for interesting future work.</p>

<p>This article is derived from
Fernando Borretti&rsquo;s <a href="https://borretti.me/article/common-lisp-sotu-2015">State of the Common Lisp ecosystem from 2015</a>, hence the introduction that sounded familiar.
This new one will be an opportunity to look at what was achieved, or what is
still lacking.</p>

<p><strong>Disclaimer</strong>: This article is not a list of every project or article of interest that came out in the last years. I wrote an overview of 2018 closer to that goal <a href="/blog/these-years-in-common-lisp-2018/">here</a>. More libraries can be discovered on the <a href="https://github.com/CodyReichert/awesome-cl">Awesome-cl</a> list, on GitHub and on <a href="https://www.cliki.net/">Cliki</a>.</p>

<p><strong>Acknowledgements</strong> I would like to thank @borodust, @ambrevar and @digikar for their kind feedback.</p>

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->

<p><strong>Table of Contents</strong></p>

<ul>
<li><a href="#application-domains">Application domains</a>

<ul>
<li><a href="#command-line">Command line</a></li>
<li><a href="#databases">Databases</a></li>
<li><a href="#concurrency">Concurrency</a></li>
<li><a href="#file-formats">File formats</a></li>
<li><a href="#gui">GUI</a></li>
<li><a href="#machine-learning">Machine Learning</a></li>
<li><a href="#system">System</a></li>
<li><a href="#web-development">Web Development</a>

<ul>
<li><a href="#backend">Backend</a></li>
<li><a href="#frontend">Frontend</a></li>
<li><a href="#javascript">JavaScript</a></li>
<li><a href="#isomorphic-web-frameworks">Isomorphic web frameworks</a></li>
</ul></li>
</ul></li>
<li><a href="#languages-interop">Languages interop</a>

<ul>
<li><a href="#apl">APL</a></li>
<li><a href="#c-c-objective-c">C, C++, Objective C</a></li>
<li><a href="#clojure">Clojure</a></li>
<li><a href="#python">Python</a></li>
<li><a href="#net-core">.Net Core</a></li>
</ul></li>
<li><a href="#development">Development</a>

<ul>
<li><a href="#implementations">Implementations</a></li>
<li><a href="#editors">Editors</a></li>
<li><a href="#developer-utilities">Developer utilities</a></li>
<li><a href="#package-management">Package Management</a></li>
<li><a href="#build-system">Build System</a></li>
<li><a href="#type-system">Type system</a></li>
<li><a href="#testing-ci">Testing, CI</a></li>
</ul></li>
<li><a href="#community">Community</a>

<ul>
<li><a href="#online-presence">Online presence</a>

<ul>
<li><a href="#new-common-lispnet-website">New common-lisp.net website</a></li>
<li><a href="#cookbook">Cookbook</a></li>
<li><a href="#awesome-cl">awesome-cl</a></li>
<li><a href="#more">More</a></li>
</ul></li>
<li><a href="#new-books">New books</a></li>
<li><a href="#companies">Companies</a></li>
<li><a href="#growth">Growth</a></li>
</ul></li>
<li><a href="#last-words">Last words</a></li>
</ul>

<!-- markdown-toc end -->

<h1 id="application-domains">Application domains</h1>

<h2 id="command-line">Command line</h2>

<p>There used to be several options to ease building and distribution of command line programs,
but now <a href="https://github.com/snmsts/roswell">Roswell</a> has gained most momentum,
and that&rsquo;s a good thing. Roswell is an implementation
manager, installer and a script runner, and one of its neat features is support for
very easily compiling tiny scripts into executables.</p>

<p>Now, <a href="https://guix.gnu.org/">GNU Guix</a> has gained many CL libraries, and becomes a contender to Roswell. Guix can be used as a package manager on top of your Unix distribution. It brings reproducible builds, rollbacks, the ability to install exact versions of any library (including system dependencies), contained environments and user profiles. It makes it easy too to install the latest version of a CL implementation and libraries and, to a certain extent, to share scripts. See the article <a href="https://ambrevar.xyz/lisp-repl-shell/index.html">A Lisp REPL as my main shell</a> for insights.</p>

<p>To parse command line arguments, <a href="https://github.com/mrkkrp/unix-opts">unix-opts</a> shows decent activity. As a reminder, the CLI arguments are stored portably in <code>uiop:command-line-arguments</code>.</p>

<p><a href="https://github.com/cl-adams/adams">Adams</a> is a new UNIX system administration tool, not unlike Chef or Ansible.</p>

<p><strong>Consolidation</strong></p>

<p>More features to the <a href="https://github.com/CodyReichert/awesome-cl#scripting">sripting libraries</a>.</p>

<p><strong>Future work</strong></p>

<p>The <a href="https://github.com/cxxxr/lem/">Lem editor</a> has built a great user interface and REPL on top of ncurses, with the cl-charms library. It would be great to re-use its components, so that Lispers could easily build similar rich terminal-based interfaces.</p>

<h2 id="databases">Databases</h2>

<p><a href="https://github.com/fukamachi/mito">Mito</a> is an ORM for Common Lisp
with migrations, relationships and PostgreSQL support. It is based on
cl-dbi (a uniform interface to the various database server-specific
libraries such as cl-postgres and cl-mysql) and SxQL (a DSL for
building safe, automatically parameterized SQL queries).</p>

<p>It also has a tutorial in the Cookbook:
<a href="https://lispcookbook.github.io/cl-cookbook/databases.html">Cookbook/databases</a>.</p>

<!-- On my blog, [an article](https://lisp-journey.gitlab.io/blog/composing-queries-with-mito-aka-replacing-lazy-querysets-and-q-objects/) -->

<!-- on how to compose queries with Mito and SxQL, and on how we only need -->

<!-- lisp knowledge to replace Django functionalities. -->

<p>There are of course more libraries in that field. Some new ones since 2015 are:</p>

<p><a href="https://github.com/ruricolist/cl-yesql">cl-yesql</a> (by the author of
Serapeum, Spinneret and other great libraries) is based on Clojure&rsquo;s
Yesql.</p>

<p><a href="https://github.com/kraison/vivace-graph-v3">vivace-graph</a> is a <strong>graph
database</strong> and Prolog implementation, taking design and inspiration from
CouchDB, neo4j and AllegroGraph.</p>

<p>Vsevolod Dyomkin, the author of Rutils, the Programming Algorithms
book and other libraries, is writing
<a href="https://github.com/vseloved/cl-agraph">cl-agraph</a>, a minimal client
to Franz Inc&rsquo;s <a href="https://allegrograph.com/">AllegroGraph</a>. AllegroGraph is a
&ldquo;horizontally distributed, multi-model (document and graph),
entity-event <strong>knowledge graph</strong> technology&rdquo;. It is proprietary and has a
free version with a limit of 5 million triples. Surely one of those Lisp hidden gems we should know more about.</p>

<p>A general migration tool was lacking. We now have
<a href="https://github.com/dnaeon/cl-migratum">cl-migratum</a>, a &ldquo;system which
provides facilities for performing database schema migrations,
designed to work with various databases&rdquo;.</p>

<p>And of course, <a href="https://github.com/dimitri/pgloader">pgloader</a> is still a Common Lisp success story.</p>

<p><strong>Achievement</strong></p>

<p>Among the emerging ORMs, Mito is the one actively maintained that Lispers seem to have chosen. Good. CLSQL certainly still works, but we don&rsquo;t hear about it and it looks outdated. So, Mito it is.</p>

<p><strong>Consolidation</strong></p>

<p>Mito has 11 contributors and is actively watched, but it probably should have another(s) core maintainers.</p>

<p><strong>Future work</strong></p>

<p>Bindings for the new databases coming out.</p>

<h2 id="concurrency">Concurrency</h2>

<p>In the last year, Manfred Bergmann developed
<a href="https://github.com/mdbergmann/cl-gserver">cl-gserver</a>. It is a
&ldquo;message passing&rdquo; library/framework with <strong>actors</strong> similar to
<strong>Erlang</strong> or <strong>Akka</strong>. It is an important achievement.</p>

<p>Its v1 features:</p>

<ul>
<li>actors can use a shared pool of message dispatchers which effectively allows to create millions of actors.</li>
<li>the possibility to create actor hierarchies. An actor can have child actors. An actor now can also &ldquo;watch&rdquo; another actor to get notified about its termination.</li>
</ul>

<p>Many other libraries exist in this area:</p>

<ul>
<li><a href="https://common-lisp.net/project/bordeaux-threads/">BordeauxThreads</a> - Portable, shared-state concurrency

<ul>
<li>the &ldquo;de-facto&rdquo; concurrency library.</li>
</ul></li>
<li><a href="https://github.com/lmj/lparallel">lparallel</a> - A library for parallel programming.

<ul>
<li>also solid, battle-tested and popular, aka de-facto.</li>
</ul></li>
<li><a href="https://github.com/hawkir/calispel">calispel</a> - <a href="https://en.wikipedia.org/wiki/Communicating_sequential_processes">CSP</a>-like channels for common lisp. With blocking, optionally buffered channels and a &ldquo;CSP select&rdquo; statement. ISC-style.

<ul>
<li>&ldquo;It is complete, flexible and easy to use. I would recommend Calispel over Lparallel and ChanL.&rdquo; @Ambrevar. <a href="https://github.com/CodyReichert/awesome-cl/issues/290">discussion</a></li>
</ul></li>
<li><a href="https://github.com/zkat/chanl">ChanL</a> - Portable, channel-based concurrency.</li>
<li><a href="https://github.com/orthecreedence/cl-async">cl-async</a> - A library for general-purpose, non-blocking programming.

<ul>
<li>works atop libuv</li>
</ul></li>
<li><a href="https://github.com/TBRSS/moira">Moira</a> -  Monitor and restart background threads. In-lisp process supervisor.</li>
<li><a href="https://gitlab.com/ediethelm/trivial-monitored-thread">trivial-monitored-thread</a> -
a Common Lisp library offering a way of spawning threads and being
informed when one any of them crash and die.</li>
<li><a href="https://github.com/lmj/lfarm">lfarm</a> - distributing work across machines (on top of lparallel and usocket).</li>
<li><a href="https://github.com/taksatou/cl-gearman">cl-gearman</a> - a library for the <a href="http://gearman.org/">Gearman</a> distributed job system.

<ul>
<li>Alexander Artemenko used it instead of lfarm for Ultralisp:
<a href="https://40ants.com/lisp-project-of-the-day/2020/06/0095-cl-gearman.html">https://40ants.com/lisp-project-of-the-day/2020/06/0095-cl-gearman.html</a>,
because &ldquo;lfarm is not well suited to environments where worker
hosts can go down and return back later&rdquo;.</li>
</ul></li>
<li><a href="https://github.com/brown/swank-crew">swank-crew</a> - distributed computation framework implemented using Swank Client.</li>
<li><a href="https://github.com/takagi/cl-coroutine">cl-coroutine</a> - a coroutine library. It uses the CL-CONT continuations library in its implementation.</li>
<li><a href="https://github.com/cosmos72/stmx">CMTX</a>: high performance transactional memory for Common Lisp.

<ul>
<li>In our opinion, a library not well known and under-appreciated.</li>
</ul></li>
</ul>

<p>(see <a href="https://github.com/CodyReichert/awesome-cl#parallelism-and-concurrency">awesome-cl#parallelism-and-concurrency</a>)</p>

<p><strong>Consolidation</strong></p>

<p>Bordeaux-Threads is <em>the</em> &ldquo;de-facto&rdquo; library, but there is some choice
paralysis between Lparallel, Calispel, Bordeaux-Threads and SBCL&rsquo;s
contribs. Use the libraries in the wild and write about them.</p>

<h2 id="file-formats">File formats</h2>

<p>There exist Common Lisp libraries for all the major file formats:</p>

<ul>
<li>XML: <a href="https://github.com/Shinmera/plump">Plump</a> (and <a href="https://github.com/Shinmera/lquery/">Lquery</a>), as well as <a href="https://common-lisp.net/project/cxml/">CXML</a>, which can parse large files incrementally.</li>
<li>JSON: <a href="https://github.com/Rudolph-Miller/jonathan">Jonathan</a>, <a href="https://common-lisp.net/project/cl-json/">cl-json</a> or <a href="https://sabracrolleton.github.io/json-review">more</a>. With utilities:

<ul>
<li><a href="https://github.com/y2q-actionman/cl-json-pointer">json-pointer</a> - A JSON Pointer implementation.</li>
<li><a href="https://github.com/gschjetne/json-mop">json-mop</a> - A metaclass for bridging CLOS and JSON objects (remind that JSON libraries can already serialize your own objects).</li>
<li><a href="https://github.com/fisxoj/json-schema">json-schema</a></li>
</ul></li>
<li>YAML: cl-yaml</li>
<li>CSV: <a href="https://github.com/AccelerationNet/cl-csv">cl-csv</a></li>
</ul>

<p><strong>Achievement</strong></p>

<p>New in 2015, Jonathan is now a good first choice for an easy to use and fast JSON encoder and decoder.</p>

<p><strong>Consolidation</strong></p>

<p>There is not a predominant JSON library. This leads to choice paralysis.</p>

<p>They all represent null values differently. We need a library that
&ldquo;does the right thing&rdquo;. See maybe the massive <a href="https://github.com/xh4/web-toolkit#json">web-toolkit</a> for its JSON handling ?</p>

<blockquote>
<p>It distinguishes null, false and [] from Lisp&rsquo;s NIL thus supports identical transformation between JSON values. It provides object constructor and accessor to build and access nesting JSON objects.</p>
</blockquote>

<p>Give the <a href="https://github.com/sharplispers/xpath">XPath</a> library some love and documentation.</p>

<p><strong>Future Work</strong></p>

<p>Still valid from 2015:</p>

<blockquote>
<p>A YAML parser so that cl-yaml doesn’t depend on the libyaml library would make distribution far simpler.</p>
</blockquote>

<h2 id="gui">GUI</h2>

<p>A usual complain in Common Lisp land is the lack of a complete,
cross-platform GUI solution. Ltk is a very good library, but Tk is
limited. Qtools is great, but is only for Qt4.</p>

<p>A lot has happened, and is still happening (if you watch the right
repositories, you know that a Qt5 wrapper is in the works (ECL already has Qt5 bindings: <a href="https://gitlab.com/eql/EQL5/">EQL5</a>, with an <a href="https://gitlab.com/eql/EQL5-Android">Android port</a>)).</p>

<p>edit: see also <a href="https://gitlab.com/eql/eql5-sailfish">EQL5-sailfish</a> for Sailfish OS. <a href="https://openrepos.net/user/13436/programs">Here</a> are two example apps.</p>

<p>Matthew Kennedy wrote excellent FFI bindings to the IUP Portable User
Interface library: <a href="https://github.com/lispnik/iup/">IUP</a>. IUP is
cross-platform (Windows, macOS, GNU/Linux, with new Android, iOS,
Cocoa and Web Assembly drivers), has many widgets (but less than Qt), has a small API and
is actively developed. IUP was created at the PUC university of Rio de Janeiro.</p>

<p>Nicolas Hafner started <a href="https://github.com/Shirakumo/alloy">Alloy</a>, a
new user interface protocol and toolkit implementation, which he uses in his Kandria game.</p>

<p>Very recently, David Botton released <a href="https://github.com/rabbibotton/clog">CLOG</a>, &ldquo;the Common Lisp Omnificent GUI&rdquo;:</p>

<blockquote>
<p>CLOG uses web technology to produce graphical user interfaces for applications locally or remotely. CLOG can take the place, or work alongside, most cross-platform GUI frameworks and website frameworks. The CLOG package starts up the connectivity to the browser or other websocket client (often a browser embedded in a native template application.)</p>

<p>It is complete enough for most uses.</p>
</blockquote>

<p>There are more GUI libraries and frameworks: <a href="https://github.com/CodyReichert/awesome-cl#Gui">https://github.com/CodyReichert/awesome-cl#Gui</a> (and more under the works). In particular, LispWorks&rsquo; CAPI is still presented as the best in town by the ones who tried it.</p>

<p><strong>Consolidation</strong></p>

<p>Since roughly October, 2020, Nicolas Hafner works full time on
<a href="https://kandria.com/">Kandria</a>. Supporting his work, through <a href="https://github.com/sponsors/Shinmera">GitHub
sponsors</a> or
<a href="https://ko-fi.com/shinmera">ko-fi</a> would be 1) a great sign of recognition and 2) useful for the ecosystem, especially for Alloy.</p>

<p>I wrote an introduction to these frameworks in the Cookbook:
<a href="https://lispcookbook.github.io/cl-cookbook/gui.html">Cookbook/gui</a>. More
examples or demo projects would be welcome.</p>

<p>There are two actively maintained diverged forks of the GTK bindings. A reunification effort is required.</p>

<p><strong>Future work</strong></p>

<p>Write a desktop application with IUP/your toolkit of choice for everyday use and make it a Common Lisp flagship.</p>

<p>Study other approaches to GUI bindings. What about
<a href="http://www.gtk-server.org/">gtk-server</a>? <a href="https://github.com/andy128k/cl-gobject-introspection">GObject introspection</a>? An
effort started for Qt: <a href="https://github.com/mrosset/giqt/">giqt</a> (in
which we recognize @ambrevar from the <a href="https://github.com/atlas-engineer/nyxt/">Nyxt
browser</a>).</p>

<h2 id="machine-learning">Machine Learning</h2>

<p>It seems that not much changed since 2015, but libraries are still being developed:</p>

<ul>
<li><a href="https://github.com/mmaul/clml">CLML</a>, developed at Mathematical Systems Inc., a Japanese company.</li>
<li><a href="https://github.com/melisgl/mgl">MGL</a></li>
</ul>

<blockquote>
<p>used by <a href="http://quotenil.com/">its author</a> to win the <a href="https://www.kaggle.com/c/higgs-boson">Higgs Boson Machine Learning Challenge</a></p>
</blockquote>

<ul>
<li><a href="https://github.com/melisgl/mgl-mat">mgl-mat</a> - a library for working with multi-dimensional arrays which supports efficient interfacing to foreign and CUDA code. BLAS and CUBLAS bindings are available.</li>
</ul>

<p>Others are less active:</p>

<ul>
<li><a href="https://gitlab.common-lisp.net/antik/antik">Antik</a> - a foundation for scientific and engineering computation in Common Lisp. It is designed not only to facilitate numerical computations, but to permit the use of numerical computation libraries and the interchange of data and procedures, whether foreign (non-Lisp) or Lisp libraries.

<ul>
<li>more than 2000 commits, last update 2 years ago.</li>
</ul></li>
</ul>

<h2 id="system">System</h2>

<p>To quote Fernando:</p>

<blockquote>
<p>UIOP, ASDF’s portable compatibility layer, contains a large set of tools for portably doing everything from querying the hostname to running external programs to manipulating environment variables.</p>
</blockquote>

<p>We should not require cl-fad anymore (but we need Osicat, which unlike UIOP is POSIX friendly).</p>

<p>Built on top of UIOP, Paul M. Rodriguez&rsquo;s <a href="https://github.com/ruricolist/cmd">cmd</a> brings in short and handy helpers to run and pipe programs.</p>

<h2 id="web-development">Web Development</h2>

<h3 id="backend">Backend</h3>

<p>Common Lisp&rsquo;s main web servers are Hunchentoot and Clack. Since 2015, Clack&rsquo;s documentation state barely improved and is still lacking.</p>

<p><a href="https://github.com/fukamachi/clack">Clack</a> is the equivalent of
WSGI/Rack. It has existed since 2009. It is an HTTP
server abstraction, that allows the user to write web applications
(or, more reasonably, web application frameworks) without depending on
a particular server. Some web frameworks are built on top of
it, for example <a href="http://8arrow.org/caveman/">Caveman2</a>.</p>

<blockquote>
<p>The importance of using Clack cannot be understated: If you build an application directly on, say, Hunchentoot, you’re tied to Hunchentoot, and if a new, faster server – like <a href="https://github.com/fukamachi/woo">Woo</a> – comes out, you have to rewrite the entire application to use it. If you write a plugin for Clack – like <a href="https://github.com/eudoxia0/clack-errors">clack-errors</a> – it is automatically usable by all applications, regardless of framework, that are built on Clack, reducing useless duplication of code.</p>

<p>With Clack, switching from Hunchentoot to Woo, and enjoying the incredible speedup, is a simple matter of installing libev and changing a keyword argument.</p>
</blockquote>

<p>This still holds true, but the situation didn&rsquo;t improve much. In comparison, Hunchentoot is very well documented (and you can read its documentation on a better looking <a href="https://common-lisp-libraries.readthedocs.io/hunchentoot/">readthedocs here</a>), and it is &ldquo;fast enough&rdquo;.</p>

<p>About Hunchentoot: Mariano Montone wrote <a href="https://github.com/mmontone/easy-routes">easy-routes</a>, a little but handy route handling facility on top of Hunchentoot. It brings:</p>

<ul>
<li>dispatch by HTTP method,</li>
<li>arguments extraction from the URL path,</li>
<li>&ldquo;decorators&rdquo; to, for example, quickly add authorization checks,</li>
<li>integration with the Djula framework to generate URLs from route names.</li>
</ul>

<p><strong>Achievement</strong></p>

<p>Several <a href="https://github.com/CodyReichert/awesome-cl#clack-plugins">Clack plugins</a>
were written, such as a single-sign on middleware.</p>

<p><strong>Consolidation</strong></p>

<p>Write more documentation for Clack. While Lispers know about it,
they don&rsquo;t necessarily adopt it because of the lack of
documentation. We can expand this <a href="https://jasom.github.io/clack-tutorial/posts/getting-started-with-clack/">getting started
guide</a>.</p>

<p><strong>Future work</strong></p>

<p>Build a batteries-included framework.</p>

<h3 id="frontend">Frontend</h3>

<p>Many HTML generators and template libraries exist (see the list below). However, some new and good ones appeared lately:</p>

<ul>
<li><a href="https://github.com/mmontone/ten">TEN</a>, by Djula&rsquo;s maintainer, brings the completness of Djula with the usability of Eco (by Fernando Borretti), aka: you write Django-like HTML templates but you can interleave any Lisp code.</li>
<li><a href="https://github.com/moderninterpreters/markup">markup</a> - a JSX-like templating engine, where HTML tags are Common Lisp code. Comes with an Emacs package.</li>
</ul>

<p>Other HTML generators and templating engines include:</p>

<ul>
<li><a href="https://github.com/ruricolist/spinneret">spinneret</a> - Common Lisp HTML5 generator.</li>
<li><a href="http://weitz.de/cl-who/">cl-who</a> - The venerable HTML generator.</li>
<li><a href="https://github.com/mmontone/djula">Djula</a> - A port of Django&rsquo;s template engine to Common Lisp.</li>
<li><a href="https://github.com/archimag/cl-closure-template">cl-closure-template</a> - Implementation of Google&rsquo;s Closure templates. [LLGPL][8].</li>
<li><a href="https://shinmera.github.io/clip">clip</a> - An HTML template processor where the templates are written in HTML.</li>
</ul>

<p>We have nice other building blocks, such as a nice form handling
library (<a href="https://github.com/mmontone/cl-forms">cl-forms</a>) and
libraries to create Open-API interfaces. An integrated, opinionated
all-in-one solution could be a productivity boom.</p>

<p><strong>Consolidation</strong></p>

<p>Djula is easy to work with. It could do with more built-in filters.</p>

<p>As in 2015:</p>

<blockquote>
<p>The foundation is finished, now it’s time to write higher-level layers. An extensible administration framework for Clack applications, like Django’s Admin, would be a good example.</p>
</blockquote>

<h3 id="javascript">JavaScript</h3>

<p>The two &ldquo;historical&rdquo; Common Lisp to JavaScript compilers are:</p>

<ul>
<li><a href="https://github.com/vsedach/Parenscript">Parenscript</a>, a DSL that compiles a subset of Common Lisp to idiomatic JavaScript, and</li>
<li><a href="https://github.com/davazp/jscl">JSCL</a>, a CL-to-JS compiler designed to be self-hosting from day one. JSCL is not complete (yet), it lacks CLOS, format and loop.</li>
</ul>

<p>Two new are in development:</p>

<ul>
<li><a href="https://github.com/cxxxr/valtan">Valtan</a>, a CL to JS compiler.</li>
<li><a href="https://tailrecursion.com/JACL/">JACL</a>, JavaScript Assisted Common LispIt has a <a href="https://www.youtube.com/watch?v=JYLlC_dgQ5w">recording from ELS 2020</a>.</li>
</ul>

<p><strong>Consolidation</strong></p>

<p>Help develop one of the existing CL-to-JS implementations. Why not have a look at
JSCL&rsquo;s <a href="https://github.com/jscl-project/jscl/issues">issues</a>?</p>

<p>Bring some new macros to ParenScript for new JavaScript idioms, as <a href="https://github.com/BnMcGn/paren6/">Paren6</a>. For example, allow to write <code>async</code> and <code>await</code>.</p>

<h3 id="isomorphic-web-frameworks">Isomorphic web frameworks</h3>

<p>Weblocks is an already old framework that allows to write dynamic web
applications without writing JavaScript (it isn&rsquo;t as dynamic as modern
JS frameworks, there is no &ldquo;double data binding&rdquo;). Its server-based
components use Ajax if available or fallback to plain HTTP and
update the DOM. It is a framework in the vein of Smalltalk&rsquo;s Seaside.</p>

<p>Weblocks was getting old and unmaintained but Alexander Artemenko greatly updated and refactored it in his <a href="https://github.com/40ants/weblocks/">Reblocks</a> branch. He uses it for the <a href="https://ultralisp.org/">Ultralisp</a> website, and more apps. You can reach users and developers <a href="https://gitter.im/40ants/weblocks">on Gitter</a>.</p>

<p>Recently, a very new web framework appeared:
<a href="https://github.com/interactive-ssr">ISSR</a>, for Interactive
Server-Side rendering. It links a client to the server with a
websocket connection and updates the DOM selectively. It is thus not
unlike Phoenix&rsquo;s LiveView or
<a href="https://github.com/hotwired/turbo">Hotwire</a>.</p>

<p>See this <a href="http://cjackson.tk/todo-tutorial">todo-app tutorial</a>.</p>

<p><strong>Achievement</strong></p>

<p>Reviving Weblocks and releasing CLOG and ISSR are great achievements. However, work is only started to create a community of users around them.</p>

<h1 id="languages-interop">Languages interop</h1>

<p>New solutions arose to interoperate with other runtimes.</p>

<h2 id="apl">APL</h2>

<p><a href="https://github.com/phantomics/april">April</a> brings the APL programming language (a subset thereof) to Common Lisp. Replace hundreds of lines of number-crunching code with a single line of APL.</p>

<h2 id="c-c-objective-c">C, C++, Objective C</h2>

<p>We had <a href="https://github.com/cffi/cffi">CFFI</a> (a portable foreign function interface for CL), <a href="https://github.com/rpav/c2ffi">C2FFI</a> (Clang-based FFI wrapper generator), then <a href="https://github.com/rpav/cl-autowrap">cl-autowrap</a>, a c2ffi-based wrapper generator that makes creating C bindings real quick.</p>

<p>Pavel Korolev is developing <a href="https://github.com/borodust/claw">CLAW</a>, started as a fork of cl-autowrap, which brings <strong>C++ support</strong>. For practice he generated bindings to GLM or <a href="https://github.com/borodust/claw-filament">to the Filament</a> rendering engine.</p>

<p><strong>Achievement</strong></p>

<p>It will be a great achievement when CLAW is officially ready to use. This is not yet the case (though the GLM bindings basically do their hello world on Android, which is an achievement per se).</p>

<h2 id="clojure">Clojure</h2>

<p><a href="https://github.com/lsevero/abclj">ABCLJ</a> provides a &ldquo;dead easy  Clojure to Common lisp interop&rdquo;:</p>

<blockquote>
<p>instead of rewriting the whole Clojure langugage on CL I&rsquo;m embedding ABCL in Clojure. Since both are implemented in Java and Clojure has an awesome java interop is easy to have full access on the ABCL Common Lisp environment. This way we have complete support for both Clojure and Common Lisp.</p>
</blockquote>

<p>But why?</p>

<blockquote>
<p>The reason I wanted to see Clojure and Common Lisp working with each other was to use CL programs/libraries on Clojure, especially Maxima and ACL2. Since ABCL already compiles and runs Maxima it should be possible but we are very far from it 🤷.</p>

<p>There are others of attempts to shorten the gap between clojure and common lisp like Cloture and clclojure. Once they are complete Clojure will benefit from native binaries and excelent compilers like SBCL, however they are far from complete.</p>
</blockquote>

<p>On the topic, see this talk by Alan Dipert: <a href="https://www.youtube.com/watch?v=44Q9ew9JH_U">&ldquo;Common Lisp for the curious Clojurian&rdquo;</a>.</p>

<p>Abstract:</p>

<hr />

<blockquote>
<p>“If I had to be stranded with something other than Clojure, I’d be happiest with a good Common Lisp and its source code.” - Rich Hickey, 2011</p>
</blockquote>

<p>Common Lisp (CL) and Clojure are both dialects of Lisp. Rich Hickey, the creator of Clojure, learned CL and used it professionally before creating Clojure.</p>

<p>What can Clojure do that CL can’t, and vice versa? Why would anyone use CL today, when both Clojure and ClojureScript exist?</p>

<p>In this talk, I will try to answer these questions and more, from the perspective of a long-time Clojurian with a growing passion for CL.</p>

<hr />

<h2 id="python">Python</h2>

<p><a href="https://github.com/bendudson/py4cl">py4cl</a> is the new lib in town. It allows Common Lisp code to access Python libraries. It is basically the inverse of <a href="https://github.com/marcoheisig/cl4py">cl4py</a>.</p>

<p>See also <a href="https://github.com/cxxxr/async-process/">async-process</a> and,
while we&rsquo;re at it, my <a href="/pythonvslisp">comparison of Python VS Common
Lisp</a>, where we look at the differences of workflows and
ecosystems.</p>

<p><strong>Achievement</strong></p>

<p>Calling to Python and hooking into its ecosystem is easier than ever.</p>

<p><strong>Future work</strong></p>

<p>Improving CL libraries such as
<a href="https://github.com/numcl/numcl">Numcl</a> (a Numpy clone) is what&rsquo;s
required to drive Common Lisp forward.</p>

<h2 id="net-core">.Net Core</h2>

<p><a href="https://github.com/Lovesan/bike">Bike</a> is a cross-platform .Net Core interface.</p>

<h1 id="development">Development</h1>

<h2 id="implementations">Implementations</h2>

<p>All implementations saw new releases, except CLisp, whose development however continues.</p>

<p>Active implementations include: ABCL, CCL, CLASP, ECL, LispWorks, AllegroCL, SBCL. And to a certain extent, GNU CLisp, SICL (which is the newest one) and Corman Lisp (a CL development environment for Windows) (regenerated <a href="https://github.com/sharplispers/cormanlisp">here</a>).</p>

<p>ABCL <a href="https://abcl-dev.blogspot.com/2020/10/abcl-180.html">jumped to v1.8.0</a> to support openjdk15.</p>

<p>SBCL still ships monthly releases. It turned 20 and keeps improving (RISC-V port, M1 port, block compilation, more compile-time type checking…). We can read a blog on the party held in Vienna <a href="https://mstmetent.blogspot.com/2020/01/sbcl20-in-vienna-last-month-i-attended.html">here</a>. Did you know that Doug Katzman of Google fame contributes to SBCL?</p>

<p>(edit:)</p>

<blockquote>
<p>Doug Katzman talked about his work at Google getting SBCL to work with Unix better. For those of you who don’t know, he’s done a lot of work on SBCL over the past couple of years, not only adding a lot of new features to the GC and making it play better with applications which have alien parts to them, but also has done a tremendous amount of cleanup on the internals and has helped SBCL become even more Sanely Bootstrappable. That’s a topic for another time, and I hope Doug or Christophe will have the time to write up about the recent improvements to the process, since it really is quite interesting.</p>

<p>Anyway, what Doug talked about was his work on making SBCL more amenable to external debugging tools, such as gdb and external profilers. It seems like they interface with aliens a lot from Lisp at Google, so it’s nice to have backtraces from alien tools understand Lisp. It turns out a lot of prerequisite work was needed to make SBCL play nice like this, including implementing a non-moving GC runtime, so that Lisp objects and especially Lisp code (which are normally dynamic space objects and move around just like everything else) can’t evade the aliens and will always have known locations.</p>
</blockquote>

<!-- SICL was able to load the Alexandria library. Some of its components are already used in the wild (for example, the [Eclector](https://github.com/s-expressionists/Eclector) Common Lisp reader). -->

<h2 id="editors">Editors</h2>

<p>Here too, great progress has been made. While a usual complain of non-Lispers was the lack of editor support besides Emacs (and Vim), we now nearly reach choice paralysis:</p>

<ul>
<li><a href="https://portacle.github.io/">Portacle</a> is the easiest way to get started with Emacs. It is portable and multi-platform, ready-to-use in three clicks. It ships Emacs, SBCL, Slime, Quicklisp and git.</li>
<li><a href="https://github.com/neil-lindquist/SLIMA/">SLIMA</a> is the Atom extension. It is nearly as good as Slime for Emacs.</li>
<li>VSCode has two extensions: <a href="https://github.com/ailisp/commonlisp-vscode">commonlisp-vscode</a>, using the Language Server Protocol, and <a href="https://github.com/nobody-famous/alive">Alive</a>, more recent, using a Lisp backend (Swank) as traditional extensions.</li>
<li>Sublime Text got a good extension: <a href="https://github.com/s-clerc/slyblime">Slyblime</a> is an implementation of SLY and it uses the same backend (SLYNK). It ships advanced features including a debugger with stack frame inspection.</li>
<li><a href="https://github.com/cxxxr/lem/">Lem</a> is an editor written in Common Lisp. It allows to start developing in CL at once, and it supports other languages.</li>
<li>we have a <a href="https://github.com/yitzchak/common-lisp-jupyter">Jupyter kernel</a> for CL.</li>
<li>the <a href="https://github.com/Ragnaroek/dandelion/">Dandelion Eclipse plugin</a> was re-discovered. While it isn&rsquo;t as feature-rich as others (no interactive debugger for example), it has its users. It specifically targets beginners.</li>
</ul>

<p>Last but not least, if you want to play in your iPhone or iPad, the <a href="https://codeplayground.app/">CodePlayground</a> app got Lisp support via CCL.</p>

<p><strong>Consolidation</strong></p>

<p><a href="https://github.com/joaotavora/sly">SLY</a> might need more praise. It has sound features such as SLY stickers and the new <a href="https://github.com/joaotavora/sly-stepper">SLY stepper</a>.</p>

<h2 id="developer-utilities">Developer utilities</h2>

<p>Life continues to improve for the developper. We will cite some new tools:</p>

<ul>
<li><a href="https://github.com/40ants/cl-flamegraph">cl-flamegraph</a> is a wrapper around SBCL&rsquo;s statistical profiler to generate FlameGraph charts from Common Lisp programs.</li>
<li><a href="https://github.com/TeMPOraL/tracer">tracer</a> is a tracing profiler for Common Lisp, with output suitable for display in Chrome’s/Chromium’s Tracing Viewer.</li>
<li><a href="http://www.martin-loetzsch.de/gtfl/">GTFL</a> is a graphical terminal for Lisp, meant for Lisp programmers who want to debug or visualize their own algorithms. It is a graphical trace in the browser.</li>
<li><a href="https://gitlab.com/ambrevar/lisp-repl-core-dumper/">Lisp REPL core dumper</a> is a portable wrapper to generate Lisp cores on demand to start a REPL blazingly fast. It can preload provided systems to help build a collection of specialized Lisp cores.

<ul>
<li>if you are used to working in different environments that require their own set of libraries, this core dumper (optionally along with SLY&rsquo;s mrepl) can make switching from one another easier and faster.</li>
</ul></li>
</ul>

<h2 id="package-management">Package Management</h2>

<p>Quicklisp is the de-facto package manager. However, we now have:</p>

<ul>
<li><a href="https://ultralisp.org/">Ultralisp</a>, a Quicklisp distribution that builds every 5 minutes. We can add our project in two clicks.</li>
<li><a href="https://gitlab.common-lisp.net/clpm/clpm">CLPM</a>, a new package manager that is compatible with Quicklisp, that allows to pin exact versions of dependencies, that is usable from the command line and that supports HTTPS.</li>
</ul>

<p>Not forgetting Qlot, to install Quicklisp libraries relative to a directory.</p>

<p>Last but not least, as said earlier, many CL libraries were packaged for Guix (most notably by <a href="https://ambrevar.xyz">Pierre Neidhart</a> of Nyxt).</p>

<p><strong>Achievement</strong></p>

<p>Ultralisp solves the 1-month release schedule of Quicklisp (which is a feature, but not to everyone&rsquo;s taste) and makes it straightforward and quick to publish a library. CLPM by tackling a different approach solves other Quicklisp limitations. Both are great achievements.</p>

<p>Ultralisp also has a search box that searches a symbol on all its registered libraries. Very useful.</p>

<p><strong>Future work</strong></p>

<p>Alexander is working on allowing every Ultralisp user to create his own Quicklisp dist in a few clicks.</p>

<h2 id="build-system">Build System</h2>

<p>Same as 2015, ASDF is the de-facto build system.</p>

<blockquote>
<p>Every project has an .asd file, called a system definition file, which defines project metadata (author, maintainer, homepage, etc.) and the components.</p>

<p>This, to me, is one of the major selling points of Common Lisp. With languages like Python, every file imports whatever it needs, and your project becomes a massive graph of interdependent files. In ASDF, you basically list the files in your project in the order in which they are defined. Or, you can specify the dependencies between the files, and let ASDF figure out a linear ordering. The point is that dependencies are explicit, and clearly spelled out.</p>
</blockquote>

<!-- ## Documentation -->

<h2 id="type-system">Type system</h2>

<p>Quoting Fernando:</p>

<blockquote>
<p>There’s not much to say here, except that Common Lisp has a pretty great type system that is not exploited nearly enough.</p>
</blockquote>

<p>And to our greatest pleasure, SBCL&rsquo;s type system continues to improve. For example, SBCL 1.5.9 now gives type warnings when a slot declared type doesn&rsquo;t match its <code>initform</code>. It continued to improve on SBCL 2.0 and onwards.</p>

<p>Moreover, the <a href="https://github.com/stylewarning/coalton/">Coalton</a> library is bringing a dialect of ML on top of CL, in order to write <strong>statically typed programs</strong> similar in spirit to Standard ML, OCaml, and Haskell.</p>

<p><strong>Consolidation</strong></p>

<p>Help develop Coalton.</p>

<h2 id="testing-ci">Testing, CI</h2>

<p>Fernando cited <a href="https://common-lisp.net/project/fiveam/docs/Introduction.html">FiveAM</a> and recommended it along with the much newer
Prove. Prove has a couple issues and is now deprecated by its author,
and its younger brother Rove is not in par yet.</p>

<p>So, use FiveAM.</p>

<p>Moreover, Common Lisp has good support for the CI/CD services out there.</p>

<p>CL Foundation&rsquo;s Docker images have integrated best practices over the
years and are recommended:
<a href="https://common-lisp.net/project/cl-docker-images/">https://common-lisp.net/project/cl-docker-images/</a></p>

<p><a href="https://github.com/neil-lindquist/CI-Utils">CI-Utils</a> regroups
utilities for various platforms (Travis, Circle, Gitlab, Github,
Appveyor, Bitbucket, Azure) and test frameworks.</p>

<p>We got a comprehensive blog post for GitHub actions: <a href="http://3bb.cc/blog/2020/09/11/github-ci/">part1</a> and <a href="http://3bb.cc/blog/2020/09/13/github-ci2/">part2</a>.</p>

<p>For Travis CI, you can also see <a href="https://github.com/luismbo/cl-travis">cl-travis</a> (for ABCL, Allegro CL, SBCL, CMUCL, CCL and ECL).</p>

<p>You will find an example for Gitlab CI on the Cookbook.</p>

<p><strong>Consolidation</strong></p>

<p>Rove or <a href="https://github.com/Shinmera/parachute">Parachute</a> would be great alternatives if developed a bit further.</p>

<p><strong>Further work</strong></p>

<p>Integration with the CI services&rsquo; advanced features such as Gitlab&rsquo;s auto DevOps.</p>

<h1 id="community">Community</h1>

<h2 id="online-presence">Online presence</h2>

<p>Common Lisp is very well documented through its standard, the Common
Lisp Hyper Spec and many books. However, we felt it was lacking good
on-line material. Good news is, the situation improved tremendously in
the last three or four years.</p>

<h3 id="new-common-lisp-net-website">New common-lisp.net website</h3>

<p><a href="https://common-lisp.net">https://common-lisp.net</a> was written anew. It looked dated. This is now fixed. Well done!</p>

<h3 id="cookbook">Cookbook</h3>

<p>The <a href="https://lispcookbook.github.io/cl-cookbook/">Common Lisp Cookbook</a> on GitHub got revived by many new contributors, included myself. It got many new content and a new UI. It is also now available in ePub and PDF, for free or as a &ldquo;pay what you want&rdquo; option.</p>

<p><strong>Consolidation</strong></p>

<p>Write content on the Cookbook. Don&rsquo;t write tutorials on your blog. Everyone can help, even new Lispers (and in fact: <em>mostly</em> new Lispers can write content best suited to the Cookbook&rsquo;s target audience).</p>

<p><strong>Future work</strong></p>

<p>Make it look world-class with a real and modern theme.</p>

<p>Help revive the <a href="https://github.com/lamberta/minispec">minispec</a> ?</p>

<h3 id="awesome-cl">awesome-cl</h3>

<p>The <a href="https://github.com/CodyReichert/awesome-cl">awesome-cl</a> list saw continuous updates and is  now a great solution to have an overview of the ecosystem and choose a library.</p>

<p>One of its goals is to break choice paralysis by recommending libraries, with its &ldquo;+1&rdquo; marks.</p>

<p><strong>Consolidation</strong></p>

<p>Help furnish and curate it.</p>

<h3 id="more">More</h3>

<p>A first Common Lisp User survey was run, we can consult its results here <a href="https://docs.google.com/forms/d/e/1FAIpQLSfg7UJRKrkI3OjOHWL4xI-murE4LpQjIxsiAhFdPEmtyLX3kg/viewanalytics">on Google docs</a> and read comments <a href="https://www.reddit.com/r/lisp/comments/jwdimb/state_of_common_lisp_survey_2020_raw_results/">on reddit</a> as well as feedback on the questions <a href="https://www.reddit.com/r/Common_Lisp/comments/f8wqkj/state_of_common_lisp_survey_2020/">here</a>.</p>

<p>I agree with /u/defunkydrummer here:</p>

<blockquote>
<p>Note that many, many things that people wish to see, are already available, so perhaps we, as a community, are not fully communicating the state of our ecosystem even to our insiders (!)</p>
</blockquote>

<p>Several popular libraries have been ported to readthedocs, so the reading experience is more pleasant: <a href="https://common-lisp-libraries.readthedocs.io/">https://common-lisp-libraries.readthedocs.io/</a>.</p>

<p>Michal &ldquo;phoe&rdquo; Herda organized many online Lisp meetings, and we can find the videos on Youtube: <a href="https://www.youtube.com/c/OnlineLispMeetings/videos">https://www.youtube.com/c/OnlineLispMeetings/videos</a></p>

<p>Alexander Artemenko started <a href="https://40ants.com/lisp-project-of-the-day/">lisp project of the day</a>, a blog to review a library every day for a month, and he is now at post #219. Lately he reviewed many documentation builders for CL.</p>

<p>On a sadder note, Quickdocs closed :(</p>

<h2 id="new-books">New books</h2>

<p>We got 3 new books on Common Lisp in 2020:</p>

<ul>
<li><a href="http://vseloved.github.io/progalgs.html">Programming Algorithms</a>, originally published by Vsevolod Dyomkin on his website, then self-published in paperback and then published by Apress.</li>
<li><a href="https://github.com/Apress/common-lisp-condition-system/">the Common Lisp Condition System</a>, by Michal &ldquo;phoe&rdquo; Herda, was also published by himself and then by Apress.</li>
<li>The Cookbook that was made available in ePub and PDF :)</li>
</ul>

<p>And also:</p>

<ul>
<li>the book <a href="https://www.cambridge.org/us/academic/subjects/computer-science/computing-general-interest/calendrical-calculations-ultimate-edition-4th-edition?format=HB#resources">Calendrical calculations</a>, 4th edition, by Edward M. Reingold, Nachum Dershowitz, Cambridge Press. It provides Lisp sources.</li>
<li><a href="https://www.qrg.northwestern.edu/bps/readme.html">Building Problem Solvers</a>, by Kenneth Forbus and Johan de Kleer, MIT Press, was made available.</li>
</ul>

<h2 id="companies">Companies</h2>

<p>We now have a curated list of companies using CL: <a href="https://github.com/azzamsa/awesome-lisp-companies">awesome-cl-companies</a>. Before that list, the situation was embarassing:</p>

<blockquote>
<p>Everyone says “Nobody uses Lisp” and Lispers say “Yes they do, there’s ITA, and, um, Autocad, and, uh, oh yeah, Paul Graham wrote Viaweb in Lisp!” Not very helpful for either side. It’s about time there was a better resource.</p>
</blockquote>

<p><a href="http://pchristensen.com/blog/lisp-companies/">Peter Christensen in his first list</a></p>

<p>And see also <a href="https://lisp-lang.org/success/">lisp-lang.org&rsquo;s success stories</a>.</p>

<p>Some additions of this year include
<a href="https://graphmetrix.com/">GraphMetrix</a> (automation of document extraction and publishing for construction, property and logistics),
Doremir Music Research AB (developing <a href="https://scorecloud.com/">ScoreCloud</a>, a music notation software: you sing, it writes the score),
<a href="https://www.keepit.com/">Keepit</a> (a cloud-to-cloud backup service provider),
<a href="https://www.mind.ai">Mind AI</a> (an artificial intelligence engine and ecosystem),
<a href="http://insurevip.co.uk">Virtual Insurance Products Ltd</a> (insurance MGA with a bespoke business to business web platform) or again
<a href="https://mimix.io/">the Mimix Company</a> (creators of MSL and Nebula, new tools for working with facts and documents).</p>

<h2 id="growth">Growth</h2>

<p>We are able to compare the number of downloads of the 100 most popular Quicklisp libraries between 2015 and 2020:</p>

<p><img src="/sotu-downloads-2020.png" alt="" title="Comparing total downloads of Quicklisp libraries shows a 3x increase between 2015 and 2020." /></p>

<p>We can observe a 3x growth in five years. Of course, these figures need to be taken with a grain of salt, what they really represent is subject to interpretation. What is the role of Continuous Integration here?</p>

<p>Check it yourself: <a href="https://gitlab.com/-/snippets/2070318">snippet</a>, <a href="https://jsfiddle.net/1q3xjyeL/1/">JSFiddle</a>.</p>

<h1 id="last-words">Last words</h1>

<p>Many things are happening in the CL universe. Stay tuned!</p>

<hr />

<p>The <a href="https://gitlab.com/lisp-journey/lisp-journey.gitlab.io/-/blob/master/content/blog/state-of-the-common-lisp-ecosystem-2020.md#implementations">article source</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Why of technology</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Murilo Pereira</a> <span class="article__date">07 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I think one of the things that really separates us from the high primates is that we&rsquo;re tool builders. I read a study that measured the efficiency of locomotion for various species on the planet. The condor used the least energy to move a kilometer. Humans came in with a rather unimpressive showing about a third of the way down the list. It was not too proud a showing for the crown of creation.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ondahostil.files.wordpress.com/2018/08/yo.jpg?w=32" alt="En qué ando últimamente">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">En qué ando últimamente</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Onda Hostil</a> <span class="article__date">07 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        El final del 2020 fue una auténtica locura, tanto que tengo la investigación parada desde hace meses y hago los deberes de italiano en el tren. Eso sí, entre toda la locura, descubrí que mi charla de la esLibre del año anterior está ahora en PeerTube: y colaboré con mi voz en un pequeño vídeo [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Real Novelty of the ARPANET</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Two-Bit History</a> <span class="article__date">07 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        If you run an image search for the word “ARPANET,” you will find lots of maps showing how the government research network expanded steadily across the country throughout the late ’60s and early ’70s. I’m guessing that most people reading or hearing about the ARPANET for the first time encounter one of these maps. Obviously, the maps are interesting—it’s hard to believe that there were once so few networked computers that their locations could all be conveyed with what is really pretty lo-fi cartography. (We’re talking 1960s overhead projector diagrams here. You know the vibe.) But the problem with the maps, drawn as they are with bold lines stretching across the continent, is that they reinforce the idea that the ARPANET’s paramount achievement was connecting computers across the vast distances of the United States for the first time.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Tendencias en Programación, Ops, IA y Web en 2021 según O’Reilly Media">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Tendencias en Programación, Ops, IA y Web en 2021 según O’Reilly Media</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">06 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Recientemente O&#8217;Reilly Media publicó un completo informe titulado <a href="https://www.oreilly.com/radar/where-programming-ops-ai-and-the-cloud-are-headed-in-2021/" data-type="URL" data-id="https://www.oreilly.com/radar/where-programming-ops-ai-and-the-cloud-are-headed-in-2021/">Where Programming, Ops, AI, and the Cloud are Headed in 2021. </a>Este informe, escrito por Mike Loukides, responsable de estrategia de contenidos en O&#8217;Reilly, ha sido realizado con datos obtenidos en su plataforma de aprendizaje en línea. Tal y como explica el responsable, este estudio está limitado a los usuarios de la plataforma, según las búsquedas realizadas, filtrando y agrupando por categorías. <strong>El objetivo consiste en detectar tendencias </strong>según el interés por encontrar ciertas materias, ofreciendo información sobre el uso de los materiales formativos, dentro de la plataforma, su crecimiento y las búsquedas realizadas en la misma.</p>



<p><a href="https://www.oreilly.com/" data-type="URL" data-id="https://www.oreilly.com/">O&#8217;Reilly Media </a>es una de las empresa de contenidos tecnológicos más importante a nivel mundial, y un referente para muchos profesionales del ámbito de la programación y las nuevas tecnologías. Para este episodio hemos querido compartir varios apartados del estudio y para ello, también contamos con la compañía de Antony Goetzschel.</p>



<p>Como explican en el artículo, O&#8217;Reilly tuvo que cerrar su división de organización de conferencias en marzo y la reemplazó por «superstreams virtuales». O’Reilly <strong>ha experimentado un considerable aumento</strong> en el uso de la plataforma durante el último año debido a la COVID (en especial el formato de formación en vivo que creció un 96%, los libros subieron un 11% y el vídeo un 24%).</p>



<p>Debido a la extensión del artículo hemos decidido limitarlo a:<strong> lenguajes de programación, operaciones, desarrollo web y por último inteligencia artificial. </strong>No obstante el artículo también aborda cuestiones como la seguridad, la nube y la privacidad. <strong>Es por eso que os recomendamos al 100% su lectura.</strong></p>







<p>Se trata de un valioso documento donde dan buenas pistas acerca de las tendencias más notables en el ámbito tecnológico.<strong> El informe contiene interesantes apreciaciones por parte de Mike Loukides,</strong> en especial las relacionadas con la IA y sus implicaciones. Aunque este informe esté limitado a los datos obtenidos en la plataforma de O&#8217;Reilly Media, su influencia y alcance, le otorga una indudable validez para comprender las tendencias más sólidas en los próximos años.</p>



<p></p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Updated Debian 10: 10.8 released</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Debian News</a> <span class="article__date">06 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
    The Debian project is pleased to announce the eighth update of its
stable distribution Debian 10 (codename <q>buster</q>).
This point release mainly adds corrections for security issues,
along with a few adjustments for serious problems. Security advisories
have already been published separately and are referenced where available.
  
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">CSS: efecto Marquee</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Bufa</a> <span class="article__date">05 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Un ejemplo para conseguir un bonito efecto marquee usando solo CSS. Básicamente lo conseguimos repitiendo un par de veces el texto en el html, y usando una animación infinita CSS con translateX para mover el contenedor horizontalmente de inicio a [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title"> Launching OSV - Better vulnerability triage for open source</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">05 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://raygun.com/blog/images/measure-node-performance/feature.png" alt="Accidents in space, React app bugs, Color vision in Chrome DevTools, and RegExp DoS! 🛰  — Pony Foo Weekly">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Accidents in space, React app bugs, Color vision in Chrome DevTools, and RegExp DoS! 🛰  — Pony Foo Weekly</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Pony Foo Weekly</a> <span class="article__date">04 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="f-core"><div class="md-markdown"><p>We&#x2019;re glad you could make it this week! </p> <p>With your help, we can make Pony Foo Weekly <em>even more</em> awesome: <a href="https://ponyfoo.com/weekly/submissions?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-193" target="_blank" rel="noopener noreferrer">send tips about cool resources</a>.</p> </div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://evilmartians.com/chronicles/what-i-learned-as-a-developer-from-accidents-in-space?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-193" style="color:#1bc211;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>What I, as a developer, learned from accidents in space</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/article" style="color:#e4f9e3;background-color:#1bc211" class="wy-link-tag">Article</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>How Soviet space tales help the creator of PostCSS to follow best practices in development.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/sitnikcode?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-193" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Andrey Sitnik</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-primary"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://tinyurl.com/yxcbnnvw?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-193" style="color:#1bc211;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>How to measure and improve Node.js performance</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/node.js" class="wy-link-tag">node.js</a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>If JavaScript is so fast, why are so many Node.js applications slow? I&#x2019;ll show how we can profile a Node app using both the built-in profiler and Raygun.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/raygunio?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-193" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Raygun</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/sponsored" class="wy-link-tag wy-link-sponsor">Sponsored</a></div></td><td class="wy-td wy-link-cell-image"><a href="https://tinyurl.com/yxcbnnvw?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-193" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://raygun.com/blog/images/measure-node-performance/feature.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://www.youtube.com/watch?v=LnapsmokM_4&#38;utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-193" style="color:#1bc211;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Simulating color vision deficiencies in the Blink Renderer</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/talk" style="color:#fbf2f5;background-color:#e92c6c" class="wy-link-tag">Talk</a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>How Chrome DevTools implemented color vision deficiency simulation by combining HTML/CSS/SVG knowledge with C++.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/mathias?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-193" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Mathias Bynens</p> </a></div></td><td class="wy-td wy-link-cell-image"><a href="https://www.youtube.com/watch?v=LnapsmokM_4&#38;utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-193" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://i.ytimg.com/vi/LnapsmokM_4/maxresdefault.jpg" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://charlypoly.com/publications/blazing-fast-bug-solving-react?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-193" style="color:#1bc211;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Fast bug solving on React apps</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/best-practices" style="color:#900070;background-color:#ffe270" class="wy-link-tag">Best Practices</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Charly offers tips to improve your bug solving strategy.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/where_is_charly?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-193" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Charly Poly</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://blog.superhuman.com/how-to-eliminate-regular-expression-denial-of-service-f8983bb76afc?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-193" style="color:#1bc211;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>How to eliminate regular expression denial of service</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/best-practices" style="color:#900070;background-color:#ffe270" class="wy-link-tag">Best Practices</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>When regexes go wrong, they go devastatingly wrong. Conrad shares how to avoid catastrophic downtime that you would only see in production.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/conradirwin?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-193" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Conrad Irwin</p> </a></div></td></tr></table></td></tr></table></div></div><style>html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;position:relative;vertical-align:baseline}sup{top:-.5em}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto;resize:vertical;min-height:280px;max-height:900px}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item;margin:-10px -20px;padding:10px;background-color:#f6f6f6;cursor:pointer;border-bottom:2px solid #ddd}[hidden],template{display:none}body,body:after,body:before,html,html:after,html:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*,:after,:before{-webkit-box-sizing:inherit;-moz-box-sizing:inherit;box-sizing:inherit}@-moz-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-webkit-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-o-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-moz-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@-webkit-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@-o-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}.f-core{font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}.f-mono{font-family:Consolas,Menlo,Monaco,'Lucida Console','Liberation Mono','DejaVu Sans Mono','Bitstream Vera Sans Mono','Courier New',monospace,serif}.ly-custom-heading .f-heading,.ly-custom-heading h1,.ly-custom-heading h2,.ly-custom-heading h3,.ly-custom-heading h4,.ly-custom-heading h5,.ly-custom-heading h6,.ly-lean .f-heading,.ly-lean h1,.ly-lean h2,.ly-lean h3,.ly-lean h4,.ly-lean h5,.ly-lean h6{font-family:Neuton,'Hoefler Text',Palatino,Baskerville,Georgia,'Times New Roman',serif}.ly-custom-subheading .f-subheading,.ly-lean .f-subheading{font-family:Merriweather,Georgia,serif}body{margin:0;font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif;background:#fcfcfc;color:#333}img{max-width:100%;border:none}.md-markdown figure:not(.twitter-tweet-figure){background-color:#f6f6f6}.md-markdown figure:not(.twitter-tweet-figure)>a{display:block}.md-markdown figure:not(.twitter-tweet-figure)>a>img,.md-markdown figure:not(.twitter-tweet-figure)>img{display:block;margin-left:auto;margin-right:auto}.md-markdown figcaption{padding:10px;font-style:italic;font-size:14px;background:-webkit-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-moz-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-o-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-ms-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:linear-gradient(to right,#fff9e2 33%,#fcf9ee 100%);color:#555}.md-markdown .figure-has-loaded{background:-webkit-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-moz-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-o-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-ms-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:linear-gradient(to bottom,rgba(255,255,255,0) 0,#fcf9ee 100%)}b,em,font-style italic,font-weight bold,i,ins,strong{text-decoration:none}del{text-decoration:line-through}sub,sup{bottom:0;line-height:18px}button,input{overflow:visible;border-radius:0}button{border:none;padding:6px 8px;font-size:1.2em;background:0 0}button[disabled]{color:#cbccbc!important}input,select,textarea{display:block;width:100%;padding:10px 8px;line-height:18px;border:none;font:inherit}select{height:38px}ol,ul{padding:0;margin:0;list-style-position:inside}li>ol,li>ul{margin-left:20px}hr{border:none;border-top:5px solid rgba(0,0,0,.05);margin:20px 0}kbd{display:inline-block;border:1px solid #ccc;margin:0 .1em;padding:.1em .6em;line-height:1.4;font-size:11px;background-color:#f7f7f7;-webkit-box-shadow:0 1px 0 #bbb,0 0 0 2px #fff inset;box-shadow:0 1px 0 #bbb,0 0 0 2px #fff inset;border-radius:3px;color:#333;text-shadow:0 1px 0 #fff;white-space:nowrap}iframe{display:inline-block;border:none;max-width:100%}summary:hover{opacity:.8}details{padding:10px 20px 20px;border-bottom:2px dashed #ddd}details[open] summary{margin-bottom:20px}blockquote{border:none;margin:0!important}ol,p,ul{line-height:35px}p{margin:35px 0}@media only screen and (min-width:768px){ol,p,ul{line-height:30px}}a,button,input[type=submit]{cursor:pointer;text-decoration:none}.lk-link{color:#e92c6c;border-bottom:1px solid transparent;background-color:rgba(255,255,255,.04)}.lk-link .md-code-inline{position:relative}.lk-link .md-code-inline:only-child{display:inline-block;line-height:17px}.lk-link .md-code-inline:before{content:'';position:absolute;background-color:#f1e05a;top:0;left:0;right:0;bottom:0;opacity:.04}.lk-link:visited{background-color:rgba(233,44,108,.04)}.lk-link:visited .md-code-inline:before{background-color:#e92c6c}.lk-link:hover{border-bottom:1px solid #e92c6c}.lk-rainbows{position:relative;color:#333;margin-bottom:5px}.lk-rainbows:hover:before{position:absolute;content:'';left:0;right:0;bottom:-8px;height:3px;opacity:.8;-webkit-transition:.1s ease-in-out;-moz-transition:.1s ease-in-out;-o-transition:.1s ease-in-out;-ms-transition:all .1s ease-in-out;transition:.1s ease-in-out;-webkit-animation:.5s infinite bg-rainbow;-moz-animation:.5s infinite bg-rainbow;-o-animation:.5s infinite bg-rainbow;-ms-animation:bg-rainbow .5s infinite;animation:.5s infinite bg-rainbow}.lk-icon{color:#333}.lk-icon:hover{color:#e92c6c}.lk-visitor{color:#333}.lk-visitor:after{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-left:5px}.lk-visitor.lk-visitor-large:after{font-size:1em}.lk-visitor:hover:after{color:#333;border-bottom-style:solid}.lk-visitor:visited:after{color:#7d5cff}.lk-visitor-inside{color:#333}.lk-visitor-inside .lk-visitor-target:before{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-right:5px}.lk-visitor-inside.lk-visitor-large .lk-visitor-target:before{font-size:1em}.lk-visitor-inside:hover .lk-visitor-target:before{color:#333;border-bottom-style:solid}.lk-visitor-inside:visited .lk-visitor-target:before{color:#7d5cff}.lk-visitor-before{color:#333}.lk-visitor-before:before{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-right:5px}.lk-visitor-before.lk-visitor-large:before{font-size:1em}.lk-visitor-before:hover:before{color:#333;border-bottom-style:solid}.lk-visitor-before:visited:before{color:#7d5cff}.lk-visitor-before-no-underline:before{border-bottom-width:0}.lk-link-to-green{color:#cbccbc}.lk-link-to-green:visited,.lk-link-to-green:visited:before{color:#1bc211;background-color:#1bc211}.lk-link-to-green:active{outline-color:#1bc211}.lk-link-to-green:hover,.lk-link-to-green:hover:before{color:#8be186;border-bottom-color:#1bc211}.lk-green .lk-link,a.lk-green{color:#1bc211}.lk-green .lk-link:visited,a.lk-green:visited{background-color:rgba(27,194,17,.04)}.lk-green .lk-link:visited .md-code-inline:before,a.lk-green:visited .md-code-inline:before{background-color:#1bc211}.lk-green .lk-link:active,a.lk-green:active{outline-color:#1bc211}.lk-green .lk-link:hover,a.lk-green:hover{border-bottom-color:#1bc211}.lk-green.lk-icon:hover{color:#1bc211}.lk-pink-light .lk-link,a.lk-pink-light{color:#ea6c93}.lk-pink-light .lk-link:visited,a.lk-pink-light:visited{background-color:rgba(234,108,147,.04)}.lk-pink-light .lk-link:visited .md-code-inline:before,a.lk-pink-light:visited .md-code-inline:before{background-color:#ea6c93}.lk-pink-light .lk-link:active,a.lk-pink-light:active{outline-color:#ea6c93}.lk-pink-light .lk-link:hover,a.lk-pink-light:hover{border-bottom-color:#ea6c93}.lk-pink-light.lk-icon:hover{color:#ea6c93}.lk-black .lk-link,a.lk-black{color:#333}.lk-black .lk-link:visited,a.lk-black:visited{background-color:rgba(51,51,51,.04)}.lk-black .lk-link:visited .md-code-inline:before,a.lk-black:visited .md-code-inline:before{background-color:#333}.lk-black .lk-link:active,a.lk-black:active{outline-color:#333}.lk-black .lk-link:hover,a.lk-black:hover{border-bottom-color:#333}.lk-black.lk-icon:hover{color:#333}.lk-gray .lk-link,a.lk-gray{color:#999}.lk-gray .lk-link:visited,a.lk-gray:visited{background-color:rgba(153,153,153,.04)}.lk-gray .lk-link:visited .md-code-inline:before,a.lk-gray:visited .md-code-inline:before{background-color:#999}.lk-gray .lk-link:active,a.lk-gray:active{outline-color:#999}.lk-gray .lk-link:hover,a.lk-gray:hover{border-bottom-color:#999}.lk-gray.lk-icon:hover{color:#999}.lk-white .lk-link,a.lk-white{color:#fcfcfc}.lk-white .lk-link:visited,a.lk-white:visited{background-color:rgba(252,252,252,.04)}.lk-white .lk-link:visited .md-code-inline:before,a.lk-white:visited .md-code-inline:before{background-color:#fcfcfc}.lk-white .lk-link:active,a.lk-white:active{outline-color:#fcfcfc}.lk-white .lk-link:hover,a.lk-white:hover{border-bottom-color:#fcfcfc}.lk-white.lk-icon:hover{color:#fcfcfc}.lk-orange .lk-link,a.lk-orange{color:#f3720d}.lk-orange .lk-link:visited,a.lk-orange:visited{background-color:rgba(243,114,13,.04)}.lk-orange .lk-link:visited .md-code-inline:before,a.lk-orange:visited .md-code-inline:before{background-color:#f3720d}.lk-orange .lk-link:active,a.lk-orange:active{outline-color:#f3720d}.lk-orange .lk-link:hover,a.lk-orange:hover{border-bottom-color:#f3720d}.lk-orange.lk-icon:hover{color:#f3720d}.lk-lilly .lk-link,a.lk-lilly{color:#7d5cff}.lk-lilly .lk-link:visited,a.lk-lilly:visited{background-color:rgba(125,92,255,.04)}.lk-lilly .lk-link:visited .md-code-inline:before,a.lk-lilly:visited .md-code-inline:before{background-color:#7d5cff}.lk-lilly .lk-link:active,a.lk-lilly:active{outline-color:#7d5cff}.lk-lilly .lk-link:hover,a.lk-lilly:hover{border-bottom-color:#7d5cff}.lk-lilly.lk-icon:hover{color:#7d5cff}.lk-blue .lk-link,a.lk-blue{color:#1a4d7f}.lk-blue .lk-link:visited,a.lk-blue:visited{background-color:rgba(26,77,127,.04)}.lk-blue .lk-link:visited .md-code-inline:before,a.lk-blue:visited .md-code-inline:before{background-color:#1a4d7f}.lk-blue .lk-link:active,a.lk-blue:active{outline-color:#1a4d7f}.lk-blue .lk-link:hover,a.lk-blue:hover{border-bottom-color:#1a4d7f}.lk-blue.lk-icon:hover{color:#1a4d7f}.lk-inherited .lk-link,a.lk-inherited{color:inherit}.lk-inherited .lk-link:active,a.lk-inherited:active{outline-color:inherit}.lk-inherited .lk-link:hover,a.lk-inherited:hover{border-bottom-color:inherit}.lk-inherited.lk-icon:hover{color:inherit}.lk-twitter .lk-link,a.lk-twitter{color:#55acee}.lk-twitter .lk-link:visited,a.lk-twitter:visited{background-color:rgba(85,172,238,.04)}.lk-twitter .lk-link:visited .md-code-inline:before,a.lk-twitter:visited .md-code-inline:before{background-color:#55acee}.lk-twitter .lk-link:active,a.lk-twitter:active{outline-color:#55acee}.lk-twitter .lk-link:hover,a.lk-twitter:hover{border-bottom-color:#55acee}.lk-twitter.lk-icon:hover{color:#55acee}.lk-facebook .lk-link,a.lk-facebook{color:#3b5998}.lk-facebook .lk-link:visited,a.lk-facebook:visited{background-color:rgba(59,89,152,.04)}.lk-facebook .lk-link:visited .md-code-inline:before,a.lk-facebook:visited .md-code-inline:before{background-color:#3b5998}.lk-facebook .lk-link:active,a.lk-facebook:active{outline-color:#3b5998}.lk-facebook .lk-link:hover,a.lk-facebook:hover{border-bottom-color:#3b5998}.lk-facebook.lk-icon:hover{color:#3b5998}.lk-clean{background-color:transparent}.lk-chrome:hover{color:#4989f4}.lk-teal .lk-link,a.lk-teal{color:#00a19c}.lk-teal .lk-link:visited,a.lk-teal:visited{background-color:rgba(0,161,156,.04)}.lk-teal .lk-link:visited .md-code-inline:before,a.lk-teal:visited .md-code-inline:before{background-color:#00a19c}.lk-teal .lk-link:active,a.lk-teal:active{outline-color:#00a19c}.lk-teal .lk-link:hover,a.lk-teal:hover{border-bottom-color:#00a19c}.lk-teal.lk-icon:hover{color:#00a19c}table{width:100%;border-spacing:0;border-collapse:separate}td,th{padding:8px}@media only screen and (max-width:950px){.table-responsive{display:block}.table-responsive>thead{display:none}.table-responsive>tbody,.table-responsive>tfoot{display:block}.table-responsive>tbody>tr,.table-responsive>tfoot>tr{display:block;background-color:rgba(203,204,188,.1);margin-bottom:30px}.table-responsive>tbody>tr:nth-child(even),.table-responsive>tfoot>tr:nth-child(even){background-color:rgba(203,204,188,.15)}.table-responsive>tbody>tr:last-child,.table-responsive>tfoot>tr:last-child{margin-bottom:0}.table-responsive>tbody>tr>td,.table-responsive>tfoot>tr>td{display:block;text-align:left}.table-responsive>tbody>tr>td:before,.table-responsive>tfoot>tr>td:before{display:block;content:attr(data-label);color:#555;font-size:13px;margin:0 0 5px}.table-responsive .table-responsive-hide{display:none}}.c-oreilly-teal{color:#00a19c}.c-yellow-highlight{color:#ffe270}.c-dark-orange{color:#f3720d}.c-pink{color:#e92c6c}.c-purple{color:#900070}.c-blue{color:#1a4d7f}.c-dark-turquoise{color:#1686a2}.c-dark-green{color:#1bc211}.c-white{color:#fcfcfc}.c-gray{color:#b7b7b7}.c-lilly{color:#7d5cff}.c-teal{color:#3aca96}.c-bg-oreilly-teal{background-color:#00a19c}.c-bg-yellow-highlight{background-color:#ffe270}.c-bg-dark-orange{background-color:#f3720d}.c-bg-pink{background-color:#e92c6c}.c-bg-purple{background-color:#900070}.c-bg-blue{background-color:#1a4d7f}.c-bg-dark-turquoise{background-color:#1686a2}.c-bg-dark-green{background-color:#1bc211}.c-bg-white{background-color:#fcfcfc}.c-bg-gray{background-color:#b7b7b7}.c-bg-lilly{background-color:#7d5cff}.c-bg-teal{background-color:#3aca96}.tj-emoji{width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em}.dc-header{margin-bottom:60px}.dc-heading{text-align:center;font-size:4em;padding:0 10px;margin-top:0;margin-bottom:10px}.dc-role{line-height:26px;padding:0 20px;margin-top:10px;text-align:center;font-style:italic;color:#cbccbc}.dc-colored{background:#f6f6f6;border-top:9px solid rgba(125,92,255,.5)}.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:800px}.md-markdown blockquote:not(.twitter-tweet){margin:0;padding:20px 0;border:none;border-top:5px solid rgba(0,0,0,.05);border-bottom:5px solid rgba(0,0,0,.05)}.md-markdown blockquote:not(.twitter-tweet) h1,.md-markdown blockquote:not(.twitter-tweet) h2,.md-markdown blockquote:not(.twitter-tweet) h3,.md-markdown blockquote:not(.twitter-tweet) h4,.md-markdown blockquote:not(.twitter-tweet) h5,.md-markdown blockquote:not(.twitter-tweet) h6{margin:-20px 0;padding:20px 0}.md-markdown blockquote:not(.twitter-tweet) .md-code-block{margin:0}.md-markdown blockquote:not(.twitter-tweet) .md-code-block:last-child{margin-bottom:-20px}.md-markdown img:first-child{margin-top:0}.md-markdown img:last-child{margin-bottom:0}.md-markdown p:first-child{margin-top:0}.md-markdown p:last-child{margin-bottom:0}.md-markdown .md-code-block+ol,.md-markdown .md-code-block+ul,.md-markdown ol+.md-code-block,.md-markdown ul+.md-code-block{margin-top:35px}.md-markdown a:not(.md-heading){color:#e92c6c;border-bottom:1px solid transparent;background-color:rgba(255,255,255,.04)}.md-markdown a:not(.md-heading) .md-code-inline{position:relative}.md-markdown a:not(.md-heading) .md-code-inline:only-child{display:inline-block;line-height:17px}.md-markdown a:not(.md-heading) .md-code-inline:before{content:'';position:absolute;background-color:#f1e05a;top:0;left:0;right:0;bottom:0;opacity:.04}.md-markdown a:not(.md-heading):visited{background-color:rgba(233,44,108,.04)}.md-markdown a:not(.md-heading):visited .md-code-inline:before{background-color:#e92c6c}.md-markdown a:not(.md-heading):hover{border-bottom:1px solid #e92c6c}.md-markdown thead{background-color:#e0e0e0}.md-markdown tbody{background-color:#f6f6f6}.md-markdown tbody tr:nth-child(even){background-color:#f9f9f9}.md-markdown h1,.md-markdown h2,.md-markdown h3,.md-markdown h4,.md-markdown h5,.md-markdown h6{padding:10px 0}.md-markdown h1:first-child,.md-markdown h2:first-child,.md-markdown h3:first-child,.md-markdown h4:first-child,.md-markdown h5:first-child,.md-markdown h6:first-child{margin-top:0}.md-markdown h1:last-child,.md-markdown h2:last-child,.md-markdown h3:last-child,.md-markdown h4:last-child,.md-markdown h5:last-child,.md-markdown h6:last-child{margin-bottom:0}.md-markdown iframe{display:block;margin:35px auto}.md-markdown iframe:first-child{margin-top:0}.md-markdown iframe:last-child{margin-bottom:0}.md-markdown li>p:only-child{display:inline}.md-markdown ul{list-style-type:none}.md-markdown ul>li:before{content:'◯';margin-right:5px}.md-heading{color:inherit}.md-markdown-inline{display:inline}.md-markdown-inline p{display:inline;line-height:initial}.md-code-block,.ocha-highlighted{margin:0 -20px}.ocha-code-block{padding:18px 50px}.md-markdown:not(.mm-content-html) .md-code-block+blockquote{max-width:inherit!important;margin:0 -20px;padding-left:20px;padding-right:20px}.md-code-block .md-code{display:block}.md-markdown-summary p{margin:10px 0}@media only screen and (min-width:768px){.md-markdown h1,.md-markdown h2,.md-markdown h3,.md-markdown h4,.md-markdown h5,.md-markdown h6{margin-left:-40px;margin-right:-40px;padding:10px 40px}.md-code-block,.ocha-highlighted{margin:0 -40px}.md-markdown:not(.mm-content-html) .md-code-block+blockquote{margin:0 -40px;padding-left:40px;padding-right:40px}}@media only screen and (min-width:1300px){.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:900px}}@media only screen and (min-width:1400px){.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:1000px}.md-code-block,.md-markdown:not(.mm-content-html) .md-code-block+blockquote,.ocha-highlighted{margin:0 -400px 0 -40px}}.md-markdown-large blockquote,.md-markdown-large code,.md-markdown-large ol,.md-markdown-large p,.md-markdown-large table,.md-markdown-large ul{max-width:inherit}.md-footnotes{margin-top:80px;padding:20px 0;border-top:1px dashed #cbccbc}.md-footnote{margin:0;padding:8px 0;font-size:14px;display:-webkit-box;display:-moz-box;display:-webkit-flex;display:-ms-flexbox;display:box;display:flex;-webkit-box-align:center;-moz-box-align:center;-o-box-align:center;-ms-flex-align:center;-webkit-align-items:center;align-items:center}.md-footnote p{line-height:16px}.md-footnote-anchor{padding:2px 6px;margin-right:10px;text-align:center;font-weight:700;color:#e92c6c}.ly-custom-subheading .md-footnote-anchor,.ly-lean .md-footnote-anchor{font-family:Merriweather,Georgia,serif}.md-markdown a.md-footnote-anchor{border:1px solid #e92c6c}.md-markdown a.md-footnote-anchor:hover{background-color:#e92c6c;color:#fcfcfc}.md-footnote-ref{margin-left:1px;margin-right:3px}.md-markdown a.md-footnote-ref{border-bottom:1px dotted}.md-code-block,.md-code-inline{-webkit-text-size-adjust:none;-ms-text-size-adjust:none;text-size-adjust:none;background:#fcfcf5;color:#4d4d4c}.md-code-block{line-height:24px}.md-code{padding:8px 10px}.md-code-inline{padding:0 6px}a .md-code{color:inherit}.md-code-comment{color:#8e908c}.md-code-attribute,.md-code-built_in,.md-code-constant,.md-code-literal,.md-code-number,.md-code-params,.md-code-pragma,.md-code-preprocessor,.md-code-regexp,.md-code-tag,.md-code-variable,.md-lang-css .md-code-class,.md-lang-css .md-code-id,.md-lang-css .md-code-pseudo,.md-lang-html .md-code-doctype,.md-lang-ruby .md-code-constant,.md-lang-xml .md-code-doctype,.md-lang-xml .md-code-pi,.md-lang-xml .md-code-tag .md-code-title,color #c82829{color:#f5871f}.md-lang-css .md-code-rule .md-code-attribute,.md-lang-ruby .md-code-class .md-code-title{color:#eab700}.md-code-header,.md-code-inheritance,.md-code-name,.md-code-string,.md-code-value,.md-lang-ruby .md-code-symbol,.md-lang-xml .md-code-cdata{color:#718c00}.md-code-title,.md-lang-css .md-code-hexcolor{color:#3e999f}.md-code-function,.md-lang-coffeescript .md-code-title,.md-lang-javascript .md-code-title,.md-lang-perl .md-code-sub,.md-lang-python .md-code-decorator,.md-lang-python .md-code-title,.md-lang-ruby .md-code-function .md-code-title,.md-lang-ruby .md-code-title .md-code-keyword{color:#4271ae}.md-code-keyword,.md-lang-javascript .md-code-function{color:#8959a8}.md-lang-coffeescript .md-lang-javascript,.md-lang-javascript .md-lang-xml,.md-lang-tex .md-code-formula,.md-lang-xml .md-code-cdata,.md-lang-xml .md-lang-css,.md-lang-xml .md-lang-javascript,.md-lang-xml .vbscript{opacity:.5}.md-code-deletion{background-color:rgba(244,0,30,.05);color:#f4001e}.md-code-addition{background-color:rgba(27,194,17,.05);color:#1bc211}.md-mark{background-color:rgba(255,226,112,.5);color:inherit}.md-mark span{color:inherit}.md-heading-hover{cursor:pointer;background-color:rgba(22,134,162,.1)}.mde-text-left{text-align:left}.mde-text-center{text-align:center}.mde-text-right{text-align:right}.mde-size-small{font-size:12px}.mde-size-small,.mde-size-small p{line-height:12px}.mde-size-large{font-size:36px}.mde-size-large,.mde-size-large p{line-height:36px}.mde-size-giant{font-size:72px}.mde-size-giant,.mde-size-giant p{line-height:72px}.mde-clearfix:after{content:' ';display:block;visibility:hidden;clear:both;font-size:0;height:0}.mde-quote{margin:0;padding:20px 0;border:none;border-top:5px solid rgba(0,0,0,.05);border-bottom:5px solid rgba(0,0,0,.05)}.mde-core{font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}.mde-mono{font-family:Consolas,Menlo,Monaco,'Lucida Console','Liberation Mono','DejaVu Sans Mono','Bitstream Vera Sans Mono','Courier New',monospace,serif}.ly-custom-heading .mde-heading,.ly-lean .mde-heading{font-family:Neuton,'Hoefler Text',Palatino,Baskerville,Georgia,'Times New Roman',serif}.ly-custom-subheading .mde-subheading,.ly-lean .mde-subheading{font-family:Merriweather,Georgia,serif}.mde-pad-0{padding:0}.mde-pad-5{padding:5px}.mde-pad-10{padding:10px}.mde-pad-15{padding:15px}.mde-pad-20{padding:20px}.mde-pad-25{padding:25px}.mde-pad-30{padding:30px}.mde-pad-50{padding:50px}.mde-mar-0{margin:0}.mde-mar-5{margin:5px}.mde-mar-10{margin:10px}.mde-mar-15{margin:15px}.mde-mar-20{margin:20px}.mde-mar-25{margin:25px}.mde-mar-30{margin:30px}.mde-mar-50{margin:50px}@media only screen and (min-width:900px){.mde-left{float:left}.mde-right{float:right}.mde-inline{display:inline-block;vertical-align:top}.mde-20{max-width:20%}.mde-25{max-width:25%}.mde-33{max-width:33.3333333333%}.mde-50{max-width:50%}.mde-66{max-width:66.6666666666%}.mde-75{max-width:75%}}.twitter-tweet-figure{background:0 0;padding:0}.twitter-tweet-figure:before{content:none}.twitter-tweet-figure .twitter-tweet{margin:0 auto}blockquote.twitter-tweet{overflow:hidden;color:#1c2022;background-color:#fff;border:1px solid #e1e8ed;border-radius:4px;width:500px;max-width:100%;min-width:220px;padding:1.25rem 1.25rem .725rem}blockquote.twitter-tweet:before{content:none}blockquote.twitter-tweet p{white-space:pre-wrap;font:16px/1.4 Helvetica,Roboto,'Segoe UI',Calibri,'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}blockquote.twitter-tweet a,blockquote.twitter-tweet a:visited{color:#2b7bb9}.wy-container{margin:0 auto;padding:20px 0;max-width:800px}.wy-container .md-markdown p{line-height:22px;margin:10px 0}.wy-container .md-markdown p:first-child{margin-top:0}.wy-container .md-markdown p:last-child{margin-bottom:0}.wy-container .md-markdown blockquote:not(.twitter-tweet){padding:10px 0}.wy-container .md-code-block{margin:0;padding:10px;white-space:pre-wrap}.wy-table{width:100%;padding:0}.wy-td{padding:0}.wy-section-link,.wy-section-markdown,.wy-section-poll,.wy-section-summary{padding-top:25px}.wy-section-thanks{margin-top:25px;padding:10px;font-size:15px;background-color:#f2fcf2}.wy-header-text,.wy-issue{display:inline-block;margin:10px 0;line-height:24px}.wy-issue{float:right;font-size:12px}.wy-issue-content{display:block;padding:0 5px;background-color:#fcfcfc}.wy-section-header{padding-top:40px}.wy-section-header h1,.wy-section-header h2,.wy-section-header h3,.wy-section-header h4,.wy-section-header h5,.wy-section-header h6{margin:0}.wy-section-header p{line-height:inherit}.wy-header-td{padding:0}.wy-header-content{margin:0 10px}.wy-header-text{color:#fcfcfc;text-shadow:1px 1px 0 #1a4d7f;font-weight:700;font-size:24px}.wy-content{padding-bottom:25px}.wy-link-addendum,.wy-link-tag,.wy-link-title{display:inline-block;vertical-align:bottom;margin-bottom:10px}.wy-link-title{border-bottom:1px solid;font-size:20px;margin-right:10px}.wy-link-tag{background-color:#1a4d7f;color:#fcfcfc;text-transform:uppercase;font-size:13px;margin-right:5px;padding:2px 4px}.wy-link-tag:last-child{margin-right:0}.wy-link-addendum{color:#999;margin-left:5px}.wy-link-addendum:hover{border-bottom-color:transparent}.wy-link-title-section{position:relative}.wy-link-stats{position:absolute;right:0;background-color:#3aca96;color:#fcfcfc;border-bottom:1px solid #299a71}.wy-link-stats-logo{background-color:rgba(0,0,0,.1);color:#299a71}.wy-link-stat{margin:3px}.wy-link-description{font-size:14px;color:#666}.wy-link-source-section{margin-top:10px}.wy-link-source{margin-right:10px;margin-bottom:10px;display:inline-block;vertical-align:middle;color:#55acee}.wy-link-source-plain{color:#333}.wy-link-source.wy-link-source-plain a{color:#55acee}.wy-link-source.wy-link-source-plain a:visited{background-color:rgba(85,172,238,.04)}.wy-link-source.wy-link-source-plain a:visited .md-code-inline:before{background-color:#55acee}.wy-link-source.wy-link-source-plain a:active{outline-color:#55acee}.wy-link-source.wy-link-source-plain a:hover{border-bottom-color:#55acee}.wy-link-sponsor{background-color:transparent;color:#999;outline:#999 solid 1px}.wy-link-cell-before-image{vertical-align:middle;width:70%}.wy-link-cell-image{padding-left:10px}.wy-link-image-anchor{display:block;overflow:hidden;max-height:300px}.wy-link-image{display:block;margin:0 auto}.wy-footer-table{margin:20px 0}.wy-footer-cell{text-align:center}.wy-read-online{font-size:13px}.wy-section-link-job .wy-link-source,.wy-section-link-job .wy-link-title{font-size:14px}.wy-section-link-job .wy-link-description{font-size:12px}.wy-link-pixel{float:right}@media only screen and (max-width:500px){.wy-issue-publication,.wy-issue-separator{display:none}}.md-code-block{margin:0!important;padding:10px}</style>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Descubriendo la programación funcional – Swift con Valentina Rubane">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Descubriendo la programación funcional – Swift con Valentina Rubane</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">04 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Con este séptimo episodio cerramos esta serie especial sobre programación funcional. En esta ocasión Andros Fenollosa vuelve con una habitual de este podcast: la desarrolladora y diseñadora Valentina Rubane. Ella es compañera de Andros en Sapps, su estudio de aplicaciones web y móviles en Valencia. Valentina viene para hablar del <a href="https://swift.org/" data-type="URL" data-id="https://swift.org/">lenguaje Swift</a>, un lenguaje de propósito general, multiparadigma y compilado desarrollado por Apple y la comunidad de código abierto.</p>



<p>Como es habitual con otros invitados en esta serie sobre programación funcional, seguiremos el habitual turno de preguntas para hablar sobre este lenguaje:</p>



<ol><li>¿Qué pasó por tu cabeza para meterte en la programación funcional?</li><li>Dime algunas características que te rompieron la cabeza y te enamoraron.</li><li>¿Qué es Swift y cuál es su origen?</li><li>¿Por qué hay tanto objeto si es funcional?</li><li>¿Es open? ¿Quién es el autor? ¿se desarrolla por comunidad?</li><li>¿Qué lo hace especial respecto al resto?</li><li>¿Quién lo usa? ¿Para quién está orientado?</li><li>Hablemos de MacOS. Solo podemos usarlo para hacer APP de iOS. ¿Es cierto?</li><li>¿Cuáles son tus frameworks favoritos?</li><li>¿Cuál crees que es el futuro del ecosistema?</li></ol>



<p></p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Know, Prevent, Fix: A framework for shifting the discussion around vulnerabilities in open source</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">03 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">JavaScript: contar número «pulsaciones» de una tecla</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Bufa</a> <span class="article__date">02 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Ejemplo javascript para calcular el número de veces que pulsamos una determinada tecla de nuestro teclado usando el evento onkeyup y keyCode para obtener la tecla correspondiente. En el siguiente ejemplo vamos a contar el nº total de veces que [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2021/204-negligible-error.png" alt="Negligible Error">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Negligible Error</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">02 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2021/204-negligible-error.png" alt="Negligible Error" title="Enjoy your coffee" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Cambios en los RHEL de Red Hat, AMD Threadripper, Amazon libera EKS y Elastic cambia su licencia">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cambios en los RHEL de Red Hat, AMD Threadripper, Amazon libera EKS y Elastic cambia su licencia</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">01 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Este nuevo episodio de Informe Nube, David Vaquero y Antony Goetzschel ofrecen un recorrido de diversas noticias relacionadas con la nube. Para este episodio:</p>



<p>Red Hat presenta nuevos programas para acceder a los programas Enterprise. <a href="http://redhat.com/en/blog/new-year-new-red-hat-enterprise-linux-programs-easier-ways-access-rhel?extIdCarryOver=true&#38;sc_cid=701f2000001OH7TAAW" data-type="URL" data-id="http://redhat.com/en/blog/new-year-new-red-hat-enterprise-linux-programs-easier-ways-access-rhel?extIdCarryOver=true&#38;sc_cid=701f2000001OH7TAAW">Más informacion de Red Hat Developer Program. </a></p>



<p>AMD presenta los microprocedadores Ryzen Threadripper Pro con tres nuevas placas WRX80. <a href="https://wccftech.com/amds-ryzen-threadripper-pro-cpus-wrx80-motherboards-consumer-launch-march-2021/" data-type="URL" data-id="https://wccftech.com/amds-ryzen-threadripper-pro-cpus-wrx80-motherboards-consumer-launch-march-2021/">Más información.</a><br></p>



<p>Amazon libera EKS Distro (EKS-D), una distribución basada en Kubernetes y usada por el servicio Elastic Kubernetes de Amazon para crear confiables y seguros clusters de Kubernetes.  <a href="https://github.com/aws/eks-distro" data-type="URL" data-id="https://github.com/aws/eks-distro">Más información en el Github de AWS. </a></p>



<p>Elastic cambia su licencia. https://www.elastic.co/es/blog/license-change-clarification y <a href="https://www.muylinux.com/2021/01/25/amazon-bifurca-elasticsearch-open-source/" data-type="URL" data-id="https://www.muylinux.com/2021/01/25/amazon-bifurca-elasticsearch-open-source/">el papel que juega AWS. </a><br></p>



<p> </p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://diarioestoico.com/wp-content/uploads/2020/03/cropped-logo-estoico-footer-150x150-1-32x32.png" alt="CÓMO VENCER LA PROCRASTINACIÓN CON ESTOICISMO">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">CÓMO VENCER LA PROCRASTINACIÓN CON ESTOICISMO</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Diario Estoico</a> <span class="article__date">01 02 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Vencer la procrastinación y las emociones detrás de ella, no es dicho y hecho, por eso, acudir a una filosofía práctica como es el estoicismo te puede ayudar a forjar la actitud necesaria para tomar acción y convertirte hoy en la persona que potencialmente ya eres. En este artículo veremos qué hay detrás de ese [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Unexpected Find That Freed 20GB of Unused Index Space</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">31 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>In this article I describe the process we took to identify potential free space, and one surprising find that helped up clear up ~10GB of unused indexed values!</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Emacs: from catching up to getting ahead</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Murilo Pereira</a> <span class="article__date">31 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I started using Emacs almost exactly four years ago, after almost a decade of Vim. I made the switch cold turkey. I vividly remember being extremely frustrated by unbearable slowness while editing a Clojure file at work. With no sane way of debugging it, just moving the cursor up and down would result in so much lag that I had to step away from the computer to breathe for a while.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">video html5: «autoplay» no funciona en iphone</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Bufa</a> <span class="article__date">30 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Si tienes un video html5 con autoplay y no se reproduce automáticamente en dispositivos iOS táctiles (iphone / ipad) comprueba que tenga los siguientes 3 atributos autoplay, muted y playsinline, ejemplo: &#60;video width=&#34;320&#34; height=&#34;240&#34; autoplay muted playsinline&#62; &#60;source src=&#34;tu-video.mp4&#34; type=&#34;video/mp4&#34;&#62; [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Google Summer of Code 2021 is open for mentor organization applications!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Google Open Source Blog</a> <span class="article__date">29 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure 1.10.2 release</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">26 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Clojure 1.10.2 includes a number of improvements for Java interop/compatibility:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Fixes an issue in the <code>locking</code> macro to satisfy more stringent Java verifiers (particularly, Graal)</p>
</li>
<li>
<p>Fix for invocation of static interface methods with primitives</p>
</li>
<li>
<p><code>proxy</code> was incorrectly emitting Java 5 bytecode, now will be Java 8 to match all other code gen</p>
</li>
<li>
<p>Spec now compiled to Java 8 bytecode instead of Java 5 bytecode</p>
</li>
<li>
<p>Many fixes for reflection, javadoc urls, Java deprecation warnings, etc</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Other important Clojure fixes:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Fix <code>case</code> expression branch analysis resulting in compilation error</p>
</li>
<li>
<p>Fix <code>nth</code> with not-found value on regex matcher</p>
</li>
<li>
<p>Improve <code>vector-of</code> impls with equals, hashing, metadata support to match other colls</p>
</li>
<li>
<p>Fix printing of some maps with namespace syntax</p>
</li>
<li>
<p>Various doc string and error message fixes</p>
</li>
<li>
<p>Perf improvement - use transients in <code>zipmap</code></p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_detailed_changelog"><a class="anchor" href="#_detailed_changelog"></a>Detailed changelog</h2>
<div class="sectionbody">
<div class="paragraph">
<p>See the <a href="https://github.com/clojure/clojure/blob/master/changes.md#changes-to-clojure-in-version-1102">change log</a> for a complete list of all changes in Clojure 1.10.2.</p>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Fullstack Adventure</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">26 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://diarioestoico.com/wp-content/uploads/2020/03/cropped-logo-estoico-footer-150x150-1-32x32.png" alt="DESAMOR DESDE EL ESTOICISMO">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">DESAMOR DESDE EL ESTOICISMO</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Diario Estoico</a> <span class="article__date">24 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        No existe una receta universal para la superación del dolor. Todos somos distintos en la medida en que todos somos humanos, por tanto, no amamos igual ni nos rompemos igual. Por eso, las enseñanzas que recibimos del estoicismo, para aplicarlas al desamor, hay que individualizarlas. En este artículo vamos a tratar en términos generales cómo [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cathedrals, Bazaars, and Fusion Reactors</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Murilo Pereira</a> <span class="article__date">24 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Figure 1: Inside the Korean tokamak KSTAR (NFRI)
With corporations like Microsoft, Oracle, and Google truly reinventing themselves to adapt to an open source world, and typical open source projects moving towards&mdash;oftentimes centralized&mdash;governance models, the Cathedral&ndash;Bazaar dichotomy feels increasingly less relevant.
It was met with criticism even back in the 90s. While being an entertaining piece of history with useful takeaways, its most important achievement was arguably helping create a sense of identity for hacker culture via the revolutionary Open Source movement, and promoting the value of the Internet for software development.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Descubriendo la programación funcional – Lisp con Diego Sevilla">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Descubriendo la programación funcional – Lisp con Diego Sevilla</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">23 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Sexta entrega de la travesía de descubrimiento por la programación funcional. En esta ocasión Andros invita a<a href="https://twitter.com/diegosevilla" data-type="URL" data-id="https://twitter.com/diegosevilla"> Diego Sevilla</a>, profesor en la Universidad de Murcia para hablar de Lisp, uno de los lenguajes de programación más longevos y raíz de otros dialectos como Scheme, Clojure, Common Lisp o Emacs Lisp.</p>



<p>Se puede asegurar que familia de Lisp tiene una larga historia que ha ayudado a modelar a otros lenguajes. Todo un pionero para lenguajes tan conocidos como Perl, Python, Javascript, Lua, Scala, Ruby, R, Elixir, Haskell… entre otros. Y que, a pesar de haber nacido en 1958 continúa gozando de salud juvenil. Lisp se puede utilizar en 10 dialectos diferentes, como por ejemplo Clojure, del que ya hablamos en el <a href="https://republicaweb.es/podcast/descubriendo-la-programacion-funcional-clojure-con-vachi/" data-type="URL" data-id="https://republicaweb.es/podcast/descubriendo-la-programacion-funcional-clojure-con-vachi/">primer episodio de la serie programación funcional.</a></p>



<p>Con <a href="http://neuromancer.inf.um.es/fm/">Diego Sevilla </a>hablamos mucho sobre <a href="https://www.gnu.org/software/emacs/" data-type="URL" data-id="https://www.gnu.org/software/emacs/">GNU Emacs</a>, la situación actual de Lisp, de Common Lisp, del invierno de la IA y su renacimiento, de la perenne habilidad de Lisp para continuar siendo un lenguaje valioso, altamente expresivo, con su particular sintaxis y con unas bases profundamente sólidas en conceptos matemáticos.</p>



<p>Como en anteriores episodios de la serie, conversamos sobre los comienzos de Diego en la programación funcional, su uso actual, recursos de interés para conocer el lenguaje y su comunidad.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Vanilla JS: on load</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Bufa</a> <span class="article__date">20 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A continuación un par de formas de comprobar en JavaScript cuando se ha cargado la página completamente. Si quieres saber cuando se carga toda página, incluido su html, imágenes, css, js&#8230; puedes usar alguno de estos 2 códigos js: window.addEventListener(&#039;load&#039;, [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Vanilla JS: clonar elemento</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Bufa</a> <span class="article__date">19 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Para clonar un determinado elemento/s es muy sencillo usando el método cloneNode() de javascript, con el cual puedes clonar solo el elemento padre o tmabien los hijos que tenga este. Clonar solo el elemento «padre» const clonar = document.querySelector(&#039;.mi-elemento&#039;).cloneNode(); Clonar [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://diarioestoico.com/wp-content/uploads/2020/03/cropped-logo-estoico-footer-150x150-1-32x32.png" alt="LOGRA TUS PROPÓSITOS DESDE EL ESTOICISMO">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">LOGRA TUS PROPÓSITOS DESDE EL ESTOICISMO</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Diario Estoico</a> <span class="article__date">19 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Logra tus propósitos desde el estoicismo. Conoce los frenos más habituales y las herramientas estoicas para conseguir salvarlos. Encontrar tus propósitos en la vida es nuestra labor más importante, pues de ello depende nuestro rumbo, sentido y felicidad. Para el estoicismo, es importante encontrar y definir adecuadamente nuestro objetivo pero es mucho más importante tener [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Common Lisp Cookbook Is Now Available in EPUB and PDF</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">19 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I am glad to announce that the Common Lisp Cookbook is now available in ePub and PDF.</p>

<p>It is available for free, and you can pay what you want[1] to say a
loud &ldquo;thank you&rdquo; and to further support its development. Thanks!</p>

<p>This EPUB represents the work on the span of three years where I have been constantly reading, experimenting, asking, discovering tips, tools, libraries and best-practices, built-in or not, all of which should have been easily accessible but were not. Now they are. Reviving the Cookbook project resonated in the community, as other lispers sent great contributions.</p>

<p><a style="font-size: 16px; background-color: #4CAF50; color: white; padding: 16px; cursor: pointer;" href="https://ko-fi.com/s/01fee22a32">
  Donate and download the EPUB version
</a></p>

<p>=&gt; <a href="https://lispcookbook.github.io/cl-cookbook/">https://lispcookbook.github.io/cl-cookbook/</a> &lt;=</p>

<hr />

<p>[1]: above 6 USD actually.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2021/203-pending-approval.png" alt="Pending Approval">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Pending Approval</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">19 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2021/203-pending-approval.png" alt="Pending Approval" title="Enjoy your coffee" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Los put?s amos de internet con Eduardo Collado">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Los put?s amos de internet con Eduardo Collado</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">17 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Recientes acontecimientos como la expulsión conjunta en redes sociales del todavía Presidente Trump y el bloqueo global de servicios como Parler en AWS, ofrecen una excelente oportunidad para comprender mejor un aspecto fundamental del funcionamiento de Internet, ¿Quién o quiénes gobiernan internet? ¿Quién decide cómo y de qué forma se accede a la red? ¿Hay límites a lo que las grandes empresas de internet puedan decidir en materia de libertad de expresión?</p>



<p>Para este episodio contamos con la compañía de <a href="https://www.eduardocollado.com/" data-type="URL" data-id="https://www.eduardocollado.com/">Eduardo Collado</a>, un gran profesional de las telecomunicaciones, consumado podcaster y todo un evangelista de las tecnologías de internet.&#160;Con él hablamos del poder de las operadores para inspeccionar el tráfico y de cómo podemos como usuarios, protegernos del formidable poder de las empresas de internet sobre nuestras comunicaciones.</p>



<p>Con Eduardo Collado hablamos sobre de aspectos técnicos como DNS, VPN, BGP, pero en especial sobre la idoneidad de fiar nuestros datos a empresas de telecomunicaciones y grandes empresas que dominan nuestros destinos en la red.</p>




<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The values of Emacs, the Neovim revolution, and the VSCode gorilla</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Murilo Pereira</a> <span class="article__date">17 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        In 2018 Bryan Cantrill gave a brilliant talk where he shared his recent experiences with the Rust programming language. More profoundly, he explored a facet of software that is oftentimes overlooked: the values of the software we use. To paraphrase him slightly:
Values are defined as expressions of relative importance. Two things that we&rsquo;re comparing could both be good attributes. The real question is, when you have to make a choice between two of them, what do you choose?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Vanilla JS: reproducir videos html5 automáticamente al hacer scroll</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Bufa</a> <span class="article__date">17 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Ejemplo de cómo reproducir automáticamente videos en html5 automáticamente al scrollear usando IntersectionObserver en javascript. De esta forma recorreremos todos los elementos video que haya en la página y observaremos cuando están visibles al hacer scroll para reproducir/pausar de forma [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://images.ponyfoo.com/uploads/notfound-5651b6306ab24b1f9e1fdb56b9db072b.png" alt="Learning new Codebases, PR Collaboration, fun with Unit Testing, GraphQL, and Maintainable React Apps! 🥦  — Pony Foo Weekly">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Learning new Codebases, PR Collaboration, fun with Unit Testing, GraphQL, and Maintainable React Apps! 🥦  — Pony Foo Weekly</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Pony Foo Weekly</a> <span class="article__date">14 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="f-core"><div class="md-markdown"><p>We&#x2019;re glad you could make it this week! </p> <p>With your help, we can make Pony Foo Weekly <em>even more</em> awesome: <a href="https://ponyfoo.com/weekly/submissions?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-192" target="_blank" rel="noopener noreferrer">send tips about cool resources</a>.</p> </div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://www.samueltaylor.org/articles/how-to-learn-a-codebase.html?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-192" style="color:#ff895c;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>How to Join a Team and Learn a Codebase</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/article" style="color:#e4f9e3;background-color:#1bc211" class="wy-link-tag">Article</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Getting familiar with a new codebase can be daunting. It doesn&#x2019;t have to be hard, though! By taking a scientific approach, leveraging prior work, and using good tools, we can get up to speed quickly.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/SamuelDataT?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-192" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Samuel Taylor</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://www.freecodecamp.org/news/optimize-pull-requests-for-reviewer-happiness/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-192" style="color:#ff895c;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Optimize pull requests for reviewer happiness</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/best-practices" style="color:#900070;background-color:#ffe270" class="wy-link-tag">Best Practices</a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Aggressively rebase commits to avoid frustrating your reviewers with shuffled narratives; Stop rebasing after review has begun to avoid disorienting and frustrating your reviewers.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/cheapsteak?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-192" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Chang Wang</p> </a></div></td><td class="wy-td wy-link-cell-image"><a href="https://www.freecodecamp.org/news/optimize-pull-requests-for-reviewer-happiness/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-192" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://images.ponyfoo.com/uploads/notfound-5651b6306ab24b1f9e1fdb56b9db072b.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-primary"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="http://srv.buysellads.com/ads/long/x/TCURIRBXTTTTTT4G3ZYMOTTTTTT22DXJZATTTTTTV3WG5UYTTTTTTBDW5JYFC5JGHRSU5R75K7NC4RDC2HNCPZIQ2AUUTAIGKJBNCR3GK2UNAYSQKM7C57QGFRBUVSPX52UUPAIDKWOUTYZL5JUCPAJC5MBCBUS2KMLCLRZ2FMLNBYZQ2EIFPRD2ZRJN4SZEKHWN5SJRKQBULASH2JNC47DIHM7ULSI62HJN4RDHHMYCOSI7HMICOS72KMNN4BZKZRYI4ZQLCT7D4ZZD2RUCCBZH5QINPZZFK6NUTAIG2MUUVBZG2YIFPRD2ZRJNOSIWKMUFVGZQ2YNN4AIW2HJNY7Q2CTYLBKQI67BUVSPX5JLU6SQR5JLNCBD52HJN4S3253UNAOQ2K7UNO?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-192" style="color:#ff895c;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Stop Wasting Time Formatting Messy Spreadsheets</p> </a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Think of the last time you imported a spreadsheet. Did it work the first time? Nearly everyone has dealt with formatting CSV or Excel files so that the data can be imported into an application. It&#x2019;s a pain! Enter Flatfile Concierge. Solve data onboarding with collaborative workspaces, intuitive data validation, and best of all, <code class="md-code md-code-inline">#nocode</code>.</p> <p><a href="http://srv.buysellads.com/ads/long/x/TCURIRBXTTTTTT4G3ZYMOTTTTTT22DXJZATTTTTTV3WG5UYTTTTTTBDW5JYFC5JGHRSU5R75K7NC4RDC2HNCPZIQ2AUUTAIGKJBNCR3GK2UNAYSQKM7C57QGFRBUVSPX52UUPAIDKWOUTYZL5JUCPAJC5MBCBUS2KMLCLRZ2FMLNBYZQ2EIFPRD2ZRJN4SZEKHWN5SJRKQBULASH2JNC47DIHM7ULSI62HJN4RDHHMYCOSI7HMICOS72KMNN4BZKZRYI4ZQLCT7D4ZZD2RUCCBZH5QINPZZFK6NUTAIG2MUUVBZG2YIFPRD2ZRJNOSIWKMUFVGZQ2YNN4AIW2HJNY7Q2CTYLBKQI67BUVSPX5JLU6SQR5JLNCBD52HJN4S3253UNAOQ2K7UNO?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-192" target="_blank" rel="noopener noreferrer">Get access</a></p> </div></div><div class="wy-link-source-section"><a href="https://ponyfoo.com/weekly/links/tagged/sponsored" class="wy-link-tag wy-link-sponsor">Sponsored</a></div></td><td class="wy-td wy-link-cell-image"><a href="http://srv.buysellads.com/ads/long/x/TCURIRBXTTTTTT4G3ZYMOTTTTTT22DXJZATTTTTTV3WG5UYTTTTTTBDW5JYFC5JGHRSU5R75K7NC4RDC2HNCPZIQ2AUUTAIGKJBNCR3GK2UNAYSQKM7C57QGFRBUVSPX52UUPAIDKWOUTYZL5JUCPAJC5MBCBUS2KMLCLRZ2FMLNBYZQ2EIFPRD2ZRJN4SZEKHWN5SJRKQBULASH2JNC47DIHM7ULSI62HJN4RDHHMYCOSI7HMICOS72KMNN4BZKZRYI4ZQLCT7D4ZZD2RUCCBZH5QINPZZFK6NUTAIG2MUUVBZG2YIFPRD2ZRJNOSIWKMUFVGZQ2YNN4AIW2HJNY7Q2CTYLBKQI67BUVSPX5JLU6SQR5JLNCBD52HJN4S3253UNAOQ2K7UNO?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-192" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://images.ponyfoo.com/uploads/Pony-foo-300x300@2x-1e5a476762f94b0c943cf7cdad5a65c5.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://nosleepjavascript.com/why-i-love-jest/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-192" style="color:#ff895c;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Jest makes unit testing fun again</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/best-practices" style="color:#900070;background-color:#ffe270" class="wy-link-tag">Best Practices</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><blockquote> <p>Jest is a full-blown, batteries included, ready to rock, testing framework that has similarities with mocha and other testing frameworks but with a much more integrated experience, making it very easy to have a production ready unit test setup out of the box with very little effort.</p> </blockquote> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/franleplant?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-192" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Francisco Guijarro &#x2014; @franleplant</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://charlypoly.com/publications/from-rest-to-graphql?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-192" style="color:#ff895c;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>From REST to GraphQL</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/graphql" class="wy-link-tag">graphql</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>All the tools to get your existing REST APIs working with GraphQL</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/where_is_charly?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-192" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Charly Poly</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://codersociety.com/blog/articles/introduction-graphql?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-192" style="color:#ff895c;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Introduction to GraphQL for Developers</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/introductory" style="color:#900070;background-color:#f7f0f5" class="wy-link-tag">Introductory</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Learn GraphQL&#x2019;s core features, how it works and operational challenges.</p> </div></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-job"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://feather-insurance.com/careers/senior-frontend-engineer?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-192" style="color:#1bc211;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Senior Frontend Engineer at Feather (Berlin / Remote)</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/job" class="wy-link-tag wy-link-sponsor">job</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>We&#x2019;re looking for a senior frontend engineer to help us take our website and web app to the next level. If you love solving other people&#x2019;s problems, then you&#x2019;ll be a good fit! Our customers love us (our Trustpilot reviews speak for themselves) and we&#x2019;re committed to building our business around customer needs.</p> </div></div><div class="wy-link-source-section"><a href="https://ponyfoo.com/weekly/links/tagged/sponsored" class="wy-link-tag wy-link-sponsor">Sponsored</a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://charlypoly.com/publications/build-maintainable-react-apps-series?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-192" style="color:#ff895c;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Build maintainable React apps</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/best-practices" style="color:#900070;background-color:#ffe270" class="wy-link-tag">Best Practices</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Full of tips and principles that will help you successfully scale React application.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/whereischarly?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-192" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Charly Poly</p> </a></div></td></tr></table></td></tr></table></div></div><style>html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;position:relative;vertical-align:baseline}sup{top:-.5em}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto;resize:vertical;min-height:280px;max-height:900px}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item;margin:-10px -20px;padding:10px;background-color:#f6f6f6;cursor:pointer;border-bottom:2px solid #ddd}[hidden],template{display:none}body,body:after,body:before,html,html:after,html:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*,:after,:before{-webkit-box-sizing:inherit;-moz-box-sizing:inherit;box-sizing:inherit}@-moz-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-webkit-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-o-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-moz-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@-webkit-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@-o-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}.f-core{font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}.f-mono{font-family:Consolas,Menlo,Monaco,'Lucida Console','Liberation Mono','DejaVu Sans Mono','Bitstream Vera Sans Mono','Courier New',monospace,serif}.ly-custom-heading .f-heading,.ly-custom-heading h1,.ly-custom-heading h2,.ly-custom-heading h3,.ly-custom-heading h4,.ly-custom-heading h5,.ly-custom-heading h6,.ly-lean .f-heading,.ly-lean h1,.ly-lean h2,.ly-lean h3,.ly-lean h4,.ly-lean h5,.ly-lean h6{font-family:Neuton,'Hoefler Text',Palatino,Baskerville,Georgia,'Times New Roman',serif}.ly-custom-subheading .f-subheading,.ly-lean .f-subheading{font-family:Merriweather,Georgia,serif}body{margin:0;font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif;background:#fcfcfc;color:#333}img{max-width:100%;border:none}.md-markdown figure:not(.twitter-tweet-figure){background-color:#f6f6f6}.md-markdown figure:not(.twitter-tweet-figure)>a{display:block}.md-markdown figure:not(.twitter-tweet-figure)>a>img,.md-markdown figure:not(.twitter-tweet-figure)>img{display:block;margin-left:auto;margin-right:auto}.md-markdown figcaption{padding:10px;font-style:italic;font-size:14px;background:-webkit-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-moz-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-o-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-ms-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:linear-gradient(to right,#fff9e2 33%,#fcf9ee 100%);color:#555}.md-markdown .figure-has-loaded{background:-webkit-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-moz-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-o-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-ms-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:linear-gradient(to bottom,rgba(255,255,255,0) 0,#fcf9ee 100%)}b,em,font-style italic,font-weight bold,i,ins,strong{text-decoration:none}del{text-decoration:line-through}sub,sup{bottom:0;line-height:18px}button,input{overflow:visible;border-radius:0}button{border:none;padding:6px 8px;font-size:1.2em;background:0 0}button[disabled]{color:#cbccbc!important}input,select,textarea{display:block;width:100%;padding:10px 8px;line-height:18px;border:none;font:inherit}select{height:38px}ol,ul{padding:0;margin:0;list-style-position:inside}li>ol,li>ul{margin-left:20px}hr{border:none;border-top:5px solid rgba(0,0,0,.05);margin:20px 0}kbd{display:inline-block;border:1px solid #ccc;margin:0 .1em;padding:.1em .6em;line-height:1.4;font-size:11px;background-color:#f7f7f7;-webkit-box-shadow:0 1px 0 #bbb,0 0 0 2px #fff inset;box-shadow:0 1px 0 #bbb,0 0 0 2px #fff inset;border-radius:3px;color:#333;text-shadow:0 1px 0 #fff;white-space:nowrap}iframe{display:inline-block;border:none;max-width:100%}summary:hover{opacity:.8}details{padding:10px 20px 20px;border-bottom:2px dashed #ddd}details[open] summary{margin-bottom:20px}blockquote{border:none;margin:0!important}ol,p,ul{line-height:35px}p{margin:35px 0}@media only screen and (min-width:768px){ol,p,ul{line-height:30px}}a,button,input[type=submit]{cursor:pointer;text-decoration:none}.lk-link{color:#e92c6c;border-bottom:1px solid transparent;background-color:rgba(255,255,255,.04)}.lk-link .md-code-inline{position:relative}.lk-link .md-code-inline:only-child{display:inline-block;line-height:17px}.lk-link .md-code-inline:before{content:'';position:absolute;background-color:#f1e05a;top:0;left:0;right:0;bottom:0;opacity:.04}.lk-link:visited{background-color:rgba(233,44,108,.04)}.lk-link:visited .md-code-inline:before{background-color:#e92c6c}.lk-link:hover{border-bottom:1px solid #e92c6c}.lk-rainbows{position:relative;color:#333;margin-bottom:5px}.lk-rainbows:hover:before{position:absolute;content:'';left:0;right:0;bottom:-8px;height:3px;opacity:.8;-webkit-transition:.1s ease-in-out;-moz-transition:.1s ease-in-out;-o-transition:.1s ease-in-out;-ms-transition:all .1s ease-in-out;transition:.1s ease-in-out;-webkit-animation:.5s infinite bg-rainbow;-moz-animation:.5s infinite bg-rainbow;-o-animation:.5s infinite bg-rainbow;-ms-animation:bg-rainbow .5s infinite;animation:.5s infinite bg-rainbow}.lk-icon{color:#333}.lk-icon:hover{color:#e92c6c}.lk-visitor{color:#333}.lk-visitor:after{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-left:5px}.lk-visitor.lk-visitor-large:after{font-size:1em}.lk-visitor:hover:after{color:#333;border-bottom-style:solid}.lk-visitor:visited:after{color:#7d5cff}.lk-visitor-inside{color:#333}.lk-visitor-inside .lk-visitor-target:before{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-right:5px}.lk-visitor-inside.lk-visitor-large .lk-visitor-target:before{font-size:1em}.lk-visitor-inside:hover .lk-visitor-target:before{color:#333;border-bottom-style:solid}.lk-visitor-inside:visited .lk-visitor-target:before{color:#7d5cff}.lk-visitor-before{color:#333}.lk-visitor-before:before{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-right:5px}.lk-visitor-before.lk-visitor-large:before{font-size:1em}.lk-visitor-before:hover:before{color:#333;border-bottom-style:solid}.lk-visitor-before:visited:before{color:#7d5cff}.lk-visitor-before-no-underline:before{border-bottom-width:0}.lk-link-to-green{color:#cbccbc}.lk-link-to-green:visited,.lk-link-to-green:visited:before{color:#1bc211;background-color:#1bc211}.lk-link-to-green:active{outline-color:#1bc211}.lk-link-to-green:hover,.lk-link-to-green:hover:before{color:#8be186;border-bottom-color:#1bc211}.lk-green .lk-link,a.lk-green{color:#1bc211}.lk-green .lk-link:visited,a.lk-green:visited{background-color:rgba(27,194,17,.04)}.lk-green .lk-link:visited .md-code-inline:before,a.lk-green:visited .md-code-inline:before{background-color:#1bc211}.lk-green .lk-link:active,a.lk-green:active{outline-color:#1bc211}.lk-green .lk-link:hover,a.lk-green:hover{border-bottom-color:#1bc211}.lk-green.lk-icon:hover{color:#1bc211}.lk-pink-light .lk-link,a.lk-pink-light{color:#ea6c93}.lk-pink-light .lk-link:visited,a.lk-pink-light:visited{background-color:rgba(234,108,147,.04)}.lk-pink-light .lk-link:visited .md-code-inline:before,a.lk-pink-light:visited .md-code-inline:before{background-color:#ea6c93}.lk-pink-light .lk-link:active,a.lk-pink-light:active{outline-color:#ea6c93}.lk-pink-light .lk-link:hover,a.lk-pink-light:hover{border-bottom-color:#ea6c93}.lk-pink-light.lk-icon:hover{color:#ea6c93}.lk-black .lk-link,a.lk-black{color:#333}.lk-black .lk-link:visited,a.lk-black:visited{background-color:rgba(51,51,51,.04)}.lk-black .lk-link:visited .md-code-inline:before,a.lk-black:visited .md-code-inline:before{background-color:#333}.lk-black .lk-link:active,a.lk-black:active{outline-color:#333}.lk-black .lk-link:hover,a.lk-black:hover{border-bottom-color:#333}.lk-black.lk-icon:hover{color:#333}.lk-gray .lk-link,a.lk-gray{color:#999}.lk-gray .lk-link:visited,a.lk-gray:visited{background-color:rgba(153,153,153,.04)}.lk-gray .lk-link:visited .md-code-inline:before,a.lk-gray:visited .md-code-inline:before{background-color:#999}.lk-gray .lk-link:active,a.lk-gray:active{outline-color:#999}.lk-gray .lk-link:hover,a.lk-gray:hover{border-bottom-color:#999}.lk-gray.lk-icon:hover{color:#999}.lk-white .lk-link,a.lk-white{color:#fcfcfc}.lk-white .lk-link:visited,a.lk-white:visited{background-color:rgba(252,252,252,.04)}.lk-white .lk-link:visited .md-code-inline:before,a.lk-white:visited .md-code-inline:before{background-color:#fcfcfc}.lk-white .lk-link:active,a.lk-white:active{outline-color:#fcfcfc}.lk-white .lk-link:hover,a.lk-white:hover{border-bottom-color:#fcfcfc}.lk-white.lk-icon:hover{color:#fcfcfc}.lk-orange .lk-link,a.lk-orange{color:#f3720d}.lk-orange .lk-link:visited,a.lk-orange:visited{background-color:rgba(243,114,13,.04)}.lk-orange .lk-link:visited .md-code-inline:before,a.lk-orange:visited .md-code-inline:before{background-color:#f3720d}.lk-orange .lk-link:active,a.lk-orange:active{outline-color:#f3720d}.lk-orange .lk-link:hover,a.lk-orange:hover{border-bottom-color:#f3720d}.lk-orange.lk-icon:hover{color:#f3720d}.lk-lilly .lk-link,a.lk-lilly{color:#7d5cff}.lk-lilly .lk-link:visited,a.lk-lilly:visited{background-color:rgba(125,92,255,.04)}.lk-lilly .lk-link:visited .md-code-inline:before,a.lk-lilly:visited .md-code-inline:before{background-color:#7d5cff}.lk-lilly .lk-link:active,a.lk-lilly:active{outline-color:#7d5cff}.lk-lilly .lk-link:hover,a.lk-lilly:hover{border-bottom-color:#7d5cff}.lk-lilly.lk-icon:hover{color:#7d5cff}.lk-blue .lk-link,a.lk-blue{color:#1a4d7f}.lk-blue .lk-link:visited,a.lk-blue:visited{background-color:rgba(26,77,127,.04)}.lk-blue .lk-link:visited .md-code-inline:before,a.lk-blue:visited .md-code-inline:before{background-color:#1a4d7f}.lk-blue .lk-link:active,a.lk-blue:active{outline-color:#1a4d7f}.lk-blue .lk-link:hover,a.lk-blue:hover{border-bottom-color:#1a4d7f}.lk-blue.lk-icon:hover{color:#1a4d7f}.lk-inherited .lk-link,a.lk-inherited{color:inherit}.lk-inherited .lk-link:active,a.lk-inherited:active{outline-color:inherit}.lk-inherited .lk-link:hover,a.lk-inherited:hover{border-bottom-color:inherit}.lk-inherited.lk-icon:hover{color:inherit}.lk-twitter .lk-link,a.lk-twitter{color:#55acee}.lk-twitter .lk-link:visited,a.lk-twitter:visited{background-color:rgba(85,172,238,.04)}.lk-twitter .lk-link:visited .md-code-inline:before,a.lk-twitter:visited .md-code-inline:before{background-color:#55acee}.lk-twitter .lk-link:active,a.lk-twitter:active{outline-color:#55acee}.lk-twitter .lk-link:hover,a.lk-twitter:hover{border-bottom-color:#55acee}.lk-twitter.lk-icon:hover{color:#55acee}.lk-facebook .lk-link,a.lk-facebook{color:#3b5998}.lk-facebook .lk-link:visited,a.lk-facebook:visited{background-color:rgba(59,89,152,.04)}.lk-facebook .lk-link:visited .md-code-inline:before,a.lk-facebook:visited .md-code-inline:before{background-color:#3b5998}.lk-facebook .lk-link:active,a.lk-facebook:active{outline-color:#3b5998}.lk-facebook .lk-link:hover,a.lk-facebook:hover{border-bottom-color:#3b5998}.lk-facebook.lk-icon:hover{color:#3b5998}.lk-clean{background-color:transparent}.lk-chrome:hover{color:#4989f4}.lk-teal .lk-link,a.lk-teal{color:#00a19c}.lk-teal .lk-link:visited,a.lk-teal:visited{background-color:rgba(0,161,156,.04)}.lk-teal .lk-link:visited .md-code-inline:before,a.lk-teal:visited .md-code-inline:before{background-color:#00a19c}.lk-teal .lk-link:active,a.lk-teal:active{outline-color:#00a19c}.lk-teal .lk-link:hover,a.lk-teal:hover{border-bottom-color:#00a19c}.lk-teal.lk-icon:hover{color:#00a19c}table{width:100%;border-spacing:0;border-collapse:separate}td,th{padding:8px}@media only screen and (max-width:950px){.table-responsive{display:block}.table-responsive>thead{display:none}.table-responsive>tbody,.table-responsive>tfoot{display:block}.table-responsive>tbody>tr,.table-responsive>tfoot>tr{display:block;background-color:rgba(203,204,188,.1);margin-bottom:30px}.table-responsive>tbody>tr:nth-child(even),.table-responsive>tfoot>tr:nth-child(even){background-color:rgba(203,204,188,.15)}.table-responsive>tbody>tr:last-child,.table-responsive>tfoot>tr:last-child{margin-bottom:0}.table-responsive>tbody>tr>td,.table-responsive>tfoot>tr>td{display:block;text-align:left}.table-responsive>tbody>tr>td:before,.table-responsive>tfoot>tr>td:before{display:block;content:attr(data-label);color:#555;font-size:13px;margin:0 0 5px}.table-responsive .table-responsive-hide{display:none}}.c-oreilly-teal{color:#00a19c}.c-yellow-highlight{color:#ffe270}.c-dark-orange{color:#f3720d}.c-pink{color:#e92c6c}.c-purple{color:#900070}.c-blue{color:#1a4d7f}.c-dark-turquoise{color:#1686a2}.c-dark-green{color:#1bc211}.c-white{color:#fcfcfc}.c-gray{color:#b7b7b7}.c-lilly{color:#7d5cff}.c-teal{color:#3aca96}.c-bg-oreilly-teal{background-color:#00a19c}.c-bg-yellow-highlight{background-color:#ffe270}.c-bg-dark-orange{background-color:#f3720d}.c-bg-pink{background-color:#e92c6c}.c-bg-purple{background-color:#900070}.c-bg-blue{background-color:#1a4d7f}.c-bg-dark-turquoise{background-color:#1686a2}.c-bg-dark-green{background-color:#1bc211}.c-bg-white{background-color:#fcfcfc}.c-bg-gray{background-color:#b7b7b7}.c-bg-lilly{background-color:#7d5cff}.c-bg-teal{background-color:#3aca96}.tj-emoji{width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em}.dc-header{margin-bottom:60px}.dc-heading{text-align:center;font-size:4em;padding:0 10px;margin-top:0;margin-bottom:10px}.dc-role{line-height:26px;padding:0 20px;margin-top:10px;text-align:center;font-style:italic;color:#cbccbc}.dc-colored{background:#f6f6f6;border-top:9px solid rgba(125,92,255,.5)}.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:800px}.md-markdown blockquote:not(.twitter-tweet){margin:0;padding:20px 0;border:none;border-top:5px solid rgba(0,0,0,.05);border-bottom:5px solid rgba(0,0,0,.05)}.md-markdown blockquote:not(.twitter-tweet) h1,.md-markdown blockquote:not(.twitter-tweet) h2,.md-markdown blockquote:not(.twitter-tweet) h3,.md-markdown blockquote:not(.twitter-tweet) h4,.md-markdown blockquote:not(.twitter-tweet) h5,.md-markdown blockquote:not(.twitter-tweet) h6{margin:-20px 0;padding:20px 0}.md-markdown blockquote:not(.twitter-tweet) .md-code-block{margin:0}.md-markdown blockquote:not(.twitter-tweet) .md-code-block:last-child{margin-bottom:-20px}.md-markdown img:first-child{margin-top:0}.md-markdown img:last-child{margin-bottom:0}.md-markdown p:first-child{margin-top:0}.md-markdown p:last-child{margin-bottom:0}.md-markdown .md-code-block+ol,.md-markdown .md-code-block+ul,.md-markdown ol+.md-code-block,.md-markdown ul+.md-code-block{margin-top:35px}.md-markdown a:not(.md-heading){color:#e92c6c;border-bottom:1px solid transparent;background-color:rgba(255,255,255,.04)}.md-markdown a:not(.md-heading) .md-code-inline{position:relative}.md-markdown a:not(.md-heading) .md-code-inline:only-child{display:inline-block;line-height:17px}.md-markdown a:not(.md-heading) .md-code-inline:before{content:'';position:absolute;background-color:#f1e05a;top:0;left:0;right:0;bottom:0;opacity:.04}.md-markdown a:not(.md-heading):visited{background-color:rgba(233,44,108,.04)}.md-markdown a:not(.md-heading):visited .md-code-inline:before{background-color:#e92c6c}.md-markdown a:not(.md-heading):hover{border-bottom:1px solid #e92c6c}.md-markdown thead{background-color:#e0e0e0}.md-markdown tbody{background-color:#f6f6f6}.md-markdown tbody tr:nth-child(even){background-color:#f9f9f9}.md-markdown h1,.md-markdown h2,.md-markdown h3,.md-markdown h4,.md-markdown h5,.md-markdown h6{padding:10px 0}.md-markdown h1:first-child,.md-markdown h2:first-child,.md-markdown h3:first-child,.md-markdown h4:first-child,.md-markdown h5:first-child,.md-markdown h6:first-child{margin-top:0}.md-markdown h1:last-child,.md-markdown h2:last-child,.md-markdown h3:last-child,.md-markdown h4:last-child,.md-markdown h5:last-child,.md-markdown h6:last-child{margin-bottom:0}.md-markdown iframe{display:block;margin:35px auto}.md-markdown iframe:first-child{margin-top:0}.md-markdown iframe:last-child{margin-bottom:0}.md-markdown li>p:only-child{display:inline}.md-markdown ul{list-style-type:none}.md-markdown ul>li:before{content:'◯';margin-right:5px}.md-heading{color:inherit}.md-markdown-inline{display:inline}.md-markdown-inline p{display:inline;line-height:initial}.md-code-block,.ocha-highlighted{margin:0 -20px}.ocha-code-block{padding:18px 50px}.md-markdown:not(.mm-content-html) .md-code-block+blockquote{max-width:inherit!important;margin:0 -20px;padding-left:20px;padding-right:20px}.md-code-block .md-code{display:block}.md-markdown-summary p{margin:10px 0}@media only screen and (min-width:768px){.md-markdown h1,.md-markdown h2,.md-markdown h3,.md-markdown h4,.md-markdown h5,.md-markdown h6{margin-left:-40px;margin-right:-40px;padding:10px 40px}.md-code-block,.ocha-highlighted{margin:0 -40px}.md-markdown:not(.mm-content-html) .md-code-block+blockquote{margin:0 -40px;padding-left:40px;padding-right:40px}}@media only screen and (min-width:1300px){.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:900px}}@media only screen and (min-width:1400px){.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:1000px}.md-code-block,.md-markdown:not(.mm-content-html) .md-code-block+blockquote,.ocha-highlighted{margin:0 -400px 0 -40px}}.md-markdown-large blockquote,.md-markdown-large code,.md-markdown-large ol,.md-markdown-large p,.md-markdown-large table,.md-markdown-large ul{max-width:inherit}.md-footnotes{margin-top:80px;padding:20px 0;border-top:1px dashed #cbccbc}.md-footnote{margin:0;padding:8px 0;font-size:14px;display:-webkit-box;display:-moz-box;display:-webkit-flex;display:-ms-flexbox;display:box;display:flex;-webkit-box-align:center;-moz-box-align:center;-o-box-align:center;-ms-flex-align:center;-webkit-align-items:center;align-items:center}.md-footnote p{line-height:16px}.md-footnote-anchor{padding:2px 6px;margin-right:10px;text-align:center;font-weight:700;color:#e92c6c}.ly-custom-subheading .md-footnote-anchor,.ly-lean .md-footnote-anchor{font-family:Merriweather,Georgia,serif}.md-markdown a.md-footnote-anchor{border:1px solid #e92c6c}.md-markdown a.md-footnote-anchor:hover{background-color:#e92c6c;color:#fcfcfc}.md-footnote-ref{margin-left:1px;margin-right:3px}.md-markdown a.md-footnote-ref{border-bottom:1px dotted}.md-code-block,.md-code-inline{-webkit-text-size-adjust:none;-ms-text-size-adjust:none;text-size-adjust:none;background:#fcfcf5;color:#4d4d4c}.md-code-block{line-height:24px}.md-code{padding:8px 10px}.md-code-inline{padding:0 6px}a .md-code{color:inherit}.md-code-comment{color:#8e908c}.md-code-attribute,.md-code-built_in,.md-code-constant,.md-code-literal,.md-code-number,.md-code-params,.md-code-pragma,.md-code-preprocessor,.md-code-regexp,.md-code-tag,.md-code-variable,.md-lang-css .md-code-class,.md-lang-css .md-code-id,.md-lang-css .md-code-pseudo,.md-lang-html .md-code-doctype,.md-lang-ruby .md-code-constant,.md-lang-xml .md-code-doctype,.md-lang-xml .md-code-pi,.md-lang-xml .md-code-tag .md-code-title,color #c82829{color:#f5871f}.md-lang-css .md-code-rule .md-code-attribute,.md-lang-ruby .md-code-class .md-code-title{color:#eab700}.md-code-header,.md-code-inheritance,.md-code-name,.md-code-string,.md-code-value,.md-lang-ruby .md-code-symbol,.md-lang-xml .md-code-cdata{color:#718c00}.md-code-title,.md-lang-css .md-code-hexcolor{color:#3e999f}.md-code-function,.md-lang-coffeescript .md-code-title,.md-lang-javascript .md-code-title,.md-lang-perl .md-code-sub,.md-lang-python .md-code-decorator,.md-lang-python .md-code-title,.md-lang-ruby .md-code-function .md-code-title,.md-lang-ruby .md-code-title .md-code-keyword{color:#4271ae}.md-code-keyword,.md-lang-javascript .md-code-function{color:#8959a8}.md-lang-coffeescript .md-lang-javascript,.md-lang-javascript .md-lang-xml,.md-lang-tex .md-code-formula,.md-lang-xml .md-code-cdata,.md-lang-xml .md-lang-css,.md-lang-xml .md-lang-javascript,.md-lang-xml .vbscript{opacity:.5}.md-code-deletion{background-color:rgba(244,0,30,.05);color:#f4001e}.md-code-addition{background-color:rgba(27,194,17,.05);color:#1bc211}.md-mark{background-color:rgba(255,226,112,.5);color:inherit}.md-mark span{color:inherit}.md-heading-hover{cursor:pointer;background-color:rgba(22,134,162,.1)}.mde-text-left{text-align:left}.mde-text-center{text-align:center}.mde-text-right{text-align:right}.mde-size-small{font-size:12px}.mde-size-small,.mde-size-small p{line-height:12px}.mde-size-large{font-size:36px}.mde-size-large,.mde-size-large p{line-height:36px}.mde-size-giant{font-size:72px}.mde-size-giant,.mde-size-giant p{line-height:72px}.mde-clearfix:after{content:' ';display:block;visibility:hidden;clear:both;font-size:0;height:0}.mde-quote{margin:0;padding:20px 0;border:none;border-top:5px solid rgba(0,0,0,.05);border-bottom:5px solid rgba(0,0,0,.05)}.mde-core{font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}.mde-mono{font-family:Consolas,Menlo,Monaco,'Lucida Console','Liberation Mono','DejaVu Sans Mono','Bitstream Vera Sans Mono','Courier New',monospace,serif}.ly-custom-heading .mde-heading,.ly-lean .mde-heading{font-family:Neuton,'Hoefler Text',Palatino,Baskerville,Georgia,'Times New Roman',serif}.ly-custom-subheading .mde-subheading,.ly-lean .mde-subheading{font-family:Merriweather,Georgia,serif}.mde-pad-0{padding:0}.mde-pad-5{padding:5px}.mde-pad-10{padding:10px}.mde-pad-15{padding:15px}.mde-pad-20{padding:20px}.mde-pad-25{padding:25px}.mde-pad-30{padding:30px}.mde-pad-50{padding:50px}.mde-mar-0{margin:0}.mde-mar-5{margin:5px}.mde-mar-10{margin:10px}.mde-mar-15{margin:15px}.mde-mar-20{margin:20px}.mde-mar-25{margin:25px}.mde-mar-30{margin:30px}.mde-mar-50{margin:50px}@media only screen and (min-width:900px){.mde-left{float:left}.mde-right{float:right}.mde-inline{display:inline-block;vertical-align:top}.mde-20{max-width:20%}.mde-25{max-width:25%}.mde-33{max-width:33.3333333333%}.mde-50{max-width:50%}.mde-66{max-width:66.6666666666%}.mde-75{max-width:75%}}.twitter-tweet-figure{background:0 0;padding:0}.twitter-tweet-figure:before{content:none}.twitter-tweet-figure .twitter-tweet{margin:0 auto}blockquote.twitter-tweet{overflow:hidden;color:#1c2022;background-color:#fff;border:1px solid #e1e8ed;border-radius:4px;width:500px;max-width:100%;min-width:220px;padding:1.25rem 1.25rem .725rem}blockquote.twitter-tweet:before{content:none}blockquote.twitter-tweet p{white-space:pre-wrap;font:16px/1.4 Helvetica,Roboto,'Segoe UI',Calibri,'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}blockquote.twitter-tweet a,blockquote.twitter-tweet a:visited{color:#2b7bb9}.wy-container{margin:0 auto;padding:20px 0;max-width:800px}.wy-container .md-markdown p{line-height:22px;margin:10px 0}.wy-container .md-markdown p:first-child{margin-top:0}.wy-container .md-markdown p:last-child{margin-bottom:0}.wy-container .md-markdown blockquote:not(.twitter-tweet){padding:10px 0}.wy-container .md-code-block{margin:0;padding:10px;white-space:pre-wrap}.wy-table{width:100%;padding:0}.wy-td{padding:0}.wy-section-link,.wy-section-markdown,.wy-section-poll,.wy-section-summary{padding-top:25px}.wy-section-thanks{margin-top:25px;padding:10px;font-size:15px;background-color:#f2fcf2}.wy-header-text,.wy-issue{display:inline-block;margin:10px 0;line-height:24px}.wy-issue{float:right;font-size:12px}.wy-issue-content{display:block;padding:0 5px;background-color:#fcfcfc}.wy-section-header{padding-top:40px}.wy-section-header h1,.wy-section-header h2,.wy-section-header h3,.wy-section-header h4,.wy-section-header h5,.wy-section-header h6{margin:0}.wy-section-header p{line-height:inherit}.wy-header-td{padding:0}.wy-header-content{margin:0 10px}.wy-header-text{color:#fcfcfc;text-shadow:1px 1px 0 #1a4d7f;font-weight:700;font-size:24px}.wy-content{padding-bottom:25px}.wy-link-addendum,.wy-link-tag,.wy-link-title{display:inline-block;vertical-align:bottom;margin-bottom:10px}.wy-link-title{border-bottom:1px solid;font-size:20px;margin-right:10px}.wy-link-tag{background-color:#1a4d7f;color:#fcfcfc;text-transform:uppercase;font-size:13px;margin-right:5px;padding:2px 4px}.wy-link-tag:last-child{margin-right:0}.wy-link-addendum{color:#999;margin-left:5px}.wy-link-addendum:hover{border-bottom-color:transparent}.wy-link-title-section{position:relative}.wy-link-stats{position:absolute;right:0;background-color:#3aca96;color:#fcfcfc;border-bottom:1px solid #299a71}.wy-link-stats-logo{background-color:rgba(0,0,0,.1);color:#299a71}.wy-link-stat{margin:3px}.wy-link-description{font-size:14px;color:#666}.wy-link-source-section{margin-top:10px}.wy-link-source{margin-right:10px;margin-bottom:10px;display:inline-block;vertical-align:middle;color:#55acee}.wy-link-source-plain{color:#333}.wy-link-source.wy-link-source-plain a{color:#55acee}.wy-link-source.wy-link-source-plain a:visited{background-color:rgba(85,172,238,.04)}.wy-link-source.wy-link-source-plain a:visited .md-code-inline:before{background-color:#55acee}.wy-link-source.wy-link-source-plain a:active{outline-color:#55acee}.wy-link-source.wy-link-source-plain a:hover{border-bottom-color:#55acee}.wy-link-sponsor{background-color:transparent;color:#999;outline:#999 solid 1px}.wy-link-cell-before-image{vertical-align:middle;width:70%}.wy-link-cell-image{padding-left:10px}.wy-link-image-anchor{display:block;overflow:hidden;max-height:300px}.wy-link-image{display:block;margin:0 auto}.wy-footer-table{margin:20px 0}.wy-footer-cell{text-align:center}.wy-read-online{font-size:13px}.wy-section-link-job .wy-link-source,.wy-section-link-job .wy-link-title{font-size:14px}.wy-section-link-job .wy-link-description{font-size:12px}.wy-link-pixel{float:right}@media only screen and (max-width:500px){.wy-issue-publication,.wy-issue-separator{display:none}}.md-code-block{margin:0!important;padding:10px}</style>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">State of Clojure 2021 Survey</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">14 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div class="paragraph">
<p>It&#8217;s time for the annual State of Clojure Community Survey!</p>
</div>
<div class="paragraph">
<p>If you are a user of Clojure or ClojureScript, we are greatly interested in your responses to the following survey:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://www.surveymonkey.com/r/clojure2021">State of Clojure 2021</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The survey contains five pages:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>General info</p>
</li>
<li>
<p>Tool usage</p>
</li>
<li>
<p>Questions specific to JVM Clojure (skip if not applicable)</p>
</li>
<li>
<p>Questions specific to ClojureScript (skip if not applicable)</p>
</li>
<li>
<p>Final comments</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>Only the first two questions are required, please skip any questions that are not applicable.</p>
</div>
<div class="paragraph">
<p>The survey will close January 29th, after which all of the data will be released with some analysis. We greatly appreciate your input!</p>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Introducción a Terraform sobre Digital Ocean">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Introducción a Terraform sobre Digital Ocean</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">13 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Para este segundo episodio de Informe Nube, <a href="https://cursosdedesarrollo.com" data-type="URL" data-id="https://cursosdedesarrollo.com">David Vaquero</a> y <a href="https://twitter.com/dev_ago" data-type="URL" data-id="https://twitter.com/dev_ago">Antony Goetzschel</a>, ofrecen una introducción a Terraform y un despliegue de una infraestructura sobre la plataforma de cloud Digital Ocean. </p>



<p><a href="https://www.terraform.io/" data-type="URL" data-id="https://www.terraform.io/">Terraform </a>es una interfaz de línea de comandos que permite gestionar cientes de servicios en la nube.  Terraform codifica las API de los servicios cloud en ficheros de configuración declarativos. Esta introducción permite comprender los aspectos básicos de Terraform y se utilizan como ejemplos los servicios de Digital Ocean. </p>




<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A rabbit hole full of Lisp</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Murilo Pereira</a> <span class="article__date">13 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        At work I contribute to a moderately-sized monorepo at 70 thousand files, 8-digit lines of code and hundreds of PRs merged every day. One day I opened a remote buffer at that repository and ran M-x find-file.
find-file is an interactive function that shows a narrowed list of files in the current directory, prompts the user to filter and scroll through candidates, and for a file to open. Emacs froze for 5 seconds before showing me the find-file prompt.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2021/202-task-story-epic-quest.png" alt="Task, Story, Epic, Quest">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Task, Story, Epic, Quest</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">13 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2021/202-task-story-epic-quest.png" alt="Task, Story, Epic, Quest" title="Enjoy your coffee" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">reCAPTCHA v3: ocultar insignia</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Bufa</a> <span class="article__date">11 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Solo 2 simples pasos para ocular la insignia del reCAPTCHA v3 de Google. Esta puede llegar a ser muy intrusiva en el diseño de nuestra web, especialmente en versiones móviles ocupando la parte inferior derecha de la pantalla. Para poder [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">What&#39;s good about staying inside Emacs?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Murilo Pereira</a> <span class="article__date">11 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        One of the oldest pieces of software still in use was recently described as
A sort of hybrid between Windows Notepad, a monolithic-kernel operating system, and the International Space Station.
Of course, they were talking about Emacs. And yes, it is kinda true.
I&rsquo;ve been using Emacs for a while and had opportunities to use it to work on projects in remote machines. There are a few quirks, but after changing a setting here and there, Tramp is mostly usable.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Re-Introducing Hash Indexes in PostgreSQL</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">10 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>There is a type of index you are probably not using, and may have never even heard of. It is wildly unpopular, and until a few PostgreSQL versions ago it was highly discouraged and borderline unusable, but under some circumstances it can out-perform even a B-Tree index.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hyperreals *R: Clausuras en python - Parte&amp;#160;2</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">10 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <h2>&#193;mbitos&nbsp;anidados</h2>
<p>La importancia de disponer de <em>clausuras</em> va m&#225;s all&#225; de saber d&#243;nde se eval&#250;a
la funci&#243;n. Si fuera posible encapsular una funci&#243;n junto con su propio entorno
de ejecuci&#243;n, podr&#237;amos conseguir que la funci&#243;n tenga <em>&#8220;memoria&#8221;</em> o, dicho de
otro modo, que sea capaz de conservar sus propios estados entre llamadas a la
funci&#243;n. Este <em>empaquetado</em> de funci&#243;n y entorno de ejecuci&#243;n se denomina a
veces <strong>clausuras verdaderas</strong> y suele ser la principal caracter&#237;stica de los
llamados <em>Lenguajes Funcionales</em>.</p>
<p>En python podemos crear estas <em>clausuras verdaderas</em> con *<em>funciones anidadas</em>,
donde una funci&#243;n est&#225; definida dentro del &#225;mbito de la&nbsp;otra.</p>
<p>Un ejemplo&nbsp;sencillo:</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">incr</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">aux</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">x</span> <span class="o">+</span> <span class="n">n</span>

    <span class="k">return</span> <span class="n">aux</span>


<span class="n">inc5</span> <span class="o">=</span> <span class="n">incr</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>

<span class="nb">print</span><span class="p">(</span><span class="n">inc5</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span>  <span class="c1"># --&gt;15</span>
</code></pre></div>

<p>Como resultado se devuelve la funci&#243;n <code>aux</code>, definida dentro del &#225;mbito de
<code>incr</code> y que emplea de &#233;ste la variable <code>n</code>. Internamente, se conserva la
referencia a la variable <code>n</code>, pero no ser&#225; accesible desde fuera de la funci&#243;n
<code>aux</code>. Hemos podido empaquetar la funci&#243;n junto con el entorno donde se&nbsp;defini&#243;.</p>
<p>Pongamos otro&nbsp;ejemplo:</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">count</span><span class="p">():</span>
    <span class="n">num</span> <span class="o">=</span> <span class="mi">0</span>

    <span class="k">def</span> <span class="nf">aux</span><span class="p">():</span>
        <span class="n">num</span> <span class="o">+=</span> <span class="mi">1</span>
        <span class="k">return</span> <span class="n">num</span>

    <span class="k">return</span> <span class="n">aux</span>


<span class="n">c1</span> <span class="o">=</span> <span class="n">count</span><span class="p">()</span>

<span class="n">c1</span><span class="p">()</span>  <span class="c1"># --&gt; 1</span>
<span class="n">c1</span><span class="p">()</span>  <span class="c1"># --&gt; 2</span>
<span class="n">c1</span><span class="p">()</span>  <span class="c1"># --&gt; 3</span>
</code></pre></div>

<p>Si pruebas este c&#243;digo te dar&#225; error. La funci&#243;n anidada <code>aux</code> intenta modificar
la variable <code>num</code>. Para este caso, la variable se crea dentro del &#225;mbito m&#225;s
interno, en lugar de usar la variable disponible. Y como se intenta modificar la
variable antes de asignarle un valor, entonces se produce el&nbsp;error.</p>
<p>Como soluci&#243;n, podr&#237;amos hacer la variable <code>num</code> global para que fuera accesible
por todos los &#225;mbitos. Pero esta soluci&#243;n no es buena ya que nos abrir&#237;a el
empaquetado. Para python3 podr&#237;amos declarar la variable como <code>nonlocal</code> para
que se busque en los &#225;mbitos&nbsp;superiores:</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">count</span><span class="p">():</span>
    <span class="n">num</span> <span class="o">=</span> <span class="mi">0</span>

    <span class="k">def</span> <span class="nf">aux</span><span class="p">():</span>
        <span class="k">nonlocal</span> <span class="n">num</span>
        <span class="n">num</span> <span class="o">+=</span> <span class="mi">1</span>
        <span class="k">return</span> <span class="n">num</span>

    <span class="k">return</span> <span class="n">aux</span>
</code></pre></div>

<p>Como soluci&#243;n para salir del paso, se puede evitar la reasignaci&#243;n de variables.
Por ejemplo, usando una&nbsp;lista:</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">count</span><span class="p">():</span>
    <span class="n">num</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span>

    <span class="k">def</span> <span class="nf">aux</span><span class="p">():</span>
        <span class="n">num</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
        <span class="k">return</span> <span class="n">num</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>

    <span class="k">return</span> <span class="n">aux</span>
</code></pre></div>

<p>Ya s&#233; que no es muy elegante, pero hay otras formas de hacerlo&nbsp;mejor.</p>
<h2>Generadores</h2>
<p>Una de las formas m&#225;s comunes de usar clausuras es a trav&#233;s de <strong>generadores</strong>.
B&#225;sicamente, son funciones que en lugar de usar <code>return</code> utilizan <code>yield</code> para
devolver un valor. Entre invocaciones, se conserva el entorno de ejecuci&#243;n y
contin&#250;an desde el punto desde donde estaba. Para el ejemplo&nbsp;anterior:</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">count</span><span class="p">():</span>
    <span class="n">num</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
        <span class="n">num</span> <span class="o">+=</span> <span class="mi">1</span>
        <span class="k">yield</span> <span class="n">num</span>


<span class="n">c1</span> <span class="o">=</span> <span class="n">count</span><span class="p">()</span>
<span class="nb">next</span><span class="p">(</span><span class="n">c1</span><span class="p">)</span>  <span class="c1"># --&gt; 1</span>
<span class="nb">next</span><span class="p">(</span><span class="n">c1</span><span class="p">)</span>  <span class="c1"># --&gt; 2</span>
</code></pre></div>

<h2>Objetos&nbsp;funciones</h2>
<p>En los ejemplos que hemos visto, podr&#237;amos tener varias clausuras de una misma
funci&#243;n. Si hemos hecho bien las tareas, la ejecuci&#243;n de estas clausuras son&nbsp;independientes:</p>
<div class="highlight"><pre><span></span><code><span class="n">c1</span> <span class="o">=</span> <span class="n">count</span><span class="p">()</span>
<span class="n">c2</span> <span class="o">=</span> <span class="n">count</span><span class="p">()</span>

<span class="nb">next</span><span class="p">(</span><span class="n">c1</span><span class="p">)</span>  <span class="c1"># --&gt;1</span>
<span class="nb">next</span><span class="p">(</span><span class="n">c1</span><span class="p">)</span>  <span class="c1"># --&gt;2</span>
<span class="nb">next</span><span class="p">(</span><span class="n">c2</span><span class="p">)</span>  <span class="c1"># --&gt;1</span>
<span class="nb">next</span><span class="p">(</span><span class="n">c2</span><span class="p">)</span>  <span class="c1"># --&gt;2</span>
<span class="nb">next</span><span class="p">(</span><span class="n">c1</span><span class="p">)</span>  <span class="c1"># --&gt;3</span>
</code></pre></div>

<p>Con ello es posible establecer una analog&#237;a con clases y objetos. La definici&#243;n
de la funci&#243;n ser&#237;a la <em>clase</em> y la clausura la <em>instancia</em> de la&nbsp;clase.</p>
<p>&#191;Y si lo hacemos posible? En python se denominan <em>callables</em> a todo objeto que
tenga un m&#233;todo <code>__call__</code>, comport&#225;ndose como si fueran funciones
(<em>Functores</em>). Contruyamos una <em>callable</em> que funcione como una funci&#243;n con&nbsp;clausura:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">Count</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">num</span> <span class="o">=</span> <span class="mi">0</span>

    <span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">num</span> <span class="o">+=</span> <span class="mi">1</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">num</span>


<span class="n">c1</span> <span class="o">=</span> <span class="n">Count</span><span class="p">()</span>
<span class="n">c1</span><span class="p">()</span>  <span class="c1"># --&gt;1</span>
<span class="n">c1</span><span class="p">()</span>  <span class="c1"># --&gt;2</span>
<span class="n">c1</span><span class="p">()</span>  <span class="c1"># --&gt;3</span>
</code></pre></div>

<p>Sin duda es la manera m&#225;s elegante de usar clausuras que tenemos en python.
Evita muchos problemas y nos da una gran potencia a la hora de resolver algunos&nbsp;problemas.</p>
<p>Por ejemplo: imagina que queremos recorrer una lista de n&#250;meros, excluyendo los
que sean pares, y siempre que la suma total de los n&#250;meros que ya hemos visitado
no supere cierto&nbsp;l&#237;mite.</p>
<p>En una primera aproximaci&#243;n se podr&#237;a crear un&nbsp;generador:</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">recorr</span><span class="p">(</span><span class="n">lista</span><span class="p">,</span> <span class="n">maximo</span><span class="p">):</span>
    <span class="n">total</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">lista</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">total</span> <span class="o">+</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">maximo</span><span class="p">:</span>
                <span class="n">total</span> <span class="o">+=</span> <span class="n">i</span>
                <span class="k">yield</span> <span class="n">i</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="k">break</span>


<span class="n">recorr</span><span class="p">([</span><span class="mi">3</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">23</span><span class="p">],</span> <span class="mi">30</span><span class="p">)</span> <span class="c1">#--&gt;[3,7,11]</span>
</code></pre></div>

<p>Est&#225; bien, pero no es f&#225;cil de usar. Aunque s&#243;lo necesitemos algunos elementos,
seguramente estemos obligados a crear una lista completa con todos los
valores<sup id="fnref:1"><a class="footnote-ref" href="https://blog.ch3m4.org/feeds/python.atom.xml#fn:1">1</a></sup>. Encima, no tenemos acceso a la variable <code>total</code> para saber cu&#225;nto
han sumado el&nbsp;resultado.</p>
<p>Una alternativa con objetos funciones, mucho m&#225;s&nbsp;elegante:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">RecorrFunc</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">maximo</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">maximo</span> <span class="o">=</span> <span class="n">maximo</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">total</span> <span class="o">=</span> <span class="mi">0</span>

    <span class="k">def</span> <span class="nf">filter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">item</span><span class="p">):</span>
        <span class="n">res</span> <span class="o">=</span> <span class="n">item</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">!=</span> <span class="mi">0</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">total</span> <span class="o">+</span> <span class="n">item</span> <span class="o">&lt;</span> <span class="bp">self</span><span class="o">.</span><span class="n">maximo</span>
        <span class="k">if</span> <span class="n">res</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">total</span> <span class="o">+=</span> <span class="n">item</span>
        <span class="k">return</span> <span class="n">res</span>

    <span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">lista</span><span class="p">):</span>
        <span class="k">return</span> <span class="p">[</span><span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">lista</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">x</span><span class="p">)]</span>


<span class="n">recorr</span> <span class="o">=</span> <span class="n">RecorrFunc</span><span class="p">(</span><span class="mi">30</span><span class="p">)</span>
<span class="n">recorr</span><span class="p">([</span><span class="mi">3</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">23</span><span class="p">])</span>  <span class="c1"># --&gt;[3,7,11]</span>
<span class="nb">print</span><span class="p">(</span><span class="n">recorr</span><span class="o">.</span><span class="n">total</span><span class="p">)</span>  <span class="c1"># --&gt;21</span>
</code></pre></div>

<p>Las posibilidades de los objetos funci&#243;n son muchas. Del mismo modo que se
devuelve una lista, ser&#237;a posible devolver un iterador. Empleando las funciones
del m&#243;dulo <code>itertools</code>, y algunos trucos m&#225;s, podr&#237;amos aplicar los principios
de la programaci&#243;n funcional en python sin&nbsp;problemas.</p>
<p>Pero &#233;so lo veremos en pr&#243;ximos&nbsp;art&#237;culos.</p>
<div class="footnote">
<hr />
<ol>
<li id="fn:1">
<p>No sabemos de antemano cu&#225;ntos items vamos a obtener. Si, por ejemplo,
necesitamos s&#243;lo los tres primeros, tendremos que iterar elemento a elemento
hasta llegar a los tres que necesitamos o, bien, hasta que quede exhausto el
iterador. Con la soluci&#243;n con funtores el proceso es mucho m&#225;s directo y
eficiente.&#160;<a class="footnote-backref" href="https://blog.ch3m4.org/feeds/python.atom.xml#fnref:1" title="Jump back to footnote 1 in the text">&#8617;</a></p>
</li>
</ol>
</div>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hyperreals *R: Clausuras en python - Parte&amp;#160;1</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">10 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <h2>Funciones&nbsp;Lambda</h2>
<p>Antes de ver qu&#233; son las <strong>clausuras</strong> (<em>closures</em>), veamos qu&#233; tienen las
<em>funciones lambda</em> que las hacen tan pol&#233;micas algunas&nbsp;veces.</p>
<p>Comencemos con un ejemplo. Te recomiendo que te esfuerces en deducir c&#243;mo
funciona sin ir a probar c&#243;mo funciona. A continuaci&#243;n te pondr&#233; algunos valores
para que elijas los valores de las tres&nbsp;listas:</p>
<div class="highlight"><pre><span></span><code>    <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span>
    <span class="n">add_one</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span> <span class="o">+</span> <span class="n">i</span>

    <span class="n">lista1</span> <span class="o">=</span> <span class="p">[</span><span class="n">add_one</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]]</span>

    <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="n">lista2</span> <span class="o">=</span> <span class="p">[</span><span class="n">add_one</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]]</span>

    <span class="n">i</span> <span class="o">=</span> <span class="mi">2</span>
    <span class="n">lista3</span> <span class="o">=</span> <span class="p">[</span><span class="n">add_one</span><span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]]</span>
</code></pre></div>

<p>Valores para <code>lista1</code>:</p>
<ol>
<li><code>[0, 1, 2]</code></li>
<li><code>[1, 2, 3]</code></li>
<li><code>[0, 2, 4]</code></li>
<li><code>[1, 3, 5]</code></li>
</ol>
<p>Valores para <code>lista2</code>:</p>
<ol>
<li><code>[0, 1, 2]</code></li>
<li><code>[1, 2, 3]</code></li>
<li><code>[0, 2, 4]</code></li>
<li><code>[1, 3, 5]</code></li>
</ol>
<p>Valores para <code>lista3</code>:</p>
<ol>
<li><code>[0, 1, 2]</code></li>
<li><code>[1, 2, 3]</code></li>
<li><code>[2, 3, 4]</code></li>
<li><code>[1, 3, 5]</code></li>
</ol>
<p>Las soluciones est&#225;n al final del art&#237;culo<sup id="fnref:1"><a class="footnote-ref" href="https://blog.ch3m4.org/feeds/python.atom.xml#fn:1">1</a></sup>, pero puedes probarlo ahora para
que lo veas t&#250;&nbsp;mismo.</p>
<h3>&#191;Qu&#233; es lo que ha&nbsp;pasado?</h3>
<p>Contrariamente a lo que estamos acostrumbrados con las funciones normales, la
evaluaci&#243;n de una <em>funci&#243;n lambda</em> se hace dentro del entorno donde se ejecuta,
independiente del entorno donde se ha definido. As&#237; pu&#233;s, en la <em>funci&#243;n lambda</em>
<code>lambda x: x+i</code>, la variable <code>i</code> toma el valor de esta variable en el momento de
evaluar la funci&#243;n. Como se usa esta variable para la compresi&#243;n de la lista,
ir&#225; cambiando de valor a medida que se recorre la lista <code>[0,1,2]</code>, por lo que la
expresi&#243;n <code>add_one(i)</code> termina convirti&#233;ndose en la expresi&#243;n <code>i+i</code>, y la
expresi&#243;n <code>add_one(i+1)</code> en <code>i+1+i</code>.</p>
<p>Tiene un funcionamiento similar a los <em>macros</em>, donde se sustituye
<em>literalmente</em> la llamada a la funci&#243;n por la expresi&#243;n equivalente. En python3,
se hace m&#225;s evidente al denominarse <em>expresiones lambda</em> en lugar de <em>funciones
lambda</em>.</p>
<h2>Clausuras</h2>
<p>En una funci&#243;n podemos distinguir dos&nbsp;partes:</p>
<ul>
<li><strong>C&#243;digo&nbsp;ejecutable</strong></li>
<li><strong>Entorno de evaluaci&#243;n</strong>, m&#225;s conocido por <strong>&#193;mbito</strong> o <strong>Scope</strong></li>
</ul>
<p>Antes de ejecutar el c&#243;digo de la funci&#243;n, se aumenta el entorno de evaluaci&#243;n
con los <em>argumentos de entrada</em> de la&nbsp;funci&#243;n.</p>
<p>Seg&#250;n en qu&#233; entorno se evalua la funci&#243;n, tenemos dos&nbsp;&#225;mbitos:</p>
<ul>
<li><strong>Clausura</strong>, tambi&#233;n llamado <strong>&#193;mbito l&#233;xico</strong> o <strong>&#193;mbito
  Est&#225;tico</strong>, cuando la funci&#243;n se evalua en el entorno donde se ha&nbsp;definido.</li>
<li><strong>&#193;mbito din&#225;mico</strong> cuando se evalua en el entorno donde se invoca la&nbsp;funci&#243;n.</li>
</ul>
<p>Con esta definici&#243;n, podemos afirmar que en python las funciones tienen <em>&#225;mbito
l&#233;xico</em>, con excepci&#243;n de las funciones lambda que tienen <em>&#225;mbito din&#225;mico</em>.</p>
<p>No voy a considerar las ventajas de uno u otro tipo. Por lo general, las
<em>clausuras</em> se consideran mejores para desacoplar el c&#243;digo de la funci&#243;n del
c&#243;digo donde se invoca, lo que ayuda mucho al mantenimiento y correcci&#243;n de
errores. Es por ello la manera normal de crear funciones en la mayor&#237;a de
lenguajes de&nbsp;programaci&#243;n.</p>
<h3>&#191;C&#243;mo hacer que una funci&#243;n lambda se comporte como si tuviera <em>clausura</em>?</h3>
<p>La forma de hacer que un funci&#243;n lambda se evalue en el entorno donde se define
consiste en pasar las variables de ese entorno que necesite en los argumentos de
entrada, casi siempre como argumentos por&nbsp;defecto.</p>
<p>En el ejemplo anterior&nbsp;ser&#237;a:</p>
<div class="highlight"><pre><span></span><code>  <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span>
  <span class="n">add_one</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">x</span><span class="p">,</span> <span class="n">i</span><span class="o">=</span><span class="n">i</span><span class="p">:</span> <span class="n">x</span> <span class="o">+</span> <span class="n">i</span>
</code></pre></div>

<p>que equivaldr&#225;&nbsp;a</p>
<div class="highlight"><pre><span></span><code>  <span class="n">add_one</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">x</span><span class="p">,</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</span><span class="p">:</span> <span class="n">x</span> <span class="o">+</span> <span class="n">i</span>
</code></pre></div>

<p>En este caso <code>i</code> se toma de los argumentos de la funci&#243;n, y tendr&#225; por defecto
el valor de <code>i</code> en el momento de la definici&#243;n de la funci&#243;n&nbsp;lambda.</p>
<p>No es perfecto, pero es lo mejor que tenemos. Lo recomendable es evitar las
funciones lambda complejas si no queremos llevarnos algunas&nbsp;sorpresas.</p>
<div class="footnote">
<hr />
<ol>
<li id="fn:1">
<p>Los valores de las listas son las opciones 3, 3 y 4, respectivamente.&#160;<a class="footnote-backref" href="https://blog.ch3m4.org/feeds/python.atom.xml#fnref:1" title="Jump back to footnote 1 in the text">&#8617;</a></p>
</li>
</ol>
</div>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Descubriendo la programación funcional – Scala con David Vaquero">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Descubriendo la programación funcional – Scala con David Vaquero</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">09 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Para el quinto episodio sobre la serie de programación funcional, Andros Fenollosa presenta junto al compañero David Vaquero el lenguaje Scala, otro gran lenguaje que también hace uso de la máquina virtual de Java y es multiparadigma. Esto es una las diferencias con los otros lenguajes funcionales que se han tratado en esta serie. Scala es un lenguaje diseñado por Martin Odersky y que trae juntos dos paradigmas: la orientación a objetos y la programación funcional.</p>



<p>Entre las cuestiones discutidas en el episodio:</p>



<ul><li>¿Qué pasó por tu cabeza para meterte en la programación funcional?</li><li>Dime algunas características que te rompieron la cabeza y te enamoraron.</li><li>¿Qué es Scala?</li><li>¿Cuál es su origen?</li><li>¿Qué lo hace especial respecto a Clojure?</li><li>¿Quién lo usa? ¿Para quién está orientado?</li><li>¿Cuáles son tus frameworks favoritos?</li><li>Hablemos sobre el Front-End. ¿Existe implementación?</li><li>¿Cuál crees que es el futuro del ecosistema?</li><li>¿Existe una comunidad?</li><li>Recursos y consejos para grumetes.</li><li>Anécdotas, ¿qué es lo peor y lo mejor que te has encontrado?</li></ul>







<p>No te pierdas los otros episodios de la serie sobre programación funcional sobre <a href="https://republicaweb.es/podcast/descubriendo-la-programacion-funcional-clojure-con-vachi/">Clojure</a>, <a href="https://republicaweb.es/podcast/descubriendo-la-programacion-funcional-elixir-con-erick-navarro/">Elixir</a>, <a href="https://republicaweb.es/podcast/descubriendo-la-programacion-funcional-haskell-con-hector-navarro/">Haskell</a> y <a href="https://republicaweb.es/podcast/descubriendo-la-programacion-funcional-elm-con-david-hernandez/" data-type="URL" data-id="https://republicaweb.es/podcast/descubriendo-la-programacion-funcional-elm-con-david-hernandez/">Elm.</a></p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">GitHub Commit Bot to Stack Your Contributions Graph</h1>
                            <h2 class="article__feed"><a target="_blank" href="">blog.karenying.com</a> <span class="article__date">04 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        How to become the guy she tells you not to worry about
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2021/201-the-hero.png" alt="The Hero">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Hero</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">04 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2021/201-the-hero.png" alt="The Hero" title="It doesn’t take X-Ray Vision to see you are up to no good." /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">2020 Year in Review</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">03 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>What I've been up to in 2020...</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to open a file in Emacs</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Murilo Pereira</a> <span class="article__date">03 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Part One: A Lispy Adventure Figure 1: Arun Chanchal
I&rsquo;ve recently joined a company that for security reasons doesn&rsquo;t allow their source code on laptops. Development happens strictly on workstations inside their private networks, with some using their text editor&rsquo;s support for remote file editing and others running editors on those machines via SSH.
Adapting to this situation has indirectly led me into a bit of a rabbit hole, forcing me to acknowledge my core values, better understand the relation between progress and human flourishing, and ponder about the question: why technology?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Re-solutions</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Manuel Uberti</a> <span class="article__date">03 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I’ve been studying philosophy at Ca’ Foscari for about a year and half now,
devoting most of my spare time to wonderful and wonderfully difficult books, and
enjoying every part of this journey. There is still a lot of ground to cover
because I see many gaps to fill and thoughts to process, but there is one thing
that I am sure of: it’s going to be the journey of a lifetime.</p>

<p>I’ve not been so deeply fascinated and involved with something in a long while.
Ask my wife and she is going to tell you that perhaps my love for cinema can
match this passion for philosophy. I could agree, but cinema has not really been
on my side lately<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>. Beside few exceptions<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup>, 2020 will not be remembered for the
films or the directors that inspired me to write.</p>

<p>The last days of 2020 were dedicated to planning new year’s resolutions. To be
perfectly honest, I am not a great fan of new year’s resolutions. Most of the
time I forget about them in a couple of months. To circumvent my poor will,
I decided to keep the resolutions simple, small, and practical. This is what
I wrote down on my BuJo:</p>

<ul>
  <li>More books and less films</li>
  <li>More philosophy and less fiction</li>
  <li>Running</li>
</ul>

<p>The first two are easy to adopt side by side. I watched way too many forgettable
films last year, leaving the couch with the horrible feeling of time wasted.
I do not want to repeat that. If there isn’t a film to watch, I want to turn off
the TV, forget about my Blu-ray collection, and grab the book next to me.</p>

<p>As for the kind of book to pick up, I want to avoid contemporary fiction. There
is nothing wrong with contemporary fiction, of course, but most of the
contemporary books I read in 2020 proved to be little more than decent
entertainment. There is so much to read, and it’s not just philosophy. I want
more classics on my bedside table, and I want to read more from authors I love.
Consider it a sabbatical. I intend to come back to contemporary fiction next
year.</p>

<p>Finally, running. Let’s just say I stopped for no good reason and I am waiting
for my contact lens to start again. As simple as this resolution looks,
it’s also the most necessary one. Between work and studies the time I spend at
my desk has become unhealthy, and I know how fresh air and exercise make me
feel.</p>

<p>For all the good things in this planning, I see a couple of drawbacks here. If I
manage to stick to these resolutions, computing is going to play a different
role in my life. I will still be in front of my Emacs five days a week, but
that’s about it. Whereas this means less tinkering and less <em>githubbing</em>, it also
means less writing for my blogs. Nevertheless, for the sake of my priorities,
I am willing to sacrifice writing just as I am willing to put cinema aside.</p>

<p>Happy new year.</p>

<h2 id="footnotes">Footnotes</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>The small number of articles published last year on my other blog, <a href="https://www.filmsinwords.eu/">Films in
Words</a>, is telling. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>See <a href="https://www.filmsinwords.eu/">Films in Words</a>. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Re-solutions</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Manuel Uberti</a> <span class="article__date">03 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I’ve been studying philosophy at Ca’ Foscari for about a year and half now,
devoting most of my spare time to wonderful and wonderfully difficult books, and
enjoying every part of this journey. There is still a lot of ground to cover
because I see many gaps to fill and thoughts to process, but there is one thing
that I am sure of: it’s going to be the journey of a lifetime.</p>

<p>I’ve not been so deeply fascinated and involved with something in a long while.
Ask my wife and she is going to tell you that perhaps my love for cinema can
match this passion for philosophy. I could agree, but cinema has not really been
on my side lately<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>. Beside few exceptions<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup>, 2020 will not be remembered for the
films or the directors that inspired me to write.</p>

<p>The last days of 2020 were dedicated to planning new year’s resolutions. To be
perfectly honest, I am not a great fan of new year’s resolutions. Most of the
time I forget about them in a couple of months. To circumvent my poor will,
I decided to keep the resolutions simple, small, and practical. This is what
I wrote down on my BuJo:</p>

<ul>
  <li>More books and less films</li>
  <li>More philosophy and less fiction</li>
  <li>Running</li>
</ul>

<p>The first two are easy to adopt side by side. I watched way too many forgettable
films last year, leaving the couch with the horrible feeling of time wasted.
I do not want to repeat that. If there isn’t a film to watch, I want to turn off
the TV, forget about my Blu-ray collection, and grab the book next to me.</p>

<p>As for the kind of book to pick up, I want to avoid contemporary fiction. There
is nothing wrong with contemporary fiction, of course, but most of the
contemporary books I read in 2020 proved to be little more than decent
entertainment. There is so much to read, and it’s not just philosophy. I want
more classics on my bedside table, and I want to read more from authors I love.
Consider it a sabbatical. I intend to come back to contemporary fiction next
year.</p>

<p>Finally, running. Let’s just say I stopped for no good reason and I am waiting
for my contact lens to start again. As simple as this resolution looks,
it’s also the most necessary one. Between work and studies the time I spend at
my desk has become unhealthy, and I know how fresh air and exercise make me
feel.</p>

<p>For all the good things in this planning, I see a couple of drawbacks here. If I
manage to stick to these resolutions, computing is going to play a different
role in my life. I will still be in front of my Emacs five days a week, but
that’s about it. Whereas this means less tinkering and less <em>githubbing</em>, it also
means less writing for my blogs. Nevertheless, for the sake of my priorities,
I am willing to sacrifice writing just as I am willing to put cinema aside.</p>

<p>Happy new year.</p>

<h2 id="footnotes">Footnotes</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>The small number of articles published last year on my other blog, <a href="https://www.filmsinwords.eu/">Films in
Words</a>, is telling. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>See <a href="https://www.filmsinwords.eu/">Films in Words</a>. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">2020 Blogging Recap</h1>
                            <h2 class="article__feed"><a target="_blank" href="">blog.karenying.com</a> <span class="article__date">01 01 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Reflecting on the last six months + the definitive ranking of my posts
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">I Tracked My Mood Every Day of 2020</h1>
                            <h2 class="article__feed"><a target="_blank" href="">blog.karenying.com</a> <span class="article__date">31 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ...using a web app I coded. A look at trends that came out of it. Color blind friendly visuals included
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Descubriendo la programación funcional – Elm con David Hernández">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Descubriendo la programación funcional – Elm con David Hernández</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">27 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Cuarto episodio de la serie especial sobre programación funcional dirigida por Andros Fenollosa. En esta ocasión se dedica al lenguaje Elm, algo particular debido a que ha sido diseñado para funcionar solo en el navegador web.  Entre otras características podemos destacar que es declarativo, está influenciado por Haskell y diseñado para obtener robustez, usabilidad y rendimiento. Este lenguaje funcional hizo su aparición en el año 2012 gracias a <a href="https://github.com/evancz" data-type="URL" data-id="https://github.com/evancz">Evan Czaplicki</a>, creador de Elm.</p>



<p>Para este episodio sobre Elm, Andros cuenta con la compañía de <a href="https://twitter.com/David_Baltha" data-type="URL" data-id="https://twitter.com/David_Baltha">David Hernandez,</a> un profesional con más de 10 años programando para empresas de servicios y productos. Aunque principalmente ha estado con PHP, también ha podido tocar Javascript, Node, Python, Java y Elm, lenguaje que le ha traído a nuestro podcast. Sus roles han sido diversos: CTO, development manager y tech lead entre otros.</p>



<p>Entre las cuestiones discutidas en el episodio:</p>



<ul>
<li>¿Cómo te metiste a la programación funcional?</li>
<li>Origen y características de Elm</li>
<li>Beneficios y diferencias de Elm</li>
<li>Desventajas de Elm</li>
<li>Frontend con Elm</li>
<li>Futuro, comunidad y recursos</li>
</ul>



<p>No te pierdas los otros episodios de la serie sobre programación funcional sobre <a href="https://republicaweb.es/podcast/descubriendo-la-programacion-funcional-clojure-con-vachi/" data-type="URL" data-id="https://republicaweb.es/podcast/descubriendo-la-programacion-funcional-clojure-con-vachi/">Clojure</a>, <a href="https://republicaweb.es/podcast/descubriendo-la-programacion-funcional-elixir-con-erick-navarro/" data-type="URL" data-id="https://republicaweb.es/podcast/descubriendo-la-programacion-funcional-elixir-con-erick-navarro/">Elixir</a> y <a href="https://republicaweb.es/podcast/descubriendo-la-programacion-funcional-haskell-con-hector-navarro/" data-type="URL" data-id="https://republicaweb.es/podcast/descubriendo-la-programacion-funcional-haskell-con-hector-navarro/">Haskell.</a></p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Blogmas 2020</h1>
                            <h2 class="article__feed"><a target="_blank" href="">blog.karenying.com</a> <span class="article__date">25 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Megapost of something I coded / designed / learned every day of December until Christmas
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Embarking in a new affair with completions</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Manuel Uberti</a> <span class="article__date">25 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>What a year this 2020. Beside the pandemic changing our lives in unpredictable
ways, from the perspective of my Emacs usage much was going on in my <code class="language-plaintext highlighter-rouge">init.el</code>
until I felt that <a href="https://www.manueluberti.eu/emacs/2020/09/08/end-of-era/">a temporary break was necessary</a>.</p>

<p>Most of my tinkering concerned the minibuffer and its completion mechanisms.
I finished last year and started this one with Helm, but I am about to close
2020 with the built-in minibuffer completion and <a href="https://github.com/oantolin/embark">Embark</a> providing candidates.
A solution that <a href="https://protesilaos.com/dotemacs/">Protesilaos Stavrou</a> explored and which has been really suiting
me.</p>

<p>Before detailing how I adapted his approach to my preferences, though, let me
give you a bit of rationale. First, Helm rocks and it rocks hard. Its power is
evident after a couple of hours with it. I briefly used Icomplete tweaked to
display its results vertically, but I didn’t find it responsive enough to stick
with it. Then I found out about Selectrum, which fixed the responsiveness but
eventually was not adding a significant difference compared to Helm. True,
Selectrum has a simpler codebase, but were I only to look at my daily
interactions with Emacs, only the user interface can tell Helm and Selectrum
apart.</p>

<p>Protesilaos took a different path. He wants to understand the code in front of
him, so the less changes the better. In this regard Helm, Selectrum, and even
Icomplete add a layer of indirection between him and the minibuffer. He is right
in this. The minibuffer is more capable than the plethora of completion
frameworks may suggest, and one can leverage its strength without forcing it to
behave in a totally new way. Protesilaos’ reasoning got me thinking. Once again,
am I looking for a solution from the outside before having really understood
what lies underneath my beloved text editor?</p>

<p>Following Protesilaos’ steps, I set up the minibuffer to rely only on <a href="https://github.com/oantolin/orderless">orderless</a>
and Embark, with <a href="https://github.com/minad/consult">Consult</a> chiming in for a some of operations like better history
in <code class="language-plaintext highlighter-rouge">shell-mode</code> and an improved <code class="language-plaintext highlighter-rouge">apropos</code>. What I added to Protesilaos’ code is the
only thing that I felt was missing: a command to search for the symbol at point
in my project, with the results displayed in an <code class="language-plaintext highlighter-rouge">embark-live-occur</code> window in
order to quickly jump to a specific entry. Over at the Consult’s GitHub there
are talks about a <code class="language-plaintext highlighter-rouge">consult-rg</code> utility which would serves this purpose, and there
has been suggestions of using <code class="language-plaintext highlighter-rouge">project-find-regexp</code> as well.</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">defun</span> <span class="nv">mu-project-find-refs</span> <span class="p">()</span>
  <span class="s">"Use `project-find-regexp' to search for thing at point."</span>
  <span class="p">(</span><span class="nv">interactive</span><span class="p">)</span>
  <span class="p">(</span><span class="nv">if-let</span> <span class="p">(</span><span class="nv">tap</span> <span class="p">(</span><span class="nv">thing-at-point</span> <span class="ss">'symbol</span><span class="p">))</span>
      <span class="p">(</span><span class="nv">project-find-regexp</span> <span class="nv">tap</span><span class="p">)</span>
    <span class="p">(</span><span class="nv">message</span> <span class="s">"Nothing at point to search for"</span><span class="p">)))</span>
</code></pre></div></div>

<p>Easy enough to understand. However, if you, like me, set up Embark like
Protesilaos does you’ll notice that this command doesn’t show any candidate
unless you type something at the <code class="language-plaintext highlighter-rouge">Jump to definition</code> prompt. The candidates are
there already, though, so I have to avoid waiting for an input and display the
candidate list immediately.</p>

<p>The solution is straightforward: just remove <code class="language-plaintext highlighter-rouge">embark-live-occur-after-input</code> from
<code class="language-plaintext highlighter-rouge">minibuffer-setup-hook</code> and use <code class="language-plaintext highlighter-rouge">embark-live-occur-after-delay</code> instead. I added a
<code class="language-plaintext highlighter-rouge">:before</code> advice on <code class="language-plaintext highlighter-rouge">mu-project-find-refs</code> for this. The beauty of this advice is
that it works elsewhere as well. For instance, I have been using it for
<code class="language-plaintext highlighter-rouge">consult-flymake</code> and <code class="language-plaintext highlighter-rouge">flyspell-correct-at-point</code> too.</p>

<p>Note that this advice requires a little change to the original
<code class="language-plaintext highlighter-rouge">minibuffer-setup-hook</code> I have lifted from Protesilaos. Instead of adding
<code class="language-plaintext highlighter-rouge">embark-live-occur-after-input</code> to it I am using this to ensure only
<code class="language-plaintext highlighter-rouge">embark-live-occur-after-input</code> is present.</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">defun</span> <span class="nv">mu-embark-live-occur-after-input</span> <span class="p">()</span>
  <span class="s">"Ensure only `embark-live-occur-after-input' is active."</span>
  <span class="p">(</span><span class="nv">remove-hook</span> <span class="ss">'minibuffer-setup-hook</span> <span class="nf">#'</span><span class="nv">embark-live-occur-after-delay</span><span class="p">)</span>
  <span class="p">(</span><span class="nv">add-hook</span> <span class="ss">'minibuffer-setup-hook</span> <span class="nf">#'</span><span class="nv">embark-live-occur-after-input</span><span class="p">))</span>
</code></pre></div></div>

<p>Without a dedicated completion framework the minibuffer may feel rather basic at
first, but do not let it deceive you with its frugality. Like <code class="language-plaintext highlighter-rouge">project.el</code>, all it
needs is love.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Embarking in a new affair with completions</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Manuel Uberti</a> <span class="article__date">25 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>What a year this 2020. Beside the pandemic changing our lives in unpredictable
ways, from the perspective of my Emacs usage much was going on in my <code class="language-plaintext highlighter-rouge">init.el</code>
until I felt that <a href="https://www.manueluberti.eu/emacs/2020/09/08/end-of-era/">a temporary break was necessary</a>.</p>

<p>Most of my tinkering concerned the minibuffer and its completion mechanisms.
I finished last year and started this one with Helm, but I am about to close
2020 with the built-in minibuffer completion and <a href="https://github.com/oantolin/embark">Embark</a> providing candidates.
A solution that <a href="https://protesilaos.com/dotemacs/">Protesilaos Stavrou</a> explored and which has been really suiting
me.</p>

<p>Before detailing how I adapted his approach to my preferences, though, let me
give you a bit of rationale. First, Helm rocks and it rocks hard. Its power is
evident after a couple of hours with it. I briefly used Icomplete tweaked to
display its results vertically, but I didn’t find it responsive enough to stick
with it. Then I found out about Selectrum, which fixed the responsiveness but
eventually was not adding a significant difference compared to Helm. True,
Selectrum has a simpler codebase, but were I only to look at my daily
interactions with Emacs, only the user interface can tell Helm and Selectrum
apart.</p>

<p>Protesilaos took a different path. He wants to understand the code in front of
him, so the less changes the better. In this regard Helm, Selectrum, and even
Icomplete add a layer of indirection between him and the minibuffer. He is right
in this. The minibuffer is more capable than the plethora of completion
frameworks may suggest, and one can leverage its strength without forcing it to
behave in a totally new way. Protesilaos’ reasoning got me thinking. Once again,
am I looking for a solution from the outside before having really understood
what lies underneath my beloved text editor?</p>

<p>Following Protesilaos’ steps, I set up the minibuffer to rely only on <a href="https://github.com/oantolin/orderless">orderless</a>
and Embark, with <a href="https://github.com/minad/consult">Consult</a> chiming in for a some of operations like better history
in <code class="language-plaintext highlighter-rouge">shell-mode</code> and an improved <code class="language-plaintext highlighter-rouge">apropos</code>. What I added to Protesilaos’ code is the
only thing that I felt was missing: a command to search for the symbol at point
in my project, with the results displayed in an <code class="language-plaintext highlighter-rouge">embark-live-occur</code> window in
order to quickly jump to a specific entry. Over at the Consult’s GitHub there
are talks about a <code class="language-plaintext highlighter-rouge">consult-rg</code> utility which would serves this purpose, and there
has been suggestions of using <code class="language-plaintext highlighter-rouge">project-find-regexp</code> as well.</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">defun</span> <span class="nv">mu-project-find-refs</span> <span class="p">()</span>
  <span class="s">"Use `project-find-regexp' to search for thing at point."</span>
  <span class="p">(</span><span class="nv">interactive</span><span class="p">)</span>
  <span class="p">(</span><span class="nv">if-let</span> <span class="p">(</span><span class="nv">tap</span> <span class="p">(</span><span class="nv">thing-at-point</span> <span class="ss">'symbol</span><span class="p">))</span>
      <span class="p">(</span><span class="nv">project-find-regexp</span> <span class="nv">tap</span><span class="p">)</span>
    <span class="p">(</span><span class="nv">message</span> <span class="s">"Nothing at point to search for"</span><span class="p">)))</span>
</code></pre></div></div>

<p>Easy enough to understand. However, if you, like me, set up Embark like
Protesilaos does you’ll notice that this command doesn’t show any candidate
unless you type something at the <code class="language-plaintext highlighter-rouge">Jump to definition</code> prompt. The candidates are
there already, though, so I have to avoid waiting for an input and display the
candidate list immediately.</p>

<p>The solution is straightforward: just remove <code class="language-plaintext highlighter-rouge">embark-live-occur-after-input</code> from
<code class="language-plaintext highlighter-rouge">minibuffer-setup-hook</code> and use <code class="language-plaintext highlighter-rouge">embark-live-occur-after-delay</code> instead. I added a
<code class="language-plaintext highlighter-rouge">:before</code> advice on <code class="language-plaintext highlighter-rouge">mu-project-find-refs</code> for this. The beauty of this advice is
that it works elsewhere as well. For instance, I have been using it for
<code class="language-plaintext highlighter-rouge">consult-flymake</code> and <code class="language-plaintext highlighter-rouge">flyspell-correct-at-point</code> too.</p>

<p>Note that this advice requires a little change to the original
<code class="language-plaintext highlighter-rouge">minibuffer-setup-hook</code> I have lifted from Protesilaos. Instead of adding
<code class="language-plaintext highlighter-rouge">embark-live-occur-after-input</code> to it I am using this to ensure only
<code class="language-plaintext highlighter-rouge">embark-live-occur-after-input</code> is present.</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">defun</span> <span class="nv">mu-embark-live-occur-after-input</span> <span class="p">()</span>
  <span class="s">"Ensure only `embark-live-occur-after-input' is active."</span>
  <span class="p">(</span><span class="nv">remove-hook</span> <span class="ss">'minibuffer-setup-hook</span> <span class="nf">#'</span><span class="nv">embark-live-occur-after-delay</span><span class="p">)</span>
  <span class="p">(</span><span class="nv">add-hook</span> <span class="ss">'minibuffer-setup-hook</span> <span class="nf">#'</span><span class="nv">embark-live-occur-after-input</span><span class="p">))</span>
</code></pre></div></div>

<p>Without a dedicated completion framework the minibuffer may feel rather basic at
first, but do not let it deceive you with its frugality. Like <code class="language-plaintext highlighter-rouge">project.el</code>, all it
needs is love.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://slimbook.es/images/1.png" alt="Controlando el tiempo de arranque con systemd-analyze">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Controlando el tiempo de arranque con systemd-analyze</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Soporte - SLIMBOOK: ultrabooks, portátiles y ordenadores GNU/Linux</a> <span class="article__date">24 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Seguro que alguna vez nos hemos preguntado por que desde hace unos días nuestra distribución de Linux tarda mas de lo habitual en arrancar, o sencillamente nos hemos planteado hacer un arranque del sistema en tiempo record.</p>
<p>Pues ahora os vamos a presentar una utilidad que nos lo va a poner mas facil que nunca!</p>
<p>Con systemd-analyze vamos a poder identificar a los culpables de esos inicios lentos o que nos causan problemas.</p>
<p>Si lo invocamos sin parametros con <code>systemd-analyze</code> obtendremos la siguiente salida:</p>
<p><img src="https://slimbook.es/images/1.png" alt="1" /></p>
<p>No es muy impresionante, pero con esta vista general del firmware, gestor de arranque, kernel y espacio de usuario ya empezamos a tener una noción de donde se nos vá la mayor parte del tiempo.</p>
<p>Si queremos mas detalles y ver los servicios uno a uno, vamos a utilizar el parametro blame: <code>systemd-analyze blame</code></p>
<p><img src="https://slimbook.es/images/2.png" alt="2" /></p>
<p>Esto ya es otra cosa y ya podemos señalar con el dedo a los culpables de nuestros lentos inicios del equipo. Ahora solo quedaría desactivar los servicios que nos estén causando problemas y a volar.</p>
<p>Pero, y si a mi no me gusta todo este ladrillo de texto y se me hace de noche intentando descifrar numeros y servicios?..</p>
<p>No digas más, el parametro plot viene al rescate. Si usamos este parametro y además redirigimos la salida a una imagen tal que así: <code>systemd-analyze plot &#62; analisisgrafico.svg</code></p>
<p><img src="https://slimbook.es/images/systemd-analyze3.png" alt="systemd analyze3" /></p>
<p>Obtendremos una gŕafica como esta que nos facilitiará aún mas si cabe el diagnostico e identificación de procesos lentos.</p>
<p>Espero que el conocimiento de esta útil herramienta os sea de ayuda en vuestros diagnosticos!</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="8 predicciones sobre cómo la tecnología continuará cambiando nuestras vidas en el 2021">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">8 predicciones sobre cómo la tecnología continuará cambiando nuestras vidas en el 2021</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">23 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Episodio dedicado a comentar el estupendo artículo de Werner Vogels, CTO y vicepresidente de Amazon, titulado <a href="https://www.allthingsdistributed.com/2020/12/cloud-predictions-2021.html" data-type="URL" data-id="https://www.allthingsdistributed.com/2020/12/cloud-predictions-2021.html">8 predicciones sobre como la tecnología continuará cambiando nuestras vidas en el 2021</a>. Este artículo publicado en su blog personal All Things Distributed, es un análisis de gran interés para comprender los cambios que la tecnología producirá no sólo en el 2021, sino también la próxima década.</p>



<p><a href="https://twitter.com/werner" data-type="URL" data-id="https://twitter.com/werner">Werner Vogels</a> demuestra un conocimiento global del impacto de la tecnología y cómo las tecnologías de<a href="https://aws.amazon.com" data-type="URL" data-id="https://aws.amazon.com"> Amazon Web Services</a> están a la vanguardia de muchas tendencias tecnológicas. Otro punto muy destacable es la absoluta confianza en la capacidad de la tecnología para mejorar nuestras vidas. Al contrario que la visión pesimista de otras personas con respecto a la tecnología, Werner desborda optimismo y un total convencimiento de que el acceso asequible a la tecnología ayudará a que muchas regiones del planeta mejoren su calidad de vida.</p>



<p>Las 8 predicciones de Werner Vogels para el 2021 y más adelante son:</p>



<ul>
<li>Predicción 1. La nube estará en todas partes.</li>
<li>Predicción 2. La internet del aprendizaje automático</li>
<li>Predicción 3: En el 2021 imágenes, video y audio hablarán más que las palabras.</li>
<li>Predicción 4: La tecnología transformará nuestros mundos físicos tanto como los mundos digitales.</li>
<li>Predicción 5. El aprendizaje en remoto se gana su sitio en la educación.</li>
<li>Predicción 6. Los negocios pequeños se lanzarán a la nube y Sudeste asiático y el áfrica subsahariana liderarán el camino.</li>
<li>Predicción 7. La computación cuántica comenzará a florecer.</li>
<li>Predicción  8. La frontera final…</li>
</ul>

Sin duda se trata de un artículo de gran interés y que por su extensión y profundidad merece una lectura sosegada. En definitiva una visión muy completa del futuro de la tecnología, de la mano de unos de los líderes tecnológicos más influyentes del mundo.
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">2020 In Review</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">23 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A look back at 2020. It's been a difficult year for many, and I'm no exception, though I've come out of it stronger than ever and ready for what comes next.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://slimbook.es/images/Ubuntu_sonido.jpg" alt="Tutorial para cancelación de ruido de fondo en Linux">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Tutorial para cancelación de ruido de fondo en Linux</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Soporte - SLIMBOOK: ultrabooks, portátiles y ordenadores GNU/Linux</a> <span class="article__date">23 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Seguramente os habréis encontrado con que en Linux hay bastantes problemas con el tema del ruido de fondo en las grabaciones con micrófono. Y en las ultimas versiones se ha agrabado el inconveniente, hasta ahora!</p>
<p>Con este sencillo tutorial vamos a crear una nueva entrada de audio filtrada para deshacernos del molesto ruido de fondo del micriófono. Estas indicaciones funcionan para los problemas con Ubuntu, Linux Mint, Debian, etc.</p>
<p>&#160;</p>
<p>Abriremos una ventana de terminal, y editaremos el fichero /etc/pulse/default.pa para añadir el filtro de cancelación de ruido de pulseaudio al final del fichero donde veremos que se cargan otros módulos similares.</p>
<p>Abriremos un terminal y escribimos:</p>
<pre xml:lang="bash" lines="false">[code]sudo nano /etc/pulse/default.pa[/code]</pre>
<p>Nuestro fichero actual,<strong> al final del mimsmo</strong>, debería contener algo así, y es ahí donde debemos añadir el filtro de cancelación de ruido:</p>
<pre xml:lang="bash" lines="false">[code]### Modules to allow autoloading of filters (such as echo cancellation)<br />### on demand. module-filter-heuristics tries to determine what filters<br />### make sense, and module-filter-apply does the heavy-lifting of<br />### loading modules and rerouting streams.<br />load-module module-filter-heuristics<br />load-module module-filter-apply[/code]</pre>
<p>Añadimos el filtro de cancelación de ruido "load-module module-echo-cancel" al final de esas opciones, quedando algo así:</p>
<pre xml:lang="bash" lines="false">[code]### Modules to allow autoloading of filters (such as echo cancellation)<br />### on demand. module-filter-heuristics tries to determine what filters<br />### make sense, and module-filter-apply does the heavy-lifting of<br />### loading modules and rerouting streams.<br />load-module module-filter-heuristics<br />load-module module-filter-apply<br />load-module module-echo-cancel[/code]</pre>
<p>Una vez añadido, reiniciaremos el servicio de audio con el siguiente comando (Ojo, si conectamos un nuevo micrófono, posiblemente debamos recargar pulseaudio de nuevo este comando):</p>
<pre xml:lang="bash" lines="false">[code]pulseaudio -k[/code]</pre>
<p>Veremos que nos han aparecido nuevos dispositivos de control en los ajustes de sonido de nuestra distribución, seleccionaremos la nueva entrada de micrófono con cancelación de audio activa.</p>
<p>Espero que noteis una mejoría en vuestras grabaciones :)</p>
<p><img src="https://slimbook.es/images/Ubuntu_sonido.jpg" alt="Ubuntu sonido" /></p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://slimbook.es/images/imagetuto/nvidia_fedora/fedora_nvidia1.png" alt="Guia de instalación drivers propietarios Nvidia en Fedora">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Guia de instalación drivers propietarios Nvidia en Fedora</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Soporte - SLIMBOOK: ultrabooks, portátiles y ordenadores GNU/Linux</a> <span class="article__date">23 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p style="text-align: justify;"><span style="font-size: 12pt;">Seguramente</span><span style="font-size: 12pt;"> mas de uno habréis querido instalar Fedora en vuestros equipos con potentes tarjetas graficas de Nvidia solo para terminar dejandolo por imposible por la cantidad de trabas y problemas que nos han puesto los de nvidia con su limitado soporte. Pues vamos a acabar con esto de golpe con un tutorial que nos permitirá cambiar el driver de codigo abierto nouveau por el propietario de Nvidia.</span></p>
<p style="text-align: justify;"><span style="font-size: 12pt;">Bueno, vamos al lío. Preparaos por que vienen curvas :)</span></p>
<p id="aviso-dl-prem" style="text-align: justify;"><strong>**Este tutorial solo funciona con escritorio x11**<br /></strong></p>
<p style="text-align: justify;">&#160;</p>
<p style="text-align: justify;"><span style="font-size: 14pt;"><strong>1.- Antes de empezar con la instalación de nuestros drivers NVIDIA, vamos a comprobar que nuestra tarjeta esta soportada.</strong></span></p>
<p style="text-align: justify;"><span style="font-size: 12pt;">Para ello vamos a lanzar en nuestra terminal (Ctrl + ALT + T) el siguiente comando:</span></p>
<pre xml:lang="bash" lines="false">[code]lspci |grep -E "VGA|3D"[/code]</pre>
<p style="text-align: justify;"><span style="font-size: 12pt;">Nos tiene que aparecer algo como esto:</span></p>
<pre xml:lang="bash" lines="false">[code]01:00.0 VGA compatible controller: NVIDIA Corporation TU106 [GeForce RTX 2060 Rev. A] (rev a1)[/code]</pre>
<p style="text-align: justify;"><span style="font-size: 12pt;">Chequea el mejor driver de tu tarjeta grafica en este enlace: <a href="http://download.nvidia.com/XFree86/Linux-x86_64/460.67/README/supportedchips.html" target="_blank">lista</a></span></p>
<p style="text-align: justify;"><span style="font-size: 12pt;">Si tienes activado UEFI Secure BOOT, hay que desactivarlo desde la BIOS.</span></p>
<p style="text-align: justify;"><br /><span style="font-size: 14pt;"><strong>2.- Instalar los drivers propietarios de NVIDIA y desactivar el driver nouveau.</strong></span></p>
<p style="text-align: justify;"><span style="font-size: 12pt;">Para descargar el paquete instalador de NVIDIA iremos al siguiente <a href="https://www.nvidia.com/Download/Find.aspx?lang=en-us" target="_blank">enlace</a> y buscamos la ultima versión del driver de nuestra tarjeta.</span></p>
<p style="text-align: justify;"><span style="font-size: 12pt;">Una vez hayamos buscado y descargado nuestro driver vamos a hacer ejecutable el .run que se nos ha descargado. Para ello ejecutamos en la terminal el siguiente comando:</span></p>
<pre xml:lang="bash" lines="false">[code]chmod +x /Descargas/NVIDIA-Linux-*.run[/code]</pre>
<p>&#160;</p>
<p style="text-align: justify;"><span style="font-size: 12pt;">- Cambiamos al usuario root&#160; con:</span></p>
<pre xml:lang="bash" lines="false"><samp><code>su -<br /></code></samp><br /><samp><code>## O ##<br /></code></samp><br /><samp><code>sudo -i</code></samp></pre>
<p style="text-align: justify;"><br /><span style="font-size: 12pt;">- Asegurate de que tu sistema esta actualizado y estas con el ultimo kernel.</span></p>
<pre xml:lang="bash" lines="false">[code]dnf update[/code]</pre>
<p style="text-align: justify;"><br /><span style="font-size: 12pt;">- Después de actualizar reinicia el equipo e inicia con el ultimo kernel.</span></p>
<pre xml:lang="bash" lines="false">reboot</pre>
<p>&#160;</p>
<p><span style="font-size: 12pt;">- Instalamos las dependencias necesarias:</span></p>
<pre xml:lang="bash" lines="false">dnf install kernel-devel kernel-headers gcc make dkms acpid libglvnd-glx libglvnd-opengl libglvnd-devel pkgconfig</pre>
<p>&#160;</p>
<p><span style="font-size: 12pt;">- Desactivamos nouveau. Podemos crear o editar etc/modprobe.d/blacklist.conf</span></p>
<p><span style="font-size: 10pt;">Añadimos ‘blacklist nouveau’</span></p>
<pre xml:lang="bash" lines="false">[code]echo "blacklist nouveau" &#62;&#62; /etc/modprobe.d/blacklist.conf[/code]</pre>
<p><br /><span style="font-size: 12pt;">-Editamos etc/default/grub</span></p>
<p><span style="font-size: 10pt;">Añadimos ‘rd.driver.blacklist=nouveau’ al final de ‘GRUB_CMDLINE_LINUX=”…”‘.</span></p>
<pre xml:lang="bash" lines="false"><samp><code>## Fedora 34 BTRFS ##<br /></code></samp><br /><samp><code>GRUB_CMDLINE_LINUX="rhgb quiet rd.driver.blacklist=nouveau"<br /></code></samp><br /><samp><code>## O CON LVM ##<br /></code></samp><br /><samp><code>GRUB_CMDLINE_LINUX="rd.lvm.lv=fedora/swap rd.lvm.lv=fedora/root rhgb quiet rd.driver.blacklist=nouveau"</code></samp></pre>
<p><br /><span style="font-size: 12pt;">- Actualizamos grub2 conf</span></p>
<pre xml:lang="bash" lines="false"><samp><code>## BIOS y UEFI ##<br /></code></samp><br /><samp><code>grub2-mkconfig -o /boot/grub2/grub.cfg<br /></code></samp></pre>
<p>&#160;</p>
<p><span style="font-size: 12pt;">- Borramos xorg-x11-drv-nouveau</span></p>
<pre xml:lang="bash" lines="false">[code]dnf remove xorg-x11-drv-nouveau[/code]</pre>
<p><br /><span style="font-size: 12pt;">- Generamos initramfs</span></p>
<pre xml:lang="bash" lines="false"><samp><code>## Copia de seguridad antigua imagen nouveau ##<br /></code></samp><br /><samp><code>mv /boot/initramfs-$(uname -r).img /boot/initramfs-$(uname -r)-nouveau.img"<br /></code></samp><br /><samp><code>## Crear nueva imagen initramfs ##<br /></code></samp><br /><samp><code>dracut /boot/initramfs-$(uname -r).img $(uname -r)"<br /><br /></code></samp></pre>
<p><span style="font-size: 12pt;">- Reiniciar en runlevel 3</span></p>
<pre xml:lang="bash" lines="false"><samp><code>systemctl set-default multi-user.target<br /></code></samp><br /><samp><code>reboot<br /><br /></code></samp></pre>
<p><span style="font-size: 12pt;">- Ahora vamos a instalar los drivers propietarios en modo texto. Nos loguearemos y volvemos a entrar como usuario root de la siguiente manera:</span></p>
<pre xml:lang="bash" lines="false"><samp><code>su -<br /></code></samp><br /><samp><code>## O ##<br /></code></samp><br /><samp><code>sudo -i</code></samp></pre>
<p><br /><span style="font-size: 12pt;">-Ejecutamos el instalador del driver que en este caso sera un .run de la siguiente manera:</span></p>
<pre xml:lang="bash" lines="false"><samp><code>./NVIDIA-Linux-*.run<br /></code></samp><br /><samp><code>## O ruta completa ##<br /></code></samp><br /><samp><code>/home/usuario/Descargas/NVIDIA-Linux-x86_64-xxx.xxx.xx.run</code></samp></pre>
<p><br /><span style="font-size: 12pt;">- Registar los módulos fuente del núcleo con DKMS:</span></p>
<p><img src="https://slimbook.es/images/imagetuto/nvidia_fedora/fedora_nvidia1.png" alt="fedora nvidia1" style="float: left;" /></p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;<br /><span style="font-size: 12pt;"></span></p>
<p><span style="font-size: 12pt;">- Bibliotecas de compatibilidad de 32 bits:</span></p>
<p><img src="https://slimbook.es/images/imagetuto/nvidia_fedora/fedora_nvidia2.png" alt="fedora nvidia2" /></p>
<p><br /><span style="font-size: 12pt;">- Instalando controladores y construyendo el módulo del kernel:</span></p>
<p><img src="https://slimbook.es/images/imagetuto/nvidia_fedora/fedora_nvidia3.png" alt="fedora nvidia3" /></p>
<p>&#160;</p>
<p><img src="https://slimbook.es/images/imagetuto/nvidia_fedora/fedora_nvidia4.png" alt="fedora nvidia4" /></p>
<p>&#160;</p>
<p><img src="https://slimbook.es/images/imagetuto/nvidia_fedora/fedora_nvidia5.png" alt="fedora nvidia5" /></p>
<p>&#160;<br /><span style="font-size: 12pt;">- Instalador automático de configuración y copia de seguridad de Xorg:</span></p>
<p><img src="https://slimbook.es/images/imagetuto/nvidia_fedora/fedora_nvidia6.png" alt="fedora nvidia6" /></p>
<p><br /><span style="font-size: 12pt;">- Instalación de drivers completada:<br /></span></p>
<p><img src="https://slimbook.es/images/imagetuto/nvidia_fedora/fedora_nvidia7.png" alt="fedora nvidia7" /></p>
<p>&#160;</p>
<p><span style="font-size: 12pt;">- Ya está todo hecho y reiniciamos de nuevo en runlevel5</span></p>
<pre xml:lang="bash" lines="false"><samp><code>systemctl set-default graphical.target<br /></code></samp><br /><samp><code>reboot</code></samp></pre>
<p>&#160;</p>
<p><span style="font-size: 12pt;">- Soporte VDPAU/VAAPI</span></p>
<p><span style="font-size: 10pt;">Habilitar el soporte de aceleración de vídeo (Nota: necesitas Geforce 8 o posterior).</span></p>
<pre xml:lang="bash" lines="false">[code]sudo dnf install vdpauinfo libva-vdpau-driver libva-utils[/code]</pre>
<p><br /><span style="font-size: 12pt;">- Para poder abrir nvidia-settings, tienes que hacer lo siguiente:</span></p>
<p><span style="font-size: 12pt;">ALT + F2 y escribir&#160; nvidia-settings</span></p>
<p><br /><span style="font-size: 14pt;"><strong>3.- Capturas de pantalla usando nvidia settings con kernel 5.11.16</strong></span></p>
<p>&#160;<img src="https://slimbook.es/images/imagetuto/nvidia_fedora/fedora_nvidia8.png" alt="fedora nvidia8" width="1060" height="596" /></p>
<p>&#160;</p>
<p><img src="https://slimbook.es/images/imagetuto/nvidia_fedora/fedora_nvidia9.png" alt="fedora nvidia9" width="1060" height="579" /></p>
<p>&#160;</p>
<p id="aviso-dl-prem" style="text-align: justify;"><strong>** El driver de nvidia en el kernel 5.11.17 no funciona. Una vez pasas al kernel 5.11.18 vuelve a funcionar sin problemas, por ello mismo hemos bloqueado que suba o baje automáticamente de kernel. No obstante si quieres eliminar el bloqueo y poder escalar de kernel, te dejo el comando para hacerlo.**<br /></strong></p>
<pre xml:lang="bash" lines="false">[code]sudo dnf versionlock delete kernel-x.x.xx-xx.xxx[/code]</pre>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">SciCloj #18: Introducing Skija</h1>
                            <h2 class="article__feed"><a target="_blank" href="">tonsky.me</a> <span class="article__date">23 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://nosinmiscookies.com/wp-content/uploads/2019/03/cropped-favicon-32x32.png" alt="Cómo ha afectado la Covid-19 en la inversión publicitaria">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cómo ha afectado la Covid-19 en la inversión publicitaria</h1>
                            <h2 class="article__feed"><a target="_blank" href="">No sin mis cookies</a> <span class="article__date">22 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>La crisis derivada de la Covid-19 ha marcado un precedente en la economía global y un punto de inflexión en el ecosistema digital, con el consiguiente impacto en la inversión publicitaria como consecuencia del cambio en la forma en la que compramos, consumimos medios y trabajamos.</p>
<p>The post <a rel="nofollow" href="https://nosinmiscookies.com/como-ha-afectado-la-covid-19-en-la-inversion-publicitaria/">Cómo ha afectado la Covid-19 en la inversión publicitaria</a> appeared first on <a rel="nofollow" href="https://nosinmiscookies.com">No sin mis cookies</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Red Hat mata CentOS y Kubernetes hace obsoleto a Docker">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Red Hat mata CentOS y Kubernetes hace obsoleto a Docker</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">21 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Primer episodio de Informe Nube, una nueva serie dedicada a la actualidad de las tecnologías cloud y contenedores. David Vaquero y <a href="https://www.linkedin.com/in/antony-ricardo-goetzschel-devago/">Antony Göetzschel </a>repasan diferentes noticias relacionadas con la nube, ofreciendo su particular análisis. Este primer episodio de la serie, trae muchas cuestiones de gran interés para los profesionales del cloud.</p>



<p>Para empezar la serie David y Antony comienzan con una de las noticias más controvertidas de los últimos meses: <strong>el cambio de dirección en CentOS Linux</strong>, la distribución surgida de un fork de Red Hat Entreprise Linux,  hacia CentOS Stream. Este cambio deja en el aire muchas instalaciones de CentOS. Para entender este movimiento es importante comprender el flujo del desarrollo de este sistema y también los intereses de IBM como propietaria de Red Hat. Por supuesto, la comunidad de software libre no ha dudado en buscar alternativas.</p>



<p>En la segunda parte del episodio se dedica a hablar sobre como Kubernetes no requiere Docker como entorno de ejecución. Sin duda, un movimiento que muestra la diversidad y velocidad de los cambios que existen en estas tecnologías.</p>



<p>Otro tema de conversación en el episodio consiste en la idoneidad de presentarse a ofertas laborales, aunque no tengas todos los conocimientos que exigen.</p>



<p>Como es un episodio de arranque, David y Antony continúan con más temas. Uno viene a raíz de un <a href="https://youtu.be/qV1lIHSf3XI" data-type="URL" data-id="https://youtu.be/qV1lIHSf3XI">vídeo de Pelado Nerd.</a> <strong>¿Cuál es la mejor solución para un cluster de Kubernetes?</strong> y el último bloque se dedica a comentar que <strong>Rancher presenta Harvester una solución HCI (Hyper-Converged infrastructure)</strong>.</p>




<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Descubriendo la programación funcional – Haskell con Héctor Navarro">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Descubriendo la programación funcional – Haskell con Héctor Navarro</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">18 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Tercera entrega de la serie especial dedicada a la programación funcional presentada por Andros Fenollosa. En este tercer episodio le toca el turno a <a href="https://www.haskell.org/" data-type="URL" data-id="https://www.haskell.org/">Haskell </a>de la mano de <a href="https://twitter.com/hectornavarro" data-type="URL" data-id="https://twitter.com/hectornavarro">Héctor Navarro</a>, profesor e investigador en el área de Algoritmos y Lenguajes de Programación. Héctor Navarro actualmente trabaja como Ingeniero de Software en Amazon.com. Desde el año 2000 hasta 2018 ha desempeñado su labor de investigador y profesor en la Universidad Central de Venezuela. A pesar de usar primordialmente Java en trabajo diario, sigue siendo un gran entusiasta de Haskell y de la programación funcional.</p>



<p>Haskell es un lenguaje de programación funcionalmente puro, con tipado estático y evaluación perezosa. Su nombre fue otorgado por <a href="https://es.wikipedia.org/wiki/Haskell_Curry" data-type="URL" data-id="https://es.wikipedia.org/wiki/Haskell_Curry">Haskell Curry, </a>matemático y lógico estadounidense que aportó el cálculo Lambda (un sistema para definir funciones y recursión creado por el matemático y lógico <a href="https://es.wikipedia.org/wiki/Alonzo_Church" data-type="URL" data-id="https://es.wikipedia.org/wiki/Alonzo_Church">Alonzo Church</a>), siendo este muy influyente dentro del lenguaje. Con Héctor Navarro tenemos oportunidad de tratar interesantes cuestiones del lenguaje:</p>



<ul><li>¿Qué pasó por tu cabeza para meterte en la programación funcional?</li><li>Dime algunas características que te rompieron la cabeza y te enamoraron.</li><li>¿Qué es Haskell y cuál es su orgien?</li><li>¿Qué lo hace especial respecto a otros lenguajes?</li><li>¿Quién usa Haskell y para quién está orientado?</li><li>¿Qué son las monadas?</li><li>¿Cuáles son tus frameworks favoritos?</li><li>Hablemos sobre el Front-End. ¿Existe implementación? ¿Tal vez Elm?</li><li>¿Cuál crees que es el futuro del ecosistema?</li><li>¿Existe una comunidad?</li><li>Recursos y consejos para grumetes.</li></ul>



<p>En esta interesante conversación Héctor Navarro nos cuenta detalles relevantes sobre Haskell, aplicaciones, usos, herramientas y recursos. </p>



<p>No olvidéis escuchar y visitar los enlaces de los dos primeros episodios de la serie sobre programación funcional:</p>



<ul>
<li><a href="https://republicaweb.es/podcast/descubriendo-la-programacion-funcional-elixir-con-erick-navarro/">Descubriendo la programación funcional – Elixir con Erick Navarro</a></li>
<li><a href="https://republicaweb.es/podcast/descubriendo-la-programacion-funcional-clojure-con-vachi/">Descubriendo la programación funcional – Clojure con Vachi</a>
</li>
</ul>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://nosinmiscookies.com/wp-content/uploads/2019/03/cropped-favicon-32x32.png" alt="Guía para comprar enlaces en blogs y periódicos">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Guía para comprar enlaces en blogs y periódicos</h1>
                            <h2 class="article__feed"><a target="_blank" href="">No sin mis cookies</a> <span class="article__date">15 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Aprende a invertir de forma inteligente en la compra de enlaces para cumplir los objetivos de tu negocio y sin tirar el dinero.</p>
<p>The post <a rel="nofollow" href="https://nosinmiscookies.com/guia-para-comprar-enlaces-en-blogs-y-periodicos/">Guía para comprar enlaces en blogs y periódicos</a> appeared first on <a rel="nofollow" href="https://nosinmiscookies.com">No sin mis cookies</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Another Common Lisp app in production</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">14 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>A quick post to celebrate the birth of another Common Lisp application
running in production©. This time, it is not open source, but I can describe it.</p>

<p>It is used by bookshops in France and Belgium to upload there catalogue to online
platforms. And no, they don&rsquo;t know, and don&rsquo;t need to know, the
language it is implemented in!</p>

<p>It is a simple application that reads data from an existing DB, builds
a text file with special rules, sends the file to an FTP server, and
does it every day. I used cl-dbi with raw SQL queries,
<a href="https://github.com/pinterface/cl-ftp">cl-ftp</a> (does its job perfectly), and a CRON job. I
built a binary that I sent to my server. It is a stand-alone
application that reads a DB that is created by a bigger Python/Django
web app (that I also develop). I didn&rsquo;t want to make this one more
bloated, so given the goals are complementary but orthogonal, I went
with a stand-alone tool.</p>

<p>That&rsquo;s it. One more!</p>

<p>Another tool I am running connects to a SOAP service, shows data on a website (with Sentry configured in production), sells products with Stripe and sends emails with Sendgrid. And I (generally) update it while it runs by connecting to the Lisp REPL. Just throwing out buzzwords to you.</p>

<p>While I&rsquo;m at it, let me stress one point, to answer in advance a kind
of feedback I already had: no, the resulting application doesn&rsquo;t use
any Lisp superpower and yes, I could have written it in Python. It
turns out Lisp is as suited as Python for this task (or then it is
more suited, since it is faster), the point is <em>I</em> benefited from Lisp&rsquo;s
superpowers during development (by using the superior REPL, being able
to build a binary and all that). In conclusion: there are <strong>tons</strong> of
places where Lisp can be used for professional needs out there.</p>

<p>Oh. In doing it, I built those two utilities:</p>

<ul>
<li><a href="https://github.com/vindarel/progressons">progressons</a>, a progress bar that holds on one line and works on the terminal as well as on Slime. It works for me©. My next goal is to make it output a prettier bar with unicode bars.</li>
<li><a href="https://github.com/vindarel/termp">termp</a>, a trivial utility that checks if we are on a real or on a dumb terminal (by checking the <code>TERM</code> environment variable). So you can <code>quit</code> or <code>error</code> out.</li>
</ul>

<p>Two more Lisp repositories on Github !</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Pro mailing list: on Common Lisp and parallel GC</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">14 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I recently enjoyed this <a href="https://mailman.common-lisp.net/pipermail/pro/2020-December/thread.html#1837">discussion on the pro mailing list</a>. It started with a call of recommendations on music software, and the discussion evolved in discussing parallel garbage collection. By the way, can you site an implementation that has parallel GC?</p>

<hr />

<p>Pascal Costanza:</p>

<p>«When moving our elPrep software away from Common Lisp, we evaluated C++, Go and Java as potential candidates, and Go turned out to provide the best balance between performance and memory use. We are still using Common Lisp for prototyping, and then translate to Go. These two languages are actually much more similar than it appears at first. […]»</p>

<p>«This was primarily for the lack of good parallel, concurrent garbage collectors in Common Lisp implementations. The CL version of elPrep was actually still a tad faster than any of the C++, Go, or Java versions, but we had to work hard to avoid long GC pauses. elPrep allocates a lot of memory, and the pause time hurts a lot. We solved this by, basically, disabling the garbage collector, and reusing memory manually as much as possible, which turned the program into almost a manually memory-managed affair.»</p>

<p>«Manual memory management became a huge burden because we wanted to add more and more components to the software, and then it becomes almost impossible to predict object lifetimes.»</p>

<p>«We evaluated Go and Java for their concurrent, parallel GCs, and C++ for its reference counting. Interestingly, reference counting is often described as more efficient than GC, but in our case that’s not true: Because there is a huge object graph at some stage that needs to be deallocated, reference counting incurs more or less the same pause that a non-concurrent GC does. That’s why we don’t expect Rust to fare better here either.»</p>

<p>«Again, we’re still prototyping in Common Lisp, which is a huge win, because this makes us much more productive.»</p>

<p>«In my opinion, prototyping in Common Lisp, and then translating to a
different programming language for creating the final product, is a
perfectly valid professional use of Common Lisp. It’s useful to know
which programming languages may be good targets for such an approach. This is, of course, not ideal, because this can easily be
misunderstood as a statement that Common Lisp is not fit for
purpose. However, I don’t see it that way, and you cannot control
people’s perceptions. In our particular case, our manager is on board with this approach, and this allows us to pay for regular licenses for LispWorks. The
approach works really well for us.»</p>

<p>Didier Verna:</p>

<p>«I&rsquo;d be curious to know if there are particularities in CL itself that make this difficult, or if it&rsquo;s simply because there&rsquo;s no manpower to improve the GCs we have currently.»</p>

<p>Stelian Ionescu:</p>

<p>«It&rsquo;s strictly a lack of manpower. Most CL implementations have GCs that were state-of-the-art 25 years ago: they&rsquo;re either mark-and-sweep or copying &amp; generational, and have to perform all collection while application threads are paused (i.e. stop-the-world), hence the collection pauses that are proportional to the heap size.»</p>

<p>«The newer GCs of Go and the JVM (ZGC and Shenandoah) are not generational and employ techniques such as pointer coloring and store/load barriers by instrumenting all object read/write operations instead of using virtual memory protection (which tends to have a non-indifferent performance penalty), and because they rely heavily on atomic operations to maintain heap consistency the stop-the-world phase is much shorter and only required to update the internal GC metadata.
The result is that instead of 99th percentile pauses of 10+ seconds that we see with QPX or other allocation-heavy applications, these newer GCs show 99th percentile pauses of &lt; 10ms, and perhaps medians going from ~500ms to 2ms (YMMV).»</p>

<p>«Here&rsquo;s a pretty good description of the difference between the two new JVM collectors and how they compare to the older ones: <a href="https://www.youtube.com/watch?v=WU_mqNBEacw.»">https://www.youtube.com/watch?v=WU_mqNBEacw.»</a></p>

<p>Martin Cracauer:</p>

<p>«No, it&rsquo;s as possible as in other languages. Some people don&rsquo;t want to pay the overall performance penalty for concurrent GC (as in total CPU time/energy spent for any given piece of work).»</p>

<p>«This particularly applies to applications that are query-based, and hence want to be as fast as possible in the non-GC part, and can GC between queries.  ITA&rsquo;s QPX is an example (although they do desire concurrent GC for better monitoring in the production environment).»</p>

<p>«Parallel GC is no problem and implemented.»</p>

<p>Pascal Costanza:</p>

<p>«Which CL implementations have a parallel GC?»</p>

<p>Jeff Caldwell:</p>

<p>«From Franz&rsquo;s doc on Allegro CL: <a href="https://franz.com/support/documentation/10.0/doc/gc.htm#multi-threading-2»">https://franz.com/support/documentation/10.0/doc/gc.htm#multi-threading-2»</a></p>

<p>Martin Cracauer:</p>

<p>«Clasp (via Boehm GC and MPS).»</p>

<p>«I thought SBCL was there, but I just checked, not yet.  I think Google
is pushing for a parallel GC instead, because of response times to
their production monitoring.»</p>

<p>«Another untapped source of performance is userfaultfd(2) in the Linux kernel.  It allows those GCs that implement a write barrier using page protections SIGSEGV to use the faster userfaultfd interface instead (as opposed to those using a bitmap).  This won&rsquo;t help concurrent GC, but parallel GC would benefit even more than single-thread GC because it uses faster system calls. Proof of concept is here: <a href="https://www.cons.org/cracauer/cracauer-userfaultfd.html»">https://www.cons.org/cracauer/cracauer-userfaultfd.html»</a></p>

<p>and:</p>

<blockquote>
<p>Don&rsquo;t the latest incarnations of ECL use the Bohem GC?</p>
</blockquote>

<p>Daniel Kochmański:</p>

<p>«They do, we plan to resurrect the homegrown gc as an alternative though.»</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Refreshing Server-Side Props</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">14 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Next allows you to do server-side data-fetching, but what happens when that data needs to change on the client? This brief tutorial shows how to re-fetch the props without doing a full server reload.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">GitHub Dark Mode is Too Dark</h1>
                            <h2 class="article__feed"><a target="_blank" href="">blog.karenying.com</a> <span class="article__date">12 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        If you hate it too this is why. Using color theory to show why GitHub dark mode is disappointing
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Desarrollando aplicaciones móviles y PWA con Vue.js">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Desarrollando aplicaciones móviles y PWA con Vue.js</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">12 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Para este episodio vuelve a acompañarnos en el podcast la diseñadora y desarrolladora web Valentina Rubane. Ella trabaja junto a Andros en Sapps, el estudio de desarrollo de aplicaciones móviles y PWA en Valencia. En este episodio hablamos de los motivos por los que Vue.js es la elección de Sapps para estudio para trabajar el desarrollo de sus aplicaciones.</p>



<p>Valentina y Andros nos cuentan entre otras muchas cosas:</p>



<ul><li>Evolución de Vue.js</li><li>Novedades de Vue.</li><li>Herramientas de desarrollo con Vue.js</li><li>Vue.cli y trabajo con componentes y librerías CSS.</li><li>Aprendizaje y metodologías de uso.</li><li>Trabajos y experiencias con proyectos de clientes. </li></ul>



<p>Sapps es el estudio surgido de Pixel Mouse y está especializados en desarrollo de aplicaciones web, móviles y también PWA. En la actualidad lo forma un grupo de varias personas con experiencia en las diferentes capas de un proyecto en internet. </p>




<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://d33wubrfki0l68.cloudfront.net/c04dc381e533899e0a59fd28059b515e6365e0fa/52d0d/images/cypress-ui.png" alt="Cypress React Testing, Accessibility Tooling, Offline Websites, and Chaos Engineering! 👱‍♀️  — Pony Foo Weekly">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cypress React Testing, Accessibility Tooling, Offline Websites, and Chaos Engineering! 👱‍♀️  — Pony Foo Weekly</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Pony Foo Weekly</a> <span class="article__date">10 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="f-core"><div class="md-markdown"><p>We&#x2019;re glad you could make it this week! </p> <p>With your help, we can make Pony Foo Weekly <em>even more</em> awesome: <a href="https://ponyfoo.com/weekly/submissions?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-191" target="_blank" rel="noopener noreferrer">send tips about cool resources</a>.</p> </div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://blog.sapegin.me/all/react-testing-4-cypress/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-191" style="color:#1bc211;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Modern React testing: Cypress and Cypress Testing Library</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/tutorial" style="color:#5aa9bc;background-color:#333" class="wy-link-tag">Tutorial</a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>You&#x2019;ll learn how to test React apps end-to-end with Cypress and Cypres Testing Library, how to mock network requests with Mock Service Worker, and how to apply testing best practices to write integration tests, that are good and resilient to changes.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/iamsapegin?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-191" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Artem Sapegin</p> </a></div></td><td class="wy-td wy-link-cell-image"><a href="https://blog.sapegin.me/all/react-testing-4-cypress/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-191" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://d33wubrfki0l68.cloudfront.net/c04dc381e533899e0a59fd28059b515e6365e0fa/52d0d/images/cypress-ui.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://blog.sapegin.me/all/accessibility-testing/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-191" style="color:#1bc211;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>The most useful accessibility testing tools and techniques</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/best-practices" style="color:#900070;background-color:#ffe270" class="wy-link-tag">Best Practices</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Shipping accessible features is as important for a frontend developer as shipping features without bugs, learn about tools and techniques that will help you achieve that.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/iamsapegin?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-191" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Artem Sapegin</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://codersociety.com/blog/articles/chaos-engineering?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-191" style="color:#1bc211;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>How to Effectively Implement Chaos Engineering</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/article" style="color:#e4f9e3;background-color:#1bc211" class="wy-link-tag">Article</a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Chaos engineering is attracting more and more attention. But why should you break something on purpose? In this article, you learn about Chaos Engineering and how to get started using it.</p> </div></div></td><td class="wy-td wy-link-cell-image"><a href="https://codersociety.com/blog/articles/chaos-engineering?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-191" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://res.cloudinary.com/codersociety/image/fetch/w_1200,h_630,c_fill/https://cdn.codersociety.com/uploads/chaos-engineering.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-primary"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://srv.buysellads.com/ads/long/x/TFGU7IBXTTTTTTHFLS6MOTTTTTTVE6OQZATTTTTTCDCAOUYTTTTTTBDW5JYFC5JGHRSU5R75K7NC4RDC2HNCPZIQ2AUUTAIGKJBNCR3GK2UNAYSQKM7C57QGFRBUVSPX52UUPAIDKWOUTYZL5JUCPAJC5MBCBUS2KMLCLRZ2FMLNBYZQ2EIFPRD2ZRJN4SZEKHWN5SJRKQBULASH2JNC47DIHM7ULSI62HJN4RDHHMYCOSI7HMICOS72KMNN4BZKZRYIVZQLCT7DTZZD2RUCCBZH5QINPZZE5QUNBSSW2HUNAQIM5JNMOYSG27BCPSIWFMWNAZZ35QBCLYSKKWNUCADG277NOAII23WUTZQJCVNI4K3C5MBCBUSWKM7CBGZWKMJNESIQK2ENYZZE2RUFLZZC2RUE?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-191" style="color:#1bc211;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Never open Excel again with the help of Flatfile Concierge</p> </a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Think of the last time you imported a spreadsheet. Did it work the first time? Nearly everyone has dealt with formatting CSV or Excel files so that the data can be imported into an application. It&#x2019;s a pain! Enter Flatfile Concierge. Solve data onboarding with collaborative workspaces, intuitive data validation, and best of all, #nocode.</p> <p><a href="https://srv.buysellads.com/ads/long/x/TFGU7IBXTTTTTTHFLS6MOTTTTTTVE6OQZATTTTTTCDCAOUYTTTTTTBDW5JYFC5JGHRSU5R75K7NC4RDC2HNCPZIQ2AUUTAIGKJBNCR3GK2UNAYSQKM7C57QGFRBUVSPX52UUPAIDKWOUTYZL5JUCPAJC5MBCBUS2KMLCLRZ2FMLNBYZQ2EIFPRD2ZRJN4SZEKHWN5SJRKQBULASH2JNC47DIHM7ULSI62HJN4RDHHMYCOSI7HMICOS72KMNN4BZKZRYIVZQLCT7DTZZD2RUCCBZH5QINPZZE5QUNBSSW2HUNAQIM5JNMOYSG27BCPSIWFMWNAZZ35QBCLYSKKWNUCADG277NOAII23WUTZQJCVNI4K3C5MBCBUSWKM7CBGZWKMJNESIQK2ENYZZE2RUFLZZC2RUE?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-191" target="_blank" rel="noopener noreferrer">Get beta access</a></p> </div></div><div class="wy-link-source-section"><a href="https://ponyfoo.com/weekly/links/tagged/sponsored" class="wy-link-tag wy-link-sponsor">Sponsored</a></div></td><td class="wy-td wy-link-cell-image"><a href="https://srv.buysellads.com/ads/long/x/TFGU7IBXTTTTTTHFLS6MOTTTTTTVE6OQZATTTTTTCDCAOUYTTTTTTBDW5JYFC5JGHRSU5R75K7NC4RDC2HNCPZIQ2AUUTAIGKJBNCR3GK2UNAYSQKM7C57QGFRBUVSPX52UUPAIDKWOUTYZL5JUCPAJC5MBCBUS2KMLCLRZ2FMLNBYZQ2EIFPRD2ZRJN4SZEKHWN5SJRKQBULASH2JNC47DIHM7ULSI62HJN4RDHHMYCOSI7HMICOS72KMNN4BZKZRYIVZQLCT7DTZZD2RUCCBZH5QINPZZE5QUNBSSW2HUNAQIM5JNMOYSG27BCPSIWFMWNAZZ35QBCLYSKKWNUCADG277NOAII23WUTZQJCVNI4K3C5MBCBUSWKM7CBGZWKMJNESIQK2ENYZZE2RUFLZZC2RUE?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-191" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://images.ponyfoo.com/uploads/Pony-foo-300x300@2x-b05ccddbc4aa45fa850c71ba5e032584.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://itnext.io/how-to-make-your-website-work-offline-b5be47b92adc?source=friends_link&#38;sk=e7ac5aa87e5f4cbba6ad3b1a2196af99&#38;utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-191" style="color:#1bc211;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>How To Make Your Website Work Offline</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/tutorial" style="color:#5aa9bc;background-color:#333" class="wy-link-tag">Tutorial</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>How to dramatically improve the performance and user experience of your website by making it work offline in one easy step</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/dannymoerkerke?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-191" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Danny Moerkerke</p> </a></div></td></tr></table></td></tr></table></div></div><style>html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;position:relative;vertical-align:baseline}sup{top:-.5em}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto;resize:vertical;min-height:280px;max-height:900px}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item;margin:-10px -20px;padding:10px;background-color:#f6f6f6;cursor:pointer;border-bottom:2px solid #ddd}[hidden],template{display:none}body,body:after,body:before,html,html:after,html:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*,:after,:before{-webkit-box-sizing:inherit;-moz-box-sizing:inherit;box-sizing:inherit}@-moz-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-webkit-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-o-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-moz-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@-webkit-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@-o-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}.f-core{font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}.f-mono{font-family:Consolas,Menlo,Monaco,'Lucida Console','Liberation Mono','DejaVu Sans Mono','Bitstream Vera Sans Mono','Courier New',monospace,serif}.ly-custom-heading .f-heading,.ly-custom-heading h1,.ly-custom-heading h2,.ly-custom-heading h3,.ly-custom-heading h4,.ly-custom-heading h5,.ly-custom-heading h6,.ly-lean .f-heading,.ly-lean h1,.ly-lean h2,.ly-lean h3,.ly-lean h4,.ly-lean h5,.ly-lean h6{font-family:Neuton,'Hoefler Text',Palatino,Baskerville,Georgia,'Times New Roman',serif}.ly-custom-subheading .f-subheading,.ly-lean .f-subheading{font-family:Merriweather,Georgia,serif}body{margin:0;font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif;background:#fcfcfc;color:#333}img{max-width:100%;border:none}.md-markdown figure:not(.twitter-tweet-figure){background-color:#f6f6f6}.md-markdown figure:not(.twitter-tweet-figure)>a{display:block}.md-markdown figure:not(.twitter-tweet-figure)>a>img,.md-markdown figure:not(.twitter-tweet-figure)>img{display:block;margin-left:auto;margin-right:auto}.md-markdown figcaption{padding:10px;font-style:italic;font-size:14px;background:-webkit-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-moz-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-o-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-ms-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:linear-gradient(to right,#fff9e2 33%,#fcf9ee 100%);color:#555}.md-markdown .figure-has-loaded{background:-webkit-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-moz-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-o-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-ms-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:linear-gradient(to bottom,rgba(255,255,255,0) 0,#fcf9ee 100%)}b,em,font-style italic,font-weight bold,i,ins,strong{text-decoration:none}del{text-decoration:line-through}sub,sup{bottom:0;line-height:18px}button,input{overflow:visible;border-radius:0}button{border:none;padding:6px 8px;font-size:1.2em;background:0 0}button[disabled]{color:#cbccbc!important}input,select,textarea{display:block;width:100%;padding:10px 8px;line-height:18px;border:none;font:inherit}select{height:38px}ol,ul{padding:0;margin:0;list-style-position:inside}li>ol,li>ul{margin-left:20px}hr{border:none;border-top:5px solid rgba(0,0,0,.05);margin:20px 0}kbd{display:inline-block;border:1px solid #ccc;margin:0 .1em;padding:.1em .6em;line-height:1.4;font-size:11px;background-color:#f7f7f7;-webkit-box-shadow:0 1px 0 #bbb,0 0 0 2px #fff inset;box-shadow:0 1px 0 #bbb,0 0 0 2px #fff inset;border-radius:3px;color:#333;text-shadow:0 1px 0 #fff;white-space:nowrap}iframe{display:inline-block;border:none;max-width:100%}summary:hover{opacity:.8}details{padding:10px 20px 20px;border-bottom:2px dashed #ddd}details[open] summary{margin-bottom:20px}blockquote{border:none;margin:0!important}ol,p,ul{line-height:35px}p{margin:35px 0}@media only screen and (min-width:768px){ol,p,ul{line-height:30px}}a,button,input[type=submit]{cursor:pointer;text-decoration:none}.lk-link{color:#e92c6c;border-bottom:1px solid transparent;background-color:rgba(255,255,255,.04)}.lk-link .md-code-inline{position:relative}.lk-link .md-code-inline:only-child{display:inline-block;line-height:17px}.lk-link .md-code-inline:before{content:'';position:absolute;background-color:#f1e05a;top:0;left:0;right:0;bottom:0;opacity:.04}.lk-link:visited{background-color:rgba(233,44,108,.04)}.lk-link:visited .md-code-inline:before{background-color:#e92c6c}.lk-link:hover{border-bottom:1px solid #e92c6c}.lk-rainbows{position:relative;color:#333;margin-bottom:5px}.lk-rainbows:hover:before{position:absolute;content:'';left:0;right:0;bottom:-8px;height:3px;opacity:.8;-webkit-transition:.1s ease-in-out;-moz-transition:.1s ease-in-out;-o-transition:.1s ease-in-out;-ms-transition:all .1s ease-in-out;transition:.1s ease-in-out;-webkit-animation:.5s infinite bg-rainbow;-moz-animation:.5s infinite bg-rainbow;-o-animation:.5s infinite bg-rainbow;-ms-animation:bg-rainbow .5s infinite;animation:.5s infinite bg-rainbow}.lk-icon{color:#333}.lk-icon:hover{color:#e92c6c}.lk-visitor{color:#333}.lk-visitor:after{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-left:5px}.lk-visitor.lk-visitor-large:after{font-size:1em}.lk-visitor:hover:after{color:#333;border-bottom-style:solid}.lk-visitor:visited:after{color:#7d5cff}.lk-visitor-inside{color:#333}.lk-visitor-inside .lk-visitor-target:before{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-right:5px}.lk-visitor-inside.lk-visitor-large .lk-visitor-target:before{font-size:1em}.lk-visitor-inside:hover .lk-visitor-target:before{color:#333;border-bottom-style:solid}.lk-visitor-inside:visited .lk-visitor-target:before{color:#7d5cff}.lk-visitor-before{color:#333}.lk-visitor-before:before{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-right:5px}.lk-visitor-before.lk-visitor-large:before{font-size:1em}.lk-visitor-before:hover:before{color:#333;border-bottom-style:solid}.lk-visitor-before:visited:before{color:#7d5cff}.lk-visitor-before-no-underline:before{border-bottom-width:0}.lk-link-to-green{color:#cbccbc}.lk-link-to-green:visited,.lk-link-to-green:visited:before{color:#1bc211;background-color:#1bc211}.lk-link-to-green:active{outline-color:#1bc211}.lk-link-to-green:hover,.lk-link-to-green:hover:before{color:#8be186;border-bottom-color:#1bc211}.lk-green .lk-link,a.lk-green{color:#1bc211}.lk-green .lk-link:visited,a.lk-green:visited{background-color:rgba(27,194,17,.04)}.lk-green .lk-link:visited .md-code-inline:before,a.lk-green:visited .md-code-inline:before{background-color:#1bc211}.lk-green .lk-link:active,a.lk-green:active{outline-color:#1bc211}.lk-green .lk-link:hover,a.lk-green:hover{border-bottom-color:#1bc211}.lk-green.lk-icon:hover{color:#1bc211}.lk-pink-light .lk-link,a.lk-pink-light{color:#ea6c93}.lk-pink-light .lk-link:visited,a.lk-pink-light:visited{background-color:rgba(234,108,147,.04)}.lk-pink-light .lk-link:visited .md-code-inline:before,a.lk-pink-light:visited .md-code-inline:before{background-color:#ea6c93}.lk-pink-light .lk-link:active,a.lk-pink-light:active{outline-color:#ea6c93}.lk-pink-light .lk-link:hover,a.lk-pink-light:hover{border-bottom-color:#ea6c93}.lk-pink-light.lk-icon:hover{color:#ea6c93}.lk-black .lk-link,a.lk-black{color:#333}.lk-black .lk-link:visited,a.lk-black:visited{background-color:rgba(51,51,51,.04)}.lk-black .lk-link:visited .md-code-inline:before,a.lk-black:visited .md-code-inline:before{background-color:#333}.lk-black .lk-link:active,a.lk-black:active{outline-color:#333}.lk-black .lk-link:hover,a.lk-black:hover{border-bottom-color:#333}.lk-black.lk-icon:hover{color:#333}.lk-gray .lk-link,a.lk-gray{color:#999}.lk-gray .lk-link:visited,a.lk-gray:visited{background-color:rgba(153,153,153,.04)}.lk-gray .lk-link:visited .md-code-inline:before,a.lk-gray:visited .md-code-inline:before{background-color:#999}.lk-gray .lk-link:active,a.lk-gray:active{outline-color:#999}.lk-gray .lk-link:hover,a.lk-gray:hover{border-bottom-color:#999}.lk-gray.lk-icon:hover{color:#999}.lk-white .lk-link,a.lk-white{color:#fcfcfc}.lk-white .lk-link:visited,a.lk-white:visited{background-color:rgba(252,252,252,.04)}.lk-white .lk-link:visited .md-code-inline:before,a.lk-white:visited .md-code-inline:before{background-color:#fcfcfc}.lk-white .lk-link:active,a.lk-white:active{outline-color:#fcfcfc}.lk-white .lk-link:hover,a.lk-white:hover{border-bottom-color:#fcfcfc}.lk-white.lk-icon:hover{color:#fcfcfc}.lk-orange .lk-link,a.lk-orange{color:#f3720d}.lk-orange .lk-link:visited,a.lk-orange:visited{background-color:rgba(243,114,13,.04)}.lk-orange .lk-link:visited .md-code-inline:before,a.lk-orange:visited .md-code-inline:before{background-color:#f3720d}.lk-orange .lk-link:active,a.lk-orange:active{outline-color:#f3720d}.lk-orange .lk-link:hover,a.lk-orange:hover{border-bottom-color:#f3720d}.lk-orange.lk-icon:hover{color:#f3720d}.lk-lilly .lk-link,a.lk-lilly{color:#7d5cff}.lk-lilly .lk-link:visited,a.lk-lilly:visited{background-color:rgba(125,92,255,.04)}.lk-lilly .lk-link:visited .md-code-inline:before,a.lk-lilly:visited .md-code-inline:before{background-color:#7d5cff}.lk-lilly .lk-link:active,a.lk-lilly:active{outline-color:#7d5cff}.lk-lilly .lk-link:hover,a.lk-lilly:hover{border-bottom-color:#7d5cff}.lk-lilly.lk-icon:hover{color:#7d5cff}.lk-blue .lk-link,a.lk-blue{color:#1a4d7f}.lk-blue .lk-link:visited,a.lk-blue:visited{background-color:rgba(26,77,127,.04)}.lk-blue .lk-link:visited .md-code-inline:before,a.lk-blue:visited .md-code-inline:before{background-color:#1a4d7f}.lk-blue .lk-link:active,a.lk-blue:active{outline-color:#1a4d7f}.lk-blue .lk-link:hover,a.lk-blue:hover{border-bottom-color:#1a4d7f}.lk-blue.lk-icon:hover{color:#1a4d7f}.lk-inherited .lk-link,a.lk-inherited{color:inherit}.lk-inherited .lk-link:active,a.lk-inherited:active{outline-color:inherit}.lk-inherited .lk-link:hover,a.lk-inherited:hover{border-bottom-color:inherit}.lk-inherited.lk-icon:hover{color:inherit}.lk-twitter .lk-link,a.lk-twitter{color:#55acee}.lk-twitter .lk-link:visited,a.lk-twitter:visited{background-color:rgba(85,172,238,.04)}.lk-twitter .lk-link:visited .md-code-inline:before,a.lk-twitter:visited .md-code-inline:before{background-color:#55acee}.lk-twitter .lk-link:active,a.lk-twitter:active{outline-color:#55acee}.lk-twitter .lk-link:hover,a.lk-twitter:hover{border-bottom-color:#55acee}.lk-twitter.lk-icon:hover{color:#55acee}.lk-facebook .lk-link,a.lk-facebook{color:#3b5998}.lk-facebook .lk-link:visited,a.lk-facebook:visited{background-color:rgba(59,89,152,.04)}.lk-facebook .lk-link:visited .md-code-inline:before,a.lk-facebook:visited .md-code-inline:before{background-color:#3b5998}.lk-facebook .lk-link:active,a.lk-facebook:active{outline-color:#3b5998}.lk-facebook .lk-link:hover,a.lk-facebook:hover{border-bottom-color:#3b5998}.lk-facebook.lk-icon:hover{color:#3b5998}.lk-clean{background-color:transparent}.lk-chrome:hover{color:#4989f4}.lk-teal .lk-link,a.lk-teal{color:#00a19c}.lk-teal .lk-link:visited,a.lk-teal:visited{background-color:rgba(0,161,156,.04)}.lk-teal .lk-link:visited .md-code-inline:before,a.lk-teal:visited .md-code-inline:before{background-color:#00a19c}.lk-teal .lk-link:active,a.lk-teal:active{outline-color:#00a19c}.lk-teal .lk-link:hover,a.lk-teal:hover{border-bottom-color:#00a19c}.lk-teal.lk-icon:hover{color:#00a19c}table{width:100%;border-spacing:0;border-collapse:separate}td,th{padding:8px}@media only screen and (max-width:950px){.table-responsive{display:block}.table-responsive>thead{display:none}.table-responsive>tbody,.table-responsive>tfoot{display:block}.table-responsive>tbody>tr,.table-responsive>tfoot>tr{display:block;background-color:rgba(203,204,188,.1);margin-bottom:30px}.table-responsive>tbody>tr:nth-child(even),.table-responsive>tfoot>tr:nth-child(even){background-color:rgba(203,204,188,.15)}.table-responsive>tbody>tr:last-child,.table-responsive>tfoot>tr:last-child{margin-bottom:0}.table-responsive>tbody>tr>td,.table-responsive>tfoot>tr>td{display:block;text-align:left}.table-responsive>tbody>tr>td:before,.table-responsive>tfoot>tr>td:before{display:block;content:attr(data-label);color:#555;font-size:13px;margin:0 0 5px}.table-responsive .table-responsive-hide{display:none}}.c-oreilly-teal{color:#00a19c}.c-yellow-highlight{color:#ffe270}.c-dark-orange{color:#f3720d}.c-pink{color:#e92c6c}.c-purple{color:#900070}.c-blue{color:#1a4d7f}.c-dark-turquoise{color:#1686a2}.c-dark-green{color:#1bc211}.c-white{color:#fcfcfc}.c-gray{color:#b7b7b7}.c-lilly{color:#7d5cff}.c-teal{color:#3aca96}.c-bg-oreilly-teal{background-color:#00a19c}.c-bg-yellow-highlight{background-color:#ffe270}.c-bg-dark-orange{background-color:#f3720d}.c-bg-pink{background-color:#e92c6c}.c-bg-purple{background-color:#900070}.c-bg-blue{background-color:#1a4d7f}.c-bg-dark-turquoise{background-color:#1686a2}.c-bg-dark-green{background-color:#1bc211}.c-bg-white{background-color:#fcfcfc}.c-bg-gray{background-color:#b7b7b7}.c-bg-lilly{background-color:#7d5cff}.c-bg-teal{background-color:#3aca96}.tj-emoji{width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em}.dc-header{margin-bottom:60px}.dc-heading{text-align:center;font-size:4em;padding:0 10px;margin-top:0;margin-bottom:10px}.dc-role{line-height:26px;padding:0 20px;margin-top:10px;text-align:center;font-style:italic;color:#cbccbc}.dc-colored{background:#f6f6f6;border-top:9px solid rgba(125,92,255,.5)}.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:800px}.md-markdown blockquote:not(.twitter-tweet){margin:0;padding:20px 0;border:none;border-top:5px solid rgba(0,0,0,.05);border-bottom:5px solid rgba(0,0,0,.05)}.md-markdown blockquote:not(.twitter-tweet) h1,.md-markdown blockquote:not(.twitter-tweet) h2,.md-markdown blockquote:not(.twitter-tweet) h3,.md-markdown blockquote:not(.twitter-tweet) h4,.md-markdown blockquote:not(.twitter-tweet) h5,.md-markdown blockquote:not(.twitter-tweet) h6{margin:-20px 0;padding:20px 0}.md-markdown blockquote:not(.twitter-tweet) .md-code-block{margin:0}.md-markdown blockquote:not(.twitter-tweet) .md-code-block:last-child{margin-bottom:-20px}.md-markdown img:first-child{margin-top:0}.md-markdown img:last-child{margin-bottom:0}.md-markdown p:first-child{margin-top:0}.md-markdown p:last-child{margin-bottom:0}.md-markdown .md-code-block+ol,.md-markdown .md-code-block+ul,.md-markdown ol+.md-code-block,.md-markdown ul+.md-code-block{margin-top:35px}.md-markdown a:not(.md-heading){color:#e92c6c;border-bottom:1px solid transparent;background-color:rgba(255,255,255,.04)}.md-markdown a:not(.md-heading) .md-code-inline{position:relative}.md-markdown a:not(.md-heading) .md-code-inline:only-child{display:inline-block;line-height:17px}.md-markdown a:not(.md-heading) .md-code-inline:before{content:'';position:absolute;background-color:#f1e05a;top:0;left:0;right:0;bottom:0;opacity:.04}.md-markdown a:not(.md-heading):visited{background-color:rgba(233,44,108,.04)}.md-markdown a:not(.md-heading):visited .md-code-inline:before{background-color:#e92c6c}.md-markdown a:not(.md-heading):hover{border-bottom:1px solid #e92c6c}.md-markdown thead{background-color:#e0e0e0}.md-markdown tbody{background-color:#f6f6f6}.md-markdown tbody tr:nth-child(even){background-color:#f9f9f9}.md-markdown h1,.md-markdown h2,.md-markdown h3,.md-markdown h4,.md-markdown h5,.md-markdown h6{padding:10px 0}.md-markdown h1:first-child,.md-markdown h2:first-child,.md-markdown h3:first-child,.md-markdown h4:first-child,.md-markdown h5:first-child,.md-markdown h6:first-child{margin-top:0}.md-markdown h1:last-child,.md-markdown h2:last-child,.md-markdown h3:last-child,.md-markdown h4:last-child,.md-markdown h5:last-child,.md-markdown h6:last-child{margin-bottom:0}.md-markdown iframe{display:block;margin:35px auto}.md-markdown iframe:first-child{margin-top:0}.md-markdown iframe:last-child{margin-bottom:0}.md-markdown li>p:only-child{display:inline}.md-markdown ul{list-style-type:none}.md-markdown ul>li:before{content:'◯';margin-right:5px}.md-heading{color:inherit}.md-markdown-inline{display:inline}.md-markdown-inline p{display:inline;line-height:initial}.md-code-block,.ocha-highlighted{margin:0 -20px}.ocha-code-block{padding:18px 50px}.md-markdown:not(.mm-content-html) .md-code-block+blockquote{max-width:inherit!important;margin:0 -20px;padding-left:20px;padding-right:20px}.md-code-block .md-code{display:block}.md-markdown-summary p{margin:10px 0}@media only screen and (min-width:768px){.md-markdown h1,.md-markdown h2,.md-markdown h3,.md-markdown h4,.md-markdown h5,.md-markdown h6{margin-left:-40px;margin-right:-40px;padding:10px 40px}.md-code-block,.ocha-highlighted{margin:0 -40px}.md-markdown:not(.mm-content-html) .md-code-block+blockquote{margin:0 -40px;padding-left:40px;padding-right:40px}}@media only screen and (min-width:1300px){.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:900px}}@media only screen and (min-width:1400px){.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:1000px}.md-code-block,.md-markdown:not(.mm-content-html) .md-code-block+blockquote,.ocha-highlighted{margin:0 -400px 0 -40px}}.md-markdown-large blockquote,.md-markdown-large code,.md-markdown-large ol,.md-markdown-large p,.md-markdown-large table,.md-markdown-large ul{max-width:inherit}.md-footnotes{margin-top:80px;padding:20px 0;border-top:1px dashed #cbccbc}.md-footnote{margin:0;padding:8px 0;font-size:14px;display:-webkit-box;display:-moz-box;display:-webkit-flex;display:-ms-flexbox;display:box;display:flex;-webkit-box-align:center;-moz-box-align:center;-o-box-align:center;-ms-flex-align:center;-webkit-align-items:center;align-items:center}.md-footnote p{line-height:16px}.md-footnote-anchor{padding:2px 6px;margin-right:10px;text-align:center;font-weight:700;color:#e92c6c}.ly-custom-subheading .md-footnote-anchor,.ly-lean .md-footnote-anchor{font-family:Merriweather,Georgia,serif}.md-markdown a.md-footnote-anchor{border:1px solid #e92c6c}.md-markdown a.md-footnote-anchor:hover{background-color:#e92c6c;color:#fcfcfc}.md-footnote-ref{margin-left:1px;margin-right:3px}.md-markdown a.md-footnote-ref{border-bottom:1px dotted}.md-code-block,.md-code-inline{-webkit-text-size-adjust:none;-ms-text-size-adjust:none;text-size-adjust:none;background:#fcfcf5;color:#4d4d4c}.md-code-block{line-height:24px}.md-code{padding:8px 10px}.md-code-inline{padding:0 6px}a .md-code{color:inherit}.md-code-comment{color:#8e908c}.md-code-attribute,.md-code-built_in,.md-code-constant,.md-code-literal,.md-code-number,.md-code-params,.md-code-pragma,.md-code-preprocessor,.md-code-regexp,.md-code-tag,.md-code-variable,.md-lang-css .md-code-class,.md-lang-css .md-code-id,.md-lang-css .md-code-pseudo,.md-lang-html .md-code-doctype,.md-lang-ruby .md-code-constant,.md-lang-xml .md-code-doctype,.md-lang-xml .md-code-pi,.md-lang-xml .md-code-tag .md-code-title,color #c82829{color:#f5871f}.md-lang-css .md-code-rule .md-code-attribute,.md-lang-ruby .md-code-class .md-code-title{color:#eab700}.md-code-header,.md-code-inheritance,.md-code-name,.md-code-string,.md-code-value,.md-lang-ruby .md-code-symbol,.md-lang-xml .md-code-cdata{color:#718c00}.md-code-title,.md-lang-css .md-code-hexcolor{color:#3e999f}.md-code-function,.md-lang-coffeescript .md-code-title,.md-lang-javascript .md-code-title,.md-lang-perl .md-code-sub,.md-lang-python .md-code-decorator,.md-lang-python .md-code-title,.md-lang-ruby .md-code-function .md-code-title,.md-lang-ruby .md-code-title .md-code-keyword{color:#4271ae}.md-code-keyword,.md-lang-javascript .md-code-function{color:#8959a8}.md-lang-coffeescript .md-lang-javascript,.md-lang-javascript .md-lang-xml,.md-lang-tex .md-code-formula,.md-lang-xml .md-code-cdata,.md-lang-xml .md-lang-css,.md-lang-xml .md-lang-javascript,.md-lang-xml .vbscript{opacity:.5}.md-code-deletion{background-color:rgba(244,0,30,.05);color:#f4001e}.md-code-addition{background-color:rgba(27,194,17,.05);color:#1bc211}.md-mark{background-color:rgba(255,226,112,.5);color:inherit}.md-mark span{color:inherit}.md-heading-hover{cursor:pointer;background-color:rgba(22,134,162,.1)}.mde-text-left{text-align:left}.mde-text-center{text-align:center}.mde-text-right{text-align:right}.mde-size-small{font-size:12px}.mde-size-small,.mde-size-small p{line-height:12px}.mde-size-large{font-size:36px}.mde-size-large,.mde-size-large p{line-height:36px}.mde-size-giant{font-size:72px}.mde-size-giant,.mde-size-giant p{line-height:72px}.mde-clearfix:after{content:' ';display:block;visibility:hidden;clear:both;font-size:0;height:0}.mde-quote{margin:0;padding:20px 0;border:none;border-top:5px solid rgba(0,0,0,.05);border-bottom:5px solid rgba(0,0,0,.05)}.mde-core{font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}.mde-mono{font-family:Consolas,Menlo,Monaco,'Lucida Console','Liberation Mono','DejaVu Sans Mono','Bitstream Vera Sans Mono','Courier New',monospace,serif}.ly-custom-heading .mde-heading,.ly-lean .mde-heading{font-family:Neuton,'Hoefler Text',Palatino,Baskerville,Georgia,'Times New Roman',serif}.ly-custom-subheading .mde-subheading,.ly-lean .mde-subheading{font-family:Merriweather,Georgia,serif}.mde-pad-0{padding:0}.mde-pad-5{padding:5px}.mde-pad-10{padding:10px}.mde-pad-15{padding:15px}.mde-pad-20{padding:20px}.mde-pad-25{padding:25px}.mde-pad-30{padding:30px}.mde-pad-50{padding:50px}.mde-mar-0{margin:0}.mde-mar-5{margin:5px}.mde-mar-10{margin:10px}.mde-mar-15{margin:15px}.mde-mar-20{margin:20px}.mde-mar-25{margin:25px}.mde-mar-30{margin:30px}.mde-mar-50{margin:50px}@media only screen and (min-width:900px){.mde-left{float:left}.mde-right{float:right}.mde-inline{display:inline-block;vertical-align:top}.mde-20{max-width:20%}.mde-25{max-width:25%}.mde-33{max-width:33.3333333333%}.mde-50{max-width:50%}.mde-66{max-width:66.6666666666%}.mde-75{max-width:75%}}.twitter-tweet-figure{background:0 0;padding:0}.twitter-tweet-figure:before{content:none}.twitter-tweet-figure .twitter-tweet{margin:0 auto}blockquote.twitter-tweet{overflow:hidden;color:#1c2022;background-color:#fff;border:1px solid #e1e8ed;border-radius:4px;width:500px;max-width:100%;min-width:220px;padding:1.25rem 1.25rem .725rem}blockquote.twitter-tweet:before{content:none}blockquote.twitter-tweet p{white-space:pre-wrap;font:16px/1.4 Helvetica,Roboto,'Segoe UI',Calibri,'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}blockquote.twitter-tweet a,blockquote.twitter-tweet a:visited{color:#2b7bb9}.wy-container{margin:0 auto;padding:20px 0;max-width:800px}.wy-container .md-markdown p{line-height:22px;margin:10px 0}.wy-container .md-markdown p:first-child{margin-top:0}.wy-container .md-markdown p:last-child{margin-bottom:0}.wy-container .md-markdown blockquote:not(.twitter-tweet){padding:10px 0}.wy-container .md-code-block{margin:0;padding:10px;white-space:pre-wrap}.wy-table{width:100%;padding:0}.wy-td{padding:0}.wy-section-link,.wy-section-markdown,.wy-section-poll,.wy-section-summary{padding-top:25px}.wy-section-thanks{margin-top:25px;padding:10px;font-size:15px;background-color:#f2fcf2}.wy-header-text,.wy-issue{display:inline-block;margin:10px 0;line-height:24px}.wy-issue{float:right;font-size:12px}.wy-issue-content{display:block;padding:0 5px;background-color:#fcfcfc}.wy-section-header{padding-top:40px}.wy-section-header h1,.wy-section-header h2,.wy-section-header h3,.wy-section-header h4,.wy-section-header h5,.wy-section-header h6{margin:0}.wy-section-header p{line-height:inherit}.wy-header-td{padding:0}.wy-header-content{margin:0 10px}.wy-header-text{color:#fcfcfc;text-shadow:1px 1px 0 #1a4d7f;font-weight:700;font-size:24px}.wy-content{padding-bottom:25px}.wy-link-addendum,.wy-link-tag,.wy-link-title{display:inline-block;vertical-align:bottom;margin-bottom:10px}.wy-link-title{border-bottom:1px solid;font-size:20px;margin-right:10px}.wy-link-tag{background-color:#1a4d7f;color:#fcfcfc;text-transform:uppercase;font-size:13px;margin-right:5px;padding:2px 4px}.wy-link-tag:last-child{margin-right:0}.wy-link-addendum{color:#999;margin-left:5px}.wy-link-addendum:hover{border-bottom-color:transparent}.wy-link-title-section{position:relative}.wy-link-stats{position:absolute;right:0;background-color:#3aca96;color:#fcfcfc;border-bottom:1px solid #299a71}.wy-link-stats-logo{background-color:rgba(0,0,0,.1);color:#299a71}.wy-link-stat{margin:3px}.wy-link-description{font-size:14px;color:#666}.wy-link-source-section{margin-top:10px}.wy-link-source{margin-right:10px;margin-bottom:10px;display:inline-block;vertical-align:middle;color:#55acee}.wy-link-source-plain{color:#333}.wy-link-source.wy-link-source-plain a{color:#55acee}.wy-link-source.wy-link-source-plain a:visited{background-color:rgba(85,172,238,.04)}.wy-link-source.wy-link-source-plain a:visited .md-code-inline:before{background-color:#55acee}.wy-link-source.wy-link-source-plain a:active{outline-color:#55acee}.wy-link-source.wy-link-source-plain a:hover{border-bottom-color:#55acee}.wy-link-sponsor{background-color:transparent;color:#999;outline:#999 solid 1px}.wy-link-cell-before-image{vertical-align:middle;width:70%}.wy-link-cell-image{padding-left:10px}.wy-link-image-anchor{display:block;overflow:hidden;max-height:300px}.wy-link-image{display:block;margin:0 auto}.wy-footer-table{margin:20px 0}.wy-footer-cell{text-align:center}.wy-read-online{font-size:13px}.wy-section-link-job .wy-link-source,.wy-section-link-job .wy-link-title{font-size:14px}.wy-section-link-job .wy-link-description{font-size:12px}.wy-link-pixel{float:right}@media only screen and (max-width:500px){.wy-issue-publication,.wy-issue-separator{display:none}}.md-code-block{margin:0!important;padding:10px}</style>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hands-Free Coding</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">09 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Earlier this year, I lost the ability to use a keyboard and mouse for extended periods. Fortunately, this wasn't as catastrophic as it sounds! This article chronicles my experience using adaptive tools like dictation and eye-tracking as my primary mechanisms for writing code.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Exhaustiveness Checking with Mypy</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">07 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>What if mypy could warn you about possible problems at "compile time"? In this article I share a little trick to get mypy to fail when a value in an enumeration type is left unhandled.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="El futuro de la profesión de desarrollador web">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">El futuro de la profesión de desarrollador web</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">06 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Se acerca el final de un año que ha dejado más claro que nunca lo difícil que resulta realizar predicciones. Todavía más en un sector tan endiablado como el desarrollo web. Por eso hemos pensado para este episodio del podcast, tratar más sobre direcciones y tendencias profesionales, en lugar de hacerlo más sobre ciertas tecnologías. Para ello planteamos un episodio con dos cuestiones de gran interés.</p>



<p><strong>¿Qué habilidades o competencias tendrán más valor en el futuro de la profesión de desarrollo web?&#160;</strong></p>



<p>En esta primera parte del episodio aportamos nuestra opinión, acerca de las competencias que tendrán más importancia en la profesión del desarrollo web. Entre varias cuestiones que aportamos:</p>



<ul><li>Trabajo en equipo, distribuido y en remoto.</li><li>Competencia en comunicación y habilidades que impliquen responder mejor y más rápido a las necesidades del cliente.</li><li>Capacidad de adaptación, concentración y flexibilidad mental.</li><li>Herramientas de UI/UX.</li><li>Interactividad con servicios o APIs de terceros.</li><li>Configuración de herramientas No Code para uso final.</li><li>Abuso de la figura de los becarios.</li><li>Arquitectura&#160;</li><li>Integración de sistemas.&#160;</li><li>Desarrollo de producto.&#160;</li><li>Conservación/atracción de equipos y talento</li></ul>



<p><strong>¿Qué tecnologías consideráis que serán absolutamente necesarias en los próximos años?</strong></p>



<p>En este segundo apartado ya intentamos hablar más sobre tecnologías y herramientas que ayudarán al trabajo del desarrollo web. Entre varias hablamos de:</p>



<ul><li>Frameworks front y back.</li><li>Herramientas todo en uno para computación en la nube (AWS)</li><li>Seguridad.</li><li>Testing.</li><li>CI / CD.</li><li>Web Components.</li><li>Swagger open api&#160;</li><li>Entornos desacoplados&#160;</li><li>JWT  &#8211; OAUTH</li><li>Linux</li><li>Docker</li><li>Notion</li><li>Emacs</li></ul>



<p>En este apartado también hablamos sobre cómo los frameworks y las librerías CSS han cubierto gran parte de las necesidades de maquetación y animación que muchos proyectos web requieren.</p>



<p>Por último indicar que estaremos encantados de recibir vuestras aportaciones a esta cuestión del futuro del desarrollo web. </p>




<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ondahostil.files.wordpress.com/2018/08/yo.jpg?w=32" alt="La memoria del dato">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">La memoria del dato</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Onda Hostil</a> <span class="article__date">05 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Vivo inmersa en una paradoja. Implica datos, memoria y gestión algorítmica a un nivel tan absurdo que me parece representativa de los tiempos que vienen vivimos. Paso a relatarla. Vivo en un pueblo no muy grande en el que hace años que el pequeño comercio no para de cerrar. Apenas hay variedad de tiendas y [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Descubriendo la programación funcional – Elixir con Erick Navarro">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Descubriendo la programación funcional – Elixir con Erick Navarro</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">05 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Andros Fenollosa sigue con su serie especial sobre Programación Funcional con Elixir. Para ello cuenta esta vez desde Perú, con el compañero <a href="https://erick.navarro.io/">Erick Navarro</a>, un experimentado programador en Python, JavaScript y por supuesto en Elixir. </p>



<p>Elixir, un lenguaje de programación funcional, concurrente, de propósito general que se ejecuta sobre la máquina virtual de Erlang (BEAM). Al funcionar sobre Erlang comparte las mismas abstracciones para desarrollar aplicaciones distribuidas y tolerantes de fallos.&#160;</p>



<p>Elixir destacado en el sector con empresas que han confiado es sus capacidades, como Pinterest o Discord. Su comunidad es tan grande que se realizan diferentes encuentros anuales e EEUU, Europa y Japón. Andros conversa con Erick sobre diferentes cuestiones:</p>



<ul><li>Elixir, origen y diferencias con otros lenguajes.</li><li>Usos y aplicaciones de Elixir.</li><li>Frameworks de Elixir</li><li>Uso en frontend.</li><li>Comunidad y recursos.</li><li>Futuro del lenguaje.</li></ul>



<p>Este episodio es el segundo en una serie especial de Programación Funcional presentada por Andros Fenollosa. <a href="https://republicaweb.es/podcast/descubriendo-la-programacion-funcional-clojure-con-vachi/">Escucha el primer episodio sobre Clojure.</a></p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Updated Debian 10: 10.7 released</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Debian News</a> <span class="article__date">05 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
    The Debian project is pleased to announce the seventh update of its
stable distribution Debian 10 (codename <q>buster</q>).
This point release mainly adds corrections for security issues,
along with a few adjustments for serious problems. Security advisories
have already been published separately and are referenced where available.
  
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/200-circle-of-ai-life.png" alt="Circle of AI Life">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Circle of AI Life</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">04 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/200-circle-of-ai-life.png" alt="Circle of AI Life" title="this might not be the first time" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Fusionar commits</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Óscar Lijó</a> <span class="article__date">03 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>¿Por qué fusionar commits? Fusionar commits es una de las cosas mas chulas que podemos hacer, manipular la historia de nuestro proyecto hace que este sea mucho más legible y que podamos encontrar el cambio que queremos más rápido. A quien no le ha pasado que aunque estaba trabajando en una tarea, ha acabado subiendo&#8230;</p>
<p>La entrada <a rel="nofollow" href="https://www.oscarlijo.com/blog/fusionar-commits/">Fusionar commits</a> aparece primero en <a rel="nofollow" href="https://www.oscarlijo.com/blog">Óscar Lijó</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://64.media.tumblr.com/f370e46192253dab6c143f71f29deb93/b5f349f6c8e42afc-1f/s540x810/ade07eb6be6bd2192e4b280f66a64df9a435d3f2.png" alt="Instapaper Weekly Sponsorship">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Instapaper Weekly Sponsorship</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Instapaper</a> <span class="article__date">03 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>We are excited to announce that we are once again opening up sponsorship slots on the Instapaper Weekly email.<br/></p><p><b>About Instapaper Weekly</b><br/></p><p><b></b></p><p>Instapaper Weekly is an algorithmically-generated newsletter that goes out every Sunday. The email contains the most popular highlight created by all Instapaper users for the week and a list of the most popular articles saved to Instapaper for each day of the past week.</p><p><b></b></p><p>The Weekly is currently delivered to approximately 3 million Instapaper users. The open rate on the mailer is 7.7 percent, with an average click-to-open rate of 0.8% on advertisements.</p><p><b></b></p><p><b>Why Sponsorships?</b></p><p><b></b></p><p>By design, the Instapaper Weekly is a reflection of what our readers consider to be the most important and noteworthy topics for a given week. Sponsoring the Weekly places your content amongst the best content Instapaper has to offer and provides access to a large, engaged audience of tech-oriented and well-read professionals.</p><p><b>Sponsoring</b><br/></p><p><b></b></p><p>As the Weekly compiles content our users found most compelling, we will be holding our sponsorship choices to the same standards of high quality. Your sponsored content should fit within our existing format for Instapaper Weekly and consist of a link, title, description, and thumbnail image. Ideally, the link would be something that our mobile-centric users can save to Instapaper for later reading.</p><p><b></b></p><p>We will run the sponsorship between the “Top Highlight” and “Most Popular” sections of the weekly email:</p><figure class="tmblr-full" data-orig-height="564" data-orig-width="500"><img src="https://64.media.tumblr.com/f370e46192253dab6c143f71f29deb93/b5f349f6c8e42afc-1f/s540x810/ade07eb6be6bd2192e4b280f66a64df9a435d3f2.png" data-orig-height="564" data-orig-width="500"/></figure><p>We are currently charging a flat rate of $2,500 for advertisements in the Instapaper Weekly, and offer one placement per week.<br/></p><p><b></b></p><p>If you’re interested in sponsoring the Instapaper Weekly, please email us at <a href="https://t.umblr.com/redirect?z=mailto%3Asponsors%40instapaper.com%3Fsubject%3DInstapaper%2BWeekly%2BSponsorship&amp;t=OGYxZjE4MGIyNjkxOTQ0Yjg3YmY0MmRiNWI3ZTYzNzdhMzhmOWM1YSxpaTg3S3kxMw%3D%3D&amp;b=t%3AOZjQZ-Pa6uMEdOyfetS5_g&amp;p=https%3A%2F%2Fblog.instapaper.com%2Fpost%2F142649520761&amp;m=1&amp;ts=1603760627">sponsors@instapaper.com</a>.</p><p>– Instapaper Team</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://nosinmiscookies.com/wp-content/uploads/2019/03/cropped-favicon-32x32.png" alt="Tres claves para hacer un currículum exitoso">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Tres claves para hacer un currículum exitoso</h1>
                            <h2 class="article__feed"><a target="_blank" href="">No sin mis cookies</a> <span class="article__date">03 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Los tiempos han cambiado. El currículum es más que una carta de presentación. Es tu marca, tu identidad, la que te diferenciará respecto a tus competidores. Descubre cómo adaptarlo al mundo digital y enamora a tu futura empresa.</p>
<p>The post <a rel="nofollow" href="https://nosinmiscookies.com/tres-claves-para-hacer-un-curriculum-exitoso/">Tres claves para hacer un currículum exitoso</a> appeared first on <a rel="nofollow" href="https://nosinmiscookies.com">No sin mis cookies</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">November 2020 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">03 12 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Read more updates from Malli, Practicalli, Clj-kondo/babashka/sci, and Datahike
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Sick of the stupid jokes? Write your own arbitrary-precision JavaScript math library</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">30 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Javascript has its fair share of ‘wat’ moments. Even though most of them have a logical explanation once you dig in, they can still be surprising. But JavaScript doesn’t deserve all the indignant laughter. And now that BigInt is officially part of the TC39 ECMAScript standard, we have options. I'm going to show you how to take advantage of them.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Sick of the stupid jokes? Write your own arbitrary-precision JavaScript math library</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">30 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Javascript has its fair share of ‘wat’ moments. Even though most of them have a logical explanation once you dig in, they can still be surprising. But JavaScript doesn’t deserve all the indignant laughter. And now that BigInt is officially part of the TC39 ECMAScript standard, we have options. I'm going to show you how to take advantage of them.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q4 2020 Funding Announcement</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">30 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together is funding clj-kondo, ClojisR, O&rsquo;Doyle Rules, and Calva $9,000 each.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Quarantine Day 259: Princeton CS Senior Takes the AP CS Exam</h1>
                            <h2 class="article__feed"><a target="_blank" href="">blog.karenying.com</a> <span class="article__date">29 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Did I get a 5? My ex-Facebook, ex-Google, ex-Airbnb, ex-boyfriend grades it
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Diferencias entre IaaS, CaaS, PaaS, FaaS y SaaS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Óscar Lijó</a> <span class="article__date">28 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Con la llegada de la nube hemos tenido que aprender una serie de términos que no estabamos acostumbrados a escuchar. Algunos de ellos son los que aparecen en el título de esta entrada. Aunque pueden parecer un trabalenguas son bastante sencillos de entender ya que todos hacen referencia a lo mismo, al nivel de gestión&#8230;</p>
<p>La entrada <a rel="nofollow" href="https://www.oscarlijo.com/blog/diferencias-entre-iaas-caas-paas-faas-y-saas/">Diferencias entre IaaS, CaaS, PaaS, FaaS y SaaS</a> aparece primero en <a rel="nofollow" href="https://www.oscarlijo.com/blog">Óscar Lijó</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Descubriendo  la programación funcional – Clojure con Vachi">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Descubriendo  la programación funcional – Clojure con Vachi</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">28 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Este es el primer episodio de una serie especial del podcast dirigida a <strong>descubrir la programación funcional. </strong>Andros Fenollosa charla con diferentes invitados sobre el paradigma de la programación funcional, los lenguajes más destacables, herramientas y el cambio de mentalidad a la hora de afrontar este tipo de programación, especialmente si vienes de la programación orientada a objetos.</p>



<p>Para este primer episodio Andros ha invitado a Vachi, un programador especializado en <a href="https://clojure.org/">Clojure </a>y actualmente trabajando en una fintech. Con Vachi habla sobre el lenguaje Clojure, sus características más destacables, principios de programación y lo que hace de Clojure un lenguaje tan atractivo para muchas empresas. También hablan de la comunidad de Clojure y recursos de interés para los que quieran comenzar con Clojure.</p>



<p>Clojure es un lenguaje multiparadigma de propósito general creado por <a href="https://es.wikipedia.org/w/index.php?title=Rich_Hickey&#38;action=edit&#38;redlink=1">Rich Hickey</a>&#160; como un dialecto de Lisp y orientado a trabajar con los datos a través de funciones. A diferencia de otros lenguajes como Python o C, Clojure se ejecuta sobre la JVM (Máquina virtual de Java).</p>




<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Tabla de códigos de estado HTTP</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Óscar Lijó</a> <span class="article__date">27 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Una tabla de códigos de estado HTTP siempre hace falta, aqui tienes una bastante completa por si ese código no te suena 1×× Informativo Código Estado Descripción 100 Continue El servidor recibe la parte inicial de la solicitud, la da por buena y tiene intención de responder cuando la tenga toda 101 Switching Protocols El&#8230;</p>
<p>La entrada <a rel="nofollow" href="https://www.oscarlijo.com/blog/tabla-de-codigos-de-estado-http/">Tabla de códigos de estado HTTP</a> aparece primero en <a rel="nofollow" href="https://www.oscarlijo.com/blog">Óscar Lijó</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/199-welcome-to-hell.png" alt="Welcome To Hell">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Welcome To Hell</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">27 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/199-welcome-to-hell.png" alt="Welcome To Hell" title="and you need to use an azerty keyboard" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Ultimate Guide to Becoming a VSCode Girl</h1>
                            <h2 class="article__feed"><a target="_blank" href="">blog.karenying.com</a> <span class="article__date">25 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The post that will have tech bros quaking in their Allbirds wool runners
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Simple React Router Nav Bar</h1>
                            <h2 class="article__feed"><a target="_blank" href="">blog.karenying.com</a> <span class="article__date">22 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Using React Router and clever CSS to create a nav bar with dots to show hover and active state
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Webflow, diseño web no code con Xavi Barrachina">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Webflow, diseño web no code con Xavi Barrachina</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">21 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Los procesos creativos y el diseño web muy a menudo suelen enfrentarse a la barrera de la codificación y las limitaciones técnicas. Desde aquellos primeros sitios web de aspecto plano y poco atractivo, la tecnología del diseño web ha ido incorporando <strong>herramientas que ayuden a expresar de mejor manera la creatividad de los diseñadores.</strong> Aunque los creadores de sitios web puedan contar con infinidad de posibilidades para comunicar sus ideas, sigue existiendo esa barrera que impone la disciplina del código.</p>



<p><strong>¿Debes ser programador para realizar tu propia página web o vivir haciendo páginas web para los demás? </strong>Son muchas las herramientas que existen para facilitar la construcción visual de sitios web, pero muchas veces los inconvenientes de utilizar esas herramientas exceden con el tiempo a su conveniencia.</p>



<p>Como ya hemos comentado en algún episodio, <a href="https://republicaweb.es/podcast/no-code-desarrolla-tus-proyectos-web-sin-necesidad-de-codigo/" data-type="URL" data-id="https://republicaweb.es/podcast/no-code-desarrolla-tus-proyectos-web-sin-necesidad-de-codigo/">el auge de las herramientas “no code”</a> está consiguiendo que la barrera de entrada se reduzca y al mismo tiempo, está consiguiendo el acceso a la tecnología web a un público con muchísimo que aportar a la experiencia de los sitios web.</p>



<p>Para este episodio invitamos a <a href="https://www.linkedin.com/in/xavibarrachina/" data-type="URL" data-id="https://www.linkedin.com/in/xavibarrachina/">Xavi Barrachina</a>, impulsor <a href="https://events.webflow.com/valencia-webflow-meetup/">de la comunidad Webflow Valencia</a> y fundador de la <a href="https://masflow.webflow.io/">agencia Masflow especializada en diseño web </a>a través de la plataforma de diseño web no code Webflow. Xavi es un emprendedor nato, apasionado del diseño, la innovación y la estrategia creativa. Con él queremos hablar de Webflow y como esta innovadora herramienta puede ayudar a crear sitios web.</p>







<p>Entre las cuestiones que hablamos con Xavi Barrachina:</p>



<ul><li>¿Qué es Webflow y qué lo diferencia de otras herramientas de creación web?</li><li>¿Cómo llegas a trabajar con Webflow y por qué te decides a montar Masflow?</li><li>¿Cómo te ayuda Webflow en tu proceso creativo?</li><li>¿Qué herramientas utilizas además de Webflow para crear los sitios web?</li><li>¿Crees que las tecnologías “no code” son el futuro del diseño web?</li><li>¿Qué aspectos del diseño web piensas que mejoran usando Webflow (relación con clientes, probar ideas o nuevos planteamientos, velocidad de puesta en funcionamiento)?</li><li>Experiencia con la comunidad de Webflow Valencia y qué tipo de eventos habéis realizado.</li></ul>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Restricting Flymake to my projects</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Manuel Uberti</a> <span class="article__date">21 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>My recent move <a href="https://www.manueluberti.eu/emacs/2020/09/23/flymake/">from Flycheck to Flymake</a> has proven to be a solid choice because
the Emacs built-in syntax checker has yet to let me down. And since by now I am
sure my love for <code class="language-plaintext highlighter-rouge">project.el</code> is absolutely obvious, could I miss the opportunity
to make these two underappreciated gems shine together?</p>

<p>Honestly, though, the credit here goes all to Protesilaos Stavrou. <a href="https://protesilaos.com/dotemacs/#h:b8bfcc05-c0d3-4093-b3fe-f06187d22c6a">His Flymake
setup</a> made me aware of a neat way to limit the use of Flymake to the places
I actually need it.</p>

<p>All I had to do was adapt it to my preferences:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">defun</span> <span class="nv">mu-flymake-mode-activate</span> <span class="p">()</span>
  <span class="s">"Activate `flymake-mode' only in my projects."</span>
  <span class="p">(</span><span class="nv">project--ensure-read-project-list</span><span class="p">)</span>
  <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">known-projects</span> <span class="p">(</span><span class="nv">project-known-project-roots</span><span class="p">))</span>
        <span class="p">(</span><span class="nv">pr</span> <span class="p">(</span><span class="nb">or</span> <span class="p">(</span><span class="nv">locate-dominating-file</span> <span class="s">"."</span> <span class="s">".git"</span><span class="p">)</span>
                <span class="nv">default-directory</span><span class="p">)))</span>
    <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">and</span> <span class="p">(</span><span class="nb">eq</span> <span class="nv">buffer-read-only</span> <span class="no">nil</span><span class="p">)</span>
             <span class="p">(</span><span class="nb">member</span> <span class="nv">pr</span> <span class="nv">known-projects</span><span class="p">))</span>
        <span class="p">(</span><span class="nv">flymake-mode</span> <span class="mi">+1</span><span class="p">)</span>
      <span class="p">(</span><span class="nv">flymake-mode</span> <span class="mi">-1</span><span class="p">))))</span>
</code></pre></div></div>

<p>I then hooked this little function to <code class="language-plaintext highlighter-rouge">prog-mode-hook</code> and <code class="language-plaintext highlighter-rouge">text-mode-hook</code> and
everything was good to go.</p>

<p>Note that <code class="language-plaintext highlighter-rouge">project.el</code> must be required before running <code class="language-plaintext highlighter-rouge">mu-flymake-mode-activate</code>,
otherwise Emacs will complain about <code class="language-plaintext highlighter-rouge">project--ensure-read-project-list</code> not being
available.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Restricting Flymake to my projects</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Manuel Uberti</a> <span class="article__date">21 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>My recent move <a href="https://www.manueluberti.eu/emacs/2020/09/23/flymake/">from Flycheck to Flymake</a> has proven to be a solid choice because
the Emacs built-in syntax checker has yet to let me down. And since by now I am
sure my love for <code class="language-plaintext highlighter-rouge">project.el</code> is absolutely obvious, could I miss the opportunity
to make these two underappreciated gems shine together?</p>

<p>Honestly, though, the credit here goes all to Protesilaos Stavrou. <a href="https://protesilaos.com/dotemacs/#h:b8bfcc05-c0d3-4093-b3fe-f06187d22c6a">His Flymake
setup</a> made me aware of a neat way to limit the use of Flymake to the places
I actually need it.</p>

<p>All I had to do was adapt it to my preferences:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">defun</span> <span class="nv">mu-flymake-mode-activate</span> <span class="p">()</span>
  <span class="s">"Activate `flymake-mode' only in my projects."</span>
  <span class="p">(</span><span class="nv">project--ensure-read-project-list</span><span class="p">)</span>
  <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">known-projects</span> <span class="p">(</span><span class="nv">project-known-project-roots</span><span class="p">))</span>
        <span class="p">(</span><span class="nv">pr</span> <span class="p">(</span><span class="nb">or</span> <span class="p">(</span><span class="nv">locate-dominating-file</span> <span class="s">"."</span> <span class="s">".git"</span><span class="p">)</span>
                <span class="nv">default-directory</span><span class="p">)))</span>
    <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">and</span> <span class="p">(</span><span class="nb">eq</span> <span class="nv">buffer-read-only</span> <span class="no">nil</span><span class="p">)</span>
             <span class="p">(</span><span class="nb">member</span> <span class="nv">pr</span> <span class="nv">known-projects</span><span class="p">))</span>
        <span class="p">(</span><span class="nv">flymake-mode</span> <span class="mi">+1</span><span class="p">)</span>
      <span class="p">(</span><span class="nv">flymake-mode</span> <span class="mi">-1</span><span class="p">))))</span>
</code></pre></div></div>

<p>I then hooked this little function to <code class="language-plaintext highlighter-rouge">prog-mode-hook</code> and <code class="language-plaintext highlighter-rouge">text-mode-hook</code> and
everything was good to go.</p>

<p>Note that <code class="language-plaintext highlighter-rouge">project.el</code> must be required before running <code class="language-plaintext highlighter-rouge">mu-flymake-mode-activate</code>,
otherwise Emacs will complain about <code class="language-plaintext highlighter-rouge">project--ensure-read-project-list</code> not being
available.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/198-feature-complete.png" alt="Feature Complete">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Feature Complete</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">20 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/198-feature-complete.png" alt="Feature Complete" title="The ultimate inspiration is the deadline" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://assets.bbhub.io/company/sites/40/2020/11/TechatBloomberg-11.10.jpg" alt="TypeScript, the Mobile Web, and WebP website optimization! ⚡  — Pony Foo Weekly">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">TypeScript, the Mobile Web, and WebP website optimization! ⚡  — Pony Foo Weekly</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Pony Foo Weekly</a> <span class="article__date">19 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="f-core"><div class="md-markdown"><p>We&#x2019;re glad you could make it this week! </p> <p>With your help, we can make Pony Foo Weekly <em>even more</em> awesome: <a href="https://ponyfoo.com/weekly/submissions?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-190" target="_blank" rel="noopener noreferrer">send tips about cool resources</a>.</p> </div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://www.techatbloomberg.com/blog/10-insights-adopting-typescript-at-scale/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-190" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>10 Insights from Adopting TypeScript at Scale</p> </a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Rob Palmer shares some of the insights &#38; lessons learned during Bloomberg Engineering&#x2019;s journey to adopt TypeScript as a first-class supported language.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/TechAtBloomberg?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-190" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Tech at Bloomberg</p> </a></div></td><td class="wy-td wy-link-cell-image"><a href="https://www.techatbloomberg.com/blog/10-insights-adopting-typescript-at-scale/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-190" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://assets.bbhub.io/company/sites/40/2020/11/TechatBloomberg-11.10.jpg" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://engineering.q42.nl/webassembly?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-190" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>From JavaScript to WebAssembly in Three Steps</p> </a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>My journey of improving the performance of our ultra resolution storytelling tool Micrio by upgrading the JavaScript-only client to WebAssembly.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/duinmarcel?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-190" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Marcel Duin</p> </a></div></td><td class="wy-td wy-link-cell-image"><a href="https://engineering.q42.nl/webassembly?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-190" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://engineering.q42.nl/content/images/2020/09/Going-From-JavaScript-to-WebAssembly-in-Three-Steps-1.jpg" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-primary"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://tinyurl.com/yyp96ue3?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-190" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Never open Excel again with the help of Flatfile Concierge</p> </a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Think of the last time you imported a spreadsheet. Did it work the first time? Nearly everyone has dealt with formatting CSV or Excel files so that the data can be imported into an application. It&#x2019;s a pain! Enter Flatfile Concierge. Solve data onboarding with collaborative workspaces, intuitive data validation, and best of all, #nocode.</p> </div></div><div class="wy-link-source-section"><a href="https://ponyfoo.com/weekly/links/tagged/sponsored" class="wy-link-tag wy-link-sponsor">Sponsored</a></div></td><td class="wy-td wy-link-cell-image"><a href="https://tinyurl.com/yyp96ue3?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-190" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://images.ponyfoo.com/uploads/Pony-foo-300x300@2x-b05ccddbc4aa45fa850c71ba5e032584.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://github.com/typesense/typesense?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-190" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Typesense: an open source alternative to Algolia</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/code" style="color:#1a4d7f;background-color:#ffe270" class="wy-link-tag">Code</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>A fast, light-weight, typo tolerant search engine for building instant search experiences.</p> </div></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://medium.com/@dannymoerkerke/were-killing-the-mobile-web-be5c5662c807?source=friends_link&#38;sk=b44b5a38ddde5d1a48cf2a9d78ace4b6&#38;utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-190" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>We&#x2019;re Killing The Mobile Web</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/point-of-view" style="color:#f3720d;background-color:#ffeada" class="wy-link-tag">Point of View</a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>The web took over desktop but on mobile native apps are the clear winner and we can only blame ourselves. But we can fix this as well.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/dannymoerkerke?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-190" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Danny Moerkerke</p> </a></div></td><td class="wy-td wy-link-cell-image"><a href="https://medium.com/@dannymoerkerke/were-killing-the-mobile-web-be5c5662c807?source=friends_link&#38;sk=b44b5a38ddde5d1a48cf2a9d78ace4b6&#38;utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-190" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://miro.medium.com/max/1200/0*0BNva5gmLzNU6THM" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://www.terryobrien.co.uk/articles/faster-websites-using-webp-images/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-190" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Faster websites using WebP images</p> </a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>The WebP image format has a smaller file size compared to PNG and JPG helping your websites load faster. Learn why and how to implement it.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/digitaltob?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-190" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Terry O&#x2019;Brien</p> </a></div></td><td class="wy-td wy-link-cell-image"><a href="https://www.terryobrien.co.uk/articles/faster-websites-using-webp-images/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-190" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://www.terryobrien.co.uk/images/social-images/faster-websites-using-webp-images.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div></div><style>html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;position:relative;vertical-align:baseline}sup{top:-.5em}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto;resize:vertical;min-height:280px;max-height:900px}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item;margin:-10px -20px;padding:10px;background-color:#f6f6f6;cursor:pointer;border-bottom:2px solid #ddd}[hidden],template{display:none}body,body:after,body:before,html,html:after,html:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*,:after,:before{-webkit-box-sizing:inherit;-moz-box-sizing:inherit;box-sizing:inherit}@-moz-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-webkit-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-o-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-moz-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@-webkit-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@-o-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}.f-core{font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}.f-mono{font-family:Consolas,Menlo,Monaco,'Lucida Console','Liberation Mono','DejaVu Sans Mono','Bitstream Vera Sans Mono','Courier New',monospace,serif}.ly-custom-heading .f-heading,.ly-custom-heading h1,.ly-custom-heading h2,.ly-custom-heading h3,.ly-custom-heading h4,.ly-custom-heading h5,.ly-custom-heading h6,.ly-lean .f-heading,.ly-lean h1,.ly-lean h2,.ly-lean h3,.ly-lean h4,.ly-lean h5,.ly-lean h6{font-family:Neuton,'Hoefler Text',Palatino,Baskerville,Georgia,'Times New Roman',serif}.ly-custom-subheading .f-subheading,.ly-lean .f-subheading{font-family:Merriweather,Georgia,serif}body{margin:0;font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif;background:#fcfcfc;color:#333}img{max-width:100%;border:none}.md-markdown figure:not(.twitter-tweet-figure){background-color:#f6f6f6}.md-markdown figure:not(.twitter-tweet-figure)>a{display:block}.md-markdown figure:not(.twitter-tweet-figure)>a>img,.md-markdown figure:not(.twitter-tweet-figure)>img{display:block;margin-left:auto;margin-right:auto}.md-markdown figcaption{padding:10px;font-style:italic;font-size:14px;background:-webkit-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-moz-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-o-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-ms-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:linear-gradient(to right,#fff9e2 33%,#fcf9ee 100%);color:#555}.md-markdown .figure-has-loaded{background:-webkit-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-moz-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-o-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-ms-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:linear-gradient(to bottom,rgba(255,255,255,0) 0,#fcf9ee 100%)}b,em,font-style italic,font-weight bold,i,ins,strong{text-decoration:none}del{text-decoration:line-through}sub,sup{bottom:0;line-height:18px}button,input{overflow:visible;border-radius:0}button{border:none;padding:6px 8px;font-size:1.2em;background:0 0}button[disabled]{color:#cbccbc!important}input,select,textarea{display:block;width:100%;padding:10px 8px;line-height:18px;border:none;font:inherit}select{height:38px}ol,ul{padding:0;margin:0;list-style-position:inside}li>ol,li>ul{margin-left:20px}hr{border:none;border-top:5px solid rgba(0,0,0,.05);margin:20px 0}kbd{display:inline-block;border:1px solid #ccc;margin:0 .1em;padding:.1em .6em;line-height:1.4;font-size:11px;background-color:#f7f7f7;-webkit-box-shadow:0 1px 0 #bbb,0 0 0 2px #fff inset;box-shadow:0 1px 0 #bbb,0 0 0 2px #fff inset;border-radius:3px;color:#333;text-shadow:0 1px 0 #fff;white-space:nowrap}iframe{display:inline-block;border:none;max-width:100%}summary:hover{opacity:.8}details{padding:10px 20px 20px;border-bottom:2px dashed #ddd}details[open] summary{margin-bottom:20px}blockquote{border:none;margin:0!important}ol,p,ul{line-height:35px}p{margin:35px 0}@media only screen and (min-width:768px){ol,p,ul{line-height:30px}}a,button,input[type=submit]{cursor:pointer;text-decoration:none}.lk-link{color:#e92c6c;border-bottom:1px solid transparent;background-color:rgba(255,255,255,.04)}.lk-link .md-code-inline{position:relative}.lk-link .md-code-inline:only-child{display:inline-block;line-height:17px}.lk-link .md-code-inline:before{content:'';position:absolute;background-color:#f1e05a;top:0;left:0;right:0;bottom:0;opacity:.04}.lk-link:visited{background-color:rgba(233,44,108,.04)}.lk-link:visited .md-code-inline:before{background-color:#e92c6c}.lk-link:hover{border-bottom:1px solid #e92c6c}.lk-rainbows{position:relative;color:#333;margin-bottom:5px}.lk-rainbows:hover:before{position:absolute;content:'';left:0;right:0;bottom:-8px;height:3px;opacity:.8;-webkit-transition:.1s ease-in-out;-moz-transition:.1s ease-in-out;-o-transition:.1s ease-in-out;-ms-transition:all .1s ease-in-out;transition:.1s ease-in-out;-webkit-animation:.5s infinite bg-rainbow;-moz-animation:.5s infinite bg-rainbow;-o-animation:.5s infinite bg-rainbow;-ms-animation:bg-rainbow .5s infinite;animation:.5s infinite bg-rainbow}.lk-icon{color:#333}.lk-icon:hover{color:#e92c6c}.lk-visitor{color:#333}.lk-visitor:after{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-left:5px}.lk-visitor.lk-visitor-large:after{font-size:1em}.lk-visitor:hover:after{color:#333;border-bottom-style:solid}.lk-visitor:visited:after{color:#7d5cff}.lk-visitor-inside{color:#333}.lk-visitor-inside .lk-visitor-target:before{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-right:5px}.lk-visitor-inside.lk-visitor-large .lk-visitor-target:before{font-size:1em}.lk-visitor-inside:hover .lk-visitor-target:before{color:#333;border-bottom-style:solid}.lk-visitor-inside:visited .lk-visitor-target:before{color:#7d5cff}.lk-visitor-before{color:#333}.lk-visitor-before:before{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-right:5px}.lk-visitor-before.lk-visitor-large:before{font-size:1em}.lk-visitor-before:hover:before{color:#333;border-bottom-style:solid}.lk-visitor-before:visited:before{color:#7d5cff}.lk-visitor-before-no-underline:before{border-bottom-width:0}.lk-link-to-green{color:#cbccbc}.lk-link-to-green:visited,.lk-link-to-green:visited:before{color:#1bc211;background-color:#1bc211}.lk-link-to-green:active{outline-color:#1bc211}.lk-link-to-green:hover,.lk-link-to-green:hover:before{color:#8be186;border-bottom-color:#1bc211}.lk-green .lk-link,a.lk-green{color:#1bc211}.lk-green .lk-link:visited,a.lk-green:visited{background-color:rgba(27,194,17,.04)}.lk-green .lk-link:visited .md-code-inline:before,a.lk-green:visited .md-code-inline:before{background-color:#1bc211}.lk-green .lk-link:active,a.lk-green:active{outline-color:#1bc211}.lk-green .lk-link:hover,a.lk-green:hover{border-bottom-color:#1bc211}.lk-green.lk-icon:hover{color:#1bc211}.lk-pink-light .lk-link,a.lk-pink-light{color:#ea6c93}.lk-pink-light .lk-link:visited,a.lk-pink-light:visited{background-color:rgba(234,108,147,.04)}.lk-pink-light .lk-link:visited .md-code-inline:before,a.lk-pink-light:visited .md-code-inline:before{background-color:#ea6c93}.lk-pink-light .lk-link:active,a.lk-pink-light:active{outline-color:#ea6c93}.lk-pink-light .lk-link:hover,a.lk-pink-light:hover{border-bottom-color:#ea6c93}.lk-pink-light.lk-icon:hover{color:#ea6c93}.lk-black .lk-link,a.lk-black{color:#333}.lk-black .lk-link:visited,a.lk-black:visited{background-color:rgba(51,51,51,.04)}.lk-black .lk-link:visited .md-code-inline:before,a.lk-black:visited .md-code-inline:before{background-color:#333}.lk-black .lk-link:active,a.lk-black:active{outline-color:#333}.lk-black .lk-link:hover,a.lk-black:hover{border-bottom-color:#333}.lk-black.lk-icon:hover{color:#333}.lk-gray .lk-link,a.lk-gray{color:#999}.lk-gray .lk-link:visited,a.lk-gray:visited{background-color:rgba(153,153,153,.04)}.lk-gray .lk-link:visited .md-code-inline:before,a.lk-gray:visited .md-code-inline:before{background-color:#999}.lk-gray .lk-link:active,a.lk-gray:active{outline-color:#999}.lk-gray .lk-link:hover,a.lk-gray:hover{border-bottom-color:#999}.lk-gray.lk-icon:hover{color:#999}.lk-white .lk-link,a.lk-white{color:#fcfcfc}.lk-white .lk-link:visited,a.lk-white:visited{background-color:rgba(252,252,252,.04)}.lk-white .lk-link:visited .md-code-inline:before,a.lk-white:visited .md-code-inline:before{background-color:#fcfcfc}.lk-white .lk-link:active,a.lk-white:active{outline-color:#fcfcfc}.lk-white .lk-link:hover,a.lk-white:hover{border-bottom-color:#fcfcfc}.lk-white.lk-icon:hover{color:#fcfcfc}.lk-orange .lk-link,a.lk-orange{color:#f3720d}.lk-orange .lk-link:visited,a.lk-orange:visited{background-color:rgba(243,114,13,.04)}.lk-orange .lk-link:visited .md-code-inline:before,a.lk-orange:visited .md-code-inline:before{background-color:#f3720d}.lk-orange .lk-link:active,a.lk-orange:active{outline-color:#f3720d}.lk-orange .lk-link:hover,a.lk-orange:hover{border-bottom-color:#f3720d}.lk-orange.lk-icon:hover{color:#f3720d}.lk-lilly .lk-link,a.lk-lilly{color:#7d5cff}.lk-lilly .lk-link:visited,a.lk-lilly:visited{background-color:rgba(125,92,255,.04)}.lk-lilly .lk-link:visited .md-code-inline:before,a.lk-lilly:visited .md-code-inline:before{background-color:#7d5cff}.lk-lilly .lk-link:active,a.lk-lilly:active{outline-color:#7d5cff}.lk-lilly .lk-link:hover,a.lk-lilly:hover{border-bottom-color:#7d5cff}.lk-lilly.lk-icon:hover{color:#7d5cff}.lk-blue .lk-link,a.lk-blue{color:#1a4d7f}.lk-blue .lk-link:visited,a.lk-blue:visited{background-color:rgba(26,77,127,.04)}.lk-blue .lk-link:visited .md-code-inline:before,a.lk-blue:visited .md-code-inline:before{background-color:#1a4d7f}.lk-blue .lk-link:active,a.lk-blue:active{outline-color:#1a4d7f}.lk-blue .lk-link:hover,a.lk-blue:hover{border-bottom-color:#1a4d7f}.lk-blue.lk-icon:hover{color:#1a4d7f}.lk-inherited .lk-link,a.lk-inherited{color:inherit}.lk-inherited .lk-link:active,a.lk-inherited:active{outline-color:inherit}.lk-inherited .lk-link:hover,a.lk-inherited:hover{border-bottom-color:inherit}.lk-inherited.lk-icon:hover{color:inherit}.lk-twitter .lk-link,a.lk-twitter{color:#55acee}.lk-twitter .lk-link:visited,a.lk-twitter:visited{background-color:rgba(85,172,238,.04)}.lk-twitter .lk-link:visited .md-code-inline:before,a.lk-twitter:visited .md-code-inline:before{background-color:#55acee}.lk-twitter .lk-link:active,a.lk-twitter:active{outline-color:#55acee}.lk-twitter .lk-link:hover,a.lk-twitter:hover{border-bottom-color:#55acee}.lk-twitter.lk-icon:hover{color:#55acee}.lk-facebook .lk-link,a.lk-facebook{color:#3b5998}.lk-facebook .lk-link:visited,a.lk-facebook:visited{background-color:rgba(59,89,152,.04)}.lk-facebook .lk-link:visited .md-code-inline:before,a.lk-facebook:visited .md-code-inline:before{background-color:#3b5998}.lk-facebook .lk-link:active,a.lk-facebook:active{outline-color:#3b5998}.lk-facebook .lk-link:hover,a.lk-facebook:hover{border-bottom-color:#3b5998}.lk-facebook.lk-icon:hover{color:#3b5998}.lk-clean{background-color:transparent}.lk-chrome:hover{color:#4989f4}.lk-teal .lk-link,a.lk-teal{color:#00a19c}.lk-teal .lk-link:visited,a.lk-teal:visited{background-color:rgba(0,161,156,.04)}.lk-teal .lk-link:visited .md-code-inline:before,a.lk-teal:visited .md-code-inline:before{background-color:#00a19c}.lk-teal .lk-link:active,a.lk-teal:active{outline-color:#00a19c}.lk-teal .lk-link:hover,a.lk-teal:hover{border-bottom-color:#00a19c}.lk-teal.lk-icon:hover{color:#00a19c}table{width:100%;border-spacing:0;border-collapse:separate}td,th{padding:8px}@media only screen and (max-width:950px){.table-responsive{display:block}.table-responsive>thead{display:none}.table-responsive>tbody,.table-responsive>tfoot{display:block}.table-responsive>tbody>tr,.table-responsive>tfoot>tr{display:block;background-color:rgba(203,204,188,.1);margin-bottom:30px}.table-responsive>tbody>tr:nth-child(even),.table-responsive>tfoot>tr:nth-child(even){background-color:rgba(203,204,188,.15)}.table-responsive>tbody>tr:last-child,.table-responsive>tfoot>tr:last-child{margin-bottom:0}.table-responsive>tbody>tr>td,.table-responsive>tfoot>tr>td{display:block;text-align:left}.table-responsive>tbody>tr>td:before,.table-responsive>tfoot>tr>td:before{display:block;content:attr(data-label);color:#555;font-size:13px;margin:0 0 5px}.table-responsive .table-responsive-hide{display:none}}.c-oreilly-teal{color:#00a19c}.c-yellow-highlight{color:#ffe270}.c-dark-orange{color:#f3720d}.c-pink{color:#e92c6c}.c-purple{color:#900070}.c-blue{color:#1a4d7f}.c-dark-turquoise{color:#1686a2}.c-dark-green{color:#1bc211}.c-white{color:#fcfcfc}.c-gray{color:#b7b7b7}.c-lilly{color:#7d5cff}.c-teal{color:#3aca96}.c-bg-oreilly-teal{background-color:#00a19c}.c-bg-yellow-highlight{background-color:#ffe270}.c-bg-dark-orange{background-color:#f3720d}.c-bg-pink{background-color:#e92c6c}.c-bg-purple{background-color:#900070}.c-bg-blue{background-color:#1a4d7f}.c-bg-dark-turquoise{background-color:#1686a2}.c-bg-dark-green{background-color:#1bc211}.c-bg-white{background-color:#fcfcfc}.c-bg-gray{background-color:#b7b7b7}.c-bg-lilly{background-color:#7d5cff}.c-bg-teal{background-color:#3aca96}.tj-emoji{width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em}.dc-header{margin-bottom:60px}.dc-heading{text-align:center;font-size:4em;padding:0 10px;margin-top:0;margin-bottom:10px}.dc-role{line-height:26px;padding:0 20px;margin-top:10px;text-align:center;font-style:italic;color:#cbccbc}.dc-colored{background:#f6f6f6;border-top:9px solid rgba(125,92,255,.5)}.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:800px}.md-markdown blockquote:not(.twitter-tweet){margin:0;padding:20px 0;border:none;border-top:5px solid rgba(0,0,0,.05);border-bottom:5px solid rgba(0,0,0,.05)}.md-markdown blockquote:not(.twitter-tweet) h1,.md-markdown blockquote:not(.twitter-tweet) h2,.md-markdown blockquote:not(.twitter-tweet) h3,.md-markdown blockquote:not(.twitter-tweet) h4,.md-markdown blockquote:not(.twitter-tweet) h5,.md-markdown blockquote:not(.twitter-tweet) h6{margin:-20px 0;padding:20px 0}.md-markdown blockquote:not(.twitter-tweet) .md-code-block{margin:0}.md-markdown blockquote:not(.twitter-tweet) .md-code-block:last-child{margin-bottom:-20px}.md-markdown img:first-child{margin-top:0}.md-markdown img:last-child{margin-bottom:0}.md-markdown p:first-child{margin-top:0}.md-markdown p:last-child{margin-bottom:0}.md-markdown .md-code-block+ol,.md-markdown .md-code-block+ul,.md-markdown ol+.md-code-block,.md-markdown ul+.md-code-block{margin-top:35px}.md-markdown a:not(.md-heading){color:#e92c6c;border-bottom:1px solid transparent;background-color:rgba(255,255,255,.04)}.md-markdown a:not(.md-heading) .md-code-inline{position:relative}.md-markdown a:not(.md-heading) .md-code-inline:only-child{display:inline-block;line-height:17px}.md-markdown a:not(.md-heading) .md-code-inline:before{content:'';position:absolute;background-color:#f1e05a;top:0;left:0;right:0;bottom:0;opacity:.04}.md-markdown a:not(.md-heading):visited{background-color:rgba(233,44,108,.04)}.md-markdown a:not(.md-heading):visited .md-code-inline:before{background-color:#e92c6c}.md-markdown a:not(.md-heading):hover{border-bottom:1px solid #e92c6c}.md-markdown thead{background-color:#e0e0e0}.md-markdown tbody{background-color:#f6f6f6}.md-markdown tbody tr:nth-child(even){background-color:#f9f9f9}.md-markdown h1,.md-markdown h2,.md-markdown h3,.md-markdown h4,.md-markdown h5,.md-markdown h6{padding:10px 0}.md-markdown h1:first-child,.md-markdown h2:first-child,.md-markdown h3:first-child,.md-markdown h4:first-child,.md-markdown h5:first-child,.md-markdown h6:first-child{margin-top:0}.md-markdown h1:last-child,.md-markdown h2:last-child,.md-markdown h3:last-child,.md-markdown h4:last-child,.md-markdown h5:last-child,.md-markdown h6:last-child{margin-bottom:0}.md-markdown iframe{display:block;margin:35px auto}.md-markdown iframe:first-child{margin-top:0}.md-markdown iframe:last-child{margin-bottom:0}.md-markdown li>p:only-child{display:inline}.md-markdown ul{list-style-type:none}.md-markdown ul>li:before{content:'◯';margin-right:5px}.md-heading{color:inherit}.md-markdown-inline{display:inline}.md-markdown-inline p{display:inline;line-height:initial}.md-code-block,.ocha-highlighted{margin:0 -20px}.ocha-code-block{padding:18px 50px}.md-markdown:not(.mm-content-html) .md-code-block+blockquote{max-width:inherit!important;margin:0 -20px;padding-left:20px;padding-right:20px}.md-code-block .md-code{display:block}.md-markdown-summary p{margin:10px 0}@media only screen and (min-width:768px){.md-markdown h1,.md-markdown h2,.md-markdown h3,.md-markdown h4,.md-markdown h5,.md-markdown h6{margin-left:-40px;margin-right:-40px;padding:10px 40px}.md-code-block,.ocha-highlighted{margin:0 -40px}.md-markdown:not(.mm-content-html) .md-code-block+blockquote{margin:0 -40px;padding-left:40px;padding-right:40px}}@media only screen and (min-width:1300px){.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:900px}}@media only screen and (min-width:1400px){.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:1000px}.md-code-block,.md-markdown:not(.mm-content-html) .md-code-block+blockquote,.ocha-highlighted{margin:0 -400px 0 -40px}}.md-markdown-large blockquote,.md-markdown-large code,.md-markdown-large ol,.md-markdown-large p,.md-markdown-large table,.md-markdown-large ul{max-width:inherit}.md-footnotes{margin-top:80px;padding:20px 0;border-top:1px dashed #cbccbc}.md-footnote{margin:0;padding:8px 0;font-size:14px;display:-webkit-box;display:-moz-box;display:-webkit-flex;display:-ms-flexbox;display:box;display:flex;-webkit-box-align:center;-moz-box-align:center;-o-box-align:center;-ms-flex-align:center;-webkit-align-items:center;align-items:center}.md-footnote p{line-height:16px}.md-footnote-anchor{padding:2px 6px;margin-right:10px;text-align:center;font-weight:700;color:#e92c6c}.ly-custom-subheading .md-footnote-anchor,.ly-lean .md-footnote-anchor{font-family:Merriweather,Georgia,serif}.md-markdown a.md-footnote-anchor{border:1px solid #e92c6c}.md-markdown a.md-footnote-anchor:hover{background-color:#e92c6c;color:#fcfcfc}.md-footnote-ref{margin-left:1px;margin-right:3px}.md-markdown a.md-footnote-ref{border-bottom:1px dotted}.md-code-block,.md-code-inline{-webkit-text-size-adjust:none;-ms-text-size-adjust:none;text-size-adjust:none;background:#fcfcf5;color:#4d4d4c}.md-code-block{line-height:24px}.md-code{padding:8px 10px}.md-code-inline{padding:0 6px}a .md-code{color:inherit}.md-code-comment{color:#8e908c}.md-code-attribute,.md-code-built_in,.md-code-constant,.md-code-literal,.md-code-number,.md-code-params,.md-code-pragma,.md-code-preprocessor,.md-code-regexp,.md-code-tag,.md-code-variable,.md-lang-css .md-code-class,.md-lang-css .md-code-id,.md-lang-css .md-code-pseudo,.md-lang-html .md-code-doctype,.md-lang-ruby .md-code-constant,.md-lang-xml .md-code-doctype,.md-lang-xml .md-code-pi,.md-lang-xml .md-code-tag .md-code-title,color #c82829{color:#f5871f}.md-lang-css .md-code-rule .md-code-attribute,.md-lang-ruby .md-code-class .md-code-title{color:#eab700}.md-code-header,.md-code-inheritance,.md-code-name,.md-code-string,.md-code-value,.md-lang-ruby .md-code-symbol,.md-lang-xml .md-code-cdata{color:#718c00}.md-code-title,.md-lang-css .md-code-hexcolor{color:#3e999f}.md-code-function,.md-lang-coffeescript .md-code-title,.md-lang-javascript .md-code-title,.md-lang-perl .md-code-sub,.md-lang-python .md-code-decorator,.md-lang-python .md-code-title,.md-lang-ruby .md-code-function .md-code-title,.md-lang-ruby .md-code-title .md-code-keyword{color:#4271ae}.md-code-keyword,.md-lang-javascript .md-code-function{color:#8959a8}.md-lang-coffeescript .md-lang-javascript,.md-lang-javascript .md-lang-xml,.md-lang-tex .md-code-formula,.md-lang-xml .md-code-cdata,.md-lang-xml .md-lang-css,.md-lang-xml .md-lang-javascript,.md-lang-xml .vbscript{opacity:.5}.md-code-deletion{background-color:rgba(244,0,30,.05);color:#f4001e}.md-code-addition{background-color:rgba(27,194,17,.05);color:#1bc211}.md-mark{background-color:rgba(255,226,112,.5);color:inherit}.md-mark span{color:inherit}.md-heading-hover{cursor:pointer;background-color:rgba(22,134,162,.1)}.mde-text-left{text-align:left}.mde-text-center{text-align:center}.mde-text-right{text-align:right}.mde-size-small{font-size:12px}.mde-size-small,.mde-size-small p{line-height:12px}.mde-size-large{font-size:36px}.mde-size-large,.mde-size-large p{line-height:36px}.mde-size-giant{font-size:72px}.mde-size-giant,.mde-size-giant p{line-height:72px}.mde-clearfix:after{content:' ';display:block;visibility:hidden;clear:both;font-size:0;height:0}.mde-quote{margin:0;padding:20px 0;border:none;border-top:5px solid rgba(0,0,0,.05);border-bottom:5px solid rgba(0,0,0,.05)}.mde-core{font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}.mde-mono{font-family:Consolas,Menlo,Monaco,'Lucida Console','Liberation Mono','DejaVu Sans Mono','Bitstream Vera Sans Mono','Courier New',monospace,serif}.ly-custom-heading .mde-heading,.ly-lean .mde-heading{font-family:Neuton,'Hoefler Text',Palatino,Baskerville,Georgia,'Times New Roman',serif}.ly-custom-subheading .mde-subheading,.ly-lean .mde-subheading{font-family:Merriweather,Georgia,serif}.mde-pad-0{padding:0}.mde-pad-5{padding:5px}.mde-pad-10{padding:10px}.mde-pad-15{padding:15px}.mde-pad-20{padding:20px}.mde-pad-25{padding:25px}.mde-pad-30{padding:30px}.mde-pad-50{padding:50px}.mde-mar-0{margin:0}.mde-mar-5{margin:5px}.mde-mar-10{margin:10px}.mde-mar-15{margin:15px}.mde-mar-20{margin:20px}.mde-mar-25{margin:25px}.mde-mar-30{margin:30px}.mde-mar-50{margin:50px}@media only screen and (min-width:900px){.mde-left{float:left}.mde-right{float:right}.mde-inline{display:inline-block;vertical-align:top}.mde-20{max-width:20%}.mde-25{max-width:25%}.mde-33{max-width:33.3333333333%}.mde-50{max-width:50%}.mde-66{max-width:66.6666666666%}.mde-75{max-width:75%}}.twitter-tweet-figure{background:0 0;padding:0}.twitter-tweet-figure:before{content:none}.twitter-tweet-figure .twitter-tweet{margin:0 auto}blockquote.twitter-tweet{overflow:hidden;color:#1c2022;background-color:#fff;border:1px solid #e1e8ed;border-radius:4px;width:500px;max-width:100%;min-width:220px;padding:1.25rem 1.25rem .725rem}blockquote.twitter-tweet:before{content:none}blockquote.twitter-tweet p{white-space:pre-wrap;font:16px/1.4 Helvetica,Roboto,'Segoe UI',Calibri,'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}blockquote.twitter-tweet a,blockquote.twitter-tweet a:visited{color:#2b7bb9}.wy-container{margin:0 auto;padding:20px 0;max-width:800px}.wy-container .md-markdown p{line-height:22px;margin:10px 0}.wy-container .md-markdown p:first-child{margin-top:0}.wy-container .md-markdown p:last-child{margin-bottom:0}.wy-container .md-markdown blockquote:not(.twitter-tweet){padding:10px 0}.wy-container .md-code-block{margin:0;padding:10px;white-space:pre-wrap}.wy-table{width:100%;padding:0}.wy-td{padding:0}.wy-section-link,.wy-section-markdown,.wy-section-poll,.wy-section-summary{padding-top:25px}.wy-section-thanks{margin-top:25px;padding:10px;font-size:15px;background-color:#f2fcf2}.wy-header-text,.wy-issue{display:inline-block;margin:10px 0;line-height:24px}.wy-issue{float:right;font-size:12px}.wy-issue-content{display:block;padding:0 5px;background-color:#fcfcfc}.wy-section-header{padding-top:40px}.wy-section-header h1,.wy-section-header h2,.wy-section-header h3,.wy-section-header h4,.wy-section-header h5,.wy-section-header h6{margin:0}.wy-section-header p{line-height:inherit}.wy-header-td{padding:0}.wy-header-content{margin:0 10px}.wy-header-text{color:#fcfcfc;text-shadow:1px 1px 0 #1a4d7f;font-weight:700;font-size:24px}.wy-content{padding-bottom:25px}.wy-link-addendum,.wy-link-tag,.wy-link-title{display:inline-block;vertical-align:bottom;margin-bottom:10px}.wy-link-title{border-bottom:1px solid;font-size:20px;margin-right:10px}.wy-link-tag{background-color:#1a4d7f;color:#fcfcfc;text-transform:uppercase;font-size:13px;margin-right:5px;padding:2px 4px}.wy-link-tag:last-child{margin-right:0}.wy-link-addendum{color:#999;margin-left:5px}.wy-link-addendum:hover{border-bottom-color:transparent}.wy-link-title-section{position:relative}.wy-link-stats{position:absolute;right:0;background-color:#3aca96;color:#fcfcfc;border-bottom:1px solid #299a71}.wy-link-stats-logo{background-color:rgba(0,0,0,.1);color:#299a71}.wy-link-stat{margin:3px}.wy-link-description{font-size:14px;color:#666}.wy-link-source-section{margin-top:10px}.wy-link-source{margin-right:10px;margin-bottom:10px;display:inline-block;vertical-align:middle;color:#55acee}.wy-link-source-plain{color:#333}.wy-link-source.wy-link-source-plain a{color:#55acee}.wy-link-source.wy-link-source-plain a:visited{background-color:rgba(85,172,238,.04)}.wy-link-source.wy-link-source-plain a:visited .md-code-inline:before{background-color:#55acee}.wy-link-source.wy-link-source-plain a:active{outline-color:#55acee}.wy-link-source.wy-link-source-plain a:hover{border-bottom-color:#55acee}.wy-link-sponsor{background-color:transparent;color:#999;outline:#999 solid 1px}.wy-link-cell-before-image{vertical-align:middle;width:70%}.wy-link-cell-image{padding-left:10px}.wy-link-image-anchor{display:block;overflow:hidden;max-height:300px}.wy-link-image{display:block;margin:0 auto}.wy-footer-table{margin:20px 0}.wy-footer-cell{text-align:center}.wy-read-online{font-size:13px}.wy-section-link-job .wy-link-source,.wy-section-link-job .wy-link-title{font-size:14px}.wy-section-link-job .wy-link-description{font-size:12px}.wy-link-pixel{float:right}@media only screen and (max-width:500px){.wy-issue-publication,.wy-issue-separator{display:none}}.md-code-block{margin:0!important;padding:10px}</style>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Pixels vs. Bricks</h1>
                            <h2 class="article__feed"><a target="_blank" href="">blog.karenying.com</a> <span class="article__date">19 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Drawing parallels between web design and major architecture movements
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/197-acceptance.png" alt="Acceptance">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Acceptance</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">18 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/197-acceptance.png" alt="Acceptance" title="I knew that coding was really the only purpose in life" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Kubernetes en producción con Antony Goetzschel">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Kubernetes en producción con Antony Goetzschel</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">15 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>En este episodio David Vaquero charla con Antony Ricardo Goetzschel CEO y fundador en la empresa alemana <a href="https://ccsolutions.io/">ccsolutions.io </a> en Múnich y además, ingeniero DevOps en el <a href="https://www.funkemedien.de/en/" data-type="URL" data-id="https://www.funkemedien.de/en/">grupo FunkeMedien,</a> una de las mayores empresas de medios de comunicación de Alemania. Ricardo es un miembro muy activo en la comunidad Slack en español de <a href="https://rancher.com/">Rancher</a>, una plataforma para la administración de cluster de <a href="https://kubernetes.io/es/" data-type="URL" data-id="https://kubernetes.io/es/">kubernetes</a>, que permite desplegar y administrar clusters de kubernetes en varios proveedores, como Amazon, Azure, Google y OpenStack.</p>



<p>Entre las cuestiones tratadas con Antony:</p>



<ul><li>Primero hablamos de ti, ¿Cómo llega un venezolano a trabajar en una empresa alemana?</li><li>¿Cómo fue el proceso de selección?</li><li>¿Cuáles son las tareas que realizas en la empresa?</li><li>Cuéntanos en qué consiste Kubernetes</li><li>¿Cuántos clústers tenéis ya en producción?</li><li>¿Cuáles son las características más destacables?¿Qué ofrece por encima de un despliegue tradicional?</li><li>¿Qué valoras más hasta la fecha de tu experiencia trabajando con Kubernetes?</li><li>¿Qué aspectos consideras más débiles de Kubernetes?</li><li>¿Tenéis una metodología GitOps?</li><li>¿Qué recursos son interesantes para Kubernetes y Rancher?¿Y en español?</li><li>¿Qué consejos puedes dar a alguien que quiere ser ingeniero de DevOps?</li></ul>




<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Lisp Interview: more questions to CLPM author. Common Lisp at university for temporal reasoning and risk-bounded planning</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">15 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>Some days ago <a href="https://www.reddit.com/r/lisp/comments/jtla4m/common_lisp_package_manager_a_package_manager_for/">on reddit/r/lisp</a>,
we got to (re)discover CLPM, the Common Lisp Package Manager.</p>

<p>Its author, Eric Timmons aka <a href="https://github.com/daewok/">daewok</a>, was kind enough to give more context, and to answer some more questions of mine, about his use of Common Lisp in his university group.</p>

<p>Below I&rsquo;ll give an overview of CLPM, stress on how it differs from
Quicklisp, and then paste the interview.</p>

<p>/Note/: it&rsquo;s the same content as on reddit, but saved from oblivion!</p>

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->

<p><strong>Table of Contents</strong></p>

<ul>
<li><a href="#clpm">CLPM</a>

<ul>
<li><a href="#context">Context</a></li>
<li><a href="#feature-set-and-comparison-to-quicklisp">Feature set and comparison to Quicklisp</a></li>
<li><a href="#more-questions-to-eric-timmons---using-lisp-at-university-for-temporal-reasoning-and-risk-bounded-planning">More questions to Eric Timmons - using Lisp at university for temporal reasoning and risk-bounded planning.</a></li>
</ul></li>
</ul>

<!-- markdown-toc end -->

<h2 id="clpm">CLPM</h2>

<h3 id="context">Context</h3>

<blockquote>
<p>CLPM author here. I&rsquo;m so happy (and shocked!) that people have found CLPM, especially given how little advertising I&rsquo;ve done for it! I&rsquo;m a PhD student in a group that does a large amount of our coding in Common Lisp. A big part of why I wrote CLPM, for better or worse, is that my group has not done a great job at versioning or maintaining backward compatibility of our various libraries throughout the years. I&rsquo;m a very applications focused person and it was incredibly frustrating when I needed to deploy some of our code that had worked in the past but found that it bit rotted. And then when I would eventually get everything rolled back to the correct point in time I had no way to release a fix that was no longer applicable on the master branch (normally because the relevant API no longer existed or had been modified in a non-backward compatible way). So I hoped that encouraging/requiring actual version numbers would help us better communicate and reason about our changes over time (and be able to release minor changes to older versions of the code) and the locking capabilities would help save us in situations like giving a demo on short notice.</p>

<p>I use CLPM as my daily driver as do a couple of the other Lisp-heavy students. It&rsquo;s been going well so far, but I was planning to convert and get feedback from a few more before attempting to spread CLPM beyond my group. That&rsquo;s unfortunately taken a lot longer than I wanted due to COVID, my personal life taking more time than normal (no worries, it&rsquo;s for good reasons!), and just general research related tasks continuing to pop up.</p>

<p>Now that the cat&rsquo;s out of the bag though, I&rsquo;d be happy to hear any feedback on it! I&rsquo;m especially interested in the perspectives of people outside my group since I&rsquo;ve been holding their hand in getting it set up and explaining my reasoning/goals to them almost every step of the way.</p>
</blockquote>

<h3 id="feature-set-and-comparison-to-quicklisp">Feature set and comparison to Quicklisp</h3>

<p>CLPM&rsquo;s <a href="https://gitlab.common-lisp.net/clpm/clpm">project page</a> (here&rsquo;s a non-official <a href="https://github.com/lisp-mirror/clpm">GitHub mirror</a>, if that helps you browse the repository) lists the project goals. Here&rsquo;s my comment and comparison to Quicklisp.</p>

<h4 id="support-and-encourage-explicitly-versioned-systems"><em>Support and encourage explicitly versioned systems</em></h4>

<blockquote>
<p>When a package upgrade introduces regressions, we should be able to use an older version.</p>
</blockquote>

<p>But, that is currently not possible with the Quicklisp client, we must refer to other tools (Qlot) or manual workarounds.</p>

<p>CLPM allows to use monthly-based releases, just as Quicklisp and from Quicklisp, but it also started <em>a new source registry</em> for Common Lisp libraries, which would:</p>

<ul>
<li>allow to <em>precisely pin dependencies</em>. It is possible to do so in ASDF, but this propriety is not used in Quicklisp (or barely, or not by most of the library authors, because Quicklisp comes as monthly distributions anyways).</li>
<li>allow to get the library&rsquo;s home URL, which surprisingly isn&rsquo;t in Quicklisp&rsquo;s metadata (last time I checked, I might be wrong). We have to look at the quicklisp-projects repository.</li>
<li>it would enforce the libraries to be on version control. Currently Quicklisp also accepts source files (as archives).</li>
</ul>

<h4 id="support-installing-multiple-package-versions-globally-and-locally"><em>Support installing multiple package versions, globally and locally</em></h4>

<p>CLPM allows to <em>manage dependencies per project</em> (per directory), and globally. With Quicklisp, it&rsquo;s only globally. Otherwise we must rely to Qlot, or load projects more manually.</p>

<p>While I personally find the Quicklisp approach great, simple to use,
sufficient in most cases and a better default than always pinning
dependencies manually, comes a point in a software life when we need
project-local dependencies.</p>

<h4 id="support-ci-cd-workflows-ship-pre-built-binaries"><em>Support CI/CD workflows - ship pre-built binaries</em></h4>

<blockquote>
<p><em>CLPM is distributed in both binary and source form</em>. Source for hackers or people who want to use a different feature set and binary for quick and easy installation in other cases.</p>
</blockquote>

<p>That&rsquo;s simpler to install, to use on CI systems, or to make you software&rsquo;s users install the dependencies.</p>

<p>Currently we can use Roswell to install Quicklisp libraries (and software) from the command line, but its installation isn&rsquo;t crystal straightforward or super fast either.</p>

<h4 id="minimize-footprint-in-development-images-and-deployments"><em>Minimize footprint in development images and deployments</em></h4>

<p>When you use CLPM and you build a binary of your program, the binary won&rsquo;t contain CLPM (or only if you choose to). When we use Quicklisp, the built image contains Quicklisp (which can be very useful, I use it to live-reload running web apps).</p>

<h4 id="support-https"><em>Support HTTPS</em></h4>

<p>Quicklisp currently doesn&rsquo;t download packages through HTTPS.</p>

<p>Cryptographic signature verification is coming.</p>

<h2 id="more-questions-to-eric-timmons-using-lisp-at-university-for-temporal-reasoning-and-risk-bounded-planning">More questions to Eric Timmons - using Lisp at university for temporal reasoning and risk-bounded planning.</h2>

<h3 id="what-are-you-using-cl-for-at-your-university">What are you using CL for at your university?</h3>

<p>My group&rsquo;s bread and butter is in temporal reasoning and risk-bounded planning and execution (including both activity and path planning). I&rsquo;m personally working on a high-level language for specifying robotic information gathering missions and an executive to plan and dispatch the missions. Language wise I think you could say it&rsquo;s a stripped down Screamer when it comes to non-deterministic programming and constraints, coupled with parallel and sequential operators and the ability to temporally constrain the relative execution time of different events in the program. There&rsquo;s a few more things, such as support for expressing PDDL-like operators, but that&rsquo;s the 10,000 foot view.</p>

<p>I mentioned I&rsquo;m applications focused and a lot of that focus of late has been on mission planning for autonomous underwater vehicles. Unfortunately, most of our code is running off the vehicles, but we&rsquo;re slowing moving more reasoning onboard.</p>

<h3 id="do-you-know-other-teams-in-your-university-that-are-using-cl-or-a-lisp-like-language">Do you know other teams in your university that are using CL? (or, a lisp-like language?)</h3>

<p>I know other groups do but I&rsquo;m not sure of the details, unfortunately.</p>

<h3 id="so-why-cl-does-it-have-a-killer-feature-that-make-your-group-use-it-it-doesn-t-have-to-have-one-though">So, why CL? Does it have a killer feature that make your group use it? (it doesn&rsquo;t have to have one though!)</h3>

<p>Ha, we started using CL long before I joined the group. From what I hear, it was originally mostly for practical reasons: it&rsquo;s the language my group&rsquo;s PI [Principal Investigator] knows the best and he needed to be able to hop onto any given project as students cycled on and off. But with respect to my personal research, I think CL is the best language for it. You can&rsquo;t beat its macros for defining DSLs and I have a lot of DSLs both in my high level language (along with some MOP code!) and the planner. Something my advisor said to me about CL that really stuck with me is that it is a fantastic language to let you write a new language for the problem you want to solve, and specifying the problem is more than half the battle in solving it.</p>

<h3 id="are-there-downsides-do-you-have-difficulties-in-certain-areas-formation">Are there downsides, do you have difficulties in certain areas? (formation?)</h3>

<p>The biggest downside for us is that students rarely come into the group with CL experience and in rare cases some students refuse to really dive into our Lisp code and stick with something they&rsquo;re more familiar with (such as Python) and end up reinventing poor facsimiles of things that exist.</p>

<p>Ignoring that particular issue, using CL does add a non-trivial amount of time to on-boarding new students. Then beyond that, we had the aforementioned issues with not versioning correctly and not maintaining backward compatibility. While that&rsquo;s really, at it&rsquo;s core, a social issue that would exist regardless of language (and is hard to avoid given the natural turn-over rate of students), the lack of a package manager with features similar to those provided in the languages students come in knowing these days certainly didn&rsquo;t help.</p>

<h3 id="how-did-you-personally-start-with-cl">How did you personally start with CL?</h3>

<p>I started with CL when I joined this group. I was given a URL to Practical Common Lisp and off I went. I kind of fell down the rabbit hole at some point and spent more time learning about the language than doing research (oops), but I think that&rsquo;s paid off by this point as I can make CL do nearly anything I can think of. The first draft (or several&hellip;) of my code may not be pretty, but they&rsquo;ll work, get the job done, and I can continue working on abstractions and mini-DSLs to my heart&rsquo;s content whenever I need to make things more clear or performant.</p>

<h3 id="can-you-tell-us-more-about-your-software-stack-implementations-most-loved-libraries-deployment-story-docker-interface-with-other-tools-monitoring">Can you tell us more about your software stack? (implementations, most loved libraries, deployment story (docker?), interface with other tools (monitoring?)…)</h3>

<p>We largely use SBCL these days. I routinely try to test on the other big Free implementations as well (ABCL, CCL, ECL) both out of a desire to be portable for portability sake and to make the code more widely useful if we ever get around to sharing it beyond our collaborators more (which I am cautiously hopeful will happen). I particularly love Hunchentoot, Drakma, basically anything from Edi Weitz, log4cl, closer-mop, and, of course, CFFI.</p>

<p>We do a lot of our deployment with Docker (which is why I&rsquo;m currently maintaining a number of CL related Docker images). I occasionally deploy things using Kubernetes (e.g., when we want to deploy our planners as a service for the students in my advisor&rsquo;s classes to use). I personally love Kubernetes, but I&rsquo;ve found that it&rsquo;s difficult to get other students up to speed on it (let alone use it!) because it&rsquo;s just one more set of things for them to learn when their focus is on graduating.</p>

<p>We&rsquo;re also working on getting more of our code running on ARM64 processors, since that&rsquo;s largely what we have available to us for low-power robots. That&rsquo;s proving to be a bit of a challenge, unfortunately because SBCL is fairly memory hungry and our algorithms are also inherently memory hungry. But in the end I think it&rsquo;ll be fine as it&rsquo;s a driving force to get us to do only the necessary reasoning onboard.</p>

<p>We don&rsquo;t have any great stories with regard to interfaces with other tools, but I have been meaning to pick up prometheus.cl and give it a try.</p>

<h3 id="anything-more-to-add">Anything more to add?</h3>

<p>CL is awesome! Nothing else comes to mind right now.</p>

<hr />

<p>Thanks again Eric.</p>

<hr />

<div style='margin-top:80px'>
<a href='https://ko-fi.com/K3K828W0V' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://cdn.ko-fi.com/cdn/kofi2.png?v=2' border='0' alt='ko-fi button' title='Yes, it helps (no fixed nor big income today) and money goes to Lisp development, for me or contributors. Thanks!'/></a>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Extending project.el</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Manuel Uberti</a> <span class="article__date">14 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>In my <a href="https://www.manueluberti.eu/emacs/2020/09/18/project/">first appreciation</a> of <code class="language-plaintext highlighter-rouge">project.el</code> I wrote about a patch for
<code class="language-plaintext highlighter-rouge">project--files-in-directory</code>. It’s a working solution, I won’t deny that, but
patching code always feels hacky. It’s like a dirty workaround you cannot avoid
to look at every time you visit your Emacs configuration.</p>

<p>By inspecting the code of <code class="language-plaintext highlighter-rouge">project.el</code> I noticed that <code class="language-plaintext highlighter-rouge">project-files</code> is a generic
function. In Emacs Lisp parlance, a generic function specifies an abstract
operation with the actual implementation provided by methods<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>. This simply means
that I can devise my own implementation of <code class="language-plaintext highlighter-rouge">project-files</code>.</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nv">cl-defmethod</span> <span class="nv">project-root</span> <span class="p">((</span><span class="nv">project</span> <span class="p">(</span><span class="nv">head</span> <span class="nv">local</span><span class="p">)))</span>
  <span class="p">(</span><span class="nb">cdr</span> <span class="nv">project</span><span class="p">))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">mu--project-files-in-directory</span> <span class="p">(</span><span class="nv">dir</span><span class="p">)</span>
  <span class="s">"Use `fd' to list files in DIR."</span>
  <span class="p">(</span><span class="k">let*</span> <span class="p">((</span><span class="nv">default-directory</span> <span class="nv">dir</span><span class="p">)</span>
         <span class="p">(</span><span class="nv">localdir</span> <span class="p">(</span><span class="nv">file-local-name</span> <span class="p">(</span><span class="nv">expand-file-name</span> <span class="nv">dir</span><span class="p">)))</span>
         <span class="p">(</span><span class="nv">command</span> <span class="p">(</span><span class="nb">format</span> <span class="s">"fd -t f -0 . %s"</span> <span class="nv">localdir</span><span class="p">)))</span>
    <span class="p">(</span><span class="nv">project--remote-file-names</span>
     <span class="p">(</span><span class="nb">sort</span> <span class="p">(</span><span class="nv">split-string</span> <span class="p">(</span><span class="nv">shell-command-to-string</span> <span class="nv">command</span><span class="p">)</span> <span class="s">"\0"</span> <span class="no">t</span><span class="p">)</span>
           <span class="nf">#'</span><span class="nb">string&lt;</span><span class="p">))))</span>

<span class="p">(</span><span class="nv">cl-defmethod</span> <span class="nv">project-files</span> <span class="p">((</span><span class="nv">project</span> <span class="p">(</span><span class="nv">head</span> <span class="nv">local</span><span class="p">))</span> <span class="k">&amp;optional</span> <span class="nv">dirs</span><span class="p">)</span>
  <span class="s">"Override `project-files' to use `fd' in local projects."</span>
  <span class="p">(</span><span class="nb">mapcan</span> <span class="nf">#'</span><span class="nv">mu--project-files-in-directory</span>
          <span class="p">(</span><span class="nb">or</span> <span class="nv">dirs</span> <span class="p">(</span><span class="nb">list</span> <span class="p">(</span><span class="nv">project-root</span> <span class="nv">project</span><span class="p">)))))</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">project.el</code> has to be made aware of my <code class="language-plaintext highlighter-rouge">local</code> type now.</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">defun</span> <span class="nv">mu-project-try-local</span> <span class="p">(</span><span class="nv">dir</span><span class="p">)</span>
  <span class="s">"Determine if DIR is a non-Git project.
DIR must include a .project file to be considered a project."</span>
  <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">root</span> <span class="p">(</span><span class="nv">locate-dominating-file</span> <span class="nv">dir</span> <span class="s">".project"</span><span class="p">)))</span>
    <span class="p">(</span><span class="nb">and</span> <span class="nv">root</span> <span class="p">(</span><span class="nb">cons</span> <span class="ss">'local</span> <span class="nv">root</span><span class="p">))))</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">mu-project-try-local</code> just needs to be added to <code class="language-plaintext highlighter-rouge">project-find-functions</code> to
make sure my non-Git projects become known and remembered across sessions when
I hit <kbd>C-x p p</kbd>. This is way more elegant than the previous patch.</p>

<p>Since I also never use Git submodules, I can push my extensions a little further.</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">defun</span> <span class="nv">mu--backend</span> <span class="p">(</span><span class="nv">dir</span><span class="p">)</span>
  <span class="s">"Check if DIR is under Git, otherwise return nil."</span>
  <span class="p">(</span><span class="nb">when</span> <span class="p">(</span><span class="nv">locate-dominating-file</span> <span class="nv">dir</span> <span class="s">".git"</span><span class="p">)</span>
    <span class="ss">'Git</span><span class="p">))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">mu-project-try-vc</span> <span class="p">(</span><span class="nv">dir</span><span class="p">)</span>
  <span class="s">"Determine if DIR is a project.
This is a thin variant of `project-try-vc':
- It takes only Git into consideration
- It does not check for submodules"</span>
  <span class="p">(</span><span class="k">let*</span> <span class="p">((</span><span class="nv">backend</span> <span class="p">(</span><span class="nv">mu--backend</span> <span class="nv">dir</span><span class="p">))</span>
         <span class="p">(</span><span class="nv">root</span>
          <span class="p">(</span><span class="nb">when</span> <span class="p">(</span><span class="nb">eq</span> <span class="nv">backend</span> <span class="ss">'Git</span><span class="p">)</span>
            <span class="p">(</span><span class="nb">or</span> <span class="p">(</span><span class="nv">vc-file-getprop</span> <span class="nv">dir</span> <span class="ss">'project-git-root</span><span class="p">)</span>
                <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">root</span> <span class="p">(</span><span class="nv">vc-call-backend</span> <span class="nv">backend</span> <span class="ss">'root</span> <span class="nv">dir</span><span class="p">)))</span>
                  <span class="p">(</span><span class="nv">vc-file-setprop</span> <span class="nv">dir</span> <span class="ss">'project-git-root</span> <span class="nv">root</span><span class="p">))))))</span>
    <span class="p">(</span><span class="nb">and</span> <span class="nv">root</span> <span class="p">(</span><span class="nb">cons</span> <span class="ss">'vc</span> <span class="nv">root</span><span class="p">))))</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">mu-project-try-vc</code> now replaces <code class="language-plaintext highlighter-rouge">project-try-vc</code> in <code class="language-plaintext highlighter-rouge">project-find-functions</code>.</p>

<h2 id="notes">Notes</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>See <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Generic-Functions.html">Generic Functions</a> in the manual. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Extending project.el</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Manuel Uberti</a> <span class="article__date">14 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>In my <a href="https://www.manueluberti.eu/emacs/2020/09/18/project/">first appreciation</a> of <code class="language-plaintext highlighter-rouge">project.el</code> I wrote about a patch for
<code class="language-plaintext highlighter-rouge">project--files-in-directory</code>. It’s a working solution, I won’t deny that, but
patching code always feels hacky. It’s like a dirty workaround you cannot avoid
to look at every time you visit your Emacs configuration.</p>

<p>By inspecting the code of <code class="language-plaintext highlighter-rouge">project.el</code> I noticed that <code class="language-plaintext highlighter-rouge">project-files</code> is a generic
function. In Emacs Lisp parlance, a generic function specifies an abstract
operation with the actual implementation provided by methods<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>. This simply means
that I can devise my own implementation of <code class="language-plaintext highlighter-rouge">project-files</code>.</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nv">cl-defmethod</span> <span class="nv">project-root</span> <span class="p">((</span><span class="nv">project</span> <span class="p">(</span><span class="nv">head</span> <span class="nv">local</span><span class="p">)))</span>
  <span class="p">(</span><span class="nb">cdr</span> <span class="nv">project</span><span class="p">))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">mu--project-files-in-directory</span> <span class="p">(</span><span class="nv">dir</span><span class="p">)</span>
  <span class="s">"Use `fd' to list files in DIR."</span>
  <span class="p">(</span><span class="k">let*</span> <span class="p">((</span><span class="nv">default-directory</span> <span class="nv">dir</span><span class="p">)</span>
         <span class="p">(</span><span class="nv">localdir</span> <span class="p">(</span><span class="nv">file-local-name</span> <span class="p">(</span><span class="nv">expand-file-name</span> <span class="nv">dir</span><span class="p">)))</span>
         <span class="p">(</span><span class="nv">command</span> <span class="p">(</span><span class="nb">format</span> <span class="s">"fd -t f -0 . %s"</span> <span class="nv">localdir</span><span class="p">)))</span>
    <span class="p">(</span><span class="nv">project--remote-file-names</span>
     <span class="p">(</span><span class="nb">sort</span> <span class="p">(</span><span class="nv">split-string</span> <span class="p">(</span><span class="nv">shell-command-to-string</span> <span class="nv">command</span><span class="p">)</span> <span class="s">"\0"</span> <span class="no">t</span><span class="p">)</span>
           <span class="nf">#'</span><span class="nb">string&lt;</span><span class="p">))))</span>

<span class="p">(</span><span class="nv">cl-defmethod</span> <span class="nv">project-files</span> <span class="p">((</span><span class="nv">project</span> <span class="p">(</span><span class="nv">head</span> <span class="nv">local</span><span class="p">))</span> <span class="k">&amp;optional</span> <span class="nv">dirs</span><span class="p">)</span>
  <span class="s">"Override `project-files' to use `fd' in local projects."</span>
  <span class="p">(</span><span class="nb">mapcan</span> <span class="nf">#'</span><span class="nv">mu--project-files-in-directory</span>
          <span class="p">(</span><span class="nb">or</span> <span class="nv">dirs</span> <span class="p">(</span><span class="nb">list</span> <span class="p">(</span><span class="nv">project-root</span> <span class="nv">project</span><span class="p">)))))</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">project.el</code> has to be made aware of my <code class="language-plaintext highlighter-rouge">local</code> type now.</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">defun</span> <span class="nv">mu-project-try-local</span> <span class="p">(</span><span class="nv">dir</span><span class="p">)</span>
  <span class="s">"Determine if DIR is a non-Git project.
DIR must include a .project file to be considered a project."</span>
  <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">root</span> <span class="p">(</span><span class="nv">locate-dominating-file</span> <span class="nv">dir</span> <span class="s">".project"</span><span class="p">)))</span>
    <span class="p">(</span><span class="nb">and</span> <span class="nv">root</span> <span class="p">(</span><span class="nb">cons</span> <span class="ss">'local</span> <span class="nv">root</span><span class="p">))))</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">mu-project-try-local</code> just needs to be added to <code class="language-plaintext highlighter-rouge">project-find-functions</code> to
make sure my non-Git projects become known and remembered across sessions when
I hit <kbd>C-x p p</kbd>. This is way more elegant than the previous patch.</p>

<p>Since I also never use Git submodules, I can push my extensions a little further.</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">defun</span> <span class="nv">mu--backend</span> <span class="p">(</span><span class="nv">dir</span><span class="p">)</span>
  <span class="s">"Check if DIR is under Git, otherwise return nil."</span>
  <span class="p">(</span><span class="nb">when</span> <span class="p">(</span><span class="nv">locate-dominating-file</span> <span class="nv">dir</span> <span class="s">".git"</span><span class="p">)</span>
    <span class="ss">'Git</span><span class="p">))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">mu-project-try-vc</span> <span class="p">(</span><span class="nv">dir</span><span class="p">)</span>
  <span class="s">"Determine if DIR is a project.
This is a thin variant of `project-try-vc':
- It takes only Git into consideration
- It does not check for submodules"</span>
  <span class="p">(</span><span class="k">let*</span> <span class="p">((</span><span class="nv">backend</span> <span class="p">(</span><span class="nv">mu--backend</span> <span class="nv">dir</span><span class="p">))</span>
         <span class="p">(</span><span class="nv">root</span>
          <span class="p">(</span><span class="nb">when</span> <span class="p">(</span><span class="nb">eq</span> <span class="nv">backend</span> <span class="ss">'Git</span><span class="p">)</span>
            <span class="p">(</span><span class="nb">or</span> <span class="p">(</span><span class="nv">vc-file-getprop</span> <span class="nv">dir</span> <span class="ss">'project-git-root</span><span class="p">)</span>
                <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">root</span> <span class="p">(</span><span class="nv">vc-call-backend</span> <span class="nv">backend</span> <span class="ss">'root</span> <span class="nv">dir</span><span class="p">)))</span>
                  <span class="p">(</span><span class="nv">vc-file-setprop</span> <span class="nv">dir</span> <span class="ss">'project-git-root</span> <span class="nv">root</span><span class="p">))))))</span>
    <span class="p">(</span><span class="nb">and</span> <span class="nv">root</span> <span class="p">(</span><span class="nb">cons</span> <span class="ss">'vc</span> <span class="nv">root</span><span class="p">))))</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">mu-project-try-vc</code> now replaces <code class="language-plaintext highlighter-rouge">project-try-vc</code> in <code class="language-plaintext highlighter-rouge">project-find-functions</code>.</p>

<h2 id="notes">Notes</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>See <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Generic-Functions.html">Generic Functions</a> in the manual. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://storage.ko-fi.com/cdn/useruploads/display/39a60d12-fa99-409d-873f-853318f811d8_orly-cover.png" alt="You can buy a preview of the Common Lisp Cookbook in ePub">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">You can buy a preview of the Common Lisp Cookbook in ePub</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">13 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://storage.ko-fi.com/cdn/useruploads/display/39a60d12-fa99-409d-873f-853318f811d8_orly-cover.png" alt="" /></p>

<p><strong>See here: <a href="https://ko-fi.com/s/01fee22a32">https://ko-fi.com/s/01fee22a32</a></strong></p>

<p>Let me try something: I propose you here to buy the ePub, even though it is meant to be available for free.</p>

<p>I contributed quite a lot to the Cookbook and I found since the
beginning that having an EPUB and/or a PDF version would be very
useful. Some years later, nobody did it, and I finally wrote a script
to bundle all the pages together and generate an ePub, and then a
PDF. It isn&rsquo;t finished though, it needs more editing, and it would
also be great to write a proper LaTeX style for the PDF. As I have one
version on disk, I thought on giving potential supporters the
opportunity to read it and fund the remaining work, or simply give a sign of
encouragement. It&rsquo;s also the opportunity for me to try this new Ko-fi
feature, and to practice speaking about financial support…</p>

<p>Let&rsquo;s turn it another way: if you support me, here&rsquo;s a reward for you, an exclusivity.
And in any case, hold on, this ePub will eventually be available for everybody.</p>

<p>Thanks!</p>

<hr />

<p>ps: About money: yes, it does a difference right now, because I don&rsquo;t
have a fixed, nor big, income. I am trying to live on my free software
activities. I have a few clients, but not enough, so I&rsquo;m trying to
diversify and get some earnings from my Lisp work. I even pay lisp
contributors to write free software (we are currently adding Stripe
payments to a web application. When it&rsquo;s done, you&rsquo;ll know everything
about it). So, the money has an impact.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://staticinstapaper.s3-us-west-2.amazonaws.com/blog/instapaper-mac.png" alt="Instapaper now available on macOS">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Instapaper now available on macOS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Instapaper</a> <span class="article__date">11 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>We’re excited to announce that Instapaper is now available on macOS! You can <a href="https://apps.apple.com/us/app/instapaper/id288545208">download Instapaper from the App Store</a> on your Mac to read all your articles offline, in full screen mode, and with all the great features from the iOS app.</p><figure data-orig-width="3840" data-orig-height="2160" data-orig-src="https://staticinstapaper.s3-us-west-2.amazonaws.com/blog/instapaper-mac.png" class="tmblr-full"><img src="https://64.media.tumblr.com/ebb603b827c0ea78ce1b0335d7400aca/7eb55e2734d7b44e-42/s540x810/5b8fe421361f6c893f96297279f0a317be54a69b.png" alt="image" data-orig-width="3840" data-orig-height="2160" data-orig-src="https://staticinstapaper.s3-us-west-2.amazonaws.com/blog/instapaper-mac.png"/></figure><p>We customized the interfaces and features to make the app feel interactive and at home on Mac. This includes a side-by-side view of folders and article list, and hover states to highlight content on mouseover.<br/></p><p>We also included new features for managing articles like hover actions, which allows you to easily like, move, archive, and delete directly from the list. With drag &amp; drop, you can quickly organize articles directly into folders.<br/></p><figure data-orig-width="1280" data-orig-height="800" data-orig-src="https://staticinstapaper.s3-us-west-2.amazonaws.com/blog/2+Drag+%26+Drop.png" class="tmblr-full"><img src="https://64.media.tumblr.com/77bee792f75b5699a8e77259b8832ab5/7eb55e2734d7b44e-3c/s540x810/686f70a1bc9cc6a9dd087a4e71c40ef62ba96ac6.png" alt="image" data-orig-width="1280" data-orig-height="800" data-orig-src="https://staticinstapaper.s3-us-west-2.amazonaws.com/blog/2+Drag+%26+Drop.png"/></figure><p>Instapaper for Mac has full keyboard navigation support, so you can navigate, read, and manage your articles using only the keyboard. Here are some of the supported keyboard shortcuts:<br/></p><p><b>Navigation</b></p><ul><li>↑: Previous Item</li><li>↓: Next Item</li><li>⏎: Select Item</li><li>Space: Page Down</li><li>⇧Space: Page Up</li><li>⌘F: Search</li><li>⇧⌘F: Search All Articles</li><li>⌘,: Preferences</li><li>⌘←: Navigate Back</li></ul><p><b>Article Management</b></p><ul><li>⌘R: Refresh Articles</li><li>⇧⌘A: Archive Article</li><li>⇧⌘D: Delete Article</li><li>⇧⌘M: Move Article</li></ul><p><b>Appearance</b></p><ul><li>⌘1: Light Mode</li><li>⌘2: Sepia Mode</li><li>⌘3: Gray Mode</li><li>⌘4: Dark Mode</li></ul><p>All available shortcuts can be found in the app menu bar located at the top of the screen.</p><p>Instapaper for macOS supports Intel and Apple Silicon Macs.</p><p><b>Instapaper iOS 8.0</b></p><p>Today we are also announcing the release of Instapaper iOS 8.0. This release contains a number of improvements that laid the foundation for building the macOS app, and also includes a few iOS-specific updates.</p><p>We redesigned the share sheet to be faster and easier to use. After saving, simply swipe down to dismiss and return to the app you were using. It’s a small change that makes a big difference in saving speed.</p><figure data-orig-width="2000" data-orig-height="2000" class="tmblr-full"><img src="https://64.media.tumblr.com/c70546f373b5fb179d388118be916824/7eb55e2734d7b44e-7f/s540x810/2d32ce4ae2cc65504614e8e77859ceea90c19112.png" alt="image" data-orig-width="2000" data-orig-height="2000"/></figure><p>Additionally, we improved the pagination feature so there’s less text clipping in a variety of different situations.</p><p>That’s Instapaper 8.0 for iOS and macOS! Instapaper for Mac has been a long standing request from our customers, and we’re really excited to bring all of the great functionality from iOS to macOS.</p><p>As always, we want to hear your questions, feature requests, and/or issues. That feedback directly informs our roadmap, and we’d love to hear from you via email to <a href="mailto:support@help.instapaper.com">support@help.instapaper.com</a> or <a href="https://twitter.com/InstapaperHelp">@InstapaperHelp</a> on Twitter.</p><p>Thank you for using Instapaper!</p><p>– Instapaper Team</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/196-effort-splitting.png" alt="Effort Splitting">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Effort Splitting</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">10 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/196-effort-splitting.png" alt="Effort Splitting" title="Nothing that 2 adapters and 1 transformer can't handle" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Front es el nuevo full stack y digitalización made in Spain">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Front es el nuevo full stack y digitalización made in Spain</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">08 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Si bien en la mayoría de los episodios nos centramos en una cuestión o entrevista, para este episodio hemos seleccionado dos artículos y una noticia de interés para la profesión del desarrollo web. Empezamos comentando el artículo de Chris Coyier publicado en lncrement y que lleva por título <a href="https://increment.com/frontend/when-frontend-means-full-stack/">When frontend means full stack.</a> Continuamos con una noticia reciente aparecida en Valencia Plaza y que hace referencia al descubrimiento de <a href="https://valenciaplaza.com/app-global-omnium-emivasa-datos-valencia">un grave error de seguridad en el acceso a una aplicación móvil.</a> Por último comentamos la columna de opinión publicada en el digital El Confidencial por Eduardo Manchón y que lleva por título <a href="https://blogs.elconfidencial.com/tecnologia/tribuna/2020-11-03/consultoria_2816084/">Las consultoras están matando al industria: la digitalización &#8216;made in Spain&#8217; hace agua.</a></p>



<h2>Cuando el frontend quiere decir full stack</h2>



<p>El artículo escrito por el conocido desarrollador Chris Coyier dibuja un acertada línea sobre el estado actual de la profesión del desarrollador frontend. Según comenta Coyier en su artículo, «los desarrolladores de frontend  se están haciendo preguntas que alguna vez habrían sido respondidas exclusivamente por los desarrolladores de backend». Los artículos de Chris Coyier suelen analizar con bastante certeza, la situación actual de la profesión. En este artículo se muestra cómo ha evolucionado el perfil del desarrollador web, las habilidades que se le piden a una persona encargada de la parte del frontal y cómo hoy en día, las opciones para la construcción de un sitio web, son enormemente complejas y también diversas.</p>



<p>Quizás una de las mejores frases del artículo sea que «el término «full stack» ha llegado a significar en gran medida «un desarrollador de frontend que hace una buena cantidad de las cosas que un desarrollador de backend solía hacer».</p>



<h2>App deja al descubierto datos personales de miles de vecinos de Valencia</h2>



<p>Andros nos cuenta esta noticia aparecida recientemente en el digital Valencia Plaza, en el que se cuenta como un profesor de la Universidad de Valencia, halló importantes defectos de seguridad en la aplicación de la empresa encargada de la gestión de aguas en Valencia.</p>



<p>Como comenta Andros, en el momento de comprobar él mismo esta información, el acceso a la app de la empresa había sido bloqueado y no se había informado del problema a los usuarios. También comentamos lo sorprendente que resulta que desde la empresa afectada, respondan que «se requieren unos mínimos conocimientos de informática para detectarlos».</p>







<h2>Digitalización made in Spain hace agua</h2>



<p>Para seguir con el mundo de las consultoras y de las aguas (curiosamente), David comenta la reciente columna de <a href="https://twitter.com/eduardomanchon">Eduardo Manchón</a>, donde se relata el sistema de desarrollo tecnológico en España, a través de consultoras. Según explica el autor del artículo «las empresas españolas han cometido el error de delegar su digitalización y dejarla en manos de consultoras».</p>



<p>Este artículo pone de manifiesto la necesidad de crear desde dentro de las empresas, una cultura tecnológica liderada por personas que comprendan bien como sea desarrollan los negocios en una economía digital.  Como indica muy bien Manchón, «la digitalización es mucho más que crear una web o una &#8216;app&#8217;, es un aprendizaje que implica cambios profundos en las personas y en el funcionamiento de las organizaciones».</p>



<p>En definitiva, un episodio diferente y con diversidad de temas orientados a la profesión del desarrollo y la tecnología en internet.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Boost Visual Accessibility by Auto Flipping Text Color</h1>
                            <h2 class="article__feed"><a target="_blank" href="">blog.karenying.com</a> <span class="article__date">07 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        White text on light backgrounds is cancelled. Dynamically change text color based on background color instead. Even Facebook gets this wrong. Do you?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">October 2020 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">04 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Read more updates from Malli, Practicalli, Clj-kondo/babashka/sci, and Datahike
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/195-election.png" alt="Election">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Election</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">03 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/195-election.png" alt="Election" title="It's now or never folks" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Chasing the Pixel-Perfect Dream</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">02 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Is it possible to create an implementation of a design that matches to-the-pixel? Well, not really, but that shouldn't discourage us! In this article, I'll show how I became designers' best friend by leveraging a series of tricks to get my implementation looking near-pixel-perfect.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Quasar un framework Vue.js para gobernarlos a todos con Salvador Santander">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Quasar un framework Vue.js para gobernarlos a todos con Salvador Santander</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">01 11 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Invitamos a un buen amigo de este podcast para hablar sobre <a href="https://quasar.dev/" data-type="URL" data-id="https://quasar.dev/">Quasar, un completo framework para Vue.js </a>dirigido a crear interfaces de alto rendimiento sobre diferentes tecnologías. Salvador Santander es técnico de desarrollo en la sección de Informática de la <a href="http://www.juntadeandalucia.es/avra/" data-type="URL" data-id="http://www.juntadeandalucia.es/avra/">Agencia de Vivienda y Rehabilitación de Andalucía </a>(AVRA), donde se encarga del desarrollo de los sitios webs de la empresa, la arquitectura de aplicaciones y el desarrollo de aplicaciones webs.</p>



<p>Salvador nos cuenta las innumerables ventajas que ha encontrado al trabajar con Quasar y como lo está incorporando en los proyectos que desarrolla dentro de AVRA. A diferencia de otros frameworks para Vue.js, Quasar tiene como punto fuerte ser una solución única para la mayoría de necesidades presentes en un proyecto web moderno. Quasar dispone de una completísima colección de componentes basados en Material Design y permite desarrollar proyectos para  SPA, SSR, PWA, aplicaciones móviles híbridas, extensiones de navegador y hasta aplicaciones de escritorio a través de Electron.</p>



<p>Entre las cuestiones que hablamos con Salvador:</p>



<ul>
<li>En qué consiste Quasar y cómo has llegado a trabajar con este framework Vue.js</li>
<li>¿Cuáles son las características más destacables?</li>
<li>¿Qué valoras más hasta la fecha de tu experiencia trabajando con Quasar?</li>
<li>¿Qué aspectos consideras más débiles de Quasar?</li>
<li>¿Qué proyecto/s estáis haciendo con Quasar?</li>
<li>¿Qué tecnologías tienes en tu radar?</li>
</ul>



<p>Salvador Santander es un buen ejemplo de cómo en la Administración Pública se desarrollan proyectos con tecnologías nuevas y cómo se trabaja para mejorar el acceso a la información para los ciudadanos.</p>




<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q3 2020 Survey Results</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">28 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Thanks so much for your support and feedback in the latest survey. This quarter we are funding four projects $9,000 each, applications are open until 6th November 11:59pm PST.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/194-get-funded.png" alt="Get Funded">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Get Funded</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">27 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/194-get-funded.png" alt="Get Funded" title="now on Kickstarter" /></p>

<p><img src="https://www.monkeyuser.com/assets/images/2020/194-1-get-funded.png" alt="Get Funded: Expansion Packs" title="now on Kickstarter" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">v2.0 Stable Release</h1>
                            <h2 class="article__feed"><a target="_blank" href="">blog.karenying.com</a> <span class="article__date">25 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        blog.karenying.com launch ... @Medium, it’s time to break up. It’s not you. It’s me
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Wikimedia es mucho más que Wikipedia con Rubén Ojeda">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Wikimedia es mucho más que Wikipedia con Rubén Ojeda</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">25 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Para este episodio contamos con la compañía de Rubén Ojeda, coordinador de proyectos en <a href="https://wikimedia.es" data-type="URL" data-id="https://wikimedia.es">Wikimedia España</a>, la asociación sin ánimo de lucro que promueve el conocimiento libre y los proyectos Wikimedia, siendo Wikipedia el más conocido de todos. Pero Wikimedia es mucho más que la Wikipedia, y en este episodio Rubén nos contará todo el trabajo que se realiza desde la asociación y cómo favorecen un mejor acceso a la cultura y el conocimiento libre.</p>



<p>Wikimedia está detrás de proyectos de difusión tan interesantes como <a href="https://www.wikidata.org/wiki/Wikidata:Main_Page">Wikidata</a>, <a href="https://commons.wikimedia.org/wiki/Main_Page">Wikimedia Commons</a>, <a href="https://es.wikiquote.org/wiki/Portada">Wikiquote</a> o <a href="https://es.wikisource.org/wiki/Portada">Wikisource</a>, pero también de otros muchos que constituyen un formidable repositorio de información compartida y libre. </p>



<p>Con Rubén Ojeda hablamos mucho sobre Wikipedia pero también de varias cuestiones sobre Wikimedia y sus proyectos:</p>



<ul>
<li>¿Qué es la Asociación Wikimedia España y cómo se constituye aquí?</li>
<li>En qué consiste una wiki y cómo se organiza a nivel editorial.
<li>¿Cómo pueden participar los ciudadanos de los proyectos Wikimedia?</li>
<li>¿Conoce el sector público y las instituciones culturales cómo compartir conocimiento a través de vuestros proyectos?</li>
<li>¿Cuáles son las mayores amenazas al conocimiento libre en la era digital?</li>
<li>¿Cómo pueden ayudar los proyectos Wikimedia a combatir la desinformación?</li>
</ul>







<p>En definitiva una conversación muy completa para conocer la labor de Wikimedia, aspectos sobre derechos digitales, contenidos libres y conocer cómo poder colaborar en los proyectos. </p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Summer of Bugs Update 2020</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">24 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The Summer of Bugs Updates includes: clj-kondo vim-iced, DataScript, Calva, reitit, Keycloak-Clojure, cljc.java-time
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Emacs and Emanuele Severino</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Manuel Uberti</a> <span class="article__date">24 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The recently available <a href="https://emacssurvey.org/">Emacs User Survey</a> made me think, once again, about the
status of the technological world around me. The survey was painstakingly
discussed on the <a href="https://lists.gnu.org/mailman/listinfo/emacs-devel">emacs-devel</a> mailing list, and generated some interesting
reactions among people outside the core developing team as well. More
interesting for the perspective of this writing are the reactions to the
discussions on <code class="language-plaintext highlighter-rouge">emacs-devel</code>, because they reveal how great the distance between
me and some members of the Emacs community has been getting.</p>

<p>You see, I am a failed Free Software supporter. I stopped campaigning in its
favour as soon as my wife’s school closed. There I had set up everything with
Free and Open Source software, and watching the teachers effectively do their
job with technological solutions they were not accustomed to made me happy. They
did not really care about the reasons behind my choices, but they respected my
contribution and were willing to overcome the first weeks of adaptation as long
as I could guarantee a comfortable working environment. When all of this ended
and I went back to software development, Free and Open Source software became
only a private concern. While still set on Linux<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>, I left Debian for Ubuntu
because I didn’t want to spend time tinkering with my operative system to get
the best out of my Dell XPS. My distro-hopping days had come to an end. I just
wanted a system that would let me code, write, and browse the Web. I chose the
easy way.</p>

<p>However, I have never stopped paying attention to the world around me and
behaving consciously. For instance, I hate wasting technology. The
3-and-a-half-year old Dell XPS where I am writing now replaced my 8-year old
Dell Inspiron, and my 7-year old HP server is still rock-solid and here to stay.
I have a 4-year old Fairphone, my first and only smartphone, that I intend to
keep for as long as possible. Beside gadgets, I’ve been on a vegan diet for
almost seven years and I consider it one of the best and most important choices
I’ve ever made regarding the ethics of what I eat. Come to think of it, as bad
as the Coronavirus crisis is turning out to be, it “fixed” the problem of
getting to the office every day, cutting my car usage down to once a week for
groceries<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup> and thus decreasing my impact on the environment.</p>

<p>This is why mixing technocraticism with pragmatism bothers me. The words
“pragmatic” and “pragmatism” have been kind of a constant in the IT world I live
in since “The Pragmatic Programmer” passed on my shelves. As every word in every
language, “pragmatic” and “pragmatism” are complex words and their actual
meaning is not trivially describable. Immanuel Kant distinguishes between
“practical” and “pragmatic”, but without asking him we can quickly see what the
dictionary tells us. According to the Oxford Learner’s Dictionary, “pragmatic”
means “solving problems in a practical and sensible way rather than by having
fixed ideas or theories”. Treccani, however, is closer to how “pragmatic” is
known nowadays: “what is being characterised by the prevailing of practical
interests over theoretical ones and ideal <em>values</em>”. I won’t digress on the
multiple meanings of “ideal” to keep it simple and because “values” is actually
the key word for me here.</p>

<p>“Pragmatic” and “pragmatism”, in common parlance, imply a separation between
theoretical thoughts and practical action, but it is actually impossible to draw
a line between the two. Every action is informed by a thought and every thought
shines a light on the action. We can act automatically without thinking about
it, sure, but that has nothing to do with voluntary actions. When we act, we act
according to a line of reasoning, and it’s that line of reasoning that
determines the value of the action. Take my choice of using Ubuntu on this Dell
XPS. A deliberate decision born out of my desire to prefer a comfortable option
instead of spending time to value more Free Software-compliant solutions.
I acted with a plan just as I acted with a plan when I chose my vegan diet.
Which choice is more pragmatic? Which one tells you more about my ethics?</p>

<p>For years now I’ve been seeing the IT world as self-involved and rarely eager to
discuss larger issues. Problems such as the environmental crisis become material
for self-congratulatory speeches at conferences around the world, while in fact
the day after the conference we resume our lives as if nothing other than
ourselves mattered. We do that because, as Emanuele Severino says, we are scared
of what is beyond ourselves. We have replaced religious myths with the myth of
technology to find the immediate answers to deep and life-changing questions
that we do not want to investigate any further.</p>

<p>It’s not easy to understand the weight of words like “pragmatism” and
“pragmatic” in a technocratic world. We live in an age where we believe that
technology is our ultimate saviour. We are driven to accept technology as it is
because of the benefits it brings to ourselves. We trust our technology because
not doing so would result in the effort of questioning it, which in turns may
unveil the details that the technocratic world goes a long distance to hide.
More importantly, questioning technology could disclose what we really are and
need to be, something that takes will and courage to face. In a time like this,
Emanuele Severino’s claim that <em>technique</em> is the dominant power of our time
sounds as forceful as ever.</p>

<h2 id="notes">Notes</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>Yes, I didn’t write GNU/Linux. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>Yes, I am a bit of a recluse. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Emacs and Emanuele Severino</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Manuel Uberti</a> <span class="article__date">24 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The recently available <a href="https://emacssurvey.org/">Emacs User Survey</a> made me think, once again, about the
status of the technological world around me. The survey was painstakingly
discussed on the <a href="https://lists.gnu.org/mailman/listinfo/emacs-devel">emacs-devel</a> mailing list, and generated some interesting
reactions among people outside the core developing team as well. More
interesting for the perspective of this writing are the reactions to the
discussions on <code class="language-plaintext highlighter-rouge">emacs-devel</code>, because they reveal how great the distance between
me and some members of the Emacs community has been getting.</p>

<p>You see, I am a failed Free Software supporter. I stopped campaigning in its
favour as soon as my wife’s school closed. There I had set up everything with
Free and Open Source software, and watching the teachers effectively do their
job with technological solutions they were not accustomed to made me happy. They
did not really care about the reasons behind my choices, but they respected my
contribution and were willing to overcome the first weeks of adaptation as long
as I could guarantee a comfortable working environment. When all of this ended
and I went back to software development, Free and Open Source software became
only a private concern. While still set on Linux<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>, I left Debian for Ubuntu
because I didn’t want to spend time tinkering with my operative system to get
the best out of my Dell XPS. My distro-hopping days had come to an end. I just
wanted a system that would let me code, write, and browse the Web. I chose the
easy way.</p>

<p>However, I have never stopped paying attention to the world around me and
behaving consciously. For instance, I hate wasting technology. The
3-and-a-half-year old Dell XPS where I am writing now replaced my 8-year old
Dell Inspiron, and my 7-year old HP server is still rock-solid and here to stay.
I have a 4-year old Fairphone, my first and only smartphone, that I intend to
keep for as long as possible. Beside gadgets, I’ve been on a vegan diet for
almost seven years and I consider it one of the best and most important choices
I’ve ever made regarding the ethics of what I eat. Come to think of it, as bad
as the Coronavirus crisis is turning out to be, it “fixed” the problem of
getting to the office every day, cutting my car usage down to once a week for
groceries<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup> and thus decreasing my impact on the environment.</p>

<p>This is why mixing technocraticism with pragmatism bothers me. The words
“pragmatic” and “pragmatism” have been kind of a constant in the IT world I live
in since “The Pragmatic Programmer” passed on my shelves. As every word in every
language, “pragmatic” and “pragmatism” are complex words and their actual
meaning is not trivially describable. Immanuel Kant distinguishes between
“practical” and “pragmatic”, but without asking him we can quickly see what the
dictionary tells us. According to the Oxford Learner’s Dictionary, “pragmatic”
means “solving problems in a practical and sensible way rather than by having
fixed ideas or theories”. Treccani, however, is closer to how “pragmatic” is
known nowadays: “what is being characterised by the prevailing of practical
interests over theoretical ones and ideal <em>values</em>”. I won’t digress on the
multiple meanings of “ideal” to keep it simple and because “values” is actually
the key word for me here.</p>

<p>“Pragmatic” and “pragmatism”, in common parlance, imply a separation between
theoretical thoughts and practical action, but it is actually impossible to draw
a line between the two. Every action is informed by a thought and every thought
shines a light on the action. We can act automatically without thinking about
it, sure, but that has nothing to do with voluntary actions. When we act, we act
according to a line of reasoning, and it’s that line of reasoning that
determines the value of the action. Take my choice of using Ubuntu on this Dell
XPS. A deliberate decision born out of my desire to prefer a comfortable option
instead of spending time to value more Free Software-compliant solutions.
I acted with a plan just as I acted with a plan when I chose my vegan diet.
Which choice is more pragmatic? Which one tells you more about my ethics?</p>

<p>For years now I’ve been seeing the IT world as self-involved and rarely eager to
discuss larger issues. Problems such as the environmental crisis become material
for self-congratulatory speeches at conferences around the world, while in fact
the day after the conference we resume our lives as if nothing other than
ourselves mattered. We do that because, as Emanuele Severino says, we are scared
of what is beyond ourselves. We have replaced religious myths with the myth of
technology to find the immediate answers to deep and life-changing questions
that we do not want to investigate any further.</p>

<p>It’s not easy to understand the weight of words like “pragmatism” and
“pragmatic” in a technocratic world. We live in an age where we believe that
technology is our ultimate saviour. We are driven to accept technology as it is
because of the benefits it brings to ourselves. We trust our technology because
not doing so would result in the effort of questioning it, which in turns may
unveil the details that the technocratic world goes a long distance to hide.
More importantly, questioning technology could disclose what we really are and
need to be, something that takes will and courage to face. In a time like this,
Emanuele Severino’s claim that <em>technique</em> is the dominant power of our time
sounds as forceful as ever.</p>

<h2 id="notes">Notes</h2>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>Yes, I didn’t write GNU/Linux. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>Yes, I am a bit of a recluse. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/193-corporate-solution.png" alt="Corporate Solution">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Corporate Solution</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">23 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/193-corporate-solution.png" alt="Corporate Solution" title="collaboratively productize multifunctional synergy" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://markosaric.com/wp-content/uploads/favicon.ico" alt="Cloudflare Analytics review">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cloudflare Analytics review</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Marko Saric</a> <span class="article__date">20 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Disclaimer 1: I&#8217;m working on Plausible Analytics, a simple, lightweight, open-source and privacy-friendly alternative to Google Analytics. Disclaimer 2: Cloudflare reached out in July saying they&#8217;d &#8220;love to chat&#8221;. It all started with this tweet by Matthew Prince. We were upfront that we&#8217;re not looking to sell or get funded and answered their questions about&#8230; <a class="more-link" href="https://markosaric.com/cloudflare-analytics-review/">Continue reading <span class="screen-reader-text">Cloudflare Analytics review</span></a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Surprising Impact of Medium-Size Texts on PostgreSQL Performance</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">19 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Any database schema is likely to have plenty of text fields. In this article I demonstrate the surprising impact of medium-size texts on query performance.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Virtualización y contenedores con Sergio López">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Virtualización y contenedores con Sergio López</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">18 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Para este episodio contamos con la compañía desde Zaragoza con Sergio López, un desarrollador de software especializado en Sistemas Operativos y Virtualización. Con Sergio queremos trazar a grandes rasgos las diferencias existentes entre la virtualización y los contenedores. Sergio López <a href="https://twitter.com/slpnix" data-type="URL" data-id="https://twitter.com/slpnix">@slpnix</a> nos cuenta los fundamentos de estas dos tecnologías, que sin duda, han revolucionado el mundo de la computación y son una de las bases de la nube.</p>



<p>Con Sergio tratamos las siguientes cuestiones:</p>



<ul>
<li>¿Qué es la virtualización y cómo ha cambiado esta tecnología el mundo de la informática?</li>
<li>¿Qué necesitamos para virtualizar una computadora y qué influye en su rendimiento?</li>
<li>¿Qué tipos de virtualización existen y cuáles son sus diferencias? 
Ejemplos y gestión de hipervisores.</li>
<li>¿Qué son los contenedores y cuál es su origen?.</li>
<li>¿Qué tipos de tecnología de contenedores existen?.</li>
<li>Presente y futuro de las tecnologías. Principales empresas y proyectos.</li>
<li>Referencias y recursos de interés.</li>
</ul>







<p>Si queréis escuchar a Sergio López, participó también recientemente en <a href="https://www.entredevyops.es/podcasts/podcast-59.html" data-type="URL" data-id="https://www.entredevyops.es/podcasts/podcast-59.html">el Podcast Entre Devs y Ops hablando sobre Microkernels. </a> De hecho, esta entrevista le sirvió a Andros para invitar a Sergio al programa.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Customize Chrome New Tab Page in 30 Seconds</h1>
                            <h2 class="article__feed"><a target="_blank" href="">blog.karenying.com</a> <span class="article__date">16 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Override Chrome’s new tab page to create a more personalized browsing experience
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Reliable REPL switching and buffer loading with CIDER</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Manuel Uberti</a> <span class="article__date">16 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>As a Clojure developer one of the most important packages in my everyday Emacs
usage is <a href="https://cider.mx/">CIDER</a>. There are many things to love about it, chief among them the
great interactive code evaluation and a sweet integration with popular Clojure
tools. I still haven’t played with its debugging facilities, but yes, I know I should.</p>

<p>However, there is something that has been bothering me for quite a while: REPL
switching and buffer loading. I cannot pinpoint the exact moment when these
seemingly simple operations have become so unreliable, but I still remember when
switching to the correct REPL buffer according to the file in front of me used
to work as expected and loading a buffer didn’t require dealing with sessions
first.</p>

<p>Let me give you more details before this writing starts to look like a random
rant. My projects are usually web applications, which means I have to write both
Clojure and ClojureScript. The Clojure side can be backed by <code class="language-plaintext highlighter-rouge">leiningen</code> or a
<code class="language-plaintext highlighter-rouge">deps.edn</code> file, and we are set on <code class="language-plaintext highlighter-rouge">shadow-cljs</code> for ClojureScript. The first thing
I normally do is jack-in with <kbd>C-c C-x j j</kbd> and then bring up the dedicated
ClojureScript REPL with <kbd>C-c C-x j s</kbd>. Opening the browser and navigate to
something along the lines of <code class="language-plaintext highlighter-rouge">localhost:3000</code> finalises the process of setting up
the ClojureScript REPL. That’s it, another good day of coding can begin. And
soon enough frustration follows.</p>

<p>I tend to move from Clojure to ClojureScript files and vice versa quite a lot,
and hitting <kbd>C-c C-z</kbd> frequently results in an unpredictable behaviour. Sometimes
the REPL of the expected type pops up, sometimes the other one appears,
sometimes I get a message about a missing REPL in the current session. Manually
linking the current buffer to the correct REPL with <kbd>C-c C-s b</kbd> seems to fix the
problem, but it’s only a matter of time. It takes a couple of buffer switching
operations to bring the issue back. It is as if the link between the buffer and
the REPL has vanished. Even worse, without that link I can forget about <kbd>C-c C-k</kbd>
to load the buffer.</p>

<p>To overcome my frustration, I sat back and looked at how exactly I interact with
CIDER:</p>

<ul>
  <li>I only deal with one project at a time</li>
  <li>I need at most two running REPLs</li>
  <li>I don’t really care about firing up dedicated REPLs for other projects. If
I change project, I simply close every buffer of the current one and start
afresh</li>
</ul>

<p>This made me realise that the whole CIDER <a href="https://docs.cider.mx/cider/0.26/usage/managing_connections.html#sessions">session</a> management is too much for my
basic needs.</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">defun</span> <span class="nv">mu--cider-repl-regex</span> <span class="p">(</span><span class="k">type</span><span class="p">)</span>
  <span class="s">"Return the regexp to get the CIDER REPL based on TYPE."</span>
  <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">eq</span> <span class="k">type</span> <span class="ss">'clj</span><span class="p">)</span>
      <span class="s">"\`*cider-repl .*clj[*]"</span>
    <span class="s">"\`*cider-repl .*cljs"</span><span class="p">))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">mu--cider-repl-buffer-name</span> <span class="p">(</span><span class="k">type</span><span class="p">)</span>
  <span class="s">"Get buffer from `buffer-list' according to TYPE."</span>
  <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">regex</span> <span class="p">(</span><span class="nv">mu--cider-repl-regex</span> <span class="k">type</span><span class="p">)))</span>
    <span class="p">(</span><span class="nb">car</span> <span class="p">(</span><span class="nv">seq-filter</span> <span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="nv">s</span><span class="p">)</span> <span class="p">(</span><span class="nv">string-match-p</span> <span class="nv">regex</span> <span class="nv">s</span><span class="p">))</span>
                     <span class="p">(</span><span class="nb">mapcar</span> <span class="nf">#'</span><span class="nv">buffer-name</span> <span class="p">(</span><span class="nv">buffer-list</span><span class="p">))))))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">mu-cider-switch-to-repl</span> <span class="p">(</span><span class="k">&amp;optional</span> <span class="k">type</span><span class="p">)</span>
  <span class="s">"Open a CIDER REPL for TYPE.
If TYPE is not passed, open a Clojure REPL."</span>
  <span class="p">(</span><span class="nv">interactive</span> <span class="s">"P"</span><span class="p">)</span>
  <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="k">type</span> <span class="p">(</span><span class="nb">or</span> <span class="k">type</span> <span class="ss">'clj</span><span class="p">)))</span>
    <span class="p">(</span><span class="nv">if-let</span> <span class="p">(</span><span class="nv">buffer</span> <span class="p">(</span><span class="nv">mu--cider-repl-buffer-name</span> <span class="k">type</span><span class="p">))</span>
        <span class="p">(</span><span class="nv">pop-to-buffer</span> <span class="nv">buffer</span><span class="p">)</span>
      <span class="p">(</span><span class="nv">message</span> <span class="s">"No CIDER REPL available"</span><span class="p">))))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">mu-cider-switch-to-cljs-repl</span> <span class="p">()</span>
  <span class="s">"Open a CIDER REPL for ClojureScript."</span>
  <span class="p">(</span><span class="nv">interactive</span><span class="p">)</span>
  <span class="p">(</span><span class="nv">mu-cider-switch-to-repl</span> <span class="ss">'cljs</span><span class="p">))</span>
</code></pre></div></div>

<p>Note that I changed the value of <code class="language-plaintext highlighter-rouge">nrepl-repl-buffer-name-template</code> to <code class="language-plaintext highlighter-rouge">*cider-repl
%j %r:%S*</code>, so you may have to change <code class="language-plaintext highlighter-rouge">mu--cider-repl-regex</code> according to the value
in your setup.</p>

<p><kbd>C-c C-z</kbd> is bound to <code class="language-plaintext highlighter-rouge">mu-cider-switch-to-repl</code> in <code class="language-plaintext highlighter-rouge">clojure-mode-map</code> and
<code class="language-plaintext highlighter-rouge">clojurec-mode-map</code>, and to <code class="language-plaintext highlighter-rouge">mu-cider-switch-to-cljs-repl</code> in
<code class="language-plaintext highlighter-rouge">clojurescript-mode-map</code>. This of course means that in <code class="language-plaintext highlighter-rouge">.cljc</code> files I always get to
a Clojure REPL, but that’s fine. The code in there has to be tested on both
REPLs anyway, so it doesn’t matter which one comes up first.</p>

<p>Now, let’s fix <kbd>C-c C-k</kbd> as well.</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">defun</span> <span class="nv">mu--cider-session-by-type</span> <span class="p">(</span><span class="k">type</span><span class="p">)</span>
  <span class="s">"Return the current CIDER session by TYPE."</span>
  <span class="p">(</span><span class="k">let*</span> <span class="p">((</span><span class="nv">regex</span> <span class="p">(</span><span class="nv">mu--cider-repl-regex</span> <span class="k">type</span><span class="p">))</span>
         <span class="p">(</span><span class="nv">system</span> <span class="p">(</span><span class="nv">sesman--system</span><span class="p">))</span>
         <span class="p">(</span><span class="nv">sessions</span> <span class="p">(</span><span class="nv">sesman-current-sessions</span> <span class="nv">system</span> <span class="o">'</span><span class="p">(</span><span class="nv">buffer</span><span class="p">))))</span>
    <span class="p">(</span><span class="nb">car</span>
     <span class="p">(</span><span class="nv">seq-filter</span> <span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="nv">s</span><span class="p">)</span>
                   <span class="p">(</span><span class="nv">string-match-p</span> <span class="nv">regex</span> <span class="p">(</span><span class="nv">buffer-name</span> <span class="p">(</span><span class="nb">cadr</span> <span class="nv">s</span><span class="p">))))</span>
                 <span class="nv">sessions</span><span class="p">))))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">mu--cider-load-buffer</span> <span class="p">(</span><span class="nv">session</span><span class="p">)</span>
  <span class="s">"Load the current buffer according to SESSION."</span>
  <span class="p">(</span><span class="k">if</span> <span class="nv">session</span>
      <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">system</span> <span class="p">(</span><span class="nv">sesman--system</span><span class="p">))</span>
            <span class="p">(</span><span class="nv">buf</span> <span class="p">(</span><span class="nv">current-buffer</span><span class="p">)))</span>
        <span class="p">(</span><span class="nv">sesman--clear-links</span><span class="p">)</span>
        <span class="p">(</span><span class="nv">sesman-link-session</span> <span class="nv">system</span> <span class="nv">session</span> <span class="ss">'buffer</span> <span class="nv">buf</span><span class="p">)</span>
        <span class="p">(</span><span class="nv">cider-load-buffer</span> <span class="nv">buf</span><span class="p">))</span>
    <span class="p">(</span><span class="nv">message</span> <span class="s">"No CIDER REPL available"</span><span class="p">)))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">mu-cider-load-clj-buffer</span> <span class="p">()</span>
  <span class="s">"Load the current Clojure buffer."</span>
  <span class="p">(</span><span class="nv">interactive</span><span class="p">)</span>
  <span class="p">(</span><span class="nv">mu--cider-load-buffer</span> <span class="p">(</span><span class="nv">mu--cider-session-by-type</span> <span class="ss">'clj</span><span class="p">)))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">mu-cider-load-cljc-buffer</span> <span class="p">()</span>
  <span class="s">"Load the current ClojureC buffer."</span>
  <span class="p">(</span><span class="nv">interactive</span><span class="p">)</span>
  <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">clj-session</span> <span class="p">(</span><span class="nv">mu--cider-session-by-type</span> <span class="ss">'clj</span><span class="p">))</span>
        <span class="p">(</span><span class="nv">cljs-session</span> <span class="p">(</span><span class="nv">mu--cider-session-by-type</span> <span class="ss">'cljs</span><span class="p">)))</span>
    <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">and</span> <span class="p">(</span><span class="nb">null</span> <span class="nv">clj-session</span><span class="p">)</span>
             <span class="p">(</span><span class="nb">null</span> <span class="nv">cljs-session</span><span class="p">))</span>
        <span class="p">(</span><span class="nv">message</span> <span class="s">"No CIDER REPL available"</span><span class="p">)</span>
      <span class="p">(</span><span class="nb">when</span> <span class="nv">clj-session</span>
        <span class="p">(</span><span class="nv">mu--cider-load-buffer</span> <span class="nv">clj-session</span><span class="p">))</span>
      <span class="p">(</span><span class="nb">when</span> <span class="nv">cljs-session</span>
        <span class="p">(</span><span class="nv">mu--cider-load-buffer</span> <span class="nv">cljs-session</span><span class="p">)))))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">mu-cider-load-cljs-buffer</span> <span class="p">()</span>
  <span class="s">"Load the current ClojureScript buffer."</span>
  <span class="p">(</span><span class="nv">interactive</span><span class="p">)</span>
  <span class="p">(</span><span class="nv">mu--cider-load-buffer</span> <span class="p">(</span><span class="nv">mu--cider-session-by-type</span> <span class="ss">'cljs</span><span class="p">)))</span>
</code></pre></div></div>

<p>Just like for <kbd>C-c C-z</kbd>, <kbd>C-c C-k</kbd> is now bound to these commands according to the
mode map. For the sake of completeness, I have also disabled both <kbd>C-c C-k</kbd> and
<kbd>C-c C-z</kbd> in <code class="language-plaintext highlighter-rouge">cider-mode-map</code> in order to avoid any kind of overshadowing by CIDER.</p>

<p>Note that this approach works well with my intended CIDER usage. It may not be
what you are looking for if you are experiencing the same problems with REPL
switching and buffer loading. Still, I have been using these commands for a
while now and I am happy with them. CIDER has become my trusted Clojure IDE
again.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Reliable REPL switching and buffer loading with CIDER</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Manuel Uberti</a> <span class="article__date">16 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>As a Clojure developer one of the most important packages in my everyday Emacs
usage is <a href="https://cider.mx/">CIDER</a>. There are many things to love about it, chief among them the
great interactive code evaluation and a sweet integration with popular Clojure
tools. I still haven’t played with its debugging facilities, but yes, I know I should.</p>

<p>However, there is something that has been bothering me for quite a while: REPL
switching and buffer loading. I cannot pinpoint the exact moment when these
seemingly simple operations have become so unreliable, but I still remember when
switching to the correct REPL buffer according to the file in front of me used
to work as expected and loading a buffer didn’t require dealing with sessions
first.</p>

<p>Let me give you more details before this writing starts to look like a random
rant. My projects are usually web applications, which means I have to write both
Clojure and ClojureScript. The Clojure side can be backed by <code class="language-plaintext highlighter-rouge">leiningen</code> or a
<code class="language-plaintext highlighter-rouge">deps.edn</code> file, and we are set on <code class="language-plaintext highlighter-rouge">shadow-cljs</code> for ClojureScript. The first thing
I normally do is jack-in with <kbd>C-c C-x j j</kbd> and then bring up the dedicated
ClojureScript REPL with <kbd>C-c C-x j s</kbd>. Opening the browser and navigate to
something along the lines of <code class="language-plaintext highlighter-rouge">localhost:3000</code> finalises the process of setting up
the ClojureScript REPL. That’s it, another good day of coding can begin. And
soon enough frustration follows.</p>

<p>I tend to move from Clojure to ClojureScript files and vice versa quite a lot,
and hitting <kbd>C-c C-z</kbd> frequently results in an unpredictable behaviour. Sometimes
the REPL of the expected type pops up, sometimes the other one appears,
sometimes I get a message about a missing REPL in the current session. Manually
linking the current buffer to the correct REPL with <kbd>C-c C-s b</kbd> seems to fix the
problem, but it’s only a matter of time. It takes a couple of buffer switching
operations to bring the issue back. It is as if the link between the buffer and
the REPL has vanished. Even worse, without that link I can forget about <kbd>C-c C-k</kbd>
to load the buffer.</p>

<p>To overcome my frustration, I sat back and looked at how exactly I interact with
CIDER:</p>

<ul>
  <li>I only deal with one project at a time</li>
  <li>I need at most two running REPLs</li>
  <li>I don’t really care about firing up dedicated REPLs for other projects. If
I change project, I simply close every buffer of the current one and start
afresh</li>
</ul>

<p>This made me realise that the whole CIDER <a href="https://docs.cider.mx/cider/0.26/usage/managing_connections.html#sessions">session</a> management is too much for my
basic needs.</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">defun</span> <span class="nv">mu--cider-repl-regex</span> <span class="p">(</span><span class="k">type</span><span class="p">)</span>
  <span class="s">"Return the regexp to get the CIDER REPL based on TYPE."</span>
  <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">eq</span> <span class="k">type</span> <span class="ss">'clj</span><span class="p">)</span>
      <span class="s">"\`*cider-repl .*clj[*]"</span>
    <span class="s">"\`*cider-repl .*cljs"</span><span class="p">))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">mu--cider-repl-buffer-name</span> <span class="p">(</span><span class="k">type</span><span class="p">)</span>
  <span class="s">"Get buffer from `buffer-list' according to TYPE."</span>
  <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">regex</span> <span class="p">(</span><span class="nv">mu--cider-repl-regex</span> <span class="k">type</span><span class="p">)))</span>
    <span class="p">(</span><span class="nb">car</span> <span class="p">(</span><span class="nv">seq-filter</span> <span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="nv">s</span><span class="p">)</span> <span class="p">(</span><span class="nv">string-match-p</span> <span class="nv">regex</span> <span class="nv">s</span><span class="p">))</span>
                     <span class="p">(</span><span class="nb">mapcar</span> <span class="nf">#'</span><span class="nv">buffer-name</span> <span class="p">(</span><span class="nv">buffer-list</span><span class="p">))))))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">mu-cider-switch-to-repl</span> <span class="p">(</span><span class="k">&amp;optional</span> <span class="k">type</span><span class="p">)</span>
  <span class="s">"Open a CIDER REPL for TYPE.
If TYPE is not passed, open a Clojure REPL."</span>
  <span class="p">(</span><span class="nv">interactive</span> <span class="s">"P"</span><span class="p">)</span>
  <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="k">type</span> <span class="p">(</span><span class="nb">or</span> <span class="k">type</span> <span class="ss">'clj</span><span class="p">)))</span>
    <span class="p">(</span><span class="nv">if-let</span> <span class="p">(</span><span class="nv">buffer</span> <span class="p">(</span><span class="nv">mu--cider-repl-buffer-name</span> <span class="k">type</span><span class="p">))</span>
        <span class="p">(</span><span class="nv">pop-to-buffer</span> <span class="nv">buffer</span><span class="p">)</span>
      <span class="p">(</span><span class="nv">message</span> <span class="s">"No CIDER REPL available"</span><span class="p">))))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">mu-cider-switch-to-cljs-repl</span> <span class="p">()</span>
  <span class="s">"Open a CIDER REPL for ClojureScript."</span>
  <span class="p">(</span><span class="nv">interactive</span><span class="p">)</span>
  <span class="p">(</span><span class="nv">mu-cider-switch-to-repl</span> <span class="ss">'cljs</span><span class="p">))</span>
</code></pre></div></div>

<p>Note that I changed the value of <code class="language-plaintext highlighter-rouge">nrepl-repl-buffer-name-template</code> to <code class="language-plaintext highlighter-rouge">*cider-repl
%j %r:%S*</code>, so you may have to change <code class="language-plaintext highlighter-rouge">mu--cider-repl-regex</code> according to the value
in your setup.</p>

<p><kbd>C-c C-z</kbd> is bound to <code class="language-plaintext highlighter-rouge">mu-cider-switch-to-repl</code> in <code class="language-plaintext highlighter-rouge">clojure-mode-map</code> and
<code class="language-plaintext highlighter-rouge">clojurec-mode-map</code>, and to <code class="language-plaintext highlighter-rouge">mu-cider-switch-to-cljs-repl</code> in
<code class="language-plaintext highlighter-rouge">clojurescript-mode-map</code>. This of course means that in <code class="language-plaintext highlighter-rouge">.cljc</code> files I always get to
a Clojure REPL, but that’s fine. The code in there has to be tested on both
REPLs anyway, so it doesn’t matter which one comes up first.</p>

<p>Now, let’s fix <kbd>C-c C-k</kbd> as well.</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">defun</span> <span class="nv">mu--cider-session-by-type</span> <span class="p">(</span><span class="k">type</span><span class="p">)</span>
  <span class="s">"Return the current CIDER session by TYPE."</span>
  <span class="p">(</span><span class="k">let*</span> <span class="p">((</span><span class="nv">regex</span> <span class="p">(</span><span class="nv">mu--cider-repl-regex</span> <span class="k">type</span><span class="p">))</span>
         <span class="p">(</span><span class="nv">system</span> <span class="p">(</span><span class="nv">sesman--system</span><span class="p">))</span>
         <span class="p">(</span><span class="nv">sessions</span> <span class="p">(</span><span class="nv">sesman-current-sessions</span> <span class="nv">system</span> <span class="o">'</span><span class="p">(</span><span class="nv">buffer</span><span class="p">))))</span>
    <span class="p">(</span><span class="nb">car</span>
     <span class="p">(</span><span class="nv">seq-filter</span> <span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="nv">s</span><span class="p">)</span>
                   <span class="p">(</span><span class="nv">string-match-p</span> <span class="nv">regex</span> <span class="p">(</span><span class="nv">buffer-name</span> <span class="p">(</span><span class="nb">cadr</span> <span class="nv">s</span><span class="p">))))</span>
                 <span class="nv">sessions</span><span class="p">))))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">mu--cider-load-buffer</span> <span class="p">(</span><span class="nv">session</span><span class="p">)</span>
  <span class="s">"Load the current buffer according to SESSION."</span>
  <span class="p">(</span><span class="k">if</span> <span class="nv">session</span>
      <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">system</span> <span class="p">(</span><span class="nv">sesman--system</span><span class="p">))</span>
            <span class="p">(</span><span class="nv">buf</span> <span class="p">(</span><span class="nv">current-buffer</span><span class="p">)))</span>
        <span class="p">(</span><span class="nv">sesman--clear-links</span><span class="p">)</span>
        <span class="p">(</span><span class="nv">sesman-link-session</span> <span class="nv">system</span> <span class="nv">session</span> <span class="ss">'buffer</span> <span class="nv">buf</span><span class="p">)</span>
        <span class="p">(</span><span class="nv">cider-load-buffer</span> <span class="nv">buf</span><span class="p">))</span>
    <span class="p">(</span><span class="nv">message</span> <span class="s">"No CIDER REPL available"</span><span class="p">)))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">mu-cider-load-clj-buffer</span> <span class="p">()</span>
  <span class="s">"Load the current Clojure buffer."</span>
  <span class="p">(</span><span class="nv">interactive</span><span class="p">)</span>
  <span class="p">(</span><span class="nv">mu--cider-load-buffer</span> <span class="p">(</span><span class="nv">mu--cider-session-by-type</span> <span class="ss">'clj</span><span class="p">)))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">mu-cider-load-cljc-buffer</span> <span class="p">()</span>
  <span class="s">"Load the current ClojureC buffer."</span>
  <span class="p">(</span><span class="nv">interactive</span><span class="p">)</span>
  <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">clj-session</span> <span class="p">(</span><span class="nv">mu--cider-session-by-type</span> <span class="ss">'clj</span><span class="p">))</span>
        <span class="p">(</span><span class="nv">cljs-session</span> <span class="p">(</span><span class="nv">mu--cider-session-by-type</span> <span class="ss">'cljs</span><span class="p">)))</span>
    <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">and</span> <span class="p">(</span><span class="nb">null</span> <span class="nv">clj-session</span><span class="p">)</span>
             <span class="p">(</span><span class="nb">null</span> <span class="nv">cljs-session</span><span class="p">))</span>
        <span class="p">(</span><span class="nv">message</span> <span class="s">"No CIDER REPL available"</span><span class="p">)</span>
      <span class="p">(</span><span class="nb">when</span> <span class="nv">clj-session</span>
        <span class="p">(</span><span class="nv">mu--cider-load-buffer</span> <span class="nv">clj-session</span><span class="p">))</span>
      <span class="p">(</span><span class="nb">when</span> <span class="nv">cljs-session</span>
        <span class="p">(</span><span class="nv">mu--cider-load-buffer</span> <span class="nv">cljs-session</span><span class="p">)))))</span>

<span class="p">(</span><span class="nb">defun</span> <span class="nv">mu-cider-load-cljs-buffer</span> <span class="p">()</span>
  <span class="s">"Load the current ClojureScript buffer."</span>
  <span class="p">(</span><span class="nv">interactive</span><span class="p">)</span>
  <span class="p">(</span><span class="nv">mu--cider-load-buffer</span> <span class="p">(</span><span class="nv">mu--cider-session-by-type</span> <span class="ss">'cljs</span><span class="p">)))</span>
</code></pre></div></div>

<p>Just like for <kbd>C-c C-z</kbd>, <kbd>C-c C-k</kbd> is now bound to these commands according to the
mode map. For the sake of completeness, I have also disabled both <kbd>C-c C-k</kbd> and
<kbd>C-c C-z</kbd> in <code class="language-plaintext highlighter-rouge">cider-mode-map</code> in order to avoid any kind of overshadowing by CIDER.</p>

<p>Note that this approach works well with my intended CIDER usage. It may not be
what you are looking for if you are experiencing the same problems with REPL
switching and buffer loading. Still, I have been using these commands for a
while now and I am happy with them. CIDER has become my trusted Clojure IDE
again.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/192-teamwork.png" alt="Teamwork">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Teamwork</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">16 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/192-teamwork.png" alt="Teamwork" title="If we all are moving forward together, then success is guaranteed." /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Congreso esLibre y PyConES 2020">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Congreso esLibre y PyConES 2020</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">10 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Dedicamos la mayor parte del episodio a hablar sobre el <a href="https://eslib.re">Congreso esLibre 2020</a> celebrado el pasado mes de septiembre. La edición de esLibre de este año se celebró finalmente online, transmitiendo desde la Universidad Rey Juan Carlos gracias al interés mostrado por su Oficina de Conocimiento y Cultura Libres (OfiLibre de la URJC). </p>



<p>David Vaquero tuvo la oportunidad de participar como ponente y en este episodio nos acerca la organización de este evento y sus promotores, las soluciones tecnológicas que utilizaron, el proceso de selección abierto de las candidaturas y también los fines que se persiguen conseguir. El Congreso esLibre 2020 reunió en dos jornadas, una variada selección de charlas y conferencias alrededor de varias pistas relacionadas con el software libre.</p>



<p>También  hacemos mención del <a href="https://24h24l.org/" data-type="URL" data-id="https://24h24l.org/">evento 24H24L</a> un evento online de 24 horas de duración que constará de 24 audios sobre el uso de GNU / Linux, experiencias profesionales y personales alrededor de seis categorías: Redes, Empresa, Desarrollo, Hardware, Multimedia y GNU/Linux.</p>



<p>En la segunda parte Andros Fenollosa nos contará su experiencia participando como organizador y ponente en la edición online de la conferencia sobre Python en España<a href="https://2020.es.pycon.org/index.html" data-type="URL" data-id="https://2020.es.pycon.org/index.html"> PyConES2020 Pandemic Edition. </a>Andros ofreció una charla sobre introducción a la programación funcional, que además colgamos como episodio bonus en el feed del podcast.</p>



<p>Por último, aportamos varios recursos y enlaces recomendados en la sección Radar del episodio.</p>




<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/191-reverse-turing-test.png" alt="Reverse Turing Test">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Reverse Turing Test</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">09 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/191-reverse-turing-test.png" alt="Reverse Turing Test" title="Because artificial intelligence will never beat human stupidity." /></p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Introducción a la Programación Funcional con Python">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Introducción a la Programación Funcional con Python</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">05 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Como episodio bonus os dejamos el audio de la charla que ofreció Andros Fenollosa en la<a href="https://2020.es.pycon.org/speaker_5.html"> Pycon España 2020,</a> que este año se realizó de manera virtual. En esta charla Andros ofrece una introducción muy interesante para conocer en qué consiste la programación funcional y en qué se diferencia de otros tipos de programación (imperativa y orientada a objetos).</p>



<p>En la web de la PyCon están colgadas todas las charlas y se pueden seguir desde su canal de YouTube.</p>




<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Full-Bleed Layout Using CSS Grid</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">05 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Certain layouts are surprisingly dastardly. On the modern web, one of the most common layouts is also one of the trickiest. In this tutorial, I break down how to build the "full-bleed" layout using CSS Grid.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ondahostil.files.wordpress.com/2018/08/yo.jpg?w=32" alt="En qué ando: desescalando">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">En qué ando: desescalando</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Onda Hostil</a> <span class="article__date">04 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        No sé si ha sido que el confinamiento y posterior desescalada me han vuelto más huraña de lo normal (y eso que el el nivel estaba ya muy alto) o porque he estado dándole vueltas a lo que significa tener un blog en una plataforma como WordPress (el compañero de Bokunoshumi lo cuenta mejor) pero [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Meme generator in emacs</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">04 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        #TIL it is possible to create memes in emacs using meme, this package allow to choose an image and add some text to it, we can also select any image and use it.
Installation   This package, at the time of writing this, is not available on melpa so we have to install it manually or using straight.el or quelpa, because I&#39;m using straight.el for my config we&#39;ll use that.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Getting started with Tsung</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">03 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        What is tsung   Tsung is a load testing tool written in erlang, it allow us to perform load testing for web applications, databases, etc. Or as its website says:
 Tsung (formerly IDX-Tsunami) is a distributed load testing tool. It is protocol-independent and can currently be used to stress HTTP, WebDAV, SOAP, PostgreSQL, MySQL, AMQP, MQTT, LDAP and Jabber/XMPP servers.
  More info is available in its web page http://tsung.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://erick.navarro.io/images/blog/getting-started-with-tsung/status-page.png" alt="Getting started with Tsung">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Getting started with Tsung</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">03 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<div id="outline-container-headline-1" class="outline-2">
<h2 id="headline-1">
What is tsung
</h2>
<div id="outline-text-headline-1" class="outline-text-2">
<p>
Tsung is a load testing tool written in erlang, it allow us to perform load testing for web applications, databases, etc. Or as its website says:</p>
<blockquote>
<p>Tsung (formerly IDX-Tsunami) is a distributed load testing tool. It is protocol-independent and can currently be used to stress HTTP, WebDAV, SOAP, PostgreSQL, MySQL, AMQP, MQTT, LDAP and Jabber/XMPP servers.</p>
</blockquote>
<p>
More info is available in its web page <a href="http://tsung.erlang-projects.org/user_manual/">http://tsung.erlang-projects.org/user_manual/</a></p>
<p>
In this post we&#39;ll cover how to test a web application and at the time of writing this the available version of <code class="verbatim">tsung</code> is <code class="verbatim">1.7.0</code>.</p>
</div>
</div>
<div id="outline-container-headline-2" class="outline-2">
<h2 id="headline-2">
Installation
</h2>
<div id="outline-text-headline-2" class="outline-text-2">
<p>
DISCLAIMER: All the steps described here are for macOS, there shouldn&#39;t be many differences for a linux system.</p>
<p>
<code class="verbatim">Tsung</code> is available on homebrew so we can install it using <code class="verbatim">brew install tsung</code>, also we&#39;ll need <code class="verbatim">perl</code> for charts generation so we can install it with <code class="verbatim">brew install perl</code> as well.</p>
<p>
In order to generate charts correctly we need to install a required dependency, we have to execute <code class="verbatim">cpan template</code> and we&#39;re almost ready to go</p>
<p>
A last step is change the perl script a little bit, in macOS is located in <code class="verbatim">/usr/local/lib/tsung/bin/tsung_stats.pl</code>. We first need to change its permissions so we can be able to edit it, we can execute <code class="verbatim">chmod 755 =/usr/local/lib/tsung/bin/tsung_stats.pl</code>. Now we can apply the following change:</p>
<div class="src src-diff">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-diff" data-lang="diff"><span style="color:#f92672">-#!/usr/bin/perl -w
</span><span style="color:#f92672"></span><span style="color:#a6e22e">+#!/usr/local/bin/perl -w
</span></code></pre></div>
</div>
<p>
As you can see we changed the location of the <code class="verbatim">perl</code> installation, this was the easiest way I found to make it work properly without the need to make some other changes to perl installation.</p>
</div>
</div>
<div id="outline-container-headline-3" class="outline-2">
<h2 id="headline-3">
Demo project
</h2>
<div id="outline-text-headline-3" class="outline-text-2">
<p>
We&#39;re going to use this <a href="https://github.com/erickgnavar/tsung_demo">example project</a> for our tests. We can follow the instructions described in its <code class="verbatim">README.md</code> file.</p>
<p>
This project have the following urls:</p>
<table>
<thead>
<tr>
<th>route</th>
<th>description</th>
<th>method</th>
<th>content type</th>
</tr>
</thead>
<tbody>
<tr>
<td>/</td>
<td>index page with an html message</td>
<td>GET</td>
<td>text/html</td>
</tr>
<tr>
<td>/ping</td>
<td>respond a pong message</td>
<td>GET</td>
<td>text/plain</td>
</tr>
<tr>
<td>/users</td>
<td>respond with a list of users in json</td>
<td>GET</td>
<td>application/json</td>
</tr>
<tr>
<td>/users</td>
<td>allow to create a new user</td>
<td>POST</td>
<td>application/json</td>
</tr>
</tbody>
</table>
<p>
We&#39;re going to write test for each of this routes.</p>
</div>
</div>
<div id="outline-container-headline-4" class="outline-2">
<h2 id="headline-4">
Defining load tests
</h2>
<div id="outline-text-headline-4" class="outline-text-2">
<p>
Tsung load tests are defined in <code class="verbatim">xml</code>, in these <code class="verbatim">xml</code> files we can define the behaviour of the test, how many clients we want to execute, define the the endpoints to be used and so on.</p>
<p>
<code class="verbatim">tsung</code> comes with some examples included, in macOS we can find them in <code class="verbatim">/usr/share/doc/tsung/examples</code> and use them as a base for creating new tests.</p>
<p>
This a simplified version of the example <code class="verbatim">http_simple.xml</code> example included in the installation folder, let&#39;s create a file called <code class="verbatim">demo.xml</code> and put this content on it:</p>
<div class="src src-xml">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-xml" data-lang="xml"><span style="color:#75715e">&lt;?xml version=&#34;1.0&#34;?&gt;</span>
<span style="color:#75715e">&lt;!DOCTYPE tsung SYSTEM &#34;/usr/local/Cellar/tsung/1.7.0/share/tsung/tsung-1.0.dtd&#34;&gt;</span>
<span style="color:#f92672">&lt;tsung</span> <span style="color:#a6e22e">loglevel=</span><span style="color:#e6db74">&#34;notice&#34;</span> <span style="color:#a6e22e">version=</span><span style="color:#e6db74">&#34;1.0&#34;</span><span style="color:#f92672">&gt;</span>
  <span style="color:#f92672">&lt;clients&gt;</span>
    <span style="color:#f92672">&lt;client</span> <span style="color:#a6e22e">host=</span><span style="color:#e6db74">&#34;localhost&#34;</span> <span style="color:#a6e22e">use_controller_vm=</span><span style="color:#e6db74">&#34;true&#34;</span><span style="color:#f92672">/&gt;</span>
  <span style="color:#f92672">&lt;/clients&gt;</span>

  <span style="color:#f92672">&lt;servers&gt;</span>
    <span style="color:#f92672">&lt;server</span> <span style="color:#a6e22e">host=</span><span style="color:#e6db74">&#34;localhost&#34;</span> <span style="color:#a6e22e">port=</span><span style="color:#e6db74">&#34;4000&#34;</span> <span style="color:#a6e22e">type=</span><span style="color:#e6db74">&#34;tcp&#34;</span><span style="color:#f92672">&gt;&lt;/server&gt;</span>
  <span style="color:#f92672">&lt;/servers&gt;</span>

  <span style="color:#f92672">&lt;load&gt;</span>
    <span style="color:#f92672">&lt;arrivalphase</span> <span style="color:#a6e22e">phase=</span><span style="color:#e6db74">&#34;1&#34;</span> <span style="color:#a6e22e">duration=</span><span style="color:#e6db74">&#34;10&#34;</span> <span style="color:#a6e22e">unit=</span><span style="color:#e6db74">&#34;minute&#34;</span><span style="color:#f92672">&gt;</span>
      <span style="color:#f92672">&lt;users</span> <span style="color:#a6e22e">arrivalrate=</span><span style="color:#e6db74">&#34;10&#34;</span> <span style="color:#a6e22e">unit=</span><span style="color:#e6db74">&#34;second&#34;</span><span style="color:#f92672">&gt;&lt;/users&gt;</span>
    <span style="color:#f92672">&lt;/arrivalphase&gt;</span>
    <span style="color:#f92672">&lt;arrivalphase</span> <span style="color:#a6e22e">phase=</span><span style="color:#e6db74">&#34;2&#34;</span> <span style="color:#a6e22e">duration=</span><span style="color:#e6db74">&#34;5&#34;</span> <span style="color:#a6e22e">unit=</span><span style="color:#e6db74">&#34;minute&#34;</span><span style="color:#f92672">&gt;</span>
      <span style="color:#f92672">&lt;users</span> <span style="color:#a6e22e">arrivalrate=</span><span style="color:#e6db74">&#34;20&#34;</span> <span style="color:#a6e22e">unit=</span><span style="color:#e6db74">&#34;second&#34;</span><span style="color:#f92672">&gt;&lt;/users&gt;</span>
    <span style="color:#f92672">&lt;/arrivalphase&gt;</span>
  <span style="color:#f92672">&lt;/load&gt;</span>

  <span style="color:#f92672">&lt;sessions&gt;</span>
    <span style="color:#f92672">&lt;session</span> <span style="color:#a6e22e">name=</span><span style="color:#e6db74">&#34;http-example&#34;</span> <span style="color:#a6e22e">probability=</span><span style="color:#e6db74">&#34;100&#34;</span> <span style="color:#a6e22e">type=</span><span style="color:#e6db74">&#34;ts_http&#34;</span><span style="color:#f92672">&gt;</span>
      <span style="color:#f92672">&lt;request&gt;</span> <span style="color:#f92672">&lt;http</span> <span style="color:#a6e22e">url=</span><span style="color:#e6db74">&#34;/&#34;</span> <span style="color:#a6e22e">method=</span><span style="color:#e6db74">&#34;GET&#34;</span> <span style="color:#a6e22e">version=</span><span style="color:#e6db74">&#34;1.1&#34;</span><span style="color:#f92672">&gt;&lt;/http&gt;</span> <span style="color:#f92672">&lt;/request&gt;</span>
      <span style="color:#f92672">&lt;request&gt;</span> <span style="color:#f92672">&lt;http</span> <span style="color:#a6e22e">url=</span><span style="color:#e6db74">&#34;/ping&#34;</span> <span style="color:#a6e22e">method=</span><span style="color:#e6db74">&#34;GET&#34;</span> <span style="color:#a6e22e">version=</span><span style="color:#e6db74">&#34;1.1&#34;</span><span style="color:#f92672">&gt;&lt;/http&gt;</span> <span style="color:#f92672">&lt;/request&gt;</span>
      <span style="color:#f92672">&lt;request&gt;</span> <span style="color:#f92672">&lt;http</span> <span style="color:#a6e22e">url=</span><span style="color:#e6db74">&#34;/users&#34;</span> <span style="color:#a6e22e">method=</span><span style="color:#e6db74">&#34;GET&#34;</span> <span style="color:#a6e22e">version=</span><span style="color:#e6db74">&#34;1.1&#34;</span><span style="color:#f92672">&gt;&lt;/http&gt;</span> <span style="color:#f92672">&lt;/request&gt;</span>
      <span style="color:#f92672">&lt;request&gt;</span> <span style="color:#f92672">&lt;http</span> <span style="color:#a6e22e">url=</span><span style="color:#e6db74">&#34;/users&#34;</span> <span style="color:#a6e22e">method=</span><span style="color:#e6db74">&#34;POST&#34;</span> <span style="color:#a6e22e">contents_from_file=</span><span style="color:#e6db74">&#34;payload.json&#34;</span> <span style="color:#a6e22e">content_type=</span><span style="color:#e6db74">&#34;application/json&#34;</span> <span style="color:#a6e22e">version=</span><span style="color:#e6db74">&#34;1.1&#34;</span><span style="color:#f92672">&gt;&lt;/http&gt;</span> <span style="color:#f92672">&lt;/request&gt;</span>
    <span style="color:#f92672">&lt;/session&gt;</span>
  <span style="color:#f92672">&lt;/sessions&gt;</span>
<span style="color:#f92672">&lt;/tsung&gt;</span></code></pre></div>
</div>
<p>
Note that the second line is pointed to a path inside the tsung installation folder, this can be changed, the <code class="verbatim">tsung-1.0.dtd</code> is available in its web page <a href="http://tsung.erlang-projects.org/user_manual/dtd.html.">http://tsung.erlang-projects.org/user_manual/dtd.html.</a></p>
<div class="src src-xml">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-xml" data-lang="xml"><span style="color:#75715e">&lt;!DOCTYPE tsung SYSTEM &#34;/usr/local/Cellar/tsung/1.7.0/share/tsung/tsung-1.0.dtd&#34;&gt;</span></code></pre></div>
</div>
<p>
Let&#39;s explain a little bit about the test sections:</p>
<div id="outline-container-headline-5" class="outline-3">
<h3 id="headline-5">
Client setup
</h3>
<div id="outline-text-headline-5" class="outline-text-3">
<p>
Tsung is a distributed testing tool so we can execute the client in different hosts, for now we&#39;ll be executing the client in our machine so we can define the client in <code class="verbatim">localhost</code>:</p>
<div class="src src-xml">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-xml" data-lang="xml"><span style="color:#f92672">&lt;clients&gt;</span>
  <span style="color:#f92672">&lt;client</span> <span style="color:#a6e22e">host=</span><span style="color:#e6db74">&#34;localhost&#34;</span> <span style="color:#a6e22e">use_controller_vm=</span><span style="color:#e6db74">&#34;true&#34;</span><span style="color:#f92672">/&gt;</span>
<span style="color:#f92672">&lt;/clients&gt;</span></code></pre></div>
</div>
</div>
</div>
<div id="outline-container-headline-6" class="outline-3">
<h3 id="headline-6">
Server setup
</h3>
<div id="outline-text-headline-6" class="outline-text-3">
<p>
This is the server who will be serving the incoming requests from <code class="verbatim">tsung</code>, in this case is the same machine and listening at port <code class="verbatim">4000</code> using a <code class="verbatim">TCP</code> connection, in a proper test it should a separate machine.</p>
<div class="src src-xml">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-xml" data-lang="xml"><span style="color:#f92672">&lt;servers&gt;</span>
  <span style="color:#f92672">&lt;server</span> <span style="color:#a6e22e">host=</span><span style="color:#e6db74">&#34;localhost&#34;</span> <span style="color:#a6e22e">port=</span><span style="color:#e6db74">&#34;4000&#34;</span> <span style="color:#a6e22e">type=</span><span style="color:#e6db74">&#34;tcp&#34;</span><span style="color:#f92672">&gt;&lt;/server&gt;</span>
<span style="color:#f92672">&lt;/servers&gt;</span></code></pre></div>
</div>
</div>
</div>
<div id="outline-container-headline-7" class="outline-3">
<h3 id="headline-7">
Load behaviour
</h3>
<div id="outline-text-headline-7" class="outline-text-3">
<p>
We can define how the test load will behave, in this case we&#39;re configuring <code class="verbatim">tsung</code> to have 2 phases:</p>
<ol>
<li>
<p>The first phase will run for 10 minutes and create 10 users every second.</p>
</li>
<li>
<p>The second phase will run for 5 minutes and create 20 users every second.</p>
</li>
</ol>
<div class="src src-xml">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-xml" data-lang="xml"><span style="color:#f92672">&lt;load&gt;</span>
  <span style="color:#f92672">&lt;arrivalphase</span> <span style="color:#a6e22e">phase=</span><span style="color:#e6db74">&#34;1&#34;</span> <span style="color:#a6e22e">duration=</span><span style="color:#e6db74">&#34;10&#34;</span> <span style="color:#a6e22e">unit=</span><span style="color:#e6db74">&#34;minute&#34;</span><span style="color:#f92672">&gt;</span>
    <span style="color:#f92672">&lt;users</span> <span style="color:#a6e22e">arrivalrate=</span><span style="color:#e6db74">&#34;10&#34;</span> <span style="color:#a6e22e">unit=</span><span style="color:#e6db74">&#34;second&#34;</span><span style="color:#f92672">&gt;&lt;/users&gt;</span>
  <span style="color:#f92672">&lt;/arrivalphase&gt;</span>

  <span style="color:#f92672">&lt;arrivalphase</span> <span style="color:#a6e22e">phase=</span><span style="color:#e6db74">&#34;2&#34;</span> <span style="color:#a6e22e">duration=</span><span style="color:#e6db74">&#34;10&#34;</span> <span style="color:#a6e22e">unit=</span><span style="color:#e6db74">&#34;minute&#34;</span><span style="color:#f92672">&gt;</span>
    <span style="color:#f92672">&lt;users</span> <span style="color:#a6e22e">arrivalrate=</span><span style="color:#e6db74">&#34;20&#34;</span> <span style="color:#a6e22e">unit=</span><span style="color:#e6db74">&#34;second&#34;</span><span style="color:#f92672">&gt;&lt;/users&gt;</span>
  <span style="color:#f92672">&lt;/arrivalphase&gt;</span>
<span style="color:#f92672">&lt;/load&gt;</span></code></pre></div>
</div>
<p>
For more info about the load configuration we can check <a href="http://tsung.erlang-projects.org/user_manual/conf-load.html">http://tsung.erlang-projects.org/user_manual/conf-load.html</a></p>
</div>
</div>
<div id="outline-container-headline-8" class="outline-3">
<h3 id="headline-8">
HTTP requests
</h3>
<div id="outline-text-headline-8" class="outline-text-3">
<p>
Now we can define what endpoints we&#39;re going to test, we can define the url, method used and some other properties that can be found in <a href="http://tsung.erlang-projects.org/user_manual/conf-sessions.html#http.">http://tsung.erlang-projects.org/user_manual/conf-sessions.html#http.</a></p>
<p>
In this case we&#39;re defining the 4 routes from our example project:</p>
<div class="src src-xml">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-xml" data-lang="xml"><span style="color:#f92672">&lt;sessions&gt;</span>
  <span style="color:#f92672">&lt;session</span> <span style="color:#a6e22e">name=</span><span style="color:#e6db74">&#34;http-example&#34;</span> <span style="color:#a6e22e">probability=</span><span style="color:#e6db74">&#34;100&#34;</span> <span style="color:#a6e22e">type=</span><span style="color:#e6db74">&#34;ts_http&#34;</span><span style="color:#f92672">&gt;</span>
    <span style="color:#f92672">&lt;request&gt;</span> <span style="color:#f92672">&lt;http</span> <span style="color:#a6e22e">url=</span><span style="color:#e6db74">&#34;/&#34;</span> <span style="color:#a6e22e">method=</span><span style="color:#e6db74">&#34;GET&#34;</span> <span style="color:#a6e22e">version=</span><span style="color:#e6db74">&#34;1.1&#34;</span><span style="color:#f92672">&gt;&lt;/http&gt;</span> <span style="color:#f92672">&lt;/request&gt;</span>
    <span style="color:#f92672">&lt;request&gt;</span> <span style="color:#f92672">&lt;http</span> <span style="color:#a6e22e">url=</span><span style="color:#e6db74">&#34;/ping&#34;</span> <span style="color:#a6e22e">method=</span><span style="color:#e6db74">&#34;GET&#34;</span> <span style="color:#a6e22e">version=</span><span style="color:#e6db74">&#34;1.1&#34;</span><span style="color:#f92672">&gt;&lt;/http&gt;</span> <span style="color:#f92672">&lt;/request&gt;</span>
    <span style="color:#f92672">&lt;request&gt;</span> <span style="color:#f92672">&lt;http</span> <span style="color:#a6e22e">url=</span><span style="color:#e6db74">&#34;/users&#34;</span> <span style="color:#a6e22e">method=</span><span style="color:#e6db74">&#34;GET&#34;</span> <span style="color:#a6e22e">version=</span><span style="color:#e6db74">&#34;1.1&#34;</span><span style="color:#f92672">&gt;&lt;/http&gt;</span> <span style="color:#f92672">&lt;/request&gt;</span>
    <span style="color:#f92672">&lt;request&gt;</span> <span style="color:#f92672">&lt;http</span> <span style="color:#a6e22e">url=</span><span style="color:#e6db74">&#34;/users&#34;</span> <span style="color:#a6e22e">method=</span><span style="color:#e6db74">&#34;POST&#34;</span> <span style="color:#a6e22e">contents_from_file=</span><span style="color:#e6db74">&#34;payload.json&#34;</span> <span style="color:#a6e22e">content_type=</span><span style="color:#e6db74">&#34;application/json&#34;</span> <span style="color:#a6e22e">version=</span><span style="color:#e6db74">&#34;1.1&#34;</span><span style="color:#f92672">&gt;&lt;/http&gt;</span> <span style="color:#f92672">&lt;/request&gt;</span>
  <span style="color:#f92672">&lt;/session&gt;</span>
<span style="color:#f92672">&lt;/sessions&gt;</span></code></pre></div>
</div>
<p>
Note that in the case of the <code class="verbatim">POST</code> request we&#39;re defining a <code class="verbatim">contents_from_file</code> property, this allow us to load the body of the request from an external file, we can define it in the same test but it&#39;s easier to have a separate file, the content of the <code class="verbatim">payload.json</code> if the following:</p>
<div class="src src-json">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-json" data-lang="json">{
  <span style="color:#f92672">&#34;name&#34;</span>: <span style="color:#e6db74">&#34;tsung&#34;</span>,
  <span style="color:#f92672">&#34;email&#34;</span>: <span style="color:#e6db74">&#34;demo@demo.com&#34;</span>
}</code></pre></div>
</div>
<p>
This file needs to be in the same folder as <code class="verbatim">demo.xml</code></p>
</div>
</div>
</div>
</div>
<div id="outline-container-headline-9" class="outline-2">
<h2 id="headline-9">
Running the load tests
</h2>
<div id="outline-text-headline-9" class="outline-text-2">
<p>
Now we have all the pieces on place so we can execute our tests, we should be in the folder where we create our <code class="verbatim">demo.xml</code> and run the following command:</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">tsung -f demo.xml start</code></pre></div>
</div>
<p>
That should returns something like this:</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">Starting Tsung
Log directory is: /Users/erick/.tsung/log/20201004-1229</code></pre></div>
</div>
<p>
For each execution <code class="verbatim">tsung</code> create a folder under <code class="verbatim">~/.tsung/log/</code> where all the data generated by the tests will be saved, <code class="verbatim">tsung</code> also has a embedded web server where we can see the results of the tests, by default it will run on <a href="http://localhost:8091/">http://localhost:8091/</a></p>
</div>
</div>
<div id="outline-container-headline-10" class="outline-2">
<h2 id="headline-10">
Reporting
</h2>
<div id="outline-text-headline-10" class="outline-text-2">
<p>
We can see live reporting in the service running at <a href="http://localhost:8091/">http://localhost:8091/</a> or we can see more detailed data using the <code class="verbatim">tsung_stats.pl</code> script.</p>
<div id="outline-container-headline-11" class="outline-3">
<h3 id="headline-11">
Dynamic reporting
</h3>
<div id="outline-text-headline-11" class="outline-text-3">
<p>
When we enter to <a href="http://localhost:8091/">http://localhost:8091/</a> we can see:</p>
<ul>
<li>
<p>A status page</p>
</li>
<li>
<p>A report page which shows stats about the load testing</p>
</li>
<li>
<p>A charts page</p>
</li>
<li>
<p>A logs page which shows all the generated log files</p>
</li>
</ul>
<div id="outline-container-headline-12" class="outline-4">
<h4 id="headline-12">
Status page
</h4>
<div id="outline-text-headline-12" class="outline-text-4">
<p>
We can see the status of the running tests:</p>
<p>
<img src="https://erick.navarro.io/images/blog/getting-started-with-tsung/status-page.png" alt="/images/blog/getting-started-with-tsung/status-page.png" title="/images/blog/getting-started-with-tsung/status-page.png" /></p>
</div>
</div>
<div id="outline-container-headline-13" class="outline-4">
<h4 id="headline-13">
Reports page
</h4>
<div id="outline-text-headline-13" class="outline-text-4">
<p>
We can see stats about the connection time, response times, OS resources usage and so on.</p>
<p>
<img src="https://erick.navarro.io/images/blog/getting-started-with-tsung/reports-page.png" alt="/images/blog/getting-started-with-tsung/reports-page.png" title="/images/blog/getting-started-with-tsung/reports-page.png" /></p>
</div>
</div>
<div id="outline-container-headline-14" class="outline-4">
<h4 id="headline-14">
Charts page
</h4>
<div id="outline-text-headline-14" class="outline-text-4">
<p>
This could be the most interesting one, we can see pretty good charts about the behave of the service that we&#39;re testing, it has the following sections:</p>
<ul>
<li>
<p>Response time</p>
</li>
<li>
<p>Throughput</p>
</li>
<li>
<p>Simultaneous users</p>
</li>
<li>
<p>Server OS monitoring</p>
</li>
<li>
<p>HTTP return code Status (rate)</p>
</li>
</ul>
<p><img src="https://erick.navarro.io/images/blog/getting-started-with-tsung/charts-page.png" alt="/images/blog/getting-started-with-tsung/charts-page.png" title="/images/blog/getting-started-with-tsung/charts-page.png" /></p>
</div>
</div>
</div>
</div>
<div id="outline-container-headline-15" class="outline-3">
<h3 id="headline-15">
Static reporting
</h3>
<div id="outline-text-headline-15" class="outline-text-3">
<p>
Once we finish the tests we can go into the log folder, <code class="verbatim">~.tsung/log/20201004-1229</code> in this case, and generate more detailed charts, see CSVs with all the resulted data and more.</p>
<p>
To generate the chart we have to run the following command inside our log folder</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">/usr/local/lib/tsung/bin/tsung_stats.pl</code></pre></div>
</div>
<p>
This will generate a few new folders inside of it:</p>
<ul>
<li>
<p><code class="verbatim">csv_data</code>: a list of <code class="verbatim">CSV</code> files with all the data to be processed in some external tool like <code class="verbatim">R</code> or a <code class="verbatim">jupyter notebook</code> for example</p>
</li>
<li>
<p><code class="verbatim">images</code>: a set of more detailed charts</p>
</li>
</ul>
<p>For example in this chart we can see the numbers of users vs the time, and as we can see the quantity was increased after 10 minutes, just like we defined in the config file.</p>
<p>
<img src="https://erick.navarro.io/images/blog/getting-started-with-tsung/users-arrival-chart.png" alt="/images/blog/getting-started-with-tsung/users-arrival-chart.png" title="/images/blog/getting-started-with-tsung/users-arrival-chart.png" /></p>
</div>
</div>
</div>
</div>
<div id="outline-container-headline-16" class="outline-2">
<h2 id="headline-16">
Final thoughts
</h2>
<div id="outline-text-headline-16" class="outline-text-2">
<p>
<code class="verbatim">tsung</code> can be used to test not only http services, it supports sql databases, websocket protocol and many more protocols, so we can use it to perform load test for many parts of our application and because it is based on plain texts configuration files we can version them to keep track of the tests we perform along the time.</p>
</div>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">September 2020 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">03 10 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Read more updates from Malli, Practicalli, Clj-kondo/babashka/sci, and Datahike
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/190-ahead-of-its-time.png" alt="Ahead of its time">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Ahead of its time</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">29 09 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/190-ahead-of-its-time.png" alt="Ahead of its time" title="-it will also suggest great online content" /></p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Building a Modern-Day Hit Counter</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">28 09 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The 90s are cool again! Funky colors! Guestbooks! In this tutorial, we'll see how the 90s-inspired hit counter works, using modern web tools like serverless functions, FaunaDB, and React.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Ten books which I read this year</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Isaak’s Blog</a> <span class="article__date">27 09 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        No doubt this was a pretty strange year with a bunch of free time. Everyone tried to kill the time as they can — watching TV shows and movies, playing video games, reading books, etc. I have read many interesting books during the quarantine and in this article, I will tell you about them.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Hay dos cosas inevitables: la muerte y los formularios">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hay dos cosas inevitables: la muerte y los formularios</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">26 09 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Los formularios nos acompañan en la mayoría de nuestros proyectos web. Los desarrolladores se afanan en que sus formularios no contengan errores y que reciban la información correcta. También deben asegurarse que se protege a la aplicación, evitando la introducción de datos maliciosos que comprometan la integridad de la aplicación.</p>



<p>También hay un trabajo de interacción y diseño muy importante. Los usuarios deben ser capaces de interactuar con nuestros formularios de una forma precisa y agradable. Todos queremos formularios intuitivos y fáciles de usar, pero huimos de los formularios largos y confusos. Los diseñadores y el equipo de marketing deben ser capaces de generar formularios que consigan los objetivos que se han propuesto con el sitio web. </p>



<p>En este episodio hablamos sobre los formularios y lo que supone su diseño y operativa. Intentaremos tratar algunos de los aspectos esenciales que tenemos que tener en cuenta para trabajar con ellos y el reto que supone crearlos y mantenerlos.</p>



<p>Entre las cuestiones que tratamos:</p>



<ul><li>¿Qué tenemos que tener en cuenta a la hora de diseñar un formulario?
</li><li>¿Qué tenemos que tener en cuenta a la hora de programar un formulario?
</li>
<li>Servicios y software dedicado a gestionar formularios.</ul>



<p>En la segunda parte del episodio damos resultados de la última encuesta que hemos realizado sobre herramientas para gestionar control de versiones y en la última sección, Radar con enlaces y herramientas de interés.</p>




<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Updated Debian 10: 10.6 released</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Debian News</a> <span class="article__date">26 09 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
    The Debian project is pleased to announce the sixth update of its
stable distribution Debian 10 (codename <q>buster</q>).
This point release mainly adds corrections for security issues,
along with a few adjustments for serious problems. Security advisories
have already been published separately and are referenced where available.
  
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Composing queries with Mito, or doing without Django lazy querysets and Q objects</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">24 09 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>When I didn&rsquo;t know Lisp at all, I skimmed at CLSQL&rsquo;s and Mito&rsquo;s
documentation and I didn&rsquo;t find a mention of &ldquo;lazy&rdquo;, &ldquo;querysets&rdquo; (a
Django term!) nor a mention of any means to compose queries. I had no
idea how I would replace <code>querysets</code>, <code>F</code> and <code>Q</code> objects and the many
functions for DB queries that were being added into newer Django
versions. I concluded that the Lisp ecosystem was lagging behind.</p>

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->

<p><strong>Table of Contents</strong></p>

<ul>
<li><a href="#the-solution">The solution</a></li>
<li><a href="#last-words">Last words</a></li>
</ul>

<!-- markdown-toc end -->

<p>Then I began to understand. And today I got the chance to rewrite a
Django query involving querysets and <code>Q</code> objects, using regular
Lisp. All you have to know is back-quote and comma.</p>

<p>We implement a simple search into a DB. The user enters one or more
words and we search against the <code>title</code> and the <code>authors</code> fields. We
want to match all words, but each can be either in the title, either
in the authors field.</p>

<p>Considering we have two products:</p>

<pre><code class="language-ascii">1 - The Lisp Condition System - phoe
2 - Implementing a blockchain in Lisp - F. Drummer
</code></pre>

<p>then searching for &ldquo;lisp cond&rdquo; must return one result. DWIM.</p>

<p>In Python, we must use <code>Q</code> objects to &ldquo;OR&rdquo; the terms with <code>|</code> (you can&rsquo;t use <code>|</code> without <code>Q</code>):</p>

<pre><code class="language-python">products = firstquery()
for word in words:
    products = products.objects.filter(Q(title__icontains=word) |
                                       Q(authors__name__icontains=word))\
                               .distinct()
</code></pre>

<p>The promise of <code>filter</code> is to be lazy, so when we chain them the ORM
 constructs one single SQL query.</p>

<p>So what does this query yield as SQL? Funnily, I didn&rsquo;t find a
built-in way to get the generated SQL and I had to use a third-party
library. Mmh, I could use special logging. The fact is, we are far
from SQL here (and, with the experience, it is NOT a good thing).</p>

<p>It looks like this (searching &ldquo;hommes femmes&rdquo; in our test DB):</p>

<pre><code class="language-sql">       SELECT DISTINCT ... FROM &quot;product&quot; LEFT OUTER JOIN ...
       WHERE
       ((&quot;product&quot;.&quot;title&quot; LIKE %hommes% ESCAPE '\'
         OR &quot;author&quot;.&quot;name&quot; LIKE %hommes% ESCAPE '\')
        AND
         (&quot;product&quot;.&quot;title&quot; LIKE %femmes% ESCAPE '\'
         OR T5.&quot;name&quot; LIKE %femmes% ESCAPE '\'))
       ORDER BY &quot;product&quot;.&quot;created&quot; DESC
       LIMIT 3
</code></pre>

<p>Does that look complicated? Does that need alien &ldquo;Q objects&rdquo;?! It&rsquo;s just a AND around two OR:</p>

<pre><code class="language-ascii">   title like keyword 1 OR author like keyword 1
AND
   title like keyword 2 OR author like keyword 2
</code></pre>

<p>Mito is the high-level library, and we compose queries with SXQL. I
already had a little query that worked with one keyword:</p>

<pre><code class="language-lisp">(defun find-product (&amp;key query (order :asc))
  (mito:select-dao 'product
    (when query
      (sxql:where (:or (:like :title (str:concat &quot;%&quot; query &quot;%&quot;))
                       (:like :authors (str:concat &quot;%&quot; query &quot;%&quot;)))))
    (sxql:order-by `(,order :created-at))))
</code></pre>

<p>If <code>:query</code> is given, we filter the search. If not, the <code>when</code> is not executed and we return all products.</p>

<p>So what we need to do is iterate over the keywords, produce as many OR
and wrap them with a AND. We want something like that (we can try in the REPL):</p>

<pre><code class="language-lisp">(:AND
 (:OR (:LIKE :TITLE &quot;%word1%&quot;)
      (:LIKE :AUTHORS &quot;%word1%&quot;))
 (:OR (:LIKE :TITLE &quot;%word2%&quot;)
      (:LIKE :AUTHORS &quot;%word2%&quot;)))
</code></pre>

<p>So:</p>

<h2 id="the-solution">The solution</h2>

<pre><code class="language-lisp">(sxql:where
 `(:and   ;; &lt;-- backquote
   ,@(loop for word in (str:words query)  ;; &lt;-- comma-splice
        :collect `(:or (:like :title ,(str:concat &quot;%&quot; word &quot;%&quot;))  ;; &lt;-- backquote, comma
                       (:like :authors ,(str:concat &quot;%&quot; word &quot;%&quot;))))))
</code></pre>

<p>(using <code>(ql:quickload &quot;str&quot;)</code>)</p>

<p>Pay attention to <code>,@</code> (comma-splice). Without it, we get a bad level
of nesting and two parenthesis before the :OR. We would get a list of
clauses, instead of each clause individually. You can try in the REPL.</p>

<p>Note: if you are uneasy with back-quote and comma, see: <a href="https://lispcookbook.github.io/cl-cookbook/macros.html">https://lispcookbook.github.io/cl-cookbook/macros.html</a></p>

<h2 id="last-words">Last words</h2>

<p>Django&rsquo;s <code>filter</code> <a href="https://docs.djangoproject.com/en/1.8/ref/models/conditional-expressions/">is similar to using a
When</a>,
which we were already using on the Lisp side without knowing it was
anything special. &ldquo;Q objects&rdquo; are easy to replace. So, Python and
Django might be easy to getting started with (or it is your feeling,
because you must learn the special syntax and its limitations, I bet
you had some &ldquo;WTF?!&rdquo; moments), but comes a time when your application
grows that you pay the price of being far from SQL (not counting the
maintenance cost).</p>

<p>With Mito and SXQL, it&rsquo;s all regular Lisp, we are closer to the metal,
the only limitation being to know the language, and a bit of SQL.</p>

<p>So we have a great example of why some Common Lisp libraries have a
surprisingly low number of commits. You know, that little voice in
your head that wonders if a library is finished or active. The author
might not need to develop feature X, thanks to Lisp&rsquo;s
expressiveness. Likewise, many questions don&rsquo;t need to be asked or
upvoted on Stack-Overflow. Though I should have asked years ago.</p>

<hr />

<ul>
<li>getting started with a DB: <a href="https://lispcookbook.github.io/cl-cookbook/databases.html">https://lispcookbook.github.io/cl-cookbook/databases.html</a></li>
<li>more DB choices: <a href="https://github.com/CodyReichert/awesome-cl#database">https://github.com/CodyReichert/awesome-cl#database</a></li>
</ul>

<hr />

<div>
You like what I'm doing?
<br/>

<a href='https://ko-fi.com/K3K828W0V' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://cdn.ko-fi.com/cdn/kofi2.png?v=2' border='0' alt='You can buy Me a Coffee at ko-fi.com' title='My hidden plan is to make Common Lisp popular again. No fixed income ATM, and I want to do more, so it helps. Thanks!'/></a>

</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/189-project-setup.png" alt="Project Setup">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Project Setup</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">22 09 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/189-project-setup.png" alt="Project Setup" title="legacy" /></p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A Friendly Introduction to Spring Physics</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">21 09 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Of all the little tips and techniques I've picked up over the years about animation, spring physics remains one of the most powerful and flexible. In this tutorial, we'll learn how to harness their power to build fluid, organic transitions.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Heliblocks para WordPress y CSS moderno con Jesús Olazagoitia">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Heliblocks para WordPress y CSS moderno con Jesús Olazagoitia</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">20 09 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Para este episodio redondo 150 contamos con la compañía del colega desarrollador web <a href="https://goiblas.com/" data-type="URL" data-id="https://goiblas.com/">Jesús Olazagoitia</a>, todo un especialista en CSS y en tecnologías frontend. Jesús es organizador del meetup WordPress Logroño y realiza desarrollos modernos en WordPress basados en frameworks JavaScript.</p>



<p>Recientemente Jesús lanzó un original proyecto personal llamado <a href="https://heliblocks.com/" data-type="URL" data-id="https://heliblocks.com/">Heliblocks.</a> Se trata de un plugin para WordPress que te permite construir y reutilizar bloques o snippets de código independientes como si fueran bloques de Gutenberg. Con Heliblocks es posible crear bloques sólo con HTML y CSS, aprovechando las potentes funcionalidades de la edición de Gutenberg.</p>



<p>Con Jesús hablamos de los motivos que le han llevado a desarrollar este proyecto y las soluciones que trata de abordar. Hablamos de su integración con Gutenberg, las posibilidades que ofrece como marketplace de snippers y también la trayectoria futura del proyecto.</p>



<p>Aprovechando su experiencia con CSS para hablar sobre variables CSS, soporte de navegadores para propiedades modernas de CSS. También hablamos de lo que suponen los Headless CMS dentro de entornos CMS como WordPress, con tecnologías como<a href="https://frontity.org/" data-type="URL" data-id="https://frontity.org/"> Frontity.</a></p>



<p>Por último con Jesús hablamos sobre otro proyecto que tiene para realizar un sistema de diseño y además sobre el futuro de WordPress.</p>



<p>En la parte final del podcast volvemos con la sección de Radar, con una aportación variada de herramientas, enlaces y recursos de gran interés para el desarrollo web y creación de contenidos en internet.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Simple Anomaly Detection Using Plain SQL</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">20 09 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Many developers think that having a critical bug in their code is the worse thing that can happen. Well, there is something much worst than that: Having a critical bug in your code and not knowing about it! Using some high school level statistics and a fair knowledge of SQL, I implemented a very simple anomaly detection system.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Estado del ecosistema PHP con Jesús Amieiro">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Estado del ecosistema PHP con Jesús Amieiro</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">12 09 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>Tras el parón veraniego, retomamos los episodios del podcast para hablar sobre PHP. Para ello tenemos como invitado a Jesús Amieiro, un gran divulgador del lenguaje, a través de su newsletter / podcast La Semana PHP. Jesús es ingeniero de telecomunicación y desarrollador web, especialista en entornos PHP.  Jesús además de su trabajo como director técnico en proyectos tecnológicos, es un gran conocedor del ecosistema PHP y participa en numerosos eventos como WordCamps y meetups.</p>



<p>Por si fuera Jesús saca tiempo para difundir oportunidades de empleo en un canal de Telegram, con ofertas de trabajo en el entorno PHP y reciente ha estrenado la versión podcast de su newsletter. </p>



<p>Entre las cuestiones que comentamos junto a Jesús Amieiro:</p>



<ul><li>Novedades más destacables de la nueva versión PHP 8.</li><li>Repaso a la actualidad de los principales frameworks y gestores de contenido.</li><li>Perfil profesional detectado a través de su canal de Telegram.</li><li>El trabajo con la newsletter y el podcast La Semana PHP.</li><li>Futuro del lenguaje y recursos interesantes.</li></ul>



<p>En definitiva una charla muy completa con un entusiasta del ecosistema PHP, que nos deja con ganas de un nuevo episodio para tratar más tecnologías.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/188-adjustment.png" alt="Adjustment">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Adjustment</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">08 09 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/188-adjustment.png" alt="Adjustment" title="And the good news is that the coffee is free" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">August 2020 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">07 09 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Read more updates from Malli, Practicalli, Clj-kondo/babashka/sci, and Datahike
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/187-new-hire.png" alt="New Hire">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">New Hire</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">31 08 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/187-new-hire.png" alt="New Hire" title="We also cut the coffee budget!" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">DebConf20 online closes</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Debian News</a> <span class="article__date">30 08 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
On Saturday 29 August 2020, the annual Debian Developers
and Contributors Conference came to a close.
  
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q3 2020 Funding Announcement</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">28 08 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together is funding clj-kondo/babashka/sci, Datahike, Malli, and Practicalli
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">July 2020 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">27 08 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Read more updates from Cider, Figwheel, Practicalli, and Re-frame
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/186-wish-granted.png" alt="Wish &#39;Granted&#39;">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Wish &#39;Granted&#39;</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">25 08 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/186-wish-granted.png" alt="Wish 'Granted'" title="Have you tried religion?" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Python libraries to make your code readable, reliable and maintainable</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Isaak’s Blog</a> <span class="article__date">24 08 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Experienced programmers understand perfectly well that in development they spend most of the time reading code and therefore they treat the process of writing code with the deepest trepidation (and sometimes with fanaticism). To write quality and maintainable code, you need to take the time to write tests and integrate QA tools. There is a whole technique aimed at test-driven development (TDD) and I will not devote this article to the topic of testing as such. Tests are absolutely necessary and there is nothing to discuss. In this article, we are going to talk about tools that help you write quality Python code.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/185-code-freeze.png" alt="Code Freeze">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Code Freeze</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">18 08 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/185-code-freeze.png" alt="Code Freeze" title="Code &quot;Freeze&quot;" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Remote teams and the half-life of social capital</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">11 08 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Remote work is a mixed bag. Some aspects are wonderful. The lack of commute and extra flexibility is great. But there are drawbacks. Being remote comes with radical changes to how we communicate. Things that were effortless and unconscious in person become tiresome when we’re remote. And right now, so many of us are trying out this remote experiment together. But as time goes on, maybe the novelty is starting to wear off.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/184-regex-explained.png" alt="Regex Explained">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Regex Explained</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">11 08 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/184-regex-explained.png" alt="Regex Explained" title="The halftime of you understanding a regex expression is inversely proportional to the number of capture groups squared." /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/183-duplicates.png" alt="Duplicates">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Duplicates</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">04 08 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/183-duplicates.png" alt="Duplicates" title="The bug is both unique and duplicate, until you spend a huge amount of time going through the backlog and the quantum superposition ends and reality collapses into one possibility or the other." /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The World’s Sneakiest Route Change</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">31 07 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Recently, I worked on a project that had a lot of dynamic data, and the ability for the user to filter through it. In this article, we'll see how I built it while maintaining fully-static, using pre-generated JSON files instead of a REST API. It's a sneaky trick, with unbeatable results from a user-experience perspective.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/182-art-overflow.png" alt="Art Overflow">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Art Overflow</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">28 07 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/182-art-overflow.png" alt="Art Overflow" title="My code is a masterpiece. Abstract, but a masterpiece" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Some SQL Tricks of an Application DBA</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">26 07 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Some tips and misconceptions about database development I gathered along the way.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cognitect Joins Nubank!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">23 07 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div class="paragraph">
<p>We are thrilled to announce that Cognitect is joining the Nubank family of companies. This is the next step in a long relationship, and opens new opportunities for Clojure worldwide. Please read the full story over on the <a href="https://cognitect.com/blog/2020/07/23/Cognitect-Joins-Nubank">Cognitect
blog</a>.</p>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Things to keep in mind when contributing to a software project</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">21 07 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        These are some are thoughts to keep in mind when we&#39;re contributing to a software project.
Know your tools   Git is maybe the most extended tool to manage version control in software and as a daily tool we should invest some time in knowing how to use it &#34;properly&#34;.
Configure your name and email properly   This helps to identify who make a change while we&#39;re browsing git log history.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Things to keep in mind when contributing to a software project</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">21 07 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>
These are some are thoughts to keep in mind when we&#39;re contributing to a software project.</p>
<div id="outline-container-headline-1" class="outline-2">
<h2 id="headline-1">
Know your tools
</h2>
<div id="outline-text-headline-1" class="outline-text-2">
<p>
<code class="verbatim">Git</code> is maybe the most extended tool to manage version control in software and as a daily tool we should invest some time in knowing how to use it &#34;properly&#34;.</p>
<div id="outline-container-headline-2" class="outline-3">
<h3 id="headline-2">
Configure your name and email properly
</h3>
<div id="outline-text-headline-2" class="outline-text-3">
<p>
This helps to identify who make a change while we&#39;re browsing git log history. Don&#39;t use initials or nicknames, in a few months or maybe years eventually you will be looking at the git log and if you see something like this <code class="verbatim">Author: XYZ &lt;xyz@some-random-provider.com&gt;</code> you won&#39;t have a clue who make that change. We can setup this information with:</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">git config --global user.name <span style="color:#e6db74">&#34;name and last name&#34;</span>
git config --global user.email <span style="color:#e6db74">&#34;work-or-personal-email&#34;</span></code></pre></div>
</div>
<p>
We can use it without <code class="verbatim">--global</code> to make these changes only in the current repository.</p>
</div>
</div>
<div id="outline-container-headline-3" class="outline-3">
<h3 id="headline-3">
Commits should have a title and a body
</h3>
<div id="outline-text-headline-3" class="outline-text-3">
<p>
A easy to remember &#34;rule&#34; could be &#34;Put what you did in the title and why you did it in the body&#34;. Memory is fragile and it could sound useless now but in a few months when you&#39;ll be looking at the log and see a commit and wanted to know why some change was made and the commit message just says &#34;Fix some error&#34; you probably will get angry with your past self.</p>
<p>
There is an article that explains this so much better than me, you could read it at <a href="https://chris.beams.io/posts/git-commit/">https://chris.beams.io/posts/git-commit/</a></p>
<p>
An easy &#34;hack&#34; to force yourself to follow this is create a &#34;commit template&#34;, it will be used when you make a commit and it will remind you about this rule. An example one could be:</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell"><span style="color:#75715e"># If applied, this commit will...</span>

<span style="color:#75715e"># Explain why this change is being made</span>

<span style="color:#75715e"># Provide links to any relevant tickets, articles or other resources</span></code></pre></div>
</div>
<p>
These lines are comments and won&#39;t be added to the final commit message.</p>
<p>
Put this in <code class="verbatim">~/.git_commit_message.txt</code> and then configure you <code class="verbatim">~/.gitconfig</code> like this:</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell"><span style="color:#f92672">[</span>commit<span style="color:#f92672">]</span>
	template <span style="color:#f92672">=</span> ~/.git_commit_message.txt</code></pre></div>
</div>
<p>
After configuring this every time you make a commit the content of <code class="verbatim">~/.git_commit_message.txt</code> will be filled into the commit message so that will remind you how to write a proper message. The editor/IDE you use to write a message will recognize this file.</p>
</div>
</div>
<div id="outline-container-headline-4" class="outline-3">
<h3 id="headline-4">
Review what your staging
</h3>
<div id="outline-text-headline-4" class="outline-text-3">
<blockquote>
<p>Friends don&#39;t let friend use <code class="verbatim">git add .</code></p>
</blockquote>
<p>
The tool you use to stage changes and then commit should allow you to stage chunks of code one by one. This way you can review what are you adding. You don&#39;t want to commit those debug messages or commented code that you were using while your working on the project. Or even worse you definitively don&#39;t want to commit credentials files.</p>
<p>
Also if you like to use <code class="verbatim">git</code> from the terminal, you can use <code class="verbatim">git add -p</code> to use an interactive mode, this will go through all the unstaged changes and will ask you one by one if you want to add them.</p>
</div>
</div>
</div>
</div>
<div id="outline-container-headline-5" class="outline-2">
<h2 id="headline-5">
Conventions and consistency
</h2>
<div id="outline-text-headline-5" class="outline-text-2">
<p>
Most projects already have a <code class="verbatim">CONTRIBUTING.md</code> file. This file has some guidelines and conventions used in the project. Take your time to read and understand it. Those guidelines exist to keep consistency across the project. They&#39;re not fixed rules and of course they could be improved but always discuss that with your team.</p>
</div>
</div>
<div id="outline-container-headline-6" class="outline-2">
<h2 id="headline-6">
Submitting a pull request
</h2>
<div id="outline-text-headline-6" class="outline-text-2">
<p>
OK you&#39;re done with a feature/fix/whatever your were working on. It&#39;s time to submit a pull request. This is a simple checklist that could be followed:</p>
<ul>
<li>
<p>Make sure your changes are in sync with the latest changes in <code class="verbatim">upstream</code>. Maybe you&#39;re been working on something for a few days but some new changes were made to the project since the last sync.</p>
</li>
<li>
<p>Make sure you ran the whole test suite, run checkers and others pre-commit workflow that your project have.</p>
</li>
<li>
<p>Check the commits you&#39;ve made. Maybe you can clean a little bit the log, remove some <code class="verbatim">WIP</code> commits or improving some messages.</p>
</li>
</ul>
<p>After you submit the pull request <strong>be your first reviewer</strong> before asking for more reviews. Once the pull request is created go to the pull request page on Github/Gitlab/etc and make a last check of your changes. Then assign the reviewers.</p>
<p>
Use tags, this way you are adding extra information that will help to understand and categorize the pull request, by looking at the tags we can know if the pull request is a fix, improvement, documentation, etc.</p>
<p>
Link your pull request with an issue. Github|Gitlab|etc have a nice feature to link pull requests with issues, for example if you&#39;re fixing a reported issue with number <code class="verbatim">10</code> add <code class="verbatim">fixes #10</code> in the pull request description and this will link it to that issue, this way we can have traceability about the work done and the issues reported.</p>
<p>
Improve pull request description, when you open a pull request Github|Gitlab|etc takes the first commit title and message and use them as title and description for the pull request so if we have made good commit messages most of the work is already done. Make review process a little easier by explaining what have you done. Maybe link another issues in different projects or bug reports related the changes you have made. Some extra context is always welcome :)</p>
</div>
</div>
<div id="outline-container-headline-7" class="outline-2">
<h2 id="headline-7">
Code review
</h2>
<div id="outline-text-headline-7" class="outline-text-2">
<p>
Keep in mind that comments made in your pull request are made about the code and not about you.</p>
<p>
Don&#39;t take a comment as a fact that should be followed immediately, reviewers can make mistakes too, if you think some suggestion doesn&#39;t apply, explain your point of view and try to understand what is the reason behind that suggestion.</p>
<p>
Don&#39;t make changes just to make reviewers happy and get your pull request merged. A code review is an excellent opportunity to get more knowledge about the project and to learn more about the code review process itself.</p>
<p>
If someone rewrite or delete some code that you wrote it isn&#39;t mean necessary is was &#34;bad code&#34; or something like that, maybe the requirement was different back then. Code has to evolve and at the end what matters the most is that the application does what is supposed to do. Also in some cases you&#39;ll be the one who is refactoring or fixing your own code after a while it was made ;)</p>
</div>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/181-side-project-showcase.png" alt="Side Project Showcase">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Side Project Showcase</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">21 07 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/181-side-project-showcase.png" alt="Side Project Showcase" title="Project ideas represented in this image are property of monkeyuser.com" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How are Lisp REPLs different from Python or Ruby REPLs ? (Hackernews, 2020)</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">14 07 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Mikelevins, <a href="https://news.ycombinator.com/item?id=23811382">https://news.ycombinator.com/item?id=23811382</a>, July 2020</p>

<p>(some more comments on <a href="https://www.reddit.com/r/lisp/comments/hqesvp/explaining_the_advantages_of_the_repl/">https://www.reddit.com/r/lisp/comments/hqesvp/explaining_the_advantages_of_the_repl/</a>)</p>

<p>(on terminology: we should maybe call Python&rsquo;s &ldquo;REPL&rdquo; a <em>shell</em>, and put emphasis on <em>image-based development</em>, instead of only saying REPL, for Lisp)</p>

<hr />

<p>I&rsquo;ve answered similar questions several times over the past few years, but I don&rsquo;t mind repeating myself. It offers me a glimmer of hope that my preferred way of working may not fade away, after all.</p>

<p>Consider the standard Common Lisp generic function <code>UPDATE-INSTANCE-FOR-REDEFINED-CLASS</code> (<a href="http://clhs.lisp.se/Body/f_upda_1.htm">http://clhs.lisp.se/Body/f_upda_1.htm</a>). It reinitializes an object when Lisp detects that the object&rsquo;s class definition has changed.</p>

<p>Ask yourself this: who would call such a function? Why would anyone ever invent it? Not only did someone invent it, a committee of some of the world&rsquo;s smartest and most experienced Lisp programmers wrote it into the ANSI standard for the language. What were they up to?</p>

<p><code>UPDATE-INSTANCE-FOR-REDEFINED-CLASS</code> is not a weird anomaly; it&rsquo;s part of a carefully-considered set of features and protocols designed to support a specific style of programming. The Lisp runtime calls it for you automatically when it touches an object whose class definition has changed.</p>

<p>If you&rsquo;ve defined a method specialized for it, then Lisp executes that method to rebuild the touched instance as if it had originally been instantiated from the class&rsquo;s new definition, and then your program goes its merry way. If you didn&rsquo;t specialize <code>UPDATE-INSTANCE-FOR-REDEFINED-CLASS</code> for this case, then the Lisp drops you into a breakloop.</p>

<p>A breakloop is an interactive repl with full access to all of the runtime&rsquo;s memory and all of the language&rsquo;s features, including visibility into the whole call stack that landed you in the breakloop. You can wander up and down the call stack, inspect anything in the runtime, edit bindings, redefine types and functions, and resume execution either at the point of control where the breakloop started, or at any other point for which the breakloop exposes a restart.</p>

<p><code>UPDATE-INSTANCE-FOR-REDEFINED-CLASS</code> is not the weird fever dream of a confused eccentric. It&rsquo;s part of a purposeful system design intended to support a style of programming in which you build a program by interacting with a live runtime and teach it, interaction-by-interaction, how to be the program you want, while it runs.</p>

<p>It&rsquo;s a particular example of a general approach to programming best exemplified by these old systems. That general approach is the answer to your question: &ldquo;Can someone knowledgeable explain how are lisp REPLs different from Python / Ruby REPLs? What is the differentiating point of REPL driven development?&rdquo;</p>

<p>The differentiating point is that the entire language and system is thoughtfully designed from the ground up with the assumption that you&rsquo;re going to be changing your work in progress while it runs, and that you should be able to change absolutely anything about it as it runs and have a reasonable expectation that it will continue to work while you do it.</p>

<p>I like to call this style of programming &ldquo;programming as teaching&rdquo;, and distinguish it from the much more widespread &ldquo;programming as carpentry&rdquo;, in which the programmer is, metaphorically speaking, at a workbench banging together artifacts and assembling them to see how they turn out.</p>

<p>To be clear, I do not claim that the teaching approach is objectively better than the carpentry approach. I claim only that I, personally, am happier and measurably more productive using the teaching approach. I know that some other programmers report the same thing, and I suspect that if the teaching style of programming were more widely known, then there would be more programmers who prefer it.</p>

<p>There are several sibling comments that assert that any language can be made to support repl-driven programming, or that offer various languages and systems as examples of repl-driven programming. I&rsquo;m sure that&rsquo;s all true, for some relatively restricted version of repl-driven programming, but the gold standard in repl-driven programming is programming as teaching in the style of old-fashioned Lisp and Smalltalk systems. These old systems offer amenities that the younger alternatives touted here do not match. I want more people to be aware of what they&rsquo;re missing.</p>

<p>Starting in the 1980s, I grew accustomed to systems that could start from cold in about a second, presenting to me a complete interactive development environment with all tools preloaded and ready to work, with the whole dynamic environment of my work in progress in the same state it was in the last time I was working with it. Moreover, I was accustomed to being able to take a single file from one machine to another to reproduce that same whole working environment equally quickly and easily on the new machine.</p>

<p>I could save the entire dynamic state of the running system to an image file, a serialized version of the running system&rsquo;s memory. I could later start up the system with that image file and be exactly where I was when I saved the image, right down to the positions and contents of all the open windows. I could save an image showing some bug or some strange behavior and give it to a colleague so that they could see it, too, and interact with the restored dynamic state to debug it.</p>

<p>I enjoyed comprehensive whole-system reflection that enabled me to view and edit absolutely everything in the running system while it ran. I could inspect absolutely everything, including the development environment and all its tools, interactively change any variable or field value, redefine any type or function, and continue to work with the changed system without stopping and restarting. (Obviously, if I made a bad change I might break the system, but remember, I could kill it and get back to where I started in a second or so).</p>

<p>I could start some process running&ndash;perhaps a 3D animation in a game, or a discrete-event simulation, or whatever&ndash;and change any values or definitions I liked to see what changed in the running process, without stopping the process to rebuild. For example, I could tell a rotating copper cube to become a glass icosahedron and reasonably expect to see my changes immediately reflected in the running program. This property is invaluable not only in games, simulations, and any kind of work with a visual-design component, but also in any kind of exploratory programming, where you&rsquo;re constructing data structures and evaluating expressions interactively to test your ideas.</p>

<p>Similarly, I could build some speculative data structure to explore an idea, and define some functions to operate on it. I could evaluate those expressions to see their results or to change the example structure. I could inspect the structure interactively and edit it in place if I think something different would work better. If I think a problem is caused by some structure or value in it, I could use the inspector to change it and see. If I thought one my my functions was doing something I didn&rsquo;t expect, I could insert a call to break, to activate a repl from inside the function call that would enable me to inspect and edit the data structure, redefine the function, and continue from there.</p>

<p>Anything the development system could do, I could do by typing an expression into the repl. As an example, nowadays you can still rebuild the whole Clozure Common Lisp environment from the ground up by typing (rebuild-ccl :full t).</p>

<p>The point is not that I would want to rebuld my Lisp from the repl all the time. The point is that the repl doesn&rsquo;t impose any aribtrary boundaries on what I can do. If the language and development environment can do it, I can do it from the repl. This is one of the properties that distinguishes the whole-system interactive design of these old tools from the more limited repls offered by newer ones. In pretty much every repl I&rsquo;ve used other than old-style Lisps and Smalltalks I&rsquo;m all the time stumbling over things you can&rsquo;t do from the repl.</p>

<p>I mentioned breakloops above. Their absence in younger languages and tools seem to me like some sort of sin, like we&rsquo;re tragically abandoning some of the best lessons of the past. Few newer development systems have them, but they&rsquo;re incredibly useful&ndash;at least if the language runtime is designed to properly support interactive programming.</p>

<p>A breakloop is a repl with all of the same affordances of the normal repl, but extended with all of the dynamic state of the control path that invoked the breakloop. If an error or an intentional call to break triggers a breakloop somewhere deep in a stack of recursive function calls, you get a repl that can see every frame of that stack, and every variable and value lexically accessible from it. You can browse all of that whole, change values, and redefine functions and types. You can resume execution at your leisure, and any changes you made in the breakloop will be visible in the resumed computation just as if that&rsquo;s how things were originally.</p>

<p>Proper breakloops don&rsquo;t just improve error messages; they replace them wholesale with an entire species of programming that lays the whole dynamic state of the system out on the table for you to examine and modify while the program continues to run.</p>

<p>Moreover, everything I just described about breakloops can also be automated. These old systems provide not only interactive tools for rummaging through the dynamic state of a suspended computation, but also APIs for handling them under program control. For example, you can wrap an arbitrary function call in condition handlers that will either drop you into a breakloop and enable you to vivisect the program state, or consult the dynamic state and compute which of several restarts to activate in order to transfer control to a path of your choosing.</p>

<p>I&rsquo;m banging up against HN&rsquo;s length limit, but the above, I hope, goes some way toward answering to your question.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://markosaric.com/wp-content/uploads/favicon.ico" alt="13% of my website visitors block Google Analytics">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">13% of my website visitors block Google Analytics</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Marko Saric</a> <span class="article__date">13 07 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        There&#8217;s widespread use of adblockers on the web but users are increasingly blocking cookies and other tracking scripts too. Browsers such as Safari, Firefox and Brave are privacy-focused. Many users install additional plugins such as uBlock Origin to better protect themselves. Is Google Analytics still efficient considering the blocking rate? How big is the data&#8230; <a class="more-link" href="https://markosaric.com/google-analytics-blocking/">Continue reading <span class="screen-reader-text">13% of my website visitors block Google Analytics</span></a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Historias del Backend con Antonio Pérez de Full Stack Podcast">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Historias del Backend con Antonio Pérez de Full Stack Podcast</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">11 07 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Vuelve nuestro amigo <a href="https://antonioperez.pro/" rel="noopener noreferrer" target="_blank">Antonio Pérez</a> al podcast para otro episodio compartido con su programa Full Stack Podcast. Antonio ya nos acompañó allá por el episodio 78 en un <a href="https://republicaweb.es/podcast/ruby-on-rails-frente-a-python-con-antonio-perez/" rel="noopener noreferrer" target="_blank">programa titulado Ruby on Rails frente a Python</a>. En ese episodio Antonio nos estuvo contando cosas muy interesantes sobre Ruby on Rails y para este episodio hemos preparado el contenido alrededor del perfil de backend.</p>
<h2>¿Qué habilidades clave debería tener un profesional del backend?</h2>
<p>Para Antonio Pérez, un desarrollador de backend debe tener un perfil muy completo con unas habilidades muy distintas: Una capacidad alta de abstracción, conocimientos de arquitectura web y un conocimiento amplio de bases de datos.</p>
<p>Para Andros un backend debe tener la capacidad de leer y entender el contexto de lo que está realizando. Por eso es importante acudir a la documentación y a los manuales. Otro aspecto es entender que es normal que no se pueda saber de todo. Por último, Andros también coincide sobre la importancia de conocer de manera sólida las bases de datos.</p>
<p>David Vaquero coincide en la necesidad de tener una base muy sólida del protocolo HTTP. También que el backend entienda bien los datos que está manejando y cómo se mueven. Y también vuelve a coincidir con la gestión de datos, caché y optimización. Por último David hace mención al conocimiento de API y al Server Side Rendering.</p>
<p>Para finalizar Javier comenta que a menudo el perfil de backend se asocia al conocimiento de un lenguaje de programación. Otro aspecto a destacar es el conocimiento de la computación y los bases del sistema operativo, procesos, memoria y red.</p>
<blockquote><p>Gran parte de los proyectos backend que se están ejecutando implican tareas de mantenimiento, monitorización y mejora. Con independencia del lenguaje, el backend necesita mucha investigación y aprendizaje. </p></blockquote>
<h2>La importancia de la gestión de las bases de datos y la memoria caché</h2>
<p>Como comenta Antonio, el backend un última instancia es servir datos: cuando mayor conocimiento y eficacia en la capa de base de datos, mejor funciona la parte de backend. Conocer los motores de bases de datos, profundo conocimiento de SQL y conocer los ORM.</p>
<p>Andros habla sobre lo básico de entender la gestión de bases de datos y pone como ejemplo la aplicación de Notion y lo fundamental que es optimizar en la capa de datos. También incidimos en el conocimiento de los básicos como programación orientada a objetos, computación y redes. Una recomendación que hacemos es el libro <a href="https://nostarch.com/foundationsofcomp" rel="noopener noreferrer" target="_blank">The Secret Life of Programs </a>publicado por No Starch Press.</p>
<p>Por último David destaca que el mundo de las bases de datos también incluye las tecnologías NoSQL y que hay que separar la teoría de base de datos con la práctica.</p>
<h2>Escribir sentencias SQL vs ORM</h2>
<p>Otro de los temas que han surgido en la conversación son los ORM vs la escritura de sentencias SQL. Antonio explica cómo en ciertas ocasiones escribir directamente las sentencias SQL resulta más productivo o eficaz que depender de un ORM. Antonio destaca Active Record de Rails como una herramienta flexible para trabajar con el acceso a datos. También hablamos brevemente algunos de los ORM más habituales.</p>
<p>El back end es la parte más cercana a la lógica de negocio y por tanto debes tener un conocimiento muy preciso y amplio de cómo funciona un negocio a </p>
<h2>El papel del cloud en el backend y el serverless</h2>
<p>Hay espacio para comentar cómo está evolucionando la computación en el lado de servidor con los servicios en la nube y más específicamente con el serverless tipo AWS Lambda. Con todo, son tecnologías que tienen un espacio determinado y que conviven con diferentes opciones en el lado de servidor. Antonio nos detalla algún ejemplo donde puede encajar este tipo de tecnologías. Otro aspecto a tener en cuenta es la optimización de esas funciones sin servidor porque pueden salir más caras que una arquitectura convencional cliente/servidor.</p>
<h2>Tecnologías de backend a tener en el radar</h2>
<p>Antonio nos cuenta algunas tecnologías a tener muy en cuenta como la contenerización, micro-servicios, serverless, entornos elásticos en la nube y la asincronía. También reserva un espacio para hablar sobre el papel de JavaScript en el lado servidor y sus reservas con respecto a sus ventajas en materia de asincronía. Por último Antonio nos ha contado sus proyectos futuros, como una web de cursos de desarrollo, estudiando tecnologías como Data Science y NoSQL.</p>



<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p><p>Nos podéis encontrar en:</p><ul><li><a href="https://republicaweb.es">Web: republicaweb.es</a></li> <li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li> <li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li><li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li> <li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li> </ul><p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!<ul><li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li> <li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li> <li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li> </ul>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">June 2020 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">09 07 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Read more updates from Fireplace, Cider, Figwheel, Practicalli, Re-frame, and Clojars
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The idiomatic comparison in Python</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Isaak’s Blog</a> <span class="article__date">08 07 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Some newbies in Python often improperly use the operators is and == without knowing how exactly they work and when to use each one. In this article, I’ll talk about the difference between them, and about the use cases of each one.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hack Keyboard Shortcuts Into Sites with a Custom Chrome Extension</h1>
                            <h2 class="article__feed"><a target="_blank" href="">blog.karenying.com</a> <span class="article__date">07 07 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Increase productivity by adding custom keyboard shortcuts to your favorite sites
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Las cheat sheets de Manz, aprendizaje y especialización en desarrollo web">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Las cheat sheets de Manz, aprendizaje y especialización en desarrollo web</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">07 07 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Nuestro episodio 147 con Manz se alargó tanto que se nos quedaban algunos temas pendientes que no queríamos perder. Por eso le planteamos a Manz un episodio adicional como bonus, dirigido a hablar sobre sus plantillas o chuletas (cheat sheets). Desde hace años Manz distribuye de manera gratuita estos útiles recursos para aprender desarrollo web.</p>
<p>Manz nos cuenta el origen de estos recursos, cómo las diseña y el público que las consume. Manz publica estas plantillas bajo un modelo de donación, pero como descarga libre y gratuita.</p>
<p>En esta conversación también surgen otros temas interesantes como son el papel del idioma inglés en los contenidos, el aprendizaje del desarrollo web y la especialización versus los perfiles generalistas en la profesión. </p>
<p>Como hemos comentado en el podcast con la entrevista, esperamos poder compartir con Manz alguna episodio adicional para tratar más temas sobre diseño y desarrollo web.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://markosaric.com/wp-content/uploads/favicon.ico" alt="Only 9% of visitors give GDPR consent to be tracked">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Only 9% of visitors give GDPR consent to be tracked</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Marko Saric</a> <span class="article__date">06 07 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Privacy regulations such as the GDPR say that you need to seek permission from your website visitors before tracking them. Most GDPR consent banner implementations are deliberately engineered to be difficult to use and are full of dark patterns that are illegal according to the law. I wanted to find out how many visitors would&#8230; <a class="more-link" href="https://markosaric.com/gdpr-consent/">Continue reading <span class="screen-reader-text">Only 9% of visitors give GDPR consent to be tracked</span></a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Thoughts about naming variables and methods</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Isaak’s Blog</a> <span class="article__date">06 07 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The proper naming of variables, functions, methods, and classes is one of the most important attributes of elegant and clean code, that clearly reflects the intentions of the programmer, without assumptions about what was meant.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A teeny-tiny note about comments and dead code</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Isaak’s Blog</a> <span class="article__date">05 07 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Comments are something that can both: ruin your code and make it better.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Divulgación y aprendizaje de tecnologías Front-end con Manz">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Divulgación y aprendizaje de tecnologías Front-end con Manz</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">04 07 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>En este episodio tenemos como invitado al divulgador Manz, autor del <a href="https://www.emezeta.com/" rel="noopener noreferrer" target="_blank">blog Emezeta</a> y creador de la chuleta (o cheat sheet)  HTML/CSS/Javascript más popular de la web. Actualmente Manz compagina su actividad de profesor en la <a href="https://www.ull.es/">Universidad de La Laguna</a> (Tenerife) con otros proyectos profesionales. Man empezó como profesor en la Oficina de Software Libre impartiendo cursos de formación en temáticas relacionadas con el desarrollo, la programación web, front-end, back-end, cloud computing, marketing digital o temas relacionados con la tecnología de internet.</p>
<p>Manz además mentoriza proyectos y startups en la Escuela de Organización Industrial. También colabora como formador y consultor en programas de emprendimiento de la Fundación INCYDE. Con él hablamos de JavaScript, Web Componentes, CSS, Shadow DOM, gestores de tareas y un montón de cosas interesantes relacionadas con el front-end.</p>
<p>Entre las cuestiones planteadas con Manz:</p>
<ul>
<li>Javascript-fatigue, ¿el Front-End es una carrera de fondo sin una meta definida?</li>
<li>¿Qué son los Webcomponents? ¿Shadow DOM? ¿Son el futuro? Ejemplos prácticos.</li>
<li>CSS-in-JS, ¿estamos invadiendo territorios o creando naciones?</li>
<li>¿Por qué necesitamos automatizadores? ¿En que se diferencian: Parcel / Webpack / Rollup / Gulp?</li>
</ul>
<p>Una interesantísima conversación con un divulgador y apasionado de las tecnologías web, con el que además dedicaremos un episodio bonus para contar su trabajo con las plantillas y sus cheat sheets de diferentes lenguajes.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The beginning of the way</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Isaak’s Blog</a> <span class="article__date">04 07 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        As we all know, the best way to learn new things is by teaching others and this blog is my way to learn new things.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">50 Shades of Dark Mode Gray</h1>
                            <h2 class="article__feed"><a target="_blank" href="">blog.karenying.com</a> <span class="article__date">03 07 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Deep dive into Spotify, Twitter, Facebook’s dark mode palettes by analyzing Hex codes
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">404: React Page Not Found</h1>
                            <h2 class="article__feed"><a target="_blank" href="">blog.karenying.com</a> <span class="article__date">02 07 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        How to avoid the dreaded "Page Not Found" bug for apps using React Router on Netlify
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Annoy (or Impress) Your Coworkers with a Slack Bot From Scratch</h1>
                            <h2 class="article__feed"><a target="_blank" href="">blog.karenying.com</a> <span class="article__date">29 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I made a Slack bot in under 30 lines of code to remind my coworker to eat lunch
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">LOS RESIDUOS EN CANARIAS. LA CULTURA DEL USAR Y TIRAR. LOS MICROPLÁSTICOS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">29 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Vivir la GPL o explotar GPL con José Conti">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Vivir la GPL o explotar GPL con José Conti</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">29 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>En este podcast hemos tratado en alguna ocasión cuestiones relacionadas con el código abierto y la dificultad que conlleva vivir de los proyectos abiertos. En este programa volvemos con estas cuestiones y hemos invitado al desarrollador especialista en WordPress, José Conti para hablar sobre GPL, o la licencia pública general GNU. Recientemente José Conti publicó un sólido artículo titulado <a href="https://redsys.joseconti.com/2020/06/21/vivir-gpl-o-explotar-gpl/" rel="noopener noreferrer" target="_blank">Vivir la GPL o explotar GPL</a>, donde trataba con detalle su vinculación profesional y personal con el software libre, y al mismo tiempo, explicaba la forma en la que muchas personas se aprovechan de ella, buscando exclusivamente un beneficio personal.</p>
<p>Con José Conti discutimos entre varias cuestiones, la finalidad de la licencia GPL, cómo encaja la GPL en el desarrollo y venta del software, su financiación y el día a día de un desarrollador que vive de un proyecto bajo esa licencia.</p>
<p>Entre las preguntas planteadas a José Conti, tenemos:</p>
<ul>
<li>¿Qué fines fundamentales persigue la licencia GPL?</li>
<li>¿Es acertado el planteamiento de la licencia GPL a la hora de repercutir valor económico al desarrollador?.</li>
<li>En tu artículo explicas que se han popularizado los sitios de reventa de plugin con un precio inferior y saltándose al desarrollador. Se amparan en que la GPL permite vender software, aunque sea una de las cuestiones más complicadas de entender de la licencia…¿Cómo explotan estos sitios la filosofía abierta de la GPL?</li>
<li>¿Son los usuarios conscientes de lo que cuesta mantener los proyectos de software?</li>
<li>¿Qué modelo considerarías más acertado para recompensar a los desarrolladores de software libre?</li>
<li>¿Qué visión tiene la comunidad WordPress respecto a la GPL?</li>
<li>¿Cómo es tu plugin de RedSys por dentro y qué relación tienes con ellos?</li>
</ul>
<p>En resumen una animada conversación con un profesional del software vinculado a un proyecto GPL y con una experiencia de gran valor creando soluciones abiertas y libres.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Roy Fielding’s Misappropriated REST Dissertation</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Two-Bit History</a> <span class="article__date">28 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        RESTful APIs are everywhere. This is funny, because how many people really know what “RESTful” is supposed to mean? I think most of us can empathize with this Hacker News poster: I’ve read several articles about REST, even a bit of the original paper. But I still have quite a vague idea about what it is. I’m beginning to think that nobody knows, that it’s simply a very poorly defined concept. I had planned to write a blog post exploring how REST came to be such a dominant paradigm for communication across the internet. I started my research by reading Roy Fielding’s 2000 dissertation, which introduced REST to the world. After reading Fielding’s dissertation, I realized that the much more interesting story here is how Fielding’s ideas came to be so widely misunderstood.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A Brief Hiatus</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">25 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        When I rebooted this blog in early 2020, the plan was to publish 1 new post every 2 weeks. No one was more surprised than myself when I actually stuck to that! Unfortunately, a few weeks ago I injured my Ulnar nerve. I spend _a lot_ of time on computers, and I think it's caught up with me. My physiotherapist…
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">I’m a Gen Z-er and I want you to stop using emojis</h1>
                            <h2 class="article__feed"><a target="_blank" href="">blog.karenying.com</a> <span class="article__date">24 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        An analysis on emoji usage in the popular app Notion
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojurists Together Summer of Bugs Selections</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">23 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The Summer of Bugs selections are: clj-kondo vim-iced, DataScript, Calva, reitit, Keycloak-Clojure, cljc.java-time
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/180-schmuck.png" alt="Schmuck">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Schmuck</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">23 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/180-schmuck.png" alt="Schmuck" title="you've really got to be some schmuck to fall for that one" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Configuring a Mac for a PC User</h1>
                            <h2 class="article__feed"><a target="_blank" href="">blog.karenying.com</a> <span class="article__date">22 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        How to finally take the plunge and configure your new Mac as a former average PC user
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="David Vaquero hace balance de su primer año en el podcast">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">David Vaquero hace balance de su primer año en el podcast</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">20 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>El primer aniversario de nuestro compañero David Vaquero en el podcast, nos da pie a realizar un episodio personal donde David nos cuente lo que ha supuesto este primer año. Aunque en este episodio hablemos de la experiencia de David, es un buen episodio para destacar lo que supone participar y producir un podcast. Es una buena oportunidad también para hacer algo de balance del último año y hablar sobre la dirección que puede tomar el programa en el futuro.</p>
<p>Entre las cuestiones que hablamos con David se incluyen:</p>
<ul>
<li>¿Cómo empezaste a escuchar el podcast?</li>
<li>¿Qué ha mejorado de tu parte profesional y personal hacer este podcast?</li>
<li>Te estás encargando de poner videos en tu canal de Youtube &#8230;¿Qué tal la experiencia?</li>
<li>¿En qué dirección debería progresar el programa?</li>
</ul>
<p>En la segunda parte del programa tratamos en la sección Radar, la aparición de la nueva versión de Bootstrap en su quinta edición (en alpha), también de Quasar un framework basado en VUEJS para PWA, Cordova/Capacitor y Electron. Por último comentamos un interesante recurso pedagógico para comprender mejor Amazon Web Services.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Adding Transitions to a React Carousel with Material-UI</h1>
                            <h2 class="article__feed"><a target="_blank" href="">blog.karenying.com</a> <span class="article__date">16 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        PowerPoint-esque slide animations + React carousel
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">LOS RESIDUOS EN CANARIAS. LA CULTURA DEL USAR Y TIRAR. VERTEDEROS ILEGALES.</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">16 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/179-release-cycle.png" alt="Release Cycle">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Release Cycle</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">16 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/179-release-cycle.png" alt="Release Cycle" title="Greetings from the future!" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">May 2020 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">15 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Read more updates from Fireplace, Cider, Figwheel, Practicalli, Re-frame, and Clojars
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">April 2020 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">15 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Read more updates from Ring, Calva, Reagent, Fireplace, and Clojars
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Let 2020 be the year PNG icons die</h1>
                            <h2 class="article__feed"><a target="_blank" href="">blog.karenying.com</a> <span class="article__date">14 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Examining a trendy store’s mysteriously blurry rating stars and proposing a solution
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Lenguajes de backend más utilizados y presentación de Tadam framework web en Clojure">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Lenguajes de backend más utilizados y presentación de Tadam framework web en Clojure</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">12 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Seguimos en el podcast con los estudios de las tecnologías más utilizadas en la web, basado en el estudio de David Vaquero sobre el millón de páginas web según Alexa. En esta ocasión nos detenemos a analizar los datos de los lenguajes de backend más utilizados. Uno a uno vemos los principales lenguajes y tecnologías web que representan el top del ranking. Entre ellas:</p>
<ul>
<li>PHP</li>
<li>LUA+ OpenResty</li>
<li>Python</li>
<li>Asp.NET</li>
<li>Java + OpenGSE</li>
<li>Ruby + Ruby on Rails</li>
<li>Javascript + NodeJS + ExpressJS</li>
</ul>
<p>Accede al estudio de David Vaquero en su página web. <a href="https://cursosdedesarrollo.com/2020/06/que-lenguajes-de-backend-son-los-mas-utilizados-en-el-millon-de-paginas-del-top-de-alexa-y-en-los-dominios-en-espana/" rel="noopener noreferrer" target="_blank">Estudio lenguajes Backend sobre millón de sitios web de Alexa.</a></p>
<p>En la segunda parte Andros nos trae su último proyecto, un framework web llamado<a href="https://www.tadam-framework.dev/" rel="noopener noreferrer" target="_blank"> Tadam </a>y que está realizado en Clojure. Se trata de un minimalista framework para crear sitios web dinámicos orientados a la programación funcional. Andros nos cuenta el potencial de Clojure para un desarrollo moderno y más fiable, al depender de un paradigma funcional, más fácil de detectar errores y mucho más predecible.</p>
<p>Para finalizar el episodio traemos en la sección de Radar, unos cuantos recursos de interés, noticias y herramientas que os ayudarán en vuestro desarrollo profesional. También comentamos algunas de las encuestas que Andros ha lanzado en nuestro grupo de Telegram Malditos Webmasters.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Using Netlify Functions with Gatsby</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">10 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Tools like Next and Gatsby are great for front-ends, but what about for apps that require a backend? Serverless functions have popped up to fill that gap, and they're *amazing*. In this tutorial, we'll see how to use Netlify Functions with Gatsby, to build full-stack web applications using the tools you already know and love!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/178-pair-programming.png" alt="Pair Programming">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Pair Programming</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">09 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/178-pair-programming.png" alt="Pair Programming" title="It's better together" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Reflexiones. COVID-19, medio ambiente y sociedad.</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">08 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://javierarcheni.com/wp-content/uploads/2021/04/cropped-favicon-javierarcheni-32x32.png" alt="Importa las tablas de tu base de datos a un nuevo proyecto Laravel">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Importa las tablas de tu base de datos a un nuevo proyecto Laravel</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Javier Archeni</a> <span class="article__date">07 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Llega un momento en el que decides que esa aplicación web que hiciste desde cero hace años, necesita actualizarse. Es posible que esa aplicación web fuera una de tus primeros trabajos o que se hiciera con algún código heredado y necesitas pasarte a un framework moderno como Laravel. Aunque la concisa documentación de Laravel explica &#8230; <a href="https://javierarcheni.com/blog/importa-las-tablas-de-tu-base-de-datos-a-un-nuevo-proyecto-laravel/">Ver más</a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Looking for a Lisp Web Developer (not a real job, but nearly)</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">05 06 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Dear lispers,</p>

<p>I decided that I can not develop three projects in parallel fast enough, so I&rsquo;m seeking for a fellow programmer to join the effort.</p>

<p><strong>Disclaimer: this is not a real position, but there is a little budget</strong></p>

<p>I recently presented my <a href="https://lisp-journey.gitlab.io/blog/a-free-software-for-bookshops-to-show-their-catalogue-online/">online catalogue for bookshops</a>. You will work on something very similar, but bigger. I need help to re-write the existing free software for bookshops in Common Lisp. The existing one is in Python. I have a prototype of the new CL one.</p>

<p>The software specifications are here and are good. We wrote them years
ago by consulting people selling books, and we now grow on our
experience acquired developing the first Python app as well as on the
feedback gathered from clients. The challenge is to build a
maintainable, fast, bug-free, easily-deployable application with an
user interface that answers the clients&rsquo; needs.</p>

<p>I ask you to have some experience in:</p>

<ul>
<li>Common Lisp</li>
<li>the web: HTML, CSS, web browser API</li>
<li>SQL</li>
</ul>

<p>You should also have a sufficiently good english to speak with me (a non-native speaker).</p>

<p>I would have tasks for you in June and July, nothing in August, and
hopefully more in September and onwards.</p>

<p>Bonus points include, in no particular order:</p>

<ul>
<li>acquaintance with JavaScript, with a JS framework (preferably Vuejs)</li>
<li>good HTML&amp;CSS design skills</li>
<li>you speak french</li>
<li>you have a good english, or good communication skills in your mother tongue</li>
<li>good backend and &ldquo;devops&rdquo; experience</li>
<li>Python experience to install and study an existing project</li>
</ul>

<p>If this appeals to you, please email me at <code>(reverse
&quot;gro.zliam@leradniv&quot;)</code> and indicate roughly how you stand in these
points, your availability in June, during the upcoming two weeks
for a meeting, and we&rsquo;ll speak further.</p>

<p>Thanks!</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Stop Using datetime.now!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">31 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>If you ever had a test that one day just started to fail, unprovoked, or a test that fails once every blue moon for no apparent reason, it's possible your code is relying on something that is not deterministic. In this article I describe a practical approach to dependency injection in Python that when used correctly, can eliminate nondeterminism and make your code easier to maintain and to test.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ondahostil.files.wordpress.com/2018/08/yo.jpg?w=32" alt="En qué ando: edición confinamiento">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">En qué ando: edición confinamiento</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Onda Hostil</a> <span class="article__date">31 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A los académicos nos han repetido hasta la saciedad que Newton (¡Newton!) fue hiperproductivo cuando debió encerrarse. Que es una oportunidad para escribir todo eso que no podíamos escribir porque cosas. Los adalides de la producción nunca se lo imaginarían, pero esas cosas1 han empeorado durante el confinamiento. Como respuesta a esta exigencia decidí ajustar [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Las crónicas de los navegadores web con Álex Barredo">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Las crónicas de los navegadores web con Álex Barredo</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">30 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Invitamos a Álex Barredo para hablar sobre el estado de los navegadores web y el ecosistema actual de uso. Además de su faceta de divulgación tecnológica en sus diferentes canales <a href="https://mixx.io/" rel="noopener noreferrer" target="_blank">(mixx.io podcasts y newsletters)</a>, Álex también siente debilidad por el mundo de los navegadores y hasta tuvo un blog donde contaba las novedades que iban surgiendo en torno a ellos. En este episodio especial hablamos con Álex de la situación actual y del aplastante liderazgo de Google en el ámbito de los navegadores de escritorio y móviles.</p>
<p>Entre las cuestiones que tratamos:</p>
<ul>
<li>¿Seguirá siendo todavía más en el futuro? ¿Se vislumbran planes para limitar con legislación antimonopolio al gigante de Google?
</li>
<li>El año pasado Microsoft Edge se rindió a los pies de Chromium, el software de código abierto que lidera Google, pasando a usar Blink y V8 como motores.¿Ha sido una decisión buena para Microsoft y mala para competencia?.
</li>
<li>Primeros navegadores, orígenes de Internet Explorer y las guerras de los navegadores en el 2000.</li>
<li>Porcentajes de uso, competencia actual entre navegadores y situación con respecto Europa, América y Asia.</li>
<li>El papel de la fundación Mozilla y el estado actual de Firefox.</li>
<li>Modelos de negocio alternativos para los navegadores y caso Brave.</li>
<li>Apple y su papel en el desarrollo con Safari.</li>
</ul>
<p>Posiblemente Álex sea una de las personas mejor informadas del panorama tecnológico y es un lujo poder compartir con él un rato para hablar sobre el estado actual de los navegadores web. Sin duda es un tema que seguirá avanzando durante los próximos meses y que ofrece un escenario donde los grandes de internet y la tecnología se disponen a seguir combatiendo en uso y funcionalidades.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://abstock.gitlab.io/search.png" alt="A free software for bookshops to show their catalogue online">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">A free software for bookshops to show their catalogue online</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">30 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>I wrote a free software for bookshops to publish their catalogue
online. Clients can now browse the available books and order them. It
is enough generic so we can show other products too.</p>

<ul>
<li><a href="https://abstock.gitlab.io/#/en/">https://abstock.gitlab.io/#/en/</a></li>
<li>sources and bug tracker: <a href="https://gitlab.com/vindarel/abstock">https://gitlab.com/vindarel/abstock</a></li>
<li>Github mirror: <a href="https://github.com/vindarel/ABStock">https://github.com/vindarel/ABStock</a></li>
<li><a href="https://frama.link/syVBKWPw">the demo</a></li>
</ul>

<p>Here&rsquo;s how a search result looks like:</p>

<p><img src="https://abstock.gitlab.io/search.png" style="max-width: 1200px"/></p>

<h1 id="features">Features</h1>

<p>The website is made generic enough for different clients, and is made
totally hackable with pre- and post- configuration files that load
your Lisp logic.</p>

<p>By default we get the following pages:</p>

<ul>
<li>the welcome screen, with:

<ul>
<li>the bookshop&rsquo;s information,</li>
<li>the search form. We can search by title, authors, publisher, shelf and ISBN(s).</li>
<li>a random pre-selection of the books to showcase, if enabled.</li>
</ul></li>
<li>an optional special page to showcase a selection of books or other products.</li>
<li>in the search results page, visitors can add a book to their shopping basket.</li>
<li>and in the basket page, they find a confirmation form, which sends
the command by email to the shop owner.</li>
</ul>

<p>There are obvious TODOs, that could be shocking by their absence, but
that I actually don&rsquo;t need yet, so they&rsquo;ll come right in time :)</p>

<ul>
<li>online payment</li>
<li>admin page

<ul>
<li>simple stats (they are brought in with the email provider, and with Matomo statistics)</li>
</ul></li>
<li>i18n, remove a still few hardcoded words</li>
</ul>

<h2 id="data">Data</h2>

<p>ABStock connects by default to the <a href="http://abelujo.cc/en/">Abelujo</a>
database. Abelujo is a free software for bookshops that I also
develop. Booksellers use it for their daily work, registering and
selling books.</p>

<p>But we can define our own products. The current possibility is
to use a <code>cards.txt</code> file. Each block expects a <code>title</code>, and that&rsquo;s
the only mandatory field. Other recognized fields are:</p>

<pre><code>((:|id| integer)
 :|title|
 :|cover|
 :|isbn|
 :|price|
 :|author|
 :|publisher|
 :|date_publication|
 :|date-publication|
 :|shelf|
 :|shelf_id|
 :|details-url|
 :|summary|
 :|quantity|
 :|repr|
 :|repr2|)
</code></pre>

<p>We can define other fields, like <code>likes</code> below, which is
actually unused in the application.</p>

<pre><code>[…]

title: Programming Algorithms
author: Vsevolod Domkin
cover: https://d2sofvawe08yqg.cloudfront.net/progalgs/hero?1586867024
details-url: https://leanpub.com/progalgs
shelf: programming
shelf_id: 99
publisher: Leanpub
price: 15
likes: 5

title: Cats
author: mother cat
cover: https://gitlab.com/abstock/abstock.gitlab.io/-/raw/master/logo.png
details-url: https://gitlab.com/abstock/abstock.gitlab.io/-/blob/master/logo.png
shelf: nature
shelf_id: 98
publisher: nature
price: 5
likes: 100

title: Screwdriver
author:
cover: https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Ftse1.mm.bing.net%2Fth%3Fid%3DOIP.jGOb7dVL1oA9VDzNVPDPpwAAAA%26pid%3DApi&amp;f=1
details-url:
shelf: craftmanship
shelf_id: 97
publisher:
price: 10
likes: 1
</code></pre>

<p>(yes there&rsquo;s a little redundancy with shelf and shelf_id to fix)</p>

<p>That gives:</p>

<p><img src="https://gitlab.com/vindarel/abstock/-/raw/master/other-data.png" style="max-width: 1200px"/></p>

<p>We could very well load a JSON, a CSV or another database when the need arises.</p>

<p>For now, we think the text loader is enough for you to define your
products and try the application.</p>

<p>It is also very easy to host, and in doing so <a href="https://lisp-journey.gitlab.io/blog/i-realized-that-to-live-reload-my-web-app-is-easy-and-convenient/">one can realize that to live-reload his Lisp web app is straighforward and very convenient</a>.</p>

<h1 id="context">Context</h1>

<p>I shipped the app the second month of our lockdown period for the
client I was working for at that moment, and no need to say it turned
100% helpful. Amazon had hell of an activity, and french alternatives
for booksellers (such as lalibrairie.com or placedeslibraires.fr)
either had stopped, either couldn&rsquo;t accept new registrations. So we
were left alone, and we did that. His clients were happy, they started
passing orders, he organized collection schedules. This happened in a
small rural village, where the inhabitants are happy to have, at
least, a (nice) bookshop in their village.</p>

<h1 id="paying-one-s-rent-with-lisp">Paying one&rsquo;s rent with Lisp</h1>

<p>So yes, I paid my rent with Common Lisp again \o/ And you see, the
software is a classical web app. I could have made it with Python or
another language that has a web server and a templating library. As I
defended before, the app doesn&rsquo;t exist thanks to CL&rsquo;s super powers. CL
had no particular advantages for this kind of web app, but no
disavantages either: it has a good web framework, a good templating
library that I liked a lot (Djula: defining custom filters was a
breeze), a good SQL wrapper, and that&rsquo;s all I asked. <em>I</em> use CL&rsquo;s
super powers during development and deployment. Clients wouldn&rsquo;t see
the difference… or would they?</p>

<p>Actually, CL has advantages <em>overall</em>: development speed, ease of
deployment, ease of hot-reload, ease to use the language features to
bypass a library&rsquo;s limitation (easy-routes had no built-in to
translate a route URL, but it turned possible with a reader macro)…
not mentioning ease of maintenance in time, speed, etc.</p>

<p>One production bug I had was due to (me apart for not testing enough)
<code>(= 3 nil)</code> throwing an error, so you must had prior checks (or, I
just realize, use <code>equalp</code>?). My Sentry dashboard is empty anyways.</p>

<h1 id="final-words-with-bonus">Final words (with bonus)</h1>

<p>The Big Plan is to Rewrite It (the other software) In Lisp, and the
project just moved from R&amp;D to POW… stay tuned, particularly if you
don&rsquo;t know what to do in june and july, I might have a small budget
for a helping hand.</p>

<hr />

<table>
    <tr>
      <td>
<a href="https://www.patreon.com/bePatron?u=35783903" data-patreon-widget-type="become-patron-button">Become a Patron!</a><script async src="https://c6.patreon.com/becomePatronButton.bundle.js"></script>
      </td>

      <td style="padding-left: 1em">
<script src="https://liberapay.com/vindarel/widgets/button.js"></script>
<noscript><a href="https://liberapay.com/vindarel/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a></noscript>
      </td>
   </tr>
</table>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Scraping a website</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">27 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I&rsquo;ve spent today writing some code to scrape a series of lessons from a website. Each lesson consists of text and image data. I wanted to save the content of each lesson, so I could read through them offline.
I&rsquo;ll go through what I did, the issues I ran into and how I solved them.
Overview I split the crawling into two steps:
 Finding all the URLs to scrape Scraping data from each one  I ended up using a mix of Python and JavaScript for this.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Local Testing on an iPhone</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">26 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Learn how to set up an ideal workflow for debugging your development server on your iPhone. This may not be the most exciting topic I've written about, but it's probably one of the most useful!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/177-devs-journey.png" alt="Dev&#39;s Journey">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Dev&#39;s Journey</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">26 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/177-devs-journey.png" alt="Dev's Journey" title="The heroe's journey is a noble but difficult path" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Bespoke software, and a really simple RSS aggregator</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">25 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        This week I built myself an RSS1 aggregator2. There are a couple of websites that are written by friends, or are of high enough quality that I want to read everything published on them, not just the things that are popular enough make their way to me via Hacker News or similar.
I had fun building it, and I think its design is interesting, so let&rsquo;s take a look at how it works.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://markosaric.com/wp-content/uploads/favicon.ico" alt="How you can help keep blogging alive and thriving">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">How you can help keep blogging alive and thriving</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Marko Saric</a> <span class="article__date">24 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I was happy to see some posts about blogging being widely discussed over the last few days. A couple of them that I wanted to highlight are &#8220;If I could bring one thing back to the internet it would be blogs&#8221; and &#8220;Blogging is not dead&#8220;. I&#8217;m a blogger myself and have been blogging for&#8230; <a class="more-link" href="https://markosaric.com/keep-blogging-alive/">Continue reading <span class="screen-reader-text">How you can help keep blogging alive and thriving</span></a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Administración y gestión de VPS con Manuel Rosa">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Administración y gestión de VPS con Manuel Rosa</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">23 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Hablamos sobre administración y gestión básica de VPS con Manuel Rosa, un inquieto Ingeniero de Telecomunicaciones especializado en electrónica. Manuel lleva varios años dedicándose a diferentes facetas del mundo tecnológico y todavía sigue iniciando diversos proyectos. Actualmente Manuel Rosa trabaja para una empresa de seguridad informática y además saca tiempo para realizar sus propios proyectos de e-commerce, marketing y SEO.</p>
<p>Con Manuel Rosa hablamos sobre la administración esencial de VPS, la tremenda competencia que existe en el mercado de servidores virtuales y sobre las herramientas recomendadas para gestionar tu propio VPS. Con Manuel hablamos de las siguientes cuestiones:</p>
<ul>
<li>¿Qué criterios deberíamos tener en cuenta para escoger un buen proveedor de VPS? ¿Algunas recomendaciones personales?.</li>
<li>¿Qué es lo primero que configuras en una VPS a parte de la clave ssh?
<li>¿Qué acciones recomiendas realizar para garantizar la seguridad mínima en un VPS? ¿Cuáles son las amenazas más habituales?.</li>
<li>¿Qué distribución recomiendas para la VPS?.</li>
<li>¿Qué tareas de mantenimiento son necesarias para un correcto funcionamiento de un VPS?<br />
¿Cómo gestionas el backup de una VPS? ¿Algún software recomendado?.</li>
<li>Docker y kubernetes para manejar la infraestructura.</li>
<li>¿Cómo ves el futuro de este tipo de productos?.</li>
<li>¿Cuándo deberíamos pasar a un servidor dedicado?.</li>
</ul>
<p>Una interesante charla con Manuel al que emplazamos a otro episodio para que nos cuente otros proyectos y su experiencia a la hora de lanzar proyectos comerciales en internet. <a href="https://www.linkedin.com/in/manuel-antonio-rosa-seivane-baa736118/" rel="noopener noreferrer" target="_blank">Puedes contactar con Manuel a través de su propio LinkedIn. </a></p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">It&#39;s 2020: let&#39;s build a node.js app with TypeScript</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">22 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        It&rsquo;s 2020. You want to build a node.js app, and you&rsquo;ve heard great things about TypeScript. You want to build it the right way this time, starting with good intentions.
As with most things JavaScript, there are a myriad of posts, Stack Overflow answers and repositories you could use to get set up. Sadly many of these are out of date. The aim of this post is to help you set up a TypeScript project for building a node.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">It&#39;s 2020: let&#39;s build a node.js app with TypeScript</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">22 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        It&rsquo;s 2020. You want to build a node.js app, and you&rsquo;ve heard great things about TypeScript. You want to build it the right way this time, starting with good intentions.
As with most things JavaScript, there are a myriad of posts, Stack Overflow answers and repositories you could use to get set up. Sadly many of these are out of date. The aim of this post is to help you set up a TypeScript project for building a node.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Animated Sparkles in React</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">19 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        In this dazzling tutorial, we'll see how to build an animated <Sparkles> component. Wrap it around text or images and watch them twinkle! This neat trick is a perfect way to emphasize positive or exciting things.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/176-code-superheroes.png" alt="Code Superheroes">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Code Superheroes</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">19 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/176-code-superheroes.png" alt="Code Superheroes" title="We're all heros in some way." /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Announcing the Clojurists Together Foundation</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">18 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together has formed a trade association to grow and expand the work that we have been doing with the Clojure community.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Announcing Summer of Bugs</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">18 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Ever wanted to take a day off to fix an annoying bug or finally ship a feature? Clojurists Together Foundation wants to make that happen.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Creating helper commands for k8s using fzf</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">17 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Kubernetes cli tool kubectl is pretty useful but when I need to execute some tasks many times during a work day it could be too verbose. So I wrote some bash functions to handle a few common tasks I use often.
 I used the power of fzf to create an interactive experience when I run any of these functions. Basically it pipes the output of a kubectl command, make some filtering using sed and awk and then build a final command which will execute what I want.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://erick.navarro.io/images/creating-helper-commands-for-k8s-using-fzf/pod_shell.gif" alt="Creating helper commands for k8s using fzf">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Creating helper commands for k8s using fzf</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">17 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>
Kubernetes cli tool <code class="verbatim">kubectl</code> is pretty useful but when I need to execute some tasks many times during a work day it could be too verbose. So I wrote some bash functions to handle a few common tasks I use often.</p>
<p>
I used the power of <a href="https://github.com/junegunn/fzf">fzf</a> to create an interactive experience when I run any of these functions. Basically it pipes the output of a <code class="verbatim">kubectl</code> command, make some filtering using <code class="verbatim">sed</code> and <code class="verbatim">awk</code> and then build a final command which will execute what I want.</p>
<p>
The common behavior of these functions is first ask for a <code class="verbatim">namespace</code> and then ask for a specific <code class="verbatim">pod</code> to make some action over its.</p>
<p>
We can see an example of how it works in the image below:</p>
<img src="https://erick.navarro.io/images/creating-helper-commands-for-k8s-using-fzf/pod_shell.gif" alt="/images/creating-helper-commands-for-k8s-using-fzf/pod_shell.gif" title="/images/creating-helper-commands-for-k8s-using-fzf/pod_shell.gif" style="display:block;margin-left:auto;margin-right:auto;"/>
<div id="outline-container-headline-1" class="outline-2">
<h2 id="headline-1">
Open a shell or a custom command inside a pod
</h2>
<div id="outline-text-headline-1" class="outline-text-2">
<p>
If we execute <code class="verbatim">pod_shell</code> without any argument it will connect to the selected pod and run <code class="verbatim">bash</code>, otherwise it will run the given command.</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell"><span style="color:#66d9ef">function</span> pod_shell <span style="color:#f92672">{</span>
    local namespace<span style="color:#f92672">=</span><span style="color:#e6db74">`</span>kubectl get ns | sed 1d | awk <span style="color:#e6db74">&#39;{print $1}&#39;</span> | fzf<span style="color:#e6db74">`</span>
    local pod<span style="color:#f92672">=</span><span style="color:#e6db74">`</span>kubectl get pods -n $namespace | sed 1d | awk <span style="color:#e6db74">&#39;{print $1}&#39;</span> | fzf<span style="color:#e6db74">`</span>
    echo <span style="color:#e6db74">&#34;Connecting to </span>$pod<span style="color:#e6db74">&#34;</span>

    <span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -z $1 <span style="color:#f92672">]</span>
    <span style="color:#66d9ef">then</span>
        kubectl -n $namespace exec -ti $pod bash
    <span style="color:#66d9ef">else</span>
        kubectl -n $namespace exec -ti $pod $1
    <span style="color:#66d9ef">fi</span>
<span style="color:#f92672">}</span></code></pre></div>
</div>
</div>
</div>
<div id="outline-container-headline-2" class="outline-2">
<h2 id="headline-2">
Run a proxy over a pod
</h2>
<div id="outline-text-headline-2" class="outline-text-2">
<p>
Same as the previous function but this one ask for a port mapping, for example <code class="verbatim">9999:5432</code> will map the port <code class="verbatim">9999</code> from the host machine to <code class="verbatim">5432</code> port on the pod.</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell"><span style="color:#66d9ef">function</span> pod_proxy <span style="color:#f92672">{</span>
    local namespace<span style="color:#f92672">=</span><span style="color:#e6db74">`</span>kubectl get ns | sed 1d | awk <span style="color:#e6db74">&#39;{print $1}&#39;</span> | fzf<span style="color:#e6db74">`</span>
    local pod<span style="color:#f92672">=</span><span style="color:#e6db74">`</span>kubectl get pods -n $namespace | sed 1d | awk <span style="color:#e6db74">&#39;{print $1}&#39;</span> | fzf<span style="color:#e6db74">`</span>
    local port_mapping
    echo <span style="color:#e6db74">&#34;Enter port mapping using the form local_port:pod_port&#34;</span>
    read port_mapping
    echo <span style="color:#e6db74">&#34;Setting up proxy to </span>$pod<span style="color:#e6db74"> on </span>$port_mapping<span style="color:#e6db74">...&#34;</span>

    kubectl port-forward -n $namespace $pod $port_mapping
<span style="color:#f92672">}</span></code></pre></div>
</div>
</div>
</div>
<div id="outline-container-headline-3" class="outline-2">
<h2 id="headline-3">
See realtime logs for a given pod
</h2>
<div id="outline-text-headline-3" class="outline-text-2">
<p>
This one just ask for a pod and attach a <code class="verbatim">kubectl</code> log command.</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell"><span style="color:#66d9ef">function</span> pod_logs <span style="color:#f92672">{</span>
    local namespace<span style="color:#f92672">=</span><span style="color:#e6db74">`</span>kubectl get ns | sed 1d | awk <span style="color:#e6db74">&#39;{print $1}&#39;</span> | fzf<span style="color:#e6db74">`</span>
    local pod<span style="color:#f92672">=</span><span style="color:#e6db74">`</span>kubectl get pods -n $namespace | sed 1d | awk <span style="color:#e6db74">&#39;{print $1}&#39;</span> | fzf<span style="color:#e6db74">`</span>
    echo <span style="color:#e6db74">&#34;Showing logs for </span>$pod<span style="color:#e6db74">&#34;</span>

    kubectl -n $namespace logs -f $pod
<span style="color:#f92672">}</span></code></pre></div>
</div>
</div>
</div>
<div id="outline-container-headline-4" class="outline-2">
<h2 id="headline-4">
Change context
</h2>
<div id="outline-text-headline-4" class="outline-text-2">
<p>
Switch between configured contexts</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell"><span style="color:#66d9ef">function</span> k8s_change_context <span style="color:#f92672">{</span>
    local context<span style="color:#f92672">=</span><span style="color:#e6db74">`</span>kubectl config get-contexts --output<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;name&#39;</span> | fzf<span style="color:#e6db74">`</span>
    echo <span style="color:#e6db74">&#34;Changing to </span>$context<span style="color:#e6db74">&#34;</span>
    kubectl config use-context $context
<span style="color:#f92672">}</span></code></pre></div>
</div>
<p>
These are some common tasks I need for a day of work but with the same logic we can build some other commands.</p>
</div>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Avoid losing window layout when editing org code blocks</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">16 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Org-mode has a nice feature that allow us to edit source code within an org file, for more info check the docs. But it has a little annoying behavior after we are done editing a source block. It loses the previous window configuration and always closes all the windows except the org window.
 In the image below we can see this behavior:
 To solve this problem we can use a simple variable to store the current window configuration just before the source code edition buffer is opened and when it&#39;s closed we can restore the previous configuration just getting the value from the variable used before.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://erick.navarro.io/images/avoid-losing-window-layout-when-editing-org-code-blocks/before.gif" alt="Avoid losing window layout when editing org code blocks">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Avoid losing window layout when editing org code blocks</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">16 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>
Org-mode has a nice feature that allow us to edit source code within an org file, for more info check the <a href="https://orgmode.org/manual/Working-with-Source-Code.html">docs</a>. But it has a little annoying behavior after we are done editing a source block. It loses the previous window configuration and always closes all the windows except the org window.</p>
<p>
In the image below we can see this behavior:</p>
<p><img src="https://erick.navarro.io/images/avoid-losing-window-layout-when-editing-org-code-blocks/before.gif" alt="/images/avoid-losing-window-layout-when-editing-org-code-blocks/before.gif" title="/images/avoid-losing-window-layout-when-editing-org-code-blocks/before.gif" /></p>
<p>
To solve this problem we can use a simple variable to store the current window configuration just before the source code edition buffer is opened and when it&#39;s closed we can restore the previous configuration just getting the value from the variable used before. We&#39;re defining two functions to accomplish this behavior, one to run before and one after we&#39;re done editing the source block.</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defvar my/org-src-block-tmp-window-configuration <span style="color:#66d9ef">nil</span>)

(defun my/org-edit-special (<span style="color:#66d9ef">&amp;optional</span> arg)
  <span style="color:#e6db74">&#34;Save current window configuration before a org-edit buffer is open.&#34;</span>
  (setq my/org-src-block-tmp-window-configuration (<span style="color:#a6e22e">current-window-configuration</span>)))

(defun my/org-edit-src-exit ()
  <span style="color:#e6db74">&#34;Restore the window configuration that was saved before org-edit-special was called.&#34;</span>
  (<span style="color:#a6e22e">set-window-configuration</span> my/org-src-block-tmp-window-configuration))</code></pre></div>
</div>
<p>
Now we need to &#34;attach&#34; these two functions to the default behavior of org-mode, to do this we can use <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Advising-Functions.html">advice-add</a> elisp function, this function allow us to &#34;attach&#34; some functionality to an existing function.</p>
<p>
The two functions that we need to advice are:</p>
<ul>
<li>
<p><code class="verbatim">org-edit-special</code>: this function is called when we press <code class="verbatim">C-c C-&#39;</code> and allow us to edit source block in a dedicated buffer.</p>
</li>
<li>
<p><code class="verbatim">org-edit-src-exit</code>: this function is called when we press <code class="verbatim">C-c C-&#39;</code> from inside of the opened buffer, it closes the buffer and return us to the org buffer.</p>
</li>
</ul>
<p>
 <code class="verbatim">my/org-edit-special</code> will run just before <code class="verbatim">org-edit-special</code> is called and <code class="verbatim">my/org-edit-src-exit</code> after <code class="verbatim">org-edit-src-exit</code> is called.</p>
<p>
We need to execute this code after org is loaded so we use <code class="verbatim">eval-after-load</code>.</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(eval-after-load <span style="color:#e6db74">&#34;org&#34;</span>
  <span style="color:#f92672">`</span>(progn
     (advice-add <span style="color:#e6db74">&#39;org-edit-special</span> :before <span style="color:#e6db74">&#39;my/org-edit-special</span>)
     (advice-add <span style="color:#e6db74">&#39;org-edit-src-exit</span> :after <span style="color:#e6db74">&#39;my/org-edit-src-exit</span>)))</code></pre></div>
</div>
<p>
The full code will be:</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defvar my/org-src-block-tmp-window-configuration <span style="color:#66d9ef">nil</span>)

(defun my/org-edit-special (<span style="color:#66d9ef">&amp;optional</span> arg)
  <span style="color:#e6db74">&#34;Save current window configuration before a org-edit buffer is open.&#34;</span>
  (setq my/org-src-block-tmp-window-configuration (<span style="color:#a6e22e">current-window-configuration</span>)))

(defun my/org-edit-src-exit ()
  <span style="color:#e6db74">&#34;Restore the window configuration that was saved before org-edit-special was called.&#34;</span>
  (<span style="color:#a6e22e">set-window-configuration</span> my/org-src-block-tmp-window-configuration))

(eval-after-load <span style="color:#e6db74">&#34;org&#34;</span>
  <span style="color:#f92672">`</span>(progn
     (advice-add <span style="color:#e6db74">&#39;org-edit-special</span> :before <span style="color:#e6db74">&#39;my/org-edit-special</span>)
     (advice-add <span style="color:#e6db74">&#39;org-edit-src-exit</span> :after <span style="color:#e6db74">&#39;my/org-edit-src-exit</span>)))</code></pre></div>
</div>
<p>
After applying the complete code the result will be:</p>
<p><img src="https://erick.navarro.io/images/avoid-losing-window-layout-when-editing-org-code-blocks/after.gif" alt="/images/avoid-losing-window-layout-when-editing-org-code-blocks/after.gif" title="/images/avoid-losing-window-layout-when-editing-org-code-blocks/after.gif" /></p>
<p>
Enjoy!</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Son sitios estáticos y sin embargo, se mueven">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Son sitios estáticos y sin embargo, se mueven</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">16 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Dedicamos este episodio a hablar sobre los sitios estáticos y el espectacular crecimiento que está experimentado el ecosistema. Sin duda el auge del JAMstack, está revolucionando la forma de trabajar un sitio web, con flujos de trabajo más sencillos, costes de mantenimiento más bajos y un rendimiento muy superior en tiempos de carga, a los acostumbrados con sistemas dinámicos. Gracias a la gran cantidad y calidad de generadores de sitios estáticos, podemos ofrecer soluciones web que ofrecen un entorno moderno de desarrollo y al mismo tiempo, aprovechan las tecnologías de acceso a datos a través de API. Desde sencillas páginas corporativas hasta blogs y páginas personales, las páginas estáticas resultan una solución ideal para servir proyectos más escalables, sin casi necesidad de mantenimiento.</p>
<p>Las herramientas derivadas del <a href="https://jamstack.wtf/" rel="noopener noreferrer" target="_blank">JAMstack</a> están propiciando que servicios como <a href="https://www.netlify.com/" rel="noopener noreferrer" target="_blank">Netlify</a> o <a href="https://vercel.com/" rel="noopener noreferrer" target="_blank">Vercel</a>, permitan el despliegue global de complejos proyectos web, a través de su plataforma y con unos costes que se encuentran muy por debajo de soluciones similares. También existen soluciones que permiten desacoplar tu CMS y concentrarte por separado en las capas de presentación y datos (Headless CMS). El futuro de estas herramientas pasa por integrar cada vez más a los usuarios finales (CMS más fluidos y fáciles de editar) y en proporcionar integraciones con otros servicios a través de APIs o servicios externos.</p>
<p>Entre las cuestiones tratadas en el episodio:</p>
<ul>
<li>¿Qué es un sitio estático y qué ventajas ofrecen?</li>
<li>¿Deberían ser muchos sitios web estáticos? ¿CMS innecesario?</li>
<li>Explosión de generadores de sitios estáticos.</li>
<li>El auge del JAMStack.</li>
<li>¿Qué son los flat-file CMS?.</li>
</ul>
<p>En la segunda parte del episodio ofrecemos interesantes recursos y enlaces relacionados con el desarrollo web. Encuentras todos esos enlaces más abajo y también los discutidos en el episodio.</p>
<h2>Versión vídeo con capturas de la sección Radar</h2>
<p></p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://raw.githubusercontent.com/vindarel/lisp-web-live-reload-example/master/start.png" alt="Today I Realized that to live reload my Lisp web app is straightforward and so convenient">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Today I Realized that to live reload my Lisp web app is straightforward and so convenient</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">12 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>We all know that we can start a web server in the REPL and develop a
web app as interactively as any other app, we know how to <a href="https://lispcookbook.github.io/cl-cookbook/debugging.html#remote-debugging">connect to
a remote Lisp
image</a>
by starting a Swank server and how to interact with it from our
favorite editor on our machine, we know we can build a self-contained
binary of the web app and simply run it, but one thing I had not
realized, despite being the basics, is that by starting the web app
with <code>sbcl --load app.lisp</code>, we are dropped into the regular Lisp
REPL, with the web server running in its own thread (as in development
mode, but unlike with the binary), and that we can consequently interact with the running app.</p>

<p>As a demonstration, you can clone <a href="https://github.com/vindarel/lisp-web-live-reload-example">this repository</a> and run the example like this:</p>

<pre><code>* rlwrap sbcl --load run.lisp

This is SBCL 1.4.5.debian, an implementation of ANSI Common Lisp.
re information about SBCL is available at &lt;http://www.sbcl.org/&gt;.
[…]
; Loading &quot;web-live-reload&quot;
..................................................
Starting the web server on port 7890
Ready. You can access the application!
*
</code></pre>

<p>it will load <code>project.asd</code>, install 3 Quicklisp dependencies (you must
have Quicklisp installed), start Hunchentoot on port 7890, and drop us
into a REPL.</p>

<p>You&rsquo;ll get this:</p>

<p><img src="https://raw.githubusercontent.com/vindarel/lisp-web-live-reload-example/master/start.png" style="max-width: 1200px"/></p>

<p>The template prints the <code>*config*</code> variable, which you can change in the REPL:</p>

<pre><code class="language-lisp">* (in-package :web-live-reload)
* (setf *config*
    '((:key &quot;Name&quot;
       :val &quot;James&quot;)
      (:key &quot;phone&quot;
       :val &quot;0098 007&quot;)
      (:key &quot;secret language?&quot;
       :val &quot;Lisp&quot;)))
</code></pre>

<p>refresh, and voilà, your new config is live.</p>

<p>For functions, it is just the same (redefine the function <code>fn</code> that
returns a string, if you want to try).</p>

<p>If a file changes (for example after a git pull), compile it with a
usual <code>load</code>: <code>(load &quot;src/web.lisp&quot;)</code>.</p>

<p>You can also reload all the app with <code>(ql:quickload :myproject)</code>,
which will install the dependencies, without needing to restart the
running image.</p>

<p>I was looking for a way to reload a user&rsquo;s config and personal data
from a running website, and this has proved very practical. I have no
downtime, it is pure Lisp, it is the workflow I am used to. I am more
cautious on using this to recompile the whole app, even though I did
it without glitches so far. The thing to <em>not</em> do is to change the
global state manually, aka to develop in production!</p>

<p>That&rsquo;s all, but that made my day.</p>

<hr />

<p>Bonus points:</p>

<ul>
<li>after a git pull, the (Djula) templates are automatically
updated. No operation is needed to see them live. (you can disable
this by pushing <code>:djula-prod</code> into the features set)</li>
<li>you&rsquo;ll understand and appreciate the difference between
<code>defparameter</code> and <code>defvar</code>. Imagine you declare a variable with
<code>(defparameter *data* nil)</code> and you populate it with some heavy
computation at the application startup. Now if you <code>load</code> the file
this declaration is in, you&rsquo;ll set the data back to <code>nil</code>. If you
declare it with <code>defvar</code>, you can live-re<code>load</code> your app and the
data doesn&rsquo;t go away. You can try both cases with the <code>*config*</code>
variable.</li>
<li>the app started a Swank server on port 4006, if you want to try on your VPS.</li>
</ul>

<hr />

<p><a href="https://www.patreon.com/bePatron?u=35783903" data-patreon-widget-type="become-patron-button">become a Patron!</a><script async src="https://c6.patreon.com/becomePatronButton.bundle.js"></script></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">I Worked Remotely in Common Lisp. Here&#39;s My Incredible Story.</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">12 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Nearly one year ago, I received an email that asked me if I was
available to do remote Lisp work. It was the day before the end of a
contract and I had to tell my team if I wanted to continue or not. I
made a virtual offering to the Lisp god and I started the Lisp job.</p>

<hr />

<p>Disclaimer: this post was written on <a href="https://www.reddit.com/r/lispadvocates/comments/fopbgn/i_have_worked_in_common_lisp_remotely_heres_my/">Lisp Advocates&rsquo;
reddit</a>. Lisp Advocates is a meme, but it&rsquo;s sort of serious too.</p>

<hr />

<p>At this time I had been in Lisp for around two years, contributing a
couple simple libraries, writing a lot of documentation, blogging,
furnishing the reddits, and being enthusiastic and polite. This is
what actually gave me the job. I had tried to contribute to a busy CL
repository, but the PR was not good enough and that irritated the
maintainer, who answered abruptly. Nothing&rsquo;s more outrageous than
receiving contributions right? But I answered with calm and
professionalism, and that got noticed by a repository watcher, who
decided he could work with me.</p>

<p>That guy already had contacts and a client, and he formed a team
around him. Our work was to build a website that would receive many visitors,
that would have a client registration form and would
have a rather simple admin dashboard, for a team of half a dozen
people. The business already existed in the form of a buggy and slow
Wordpress site, so the expectations were clear. We were three, we
worked together on the same code (with one guy more on the design). I
worked on it in a two-months period, but not full time. I&rsquo;ve had a
decent income paid straight and so I paid my rents for a few months
thanks to that experience.</p>

<p>What Lisp was good for</p>

<p>The application had no inherent difficulties. It had forms and an
admin backend. It was a website for a team of commercial people, as it
exists hundreds of thousands. And yeah, Common Lisp was suited for
that task. So we see there&rsquo;s a good margin of progression, business
and remote work wise: those thousands of websites for commercial
people can very well be done in CL.</p>

<p>Libraries, deployment and Lisp curse</p>

<p>We picked the Caveman framework, the Mito ORM and the cl-markup
templating library, with some tests in FiveAM. There was a little bit
of JavaScript, less than a thousand lines. I find Caveman a bit
convoluted but it was clear and easy. I like Mito very much and wrote
material for it. I liked to play with the web server debugging options: usually I
received the stacktraces in the debugger in my editor, but I could
choose to display them on the browser (as I&rsquo;m used with Django or
Flask). It is this time that I enjoyed so much being able to change
the faulty function, recompile it, choose the &ldquo;try again&rdquo; restart and
see the operation succeed. Now when I&rsquo;m back on Python I feel the Lisp
curse. I&rsquo;ll never be the same. I&rsquo;ll never enjoy Python as much as
before. Sigh. Anyways, we deployed the app on DigitalOcean with Fast
CGI, as documented on Caveman&rsquo;s README.</p>

<p>The bug</p>

<p>Our most difficult bug that made us loose millions was due to
<code>(string-downcase nil)</code> to return &ldquo;NIL&rdquo;, the string, instead of
<code>nil</code>. Now I use my <a href="https://github.com/vindarel/cl-str/">str</a> library
for string manipulation purposes.</p>

<p>All in all, being able to live-debug the software from the earth
proved invaluable.</p>

<p>I got also hit by a config of mine that impacted Mito&rsquo;s results. I had
set <code>*print-case*</code> to <code>:downcase</code> in my .sbclrc. I was asking Lisp to
DON&rsquo;T SHOUT AT ME ALL DAY LONG, &lsquo;cause I try to listen to music at the
same time. I fixed the Mito bug, but I don&rsquo;t use this setting anymore.</p>

<p>Voilà. This is my response to LispAdvocates&rsquo; call: <a href="https://www.reddit.com/r/lispadvocates/comments/ficdvx/tell_us_you_remote_success_story/">https://www.reddit.com/r/lispadvocates/comments/ficdvx/tell_us_you_remote_success_story/</a>.</p>

<p>There are of course lots of situations were CL is ready now to get the (remote) job done. There are people who do web dev for years in CL, but we don&rsquo;t know their story.</p>

<p>Share yours!</p>

<p>ps: stay tuned, &lsquo;cause I deployed another website in production.</p>

<hr />

<p>Some comments and answers:</p>

<blockquote>
<p>Apart from the programmer experience, were there any inherent advantages to using Common Lisp? (Speed I guess?)</p>
</blockquote>

<p>CL had no particular advantages, but no disadvantages either (and it
is my point!). As I said, it was a site with basic/easy/HTML&amp;JS
requirements, so I believe no language would&rsquo;ve had any particular
advantage. Speed was important, it was one of the main
requirements. The website felt responsive, the client was very happy
about it. For us, it was also easy and fast to deploy, which turned
important and impressed the client.</p>

<blockquote>
<p>Do you thinK a more standardized framework (from other languages) could have saved you?</p>
</blockquote>

<p>No, not with our requirements. Another framework&amp;language would have
make us loose millions at the very beginning (still figuratively)</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2020/05/gitkraken-report-devops-tools-2020-rw.png" alt="Informe sobre herramientas DevOps 2020">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Informe sobre herramientas DevOps 2020</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">09 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Dedicamos este episodio al <a href="https://www.gitkraken.com/resources/devops-report-2020" rel="noopener noreferrer" target="_blank">DevOps Tools Report 2020 realizado por Gitkraken.</a> Este informe proporciona una guía sobre las mejores herramientas DevOps, según una comunidad global de 2700 desarrolladores. DevOps se está convirtiendo en el estándar para realizar operaciones y desarrollo de software. Este completo informe hace un recorrido de las herramientas DevOps usadas en la actualidad para dibujar, un ciclo de vida completo del desarrollo de software.</p>
<p><img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2020/05/gitkraken-report-devops-tools-2020-rw.png" alt="Informe DevOps 2020 Gitkraken" width="800" height="551" class="img-responsive aligncenter size-full wp-image-2321" style="margin-top:30px;margin-bottom:30px; srcset="https://republicaweb.es/wp-content/uploads/2020/05/gitkraken-report-devops-tools-2020-rw.png 800w, https://republicaweb.es/wp-content/uploads/2020/05/gitkraken-report-devops-tools-2020-rw-300x207.png 300w, https://republicaweb.es/wp-content/uploads/2020/05/gitkraken-report-devops-tools-2020-rw-768x529.png 768w" sizes="(max-width: 800px) 100vw, 800px" /></p>
<p>Como indican en la introducción del informe, la <strong>transición hacia una cultura de DevOps </strong>requiere cambios significativos que incluyen un cambio en la mentalidad del personal, la introducción de las herramientas apropiadas y la adquisición de nuevas habilidades. Sin importar en qué fase te encuentres de tu transformación DevOps, el foco debería estar siempre en <strong>la mejora continua.</strong> Comienza con las bases y después identifica tus limitaciones propias. Una vez superes esas limitaciones, repite el proceso. </p>
<p>El informe se muestra siguiendo un gráfico en forma de infinito, donde se muestra la condición de continuidad y de iteración en el proceso de DevOps. Las fases corresponden a cada una de las disciplinas del desarrollo moderno de software: Planificación, codificación, Empaquetado / construcción, Testeo, Configuración y lanzamiento, Despliegue, Operaciones y Monitorización.</p>
<p>Cada uno de estas fases incluyen unas herramientas, que a menudo, se van repitiendo en otras fases:</p>
<table style="margin-top:30px;margin-bottom:30px">
<thead>
<tr>
<th>
<strong>FASE</strong>
</th>
<th>
<strong>Herramientas</strong>
</th>
<th>
<strong>Otras</strong>
</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>PLAN</strong></td>
<td>Jira, Trello, Gitkraken Boards, GitKraken Timelines.</td>
<td>BaseCamp, MantisBT.</td>
</tr>
<tr>
<td><strong>CODE</strong></td>
<td>Hosting: GitHub, Bitbucket, GitLab y Azure DevOps.</br><br />
Git / SCM:  GitKraken Git GUI, CLI, GitHub Desktop, Sourcetree.<br />
IDE: VS Code, IntelliJ, Visual Studio, Sublime Text.</td>
<td>Eclipse</td>
</tr>
<tr>
<td><strong>BUILD</strong></td>
<td>Jenkins, Maven Visual Studio, Gradle</td>
<td></td>
</tr>
<tr>
<td><strong>TEST</strong></td>
<td>JUnit, Selenium, Jest, PHPUnit.</td>
<td>Cypress, Postman, Swagger.</td>
</tr>
<tr>
<td><strong>RELEASE</strong></td>
<td>Ansible, Azure DevOps, Chef, Jenkins, AWS Codebuild.</td>
<td>Puppet, Circle CI.</td>
</tr>
<tr>
<td><strong>DEPLOY</strong></td>
<td>Jenkins,Azure DevOps, AWS Codebuild, GitLab.</td>
<td></td>
</tr>
<tr>
<td><strong>OPERATE</strong></td>
<td>Kubernetes, Docker, AWS</td>
</tr>
<tr>
<td><strong>MONITOR</strong></td>
<td>Google Analytics, Grafana, Azure Monitor, AWS CloudWatch</td>
<td>Datadog, New Relic</td>
</tr>
</tbody>
</table>
<p>En el episodio destacamos el auge imparable en los últimos años de las herramientas cloud y cómo la metodología DevOps irá creando perfiles específicos que gestionen su complejidad.</p>
<p>También dejamos el webinar que realizó la semana pasada David Vaquero para <a href="https://www.nextraining.es/">Nextraining</a> y titulado, 4 Herramientas OpenSource Imprescindibles en el Testing Web. En este webinar David explica JUnit, Selenium, JMeter y Jenkins.</p>
<p></p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://markosaric.com/wp-content/uploads/favicon.ico" alt="How to fix the broken web as a site owner and web developer">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to fix the broken web as a site owner and web developer</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Marko Saric</a> <span class="article__date">07 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Yesterday there was a lively discussion on Hacker News and different Subreddits around cookie consent walls not being valid according to the GDPR. Ironically, when visiting the article discussed, I was faced with one of the worst and most user-hostile implementations of the cookie law. The web is broken. Behavioral tracking without consent, abuse of&#8230; <a class="more-link" href="https://markosaric.com/broken-web/">Continue reading <span class="screen-reader-text">How to fix the broken web as a site owner and web developer</span></a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Lessons Learned Speaking at Conferences</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">06 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Speaking at conferences is equal parts exciting and terrifying. This article is a behind-the-scenes look at what the experience is like, and shares tips for getting started as a conference speaker.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to Move a Django Model to Another App</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">05 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>In my latest article for RealPython I cover some exotic migration operations, many of the built-in migration CLI commands and demonstrate important migrations concepts such as reversible migrations, migration plans and introspection.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Accessible Animations in React</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">05 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I really love animation, but not everybody does. In fact, it can make some people literally sick! In this tutorial, we'll see how to ensure that we respect user preferences, and create animations that can be disabled.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/175-diff.png" alt="Diff">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Diff</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">05 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/175-diff.png" alt="Diff" title="You don't need to be humble when you're just as bad as everyone else." /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Reconversión de negocios y profesionales al mundo de internet">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Reconversión de negocios y profesionales al mundo de internet</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">02 05 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Con las crisis llegan momentos de cambios de rumbo y nuevos horizontes. Los recientes acontecimientos han puesto al sector online en el centro de muchas acciones, encaminadas a la búsqueda de empleo o ampliar actividades relacionadas con internet. En este episodio hablamos sobre cómo afrontar la reconversión de profesionales y negocios al mundo de internet. Tanto en en el sector formativo de nuevas tecnologías como en otras actividades, es innegable que se está experimentado un renovado interés. Por tanto, uno de las grandes discusiones que realizamos en el episodio es ¿Qué le diríamos a las personas que desean ampliar su horizonte en el área digital?</p>
<p>Reservamos la segunda parte del episodio a aportar interesantes enlaces de recursos y herramientas orientadas al desarrollo y programación. Más abajo encontrarás todos los enlaces discutidos en el episodio. </p>
<p></p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Testing an Interactive Voice Response System With Python and Pytest</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">30 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>It can be very challenging to test a system that rely heavily on a third party service such as Twilio. In this article, I show how to organize your code in a way that would isolate your bushiness logic and make it easier for you to test it separately.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://markosaric.com/wp-content/uploads/favicon.ico" alt="Please get your parents off Facebook">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Please get your parents off Facebook</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Marko Saric</a> <span class="article__date">30 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The internet is a tool that has democratized content publishing. It has made information free and enabled anyone to publish whatever they want, share their beliefs and gain a following. This is amazing if you use it for good. Facebook has lowered the bar to share ideas as low as it can get and now&#8230; <a class="more-link" href="https://markosaric.com/off-facebook/">Continue reading <span class="screen-reader-text">Please get your parents off Facebook</span></a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Incredimental Builds!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">29 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Gatsby just launched an exciting new feature called "incremental builds". This article looks at what it is, how to use it, and what it means for the future of the static web.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Deploying Netlify Functions with Gatsby Cloud</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">28 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Every now and then, Gatsby developers find themselves needing a sprinkle of back-end code. We don't necessarily need a whole server, and we certainly don't want to have to deal with things like load balancing and scaling. We just need some code to run not-in-the-browser…
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/174-estimates.png" alt="Estimates">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Estimates</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">28 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/174-estimates.png" alt="Estimates" title="If you first you don't succeed, destroy all evidence you tried" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Repositorios, control de versiones y despliegues en GitHub y GitLab">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Repositorios, control de versiones y despliegues en GitHub y GitLab</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">25 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Dedicamos este episodio a hablar sobre los repositorios Git en la nube, espacios que nos permiten mantener una versión de nuestro código, trabajar de manera colaborativa, ejecutar tests y también realizar despliegues y otras mágicas funcionalidades. Empezamos el episodio tratando sobre en qué consiste un repositorio de código y cómo Git se ha convertido en el estándar a la hora de pensar en control de versiones. Centramos la conversación sobre los dos proveedores más importantes: GitHub y GitLab. El primero está considerado como la red social del código y tras su adquisición por parte de Microsoft está incorporando multitud de funcionalidades en su capa gratuita. Por su parte, GitLab es una soberbia plataforma de código abierto, dirigida a ser la solución integral para DevOps y una aplicación de Integración y Desarrollo Continuo para proyectos de software.</p>
<p>Entre las cuestiones que tratamos en el episodio, tenemos:</p>
<ul>
<li>Sistema de control de versiones Git y su uso local.</li>
<li>Diferencias esenciales entre GitHub y GitLab.</li>
<li>Clientes GUI: Github Desktop, Gitkraken, SourceTree, Git GUI, Tower, Lazygit, Sublime merge
</li>
<li>Integración con IDE’s: Atom, Brackets, Jetbrains (integración con GitHub, Git),  VSCode,
</li>
</ul>
<p>En el episodio también comentamos las cifras de una encuesta que realizamos en el grupo de Telegram Malditos Webmasters sobre el uso de estas herramientas. Las cifras son Github 64%<br />
Gitlab 20% y Bitbucket 13%.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Instapaper Save for macOS v1.1</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Instapaper</a> <span class="article__date">24 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Today we updated the <a href="https://apps.apple.com/us/app/instapaper-save/id1481302432?mt=12">Instapaper Save macOS app</a> to include more features including inline saving on Twitter, keyboard shortcut to save (Ctrl + S), and support for pasting credentials from password managers.</p><p><b></b></p><p>We also built a Share Extension for Instapaper Save, which lets you save to Instapaper from apps like Mail, News, and any other apps that support the macOS share sheet. The Share Extension also allows you to right-click links in Safari to save them.</p><p><b></b></p><p>Once you’ve downloaded the update, you can enable the system-level share by opening the share sheet from any macOS app &gt; Going to “More…” &gt; Selecting Instapaper in the Share Menu section of the Extensions menu. If you were doing that from Safari, it would look like this:</p>
<iframe src="https://player.vimeo.com/video/410653698" width="600" height="378" frameborder="0" allowfullscreen="allowfullscreen"></iframe>
<p><b></b></p><p>Lastly, we also updated our Chrome extension and Firefox add-on to fix inline saving from Twitter, and updated the Firefox shortcut to use Ctrl + S so it no longer interferes with the screenshot tool.</p><p><b></b></p><p>If you have any questions, feature requests, or issues you’d like us to sort out, please let us know at support@instapaper.com or <a href="https://twitter.com/@InstapaperHelp">@InstapaperHelp</a> on Twitter.</p><p><b></b></p><p>Thanks for using Instapaper!</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://markosaric.com/wp-content/uploads/favicon.ico" alt="How to de-Google your site to make it faster and visitor friendly">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to de-Google your site to make it faster and visitor friendly</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Marko Saric</a> <span class="article__date">24 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Did you know that 94% of sites include at least one third-party resource while the median page requests content from 9 different domains? These third-party resources represent 35% of the total network activity and 7 of the 10 most used resources are owned by Google. Third-party resources slow down the web and are a concern&#8230; <a class="more-link" href="https://markosaric.com/degoogleify/">Continue reading <span class="screen-reader-text">How to de-Google your site to make it faster and visitor friendly</span></a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-bFErYEjXmR0/XqIFb5ChZZI/AAAAAAAAvSA/rxAJ4sWBPT4Lxmw7AyQMi3gTR5u4XNVXgCLcBGAsYHQ/s640/usestate-react-js.jpg" alt="Tutorial de useState() en React.js">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Tutorial de useState() en React.js</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">23 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-bFErYEjXmR0/XqIFb5ChZZI/AAAAAAAAvSA/rxAJ4sWBPT4Lxmw7AyQMi3gTR5u4XNVXgCLcBGAsYHQ/s1600/usestate-react-js.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="720" data-original-width="1280" height="360" src="https://1.bp.blogspot.com/-bFErYEjXmR0/XqIFb5ChZZI/AAAAAAAAvSA/rxAJ4sWBPT4Lxmw7AyQMi3gTR5u4XNVXgCLcBGAsYHQ/s640/usestate-react-js.jpg" width="640" /></a></div><br />Una de las funcionalidades que a muchos les causa confusión es la de usar hooks en React. Los hooks son una característica que nos ayuda a seguir implementando componentes en React.js usando la misma estructura de función. Uno de los hooks más conocidos es el hook de estado <code>useState()</code>.<br />En este tutorial vamos a ver dónde y cuándo debemos utilizar el hook de estado en nuestras aplicaciones con React.<br /><h2 id="1-para-qu-sirve-usestate-">1. Para qué sirve useState()</h2>useState() es la forma de utilizar el estado en componentes basados en funciones. Si nosotros estamos desarrollando nuestros componentes con clases tenemos algo como lo siguiente:<br /><pre><code class="lang-jsx"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MiComponente</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span></span>{<br /><br />    constructor(props){<br />        <span class="hljs-keyword">super</span>(props);<br />        <span class="hljs-keyword">this</span>.state = {nombre: ''};<br />    }<br /><br />    handleChange = e =&gt;{<br />        <span class="hljs-keyword">this</span>.setState({nombre: e.target.value});<br />    }<br /><br />    render(){<br />        <span class="hljs-keyword">return</span>(<br />            &lt;input onChange={<span class="hljs-keyword">this</span>.handleChange()} value={<span class="hljs-keyword">this</span>.state.nombre} /&gt;<br />        );<br />    }<br />}<br /></code></pre>Cuando usamos clases tenemos que usar <code>this.state</code> y <code>this.setState()</code> para poder manipular los datos en nuestro componente. Si lo queremos ver así es un getter y un setter. Sin embargo, para hacer lo mismo en un componente basado en función necesitamos hacer uso de el hook de estado.<br /><h2 id="2-c-mo-funciona-el-hook-de-estado-">2. ¿Cómo funciona el hook de estado?</h2>El mismo ejemplo anterior hecho con clase podemos hacerlo con funciones de la siguiente forma:<br /><pre><code class="lang-jsx"><span class="hljs-keyword">import</span> {React, useState} <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;<br /><br /><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MiComponente</span>(<span class="hljs-params">props</span>)</span>{<br />    <span class="hljs-keyword">const</span> [nombre, setNombre] = useState(<span class="hljs-string">''</span>);<br /><br />    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleChange</span>(<span class="hljs-params">e</span>)</span>{<br />        setNombre(e.target.value);<br />    }<br /><br />    <span class="hljs-keyword">return</span>(<br />        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange()}</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{nombre}</span> /&gt;</span><br />    );<br />}</span><br /></code></pre><code>useState()</code> lo que nos permite hacer es hacer una desestructuración de una variable y una función. en nuestro caso la variable o estado que definimos es <code>nombre</code> y por lo tanto el siguiente parámetro es una función <code>setNombre()</code> para poder cambiar el valor de <code>nombre</code>. De la misma forma que cuando usamos clases tenemos que usar la función <code>setState()</code> para poder modificar el valor de nuestro estado, cuando usamos funciones usamos la función que definimos en la desestructuración para hacer dicho cambio.<br /><h2 id="3-se-pueden-declarar-m-s-variables-usando-usestate-">3. ¿Se pueden declarar más variables usando useState()?</h2>La respuesta es que sí. A diferencia de cuando usamos <code>state</code> y <code>setState()</code> para almacenar todos los estados de nuestos datos, usando <code>useState()</code> nos permite definir variables de forma independiente, lo cual puede ocasionar una forma más ágil de manipular los estados de los datos al tener una referencia mucho más visual de qué dato estás modificando con el nombre de la función.<br /><h2 id="conclusiones">Conclusiones</h2>Así funciona el hook de estado. Si ven la diferencia en realidad no hay ninguna, más que el mismo hecho de tener una variable y función para sustituir el <code>state</code> y <code>setState</code> que ocupamos cuando lo hacemos con componentes basados en clases.<br /><h2 id="bonus">Bonus</h2>También pueden ver en este video la explicación del hook de estado en React.js y aprovechar para suscribirse a mi canal si no lo han hecho 😊<br /><br /><div class="separator" style="clear: both; text-align: center;"><iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/wjcJ245--So/0.jpg" src="https://www.youtube.com/embed/wjcJ245--So?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div><br /><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=hLfhKBzcT6M:OULPZY0bfaQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=hLfhKBzcT6M:OULPZY0bfaQ:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=hLfhKBzcT6M:OULPZY0bfaQ:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=hLfhKBzcT6M:OULPZY0bfaQ:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=hLfhKBzcT6M:OULPZY0bfaQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=hLfhKBzcT6M:OULPZY0bfaQ:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=hLfhKBzcT6M:OULPZY0bfaQ:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=hLfhKBzcT6M:OULPZY0bfaQ:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=hLfhKBzcT6M:OULPZY0bfaQ:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=hLfhKBzcT6M:OULPZY0bfaQ:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=hLfhKBzcT6M:OULPZY0bfaQ:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=hLfhKBzcT6M:OULPZY0bfaQ:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=hLfhKBzcT6M:OULPZY0bfaQ:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=hLfhKBzcT6M:OULPZY0bfaQ:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/hLfhKBzcT6M" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojurists Together is Funding Clojars</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">23 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together is funding Clojars to improve its security, reliability, and ensure its long-term future
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://markosaric.com/wp-content/uploads/favicon.ico" alt="Ethical marketing in the GDPR, CCPA and no third-party cookies world">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Ethical marketing in the GDPR, CCPA and no third-party cookies world</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Marko Saric</a> <span class="article__date">23 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Marketers live in the world of data privacy regulations such as GDPR and CCPA, and the world where browsers block third-party cookie-based tracking. Here&#8217;s how you can grow your site and startup by practicing ethical marketing. And it&#8217;s only going to get more challenging with further regulations to be expected. You may be gradually getting&#8230; <a class="more-link" href="https://markosaric.com/ethical-marketing/">Continue reading <span class="screen-reader-text">Ethical marketing in the GDPR, CCPA and no third-party cookies world</span></a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q2 2020 Funding Announcement</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">23 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together is funding re-frame, Practicalli, CIDER/nREPL/Orchard, and Figwheel
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Quest for the Perfect Dark Mode</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">22 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Dark Mode has become common enough that it's a user expectation. And yet, creating the perfect dark mode with a statically-built site/app is deceptively tricky. In this in-depth tutorial, we'll see how to build the perfect, flicker-free, customizable theming solution for React and Gatsby apps.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/173-startup-struggles.png" alt="Startup Struggles">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Startup Struggles</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">21 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/173-startup-struggles.png" alt="Startup Struggles" title="Sometimes, you need a break" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://64.media.tumblr.com/0924b646270c9523c57c56f81ef51084/3b7c4efed4bb4651-12/s540x810/68f58284a6edae507926c39aba64ef0f97beb6bd.png" alt="Return of the Weekly">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Return of the Weekly</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Instapaper</a> <span class="article__date">17 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>We’re excited to announce the return of the Instapaper Weekly, a Sunday morning email with the most popular Instapaper articles from the previous week. The articles are chosen based on the <a href="https://blog.instapaper.com/post/123555634426">Instarank</a> algorithm, which takes into account the number of saves, reads, and likes on articles from each day. The Weekly also includes the most popular highlight from the past week.</p><figure data-orig-width="639" data-orig-height="844" class="tmblr-full"><img src="https://64.media.tumblr.com/0924b646270c9523c57c56f81ef51084/3b7c4efed4bb4651-12/s540x810/68f58284a6edae507926c39aba64ef0f97beb6bd.png" alt="image" data-orig-width="639" data-orig-height="844"/></figure><p><b></b></p><p>The Weekly was initially disabled in 2018 as we worked toward GDPR compliance. Around the same time, our email service changed their business model from volume-based to tier-based. The result was that it would cost more than twice as much to send the weekly email, which we could no longer afford as it would have significantly increased our operating costs.</p><p><b></b></p><p>While the Weekly has been disabled, it’s become one of the most frequently requested Instapaper features. Over the course of the past few months, we’ve done the work to migrate our email service provider from Mailgun to Amazon’s Simple Email Service (SES). SES has a volume-based pricing model, which allows us to send the Weekly in a cost-effective manner.</p><p><b></b></p><p>We wrote a more technical post about the migration from Mailgun to SES, which you can <a href="https://bthdonohue.com/2020/04/17/migrating-mailgun-to-ses.html">read here</a> if you’re interested, and we <a href="https://github.com/Instapaper/ses-tools">open sourced some tools</a> we made during the migration.</p><p>If you were previously receiving the Weekly, you should start seeing it in your inbox automatically. If you aren’t sure of your Weekly status or want to modify any email settings, please check your <a href="http://www.instapaper.com/user">Settings page on web.</a><br/></p><p><b></b></p><p>If you have any questions, feature requests, or issues you’d like us to sort out, please let us know at support@instapaper.com or <a href="https://twitter.com/@InstapaperHelp">@InstapaperHelp</a> on Twitter.</p><p>Thanks for using Instapaper! </p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Lanzar tu plataforma e-Learning en tiempo record con Javier Pérez">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Lanzar tu plataforma e-Learning en tiempo record con Javier Pérez</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">17 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>El e-learning está forzosamente de moda estos días. Aunque muchas organizaciones ya han hecho de la formación a distancia son modelo de negocio, otras han tenido que adaptarse con rapidez. El e-Learning es un concepto tan antiguo como la propia web y existen diferentes opciones para montar tus propios espacios de formación. Para este episodio hemos invitado a Javier Pérez Torres, responsable de la<a href="https://www.evolmind.com/"> empresa española evolMind</a>, especializada en soluciones de formación online en la nube, bajo un modelo SaaS. Su producto evolCampus es un desarrollo propio orientado a crear una plataforma de e-learning personalizable, integrada con multitud de servicios externos y todo bajo una sencilla interfaz.</p>
<p>Con Javier Pérez hablamos sobre la solución que cubre evolCampus, la situación actual del mundo e-learning y la evolución de este tipo de herramientas. Entre todas las cuestiones tratadas destacamos:</p>
<ul>
<li>Origen de la empresa y las tecnologías usadas en el proyecto.</li>
<li>Tipo de clientes que usan evolCampus.</li>
<li>Funcionalidades del servicio: SCORM, Integración con FUNDAE/SEPE, Zoom y otras plataformas de videoconferencia, Woocommerce y pagos.</li>
<li>Tipos de contenidos y actividades.</li>
<li>Seguimiento de actividades y alumnos.</li>
<li>Modelo de precios y futuro de software e-Learning.</li>
</ul>
<p>En definitiva una entrevista muy completa con una empresa española, que íntegramente desde Zaragoza desarrolla una completa solución de e-Learning bajo un modelo SaaS.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/172-async.png" alt="Async">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Async</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">14 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/172-async.png" alt="Async" title="Knock knock. Race condition. Who's there?" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">CSS Variables for React Devs</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">13 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        CSS Variables are *really* cool, and they're incredibly powerful when it comes to React! This tutorial shows how we can use them with React to create dynamic themes. We'll see how to get the most out of CSS-in-JS tools like styled-components, and how our mental frame around media queries has been wrong all along.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Algebraic Structure of Functions, illustrated using React components</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">13 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Did you know there’s an algebraic structure for functions? That may not surprise you at all. But it surprised me when I first found out about it. I knew we used functions to build algebraic structures. It never occurred to me that functions themselves might have an algebraic structure. The structure is fascinating, but functions can be rather abstract. So we'll look at some concrete things we can do with React functional components.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Algebraic Structure of Functions, illustrated using React components</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">13 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Did you know there’s an algebraic structure for functions? That may not surprise you at all. But it surprised me when I first found out about it. I knew we used functions to build algebraic structures. It never occurred to me that functions themselves might have an algebraic structure. The structure is fascinating, but functions can be rather abstract. So we'll look at some concrete things we can do with React functional components.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="No Code, desarrolla tus proyectos web sin necesidad de código">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">No Code, desarrolla tus proyectos web sin necesidad de código</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">11 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>La tendencia hacia servicios que nos permiten desarrollar proyectos web sin necesidad de saber código cada vez más es más fuerte. La etiqueta No Code hace referencia a unas herramientas que nos permiten diseñar y desarrollar soluciones web, sin necesidad de tener conocimientos de programación. Son servicios asequibles, con una interfaz intuitiva y en muchos casos con elevada capacidad de personalización.</p>
<p>En este episodio hablar de algunas de estas herramientas, las ventajas que aportan y los inconvenientes que pueden tener. Entre otras comentamos:</p>
<ul>
<li>Webflow, Landen, Notion, WordPress, Squarespace, WIX, Shopify.</li>
<li>Airtable, integraciones Google Sheets.</li>
<li>Automizaciones y flujos de trabajo: Zapier, Mautic, IFTTT o Integromat.</li>
<li>Creación de Apps, Glide App / Dropsource / Adalo</li>
<li>Voiceflow, crear skills Alexa o Google.</li>
<li>Typeform, Substack, Pico.</li>
</ul>
<p>Hablamos sobre las ventajas que nos ofrecen este tipo de servicios y su capacidad de ser integradas a través de sus API. Además también hablamos sobre las desventajas que tiene derivar nuestros proyectos a servicios propietarios y que exigen cierta dependencia a la hora de extender, migrar o combinar servicio. También hablamos de la importancia de conocer el funcionamiento interno de nuestras herramientas y cómo con el tiempo se tiende a tener cierto control de nuestro código.</p>
<p>En la última parte del episodio hablamos de recursos recomendados en diferentes materiales. Enlaces abajo.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A Static Future</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">08 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Tools like Gatsby are great for simple sites, but what about dynamic webapps with rapidly-changing data? In this article, we'll see how the technology is advancing, and all kinds of doors are opening up. "Static" sites are becoming a lot more dynamic!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Custom Djula filters</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">08 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p><a href="https://github.com/mmontone/djula/">Djula</a> is a Common Lisp port of
the Django templating language. It&rsquo;s good, it&rsquo;s proven (it&rsquo;s one of
the most downloaded Quicklisp packages), it is easy to use and it has <a href="http://mmontone.github.io/djula/doc/build/html/index.html">good
documentation</a>.</p>

<p>It basically looks like this:</p>

<pre><code class="language-html">    {% extends &quot;base.html&quot; %}
    {% block title %}Memberlist{% endblock %}
    {% block content %}
      &lt;ul&gt;
      {% for user in users %}
        &lt;li&gt;&lt;a href=&quot;{{ user.url }}&quot;&gt;{{ user.username }}&lt;/a&gt;&lt;/li&gt;
      {% endfor %}
      &lt;/ul&gt;
    {% endblock %}
</code></pre>

<p>What was missing in the documentation was how to create custom
filters. Here&rsquo;s how, and it&rsquo;s very simple.</p>

<h2 id="def-filter">def-filter</h2>

<p>Use the <code>def-filter</code> macro. Its general form is:</p>

<pre><code class="language-lisp">(def-filter :myfilter-name (value arg)
  (body))
</code></pre>

<p>It always takes the variable&rsquo;s value as argument, and it can have one
required or optional argument. For example, this is how those
built-in filters are defined:</p>

<pre><code class="language-lisp">(def-filter :capfirst (val)
  (string-capitalize (princ-to-string val)))
</code></pre>

<p>This is all there is to it. Once written, you can use it in your
templates. You can define a filter wherever you want and there is no
need to register it or to import it in your templates.</p>

<p>Here&rsquo;s a filter with a required argument:</p>

<pre><code class="language-lisp">(def-filter :add (it n)
  (+ it (parse-integer n)))
</code></pre>

<p>and with an optional one:</p>

<pre><code class="language-lisp">(def-filter :datetime (it &amp;optional format)
  (let ((timestamp …))))
</code></pre>

<p>When you need to pass a second argument, make your filter return a
lambda function and chain it with the <code>with</code> filter:</p>

<pre><code class="language-lisp">    (def-filter :replace (it regex)
       (lambda (replace)
         (ppcre:regex-replace-all regex it replace)))

    (def-filter :with (it replace)
       (funcall it replace))
</code></pre>

<p>Now we can write::</p>

<pre><code>{{ value | replace:foo | with:bar }}
</code></pre>

<p>Note: we should most probably be able to define filters with two
arguments. There&rsquo;s an open issue about that.</p>

<h2 id="error-handling">Error handling</h2>

<p>Errors are handled by the macro, but you can handle them and return a
<code>template-error</code> condition:</p>

<pre><code class="language-lisp">(def-filter :handle-error-filter (it)
   (handler-case
         (do-something)
     (condition (e)
       (template-error &quot;There was an error executing this filter: ~A&quot; e))))
</code></pre>

<p>It will be rendered on the browser with a nice stacktrace.</p>

<h2 id="final-words">Final words</h2>

<p>If you don&rsquo;t know what template engine to use for your web project,
start with it. My only criticism is that accessing variables is not
totally flexible. The <code>{{ obj.val }}</code> syntax already works to access
objects&rsquo; slots, alists, plists, hash-tables and whatnot (it uses the
excellent
<a href="https://lisp-journey.gitlab.io/blog/generice-consistent-access-of-data-structures-dotted-path/">Access</a>
library), but it won&rsquo;t work for some data (like structures), forcing
you to a bit of pre-processing before rendering the template. And you
can&rsquo;t use much logic with template tags. However, this is by
design. Djula is a port of the Django templating engine after all.</p>

<p>For more flexible templates and still write html (because, you know, we can copy-paste examples easily!), see <a href="https://github.com/eudoxia0/eco">Eco</a>. See more templates engines in the <a href="https://github.com/CodyReichert/awesome-cl#html-generators-and-templates">Awesome-cl list</a>.</p>

<p><strong>Last-minute addition</strong>: while I was writing this, Djula&rsquo;s author released <a href="https://github.com/mmontone/ten">TEN, another templating engine</a>, combining the best of Djula and Eco.</p>

<ul>
<li><a href="https://mmontone.github.io/djula/doc/build/html/filters.html#custom-filters">https://mmontone.github.io/djula/doc/build/html/filters.html#custom-filters</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">March 2020 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">08 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Read more updates from Oz, Reagent, Calva, and Ring
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Advantages of Data Oriented Programming</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">08 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>One of the biggest advantages I've found working with Clojure is its data oriented nature. Ultimately, all that code is doing is transform data. A program starts with one piece of data as the input and produces another as its output. Mainstream languages attempt to abstract over that using object oriented semantics. While practical value of such abstraction is not entirely clear, there are some tangible problems associated with this approach. Let's take a look at some drawbacks to structuring programs using OO style.</p><p>Traditionally, an object can be thought of as a type of a state machine that contains some data fields representing its internal state and provides some methods for manipulating it. An object represents the smallest compositional unit in OO, and a program is structured as a graphs of such objects that interact with one another by manipulating each others state.</p><p>The first problem we have is that each object is an ad hoc DSL. When a developer designs an object they define its API in form of methods and come up with the behaviors the object will have. This makes each object unique, and knowing how one object behaves tells you nothing regarding how the next object might behave. Rich Hickey illustrates this point in detail in his <a href='https://www.youtube.com/watch?v=aSEQfqNYNAc'>Clojure, Made Simple</a> talk. The more objects you define the more behaviors you have to keep in your head. Thus, cognitive overhead grows proportionally with the size of the program.</p><p>Any mutable objects present in the program require the developer to know the state of the objects in order to know how the program will behave. A program that is structured as a graph of interdependent state machines quickly becomes impossible to reason about. The problem stems from objects being implicitly connected via references to each other resulting in shared mutable state. This leads to lack or referential transparency and makes it impossible to do local reasoning about the code. In order to tell what a piece of code is doing you also have to track down all the code that shares references with the code you're reading.</p><p>This is one reason why sophisticated debugging tools are needed to work with code effectively in object oriented languages. The only way to tell what's happening in a large program is to run it in a debugger, try to put it in a particular state and then inspect it. Unfortunately, this approach is just a heuristic since there may be many different paths that get you to a particular state, and it's impossible to guarantee that you've covered them all.</p><p>Another notable problem with objects is that there is no standard way for serializing them creating additional pain at program boundaries. For example, we can't just take an object graph on from a web server and send it to the client. We must write custom serializers for every object adding complexity and boilerplate to our programs. A related problem occurs when composing libraries that define their own classes leading to prevalence of wrapper and adapter patterns.</p><p>All these problems disappear in a data oriented language like Clojure. Modern FP style embraces the fact that programs can be viewed as data transformation pipelines where input data is passed through a series of pure functions to transform it into desired output. Such functions can be reasoned about in isolation without having to consider the rest of the program. Plain data doesn't have any hidden behaviors or state that you have to worry about. Immutable data is both transparent and inert while objects are opaque and stateful.</p><p>As a concrete example, Pedestal HTTP server <a href='https://www.youtube.com/watch?v=0if71HOyVjY'>has around 18,000 lines of code, and 96% of it is pure functions</a>. All the IO and side effects are encapsulated in the remaining 4% of the code. This has been a common scenario for the vast majority of Clojure programs I've worked on.</p><p>Cognitive overhead associated with reasoning about code is localized as opposed to being directly influenced by the size of the application as often happens with OO. Each function can be thought of as an small individual program, and we simply pipe these programs together to solve bigger problems. Incidentally, this is the exact same approach as advocated by Ken Thompson in <a href='https://en.wikipedia.org/wiki/Unix_philosophy'>Unix philosophy</a>.</p><p>Data can also be passed across program boundaries since it's directly serializable. A Clojure web server can send its output directly to the client, and client code can operate on this data without any additional ceremony. I've discussed some of the practical benefits that stem from having standard serialization semantics in <a href='https://www.youtube.com/watch?v=IekPZpfbdaI'>this</a> presentation.</p><p>Another advantage of separating data from logic is code reuse. A pure function that transforms one piece of data into another can be used in any context. A common set of functions from the standard library can be used to manipulate data regardless where it comes from. Once you learn a few common patterns for transforming data, you can apply these patterns everywhere.</p><p>I strongly suspect that data driven APIs are a major reason why Clojure libraries tend to be so stable. When a library is simply transforming data then it's possible to get to a state where it's truly done. Once the API consisting of all the supported transformations has been defined and tested, then the API is complete. The only times the library has to be revisited is when use cases missed by tests are discovered or new features are added. This tends to happen early on during library lifecycle, and hence mature libraries need little attention from their maintainers.</p><p>Of course, this is not to say that large software cannot be written effectively using OO languages. Clearly plenty of great software has been produced using these techniques. However, the fact that complex applications can be written in a particular fashion is hardly interesting of itself. Given enough dedication and ingenuity it's possible to write complex software in any language. It's more useful to consider how different approaches impact development style in different languages.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to Provide Test Fixtures for Django Models in Pytest</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">07 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>One of the most challenging aspects of writing good tests is maintaining test fixtures. Good test fixtures motivate developers to write better tests, and bad fixtures can cripple a system to a point where developers fear and avoid them all together. The article covers everything from setting up Pytest for a Django project, creating test fixtures and how to create dependency between fixtures.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Styling Ordered Lists with CSS Counters</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">07 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Styling an ordered list can be surprisingly tricky; there's no way to get at that bullet! In this tutorial, we'll see a handy trick using CSS counters that lets us style ordered lists without breaking proper semantics.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/171-err.png" alt="Err">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Err</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">07 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/171-err.png" alt="Err" title="Overpromise and Underdeliver" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://markosaric.com/wp-content/uploads/favicon.ico" alt="Use Firefox Preview to make browsing on Android fast and distraction-free">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Use Firefox Preview to make browsing on Android fast and distraction-free</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Marko Saric</a> <span class="article__date">06 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Firefox for Android just got much better. Mozilla did a complete rewrite and has created a new generation of Firefox (Preview) that&#8217;s much more consistent with Firefox desktop experience. This post is a detailed look at Firefox Preview which when fully matured will replace the Firefox Android mobile app. A faster and more pleasant, distraction-free&#8230; <a class="more-link" href="https://markosaric.com/firefox-mobile/">Continue reading <span class="screen-reader-text">Use Firefox Preview to make browsing on Android fast and distraction-free</span></a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to Use a Differential Analyzer (to Murder People)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Two-Bit History</a> <span class="article__date">06 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A differential analyzer is a mechanical, analog computer that can solve differential equations. Differential analyzers aren’t used anymore because even a cheap laptop can solve the same equations much faster—and can do it in the background while you stream the new season of Westworld on HBO. Before the invention of digital computers though, differential analyzers allowed mathematicians to make calculations that would not have been practical otherwise.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://markosaric.com/wp-content/uploads/favicon.ico" alt="How to fight back against Google AMP">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to fight back against Google AMP</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Marko Saric</a> <span class="article__date">05 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        There&#8217;s a popular thread on Hacker News with lots of people complaining about how Google AMP (Accelerated Mobile Pages) is ruining their mobile web experience. Here&#8217;s what&#8217;s wrong with using Google AMP. This week I also got two AMP links sent to me via Telegram and to see those Google URLs replacing unique domain names&#8230; <a class="more-link" href="https://markosaric.com/google-amp/">Continue reading <span class="screen-reader-text">How to fight back against Google AMP</span></a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Google trackeando y yo con MAZA bloqueando">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Google trackeando y yo con MAZA bloqueando</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">04 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Aprovechando la reciente repercusión del <a href="https://github.com/tanrax/maza-ad-blocking" rel="noopener noreferrer" target="_blank">ad blocker realizado por Andros llamado Maza </a>en Hacker News y en blogs de referencia, hablamos en el episodio sobre tecnologías de bloqueo de anuncios. La tendencia a la instalación de soluciones para bloquear anuncios por parte de los usuarios sigue en aumento, en especial en los móviles. Esto también coincide con la incorporación de navegadores con bloqueadores nativos como Brave, extensiones para navegadores, software para móviles y aplicaciones de escritorios, VPN y soluciones basadas en DNS.</p>
<p>Por eso en ese episodio queremos hablar sobre las diferentes alternativas que existen para bloquear anuncios, su funcionamiento y cómo todo esto está influyendo en los proveedores de contenido en internet.</p>
<blockquote class="twitter-tweet mx-auto block" style="margin-top:30px;margin-bottom:30px;">
<p lang="en" dir="ltr">Maza &#8211; Local ad blocker. Like Pi-hole but local and using your operating system. Only works on Linux and macOS.<a href="https://t.co/bnHlR8DERA">https://t.co/bnHlR8DERA</a></p>
<p>&#8212; The Best Linux Blog In the Unixverse (@nixcraft) <a href="https://twitter.com/nixcraft/status/1244277617785626627?ref_src=twsrc%5Etfw">March 29, 2020</a></p></blockquote>
<p> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<p>Hablamos de soluciones de bloqueo de anuncios en el navegador con extensiones para el navegador de escritorio como uBlock Origin, navegadores nativos como Brave y otras soluciones a nivel de navegador en Firefox o en Opera. También vemos programas para bloquear los anuncios a nivel de dispositivo con programas como <a href="https://adguard.com/es/welcome.html" rel="noopener noreferrer" target="_blank">AdGuard</a> o proveedores VPN como Private Internet Access. También soluciones DNS y de hardware como <a href="https://pi-hole.net/" rel="noopener noreferrer" target="_blank">Pi-Hole</a>, <a href="https://nextdns.io/" rel="noopener noreferrer" target="_blank">NextDNS</a>, <a href="https://blog.cloudflare.com/introducing-1-1-1-1-for-families/" rel="noopener noreferrer" target="_blank">Cloudfare</a> o la propia solución de Andros MAZA.</p>
<p>También hablamos de la dinámica en el ecosistema de anuncios online, como los proveedores de programática y soluciones de monetización como Relevant ads. Comentamos también la iniciativa de Firefox Better Web con Scroll, un servicio para remunerar a creadores de contenido asociados, con una membresía mensual.</p>
<p>Por último en la sección de Radar ofrecemos una colección de recursos interesantes para el desarrollo web y profesional.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Calculator in Vim – The Expression register</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Jovica Ilic</a> <span class="article__date">04 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>As a software developer you probably have to perform actions like copying different pieces of your code from multiple files into different locations of your current Vim session. Using only system clipboard, this can be a cumbersome and time consuming task. Once you master Vim registers, your text editing efficiency will greatly improve. A register... <a class="more-link" href="https://jovicailic.org/2020/04/calculator-in-vim/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a rel="nofollow" href="https://jovicailic.org/2020/04/calculator-in-vim/">Calculator in Vim &#8211; The Expression register</a> appeared first on <a rel="nofollow" href="https://jovicailic.org">Jovica Ilic</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q2 2020 Survey Results</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">03 04 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Our call for proposals for new projects will close on Thursday, April 9th, 2020 at 11:59pm PST.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Using Markdown in Django</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">29 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>How we developed a Markdown extension to manage content in Django sites.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Learning to Learn Effectively – Tip #1</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Jovica Ilic</a> <span class="article__date">29 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>In this post, I&#8217;ll share with you one of my favorite learning tip. This tip will help you greatly improve your learning skills. It can be also useful for giving more powerful presentations. It comes from the bonus ebook Learning to Learn Effectively from my Premium package of Mastering Vim Quickly. &#8230; If you knew you had a... <a class="more-link" href="https://jovicailic.org/2020/03/learning-to-learn-effectively-tip-1/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a rel="nofollow" href="https://jovicailic.org/2020/03/learning-to-learn-effectively-tip-1/">Learning to Learn Effectively &#8211; Tip #1</a> appeared first on <a rel="nofollow" href="https://jovicailic.org">Jovica Ilic</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Estudio sobre uso de bases de datos relacionales y NoSQL">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Estudio sobre uso de bases de datos relacionales y NoSQL</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">28 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Estamos de vuelta con el estudio de David Vaquero sobre el uso de tecnologías web y esta vez tratamos las bases de datos. En <a href="https://cursosdedesarrollo.com/que-bases-de-datos-son-los-mas-utilizados-en-el-millon-de-paginas-del-top-de-alexa-y-en-los-dominios-en-espana/">su propio estudio</a> David analiza el uso de tecnologías de bases de datos sobre el millón de sitios web proporcionado por Alexa, tomando además dominios españoles. Este trabajo nos sirve para comentar los resultados y explicar las diferencias entre las bases de datos relacionales como <strong>MySQL, Percona, MariaDB o PostgreSQL y las basadas en las llamadas noSQL, con MongoDB</strong> como principal protagonista y claramente orientadas a soluciones distribuidas y escalables.</p>
<p>En el episodio David explica con  detalle las <strong>diferencias conceptuales de este tipo de base de datos y los usos a los que va dirigidos.</strong> Es una explicación muy útil para tener una idea global sobre estas tecnologías y lo crítico que puede resultar para el rendimiento y la escalabilidad de nuestros proyectos.</p>
<p>Tradicionalmente las bases de datos se han visto como una caja negra, <strong>con una abstracción muy elevada </strong>para evitar preocuparse en los detalles de acceso y manipulación de los datos. Esta abstracción libera a los profesionales de las complejidades del software, aunque la exigencia y naturaleza de ciertas aplicaciones requieren tener un control más exhaustivo de cómo funcionan, destacando la importancia de contar con profesionales que optimicen los sistemas.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://vindarel.github.io/cl-cookbook/assets/gui/nuklear.png" alt="GUI Programming in Common Lisp, part 5/5: Nuklear">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">GUI Programming in Common Lisp, part 5/5: Nuklear</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">27 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p><a href="https://github.com/Immediate-Mode-UI/Nuklear">Nuklear</a> is a small <a href="https://en.wikipedia.org/wiki/Immediate_mode_GUI">immediate-mode</a> GUI toolkit:</p>

<blockquote>
<p><a href="https://github.com/Immediate-Mode-UI/Nuklear">Nuklear</a> is a minimal-state, immediate-mode graphical user interface toolkit written in ANSI C and licensed under public domain. It was designed as a simple embeddable user interface for application and does not have any dependencies, a default render backend or OS window/input handling but instead provides a highly modular, library-based approach, with simple input state for input and draw commands describing primitive shapes as output. So instead of providing a layered library that tries to abstract over a number of platform and render backends, it focuses only on the actual UI.</p>
</blockquote>

<p>its Lisp binding is <a href="https://github.com/borodust/bodge-nuklear">Bodge-Nuklear</a>, and its higher level companions <a href="https://github.com/borodust/bodge-ui">bodge-ui</a> and <a href="https://github.com/borodust/bodge-ui-window">bodge-ui-window</a>.</p>

<p>Unlike traditional UI frameworks, Nuklear allows the developer to take
over the rendering loop or the input management. This might require
more setup, but it makes Nuklear particularly well suited for games,
or for applications where you want to create new controls.</p>

<p>Previous posts of the serie:</p>

<ul>
<li><a href="/blog/gui-programming-in-common-lisp-part-1-of-5-tk/">part 1: Ltk</a></li>
<li><a href="/blog/gui-programming-in-common-lisp-part-2-of-5-qt4-qtools/">part 2: Qt4</a></li>
<li><a href="/blog/gui-programming-in-common-lisp-part-3-of-5-gtk3/">part 3: Gtk+3</a></li>
<li><a href="/blog/gui-programming-in-common-lisp-part-4-of-5-iup/">part 4: IUP</a></li>
</ul>

<p><strong>This blog post series was initially written for the Common Lisp
Cookbook, you can (and should) read it there:</strong></p>

<p><a href="https://lispcookbook.github.io/cl-cookbook/gui.html">https://lispcookbook.github.io/cl-cookbook/gui.html</a></p>

<ul>
<li><strong>Framework written in</strong>: ANSI C, single-header library.</li>

<li><p><strong>Portability</strong>: where C runs. Nuklear doesn&rsquo;t contain
platform-specific code. No direct OS or window handling is done in
Nuklear. Instead <em>all input state has to be provided by platform
specific code</em>.</p></li>

<li><p><strong>Widgets choice</strong>: small.</p></li>

<li><p><strong>Graphical builder</strong>: no.</p></li>

<li><p><strong>Other features</strong>: fully skinnable and customisable.</p></li>

<li><p><strong>Bindings stability</strong>: stable</p></li>

<li><p><strong>Bindings activity</strong>: active</p></li>

<li><p><strong>Licence</strong>: MIT or Public Domain (unlicence).</p></li>

<li><p>Example applications:</p>

<ul>
<li><a href="https://github.com/borodust/trivial-gamekit">Trivial-gamekit</a></li>
<li><a href="https://github.com/thicksteadTHpp/Obvius/">Obvius</a> - a resurrected image processing library.</li>
<li><a href="https://github.com/borodust/notalone">Notalone</a> - an autumn 2017 Lisp Game Jam entry.</li>
</ul></li>
</ul>

<p><strong>List of widgets</strong></p>

<p>Non-exhaustive list:</p>

<pre><code>buttons, progressbar, image selector, (collapsable) tree, list, grid, range, slider, color picker,
date-picker
</code></pre>

<p><img src="https://vindarel.github.io/cl-cookbook/assets/gui/nuklear.png" alt="" /></p>

<h2 id="getting-started">Getting started</h2>

<p><strong>Disclaimer</strong>: as per the author&rsquo;s words at the time of writing,
bodge-ui is in early stages of development and not ready for general
use yet. There are some quirks that need to be fixed, which might
require some changes in the API.</p>

<p><code>bodge-ui</code> is not in Quicklisp but in its own Quicklisp distribution. Let&rsquo;s install it:</p>

<pre><code class="language-lisp">(ql-dist:install-dist &quot;http://bodge.borodust.org/dist/org.borodust.bodge.txt&quot; :replace t :prompt nil)
</code></pre>

<p>Uncomment and evaluate this line only if you want to enable the OpenGL 2
renderer:</p>

<pre><code class="language-lisp">;; (cl:pushnew :bodge-gl2 cl:*features*)
</code></pre>

<p>Quickload <code>bodge-ui-window</code>:</p>

<pre><code class="language-lisp">(ql:quickload :bodge-ui-window)
</code></pre>

<p>We can run the built-in example:</p>

<pre><code class="language-lisp">(ql:quickload :bodge-ui-window/examples)
(bodge-ui-window.example.basic:run)
</code></pre>

<p>Now let&rsquo;s define a package to write a simple application.</p>

<pre><code class="language-lisp">(cl:defpackage :bodge-ui-window-test
  (:use :cl :bodge-ui :bodge-host))
(in-package :bodge-ui-window-test)
</code></pre>

<pre><code class="language-lisp">(defpanel (main-panel
            (:title &quot;Hello Bodge UI&quot;)
            (:origin 200 50)
            (:width 400) (:height 400)
            (:options :movable :resizable
                      :minimizable :scrollable
                      :closable))
  (label :text &quot;Nested widgets:&quot;)
  (horizontal-layout
   (radio-group
    (radio :label &quot;Option 1&quot;)
    (radio :label &quot;Option 2&quot; :activated t))
   (vertical-layout
    (check-box :label &quot;Check 1&quot; :width 100)
    (check-box :label &quot;Check 2&quot;))
   (vertical-layout
    (label :text &quot;Awesomely&quot; :align :left)
    (label :text &quot;Stacked&quot; :align :centered)
    (label :text &quot;Labels&quot; :align :right)))
  (label :text &quot;Expand by width:&quot;)
  (horizontal-layout
   (button :label &quot;Dynamic&quot;)
   (button :label &quot;Min-Width&quot; :width 80)
   (button :label &quot;Fixed-Width&quot; :expandable nil :width 100))
  )

(defun run ()
  (bodge-host:open-window (make-instance 'main-window)))
</code></pre>

<p>and run it:</p>

<pre><code class="language-lisp">(run)
</code></pre>

<p><img src="https://vindarel.github.io/cl-cookbook/assets/gui/nuklear-test.png" alt="" /></p>

<p>To react to events, use the following signals:</p>

<pre><code>:on-click
:on-hover
:on-leave
:on-change
:on-mouse-press
:on-mouse-release
</code></pre>

<p>They take as argument a function with one argument, the panel. But
beware: they will be called on each rendering cycle when the widget is
on the given state, so potentially a lot of times.</p>

<h3 id="interactive-development">Interactive development</h3>

<p>If you ran the example in the REPL, you couldn&rsquo;t see what&rsquo;s cool. Put
the code in a lisp file and run it, so than you get the window. Now
you can change the panel widgets and the layout, and your changes will
be immediately applied while the application is running!</p>

<h1 id="conclusion">Conclusion</h1>

<p>Have fun, don&rsquo;t hesitate to share your experience and your apps… and contribute to the Cookbook!</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://raw.githubusercontent.com/lispnik/iup/master/docs/screenshots/sample-01.png" alt="GUI Programming in Common Lisp, part 4/5: IUP">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">GUI Programming in Common Lisp, part 4/5: IUP</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">27 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p><a href="http://webserver2.tecgraf.puc-rio.br/iup/">IUP</a> is a cross-platform GUI toolkit actively developed
at the PUC university of Rio de Janeiro, Brazil. It uses <strong>native
controls</strong>: the Windows API for Windows, Gtk3 for GNU/Linux. At the
time of writing, it has a Cocoa port in the works (as well as iOS,
Android and WASM ones). A particularity of IUP is its <strong>small API</strong>.</p>

<p>The Lisp bindings are <a href="https://github.com/lispnik/iup/">lispnik/iup</a>. They are nicely
done in that they are automatically generated from the C sources. They
can follow new IUP versions with a minimal work and the required steps
are documented. All this gives us good guarantee over the bus
factor.</p>

<p>IUP stands as a great solution in between Tk and Gtk or Qt.</p>

<p>Previous posts of the serie:</p>

<ul>
<li><a href="/blog/gui-programming-in-common-lisp-part-1-of-5-tk/">part 1: Ltk</a></li>
<li><a href="/blog/gui-programming-in-common-lisp-part-2-of-5-qt4-qtools/">part 2: Qt4</a></li>
<li><a href="/blog/gui-programming-in-common-lisp-part-3-of-5-gtk3/">part 3: Gtk+3</a></li>
</ul>

<p><strong>This blog post series was initially written for the Common Lisp
Cookbook, you can (and should) read it there:</strong></p>

<p><a href="https://lispcookbook.github.io/cl-cookbook/gui.html">https://lispcookbook.github.io/cl-cookbook/gui.html</a></p>

<ul>
<li><strong>Framework written in</strong>: C (official API also in Lua and LED)</li>

<li><p><strong>Portability</strong>: Windows and Linux, work started for
Cocoa, iOS, Android, WASM.</p></li>

<li><p><strong>Widgets choice</strong>: medium.</p></li>

<li><p><strong>Graphical builder</strong>: yes: <a href="http://webserver2.tecgraf.puc-rio.br/iup/en/iupvisualled.html">IupVisualLED</a></p></li>

<li><p><strong>Other features</strong>: OpenGL, Web browser (WebKitGTK on GNU/Linux), plotting, Scintilla text editor</p></li>

<li><p><strong>Bindings documentation</strong>: good examples and good readme, otherwise low.</p></li>

<li><p><strong>Bindings stability</strong>: alpha (but fully generated and working nicely)</p></li>

<li><p><strong>Bindings activity</strong>: low</p></li>

<li><p><strong>Licence</strong>: IUP and the bindings are MIT licenced.</p></li>
</ul>

<p><strong>List of widgets</strong></p>

<pre><code>Radio, Tabs, FlatTabs, ScrollBox, DetachBox,
Button, FlatButton, DropButton, Calendar, Canvas, Colorbar, ColorBrowser, DatePick, Dial, Gauge, Label, FlatLabel,
FlatSeparator, Link, List, FlatList, ProgressBar, Spin, Text, Toggle, Tree, Val,
listDialog, Alarm, Color, Message, Font, Scintilla, file-dialog…
Cells, Matrix, MatrixEx, MatrixList,
GLCanvas, Plot, MglPlot, OleControl, WebBrowser (WebKit/Gtk+)…
drag-and-drop
</code></pre>

<!-- editor's note: found missing a list view with columns. -->

<p><img src="https://raw.githubusercontent.com/lispnik/iup/master/docs/screenshots/sample-01.png" alt="" /></p>

<h2 id="getting-started">Getting started</h2>

<p>Please check the installation instructions upstream. You may need one
system dependency on GNU/Linux, and to modify an environment variable
on Windows.</p>

<p>Finally, do:</p>

<pre><code class="language-lisp">(ql:quickload :iup)
</code></pre>

<p>We are not going to <code>:use</code> IUP (it is a bad practice generally after all).</p>

<pre><code class="language-lisp">(defpackage :test-iup
  (:use :cl))
(in-package :test-iup)
</code></pre>

<p>The following snippet creates a dialog frame to display a text label.</p>

<pre><code class="language-lisp">(defun hello ()
  (iup:with-iup ()
    (let* ((label (iup:label :title (format nil &quot;Hello, World!~%IUP ~A~%~A ~A&quot;
                                            (iup:version)
                                            (lisp-implementation-type)
                                            (lisp-implementation-version))))
           (dialog (iup:dialog label :title &quot;Hello, World!&quot;)))
      (iup:show dialog)
      (iup:main-loop))))
(hello)
</code></pre>

<p>Important note for SBCL: we currently must trap division-by-zero
errors (see advancement on <a href="https://github.com/lispnik/iup/issues/30">this
issue</a>). So, run snippets
like so:</p>

<pre><code class="language-lisp">(defun run-gui-function ()
  #-sbcl (gui-function)
  #+sbcl
  (sb-int:with-float-traps-masked
      (:divide-by-zero :invalid)
    (gui-function)))
</code></pre>

<p><strong>How to run the main loop</strong></p>

<p>As with all the bindings seen so far, widgets are shown inside a
<code>with-iup</code> macro, and with a call to <code>iup:main-loop</code>.</p>

<p><strong>How to create widgets</strong></p>

<p>The constructor function is the name of the widget: <code>iup:label</code>,
<code>iup:dialog</code>.</p>

<p><strong>How to display a widget</strong></p>

<p>Be sure to &ldquo;show&rdquo; it: <code>(iup:show dialog)</code>.</p>

<p>You can group widgets on <code>frame</code>s, and stack them vertically or
horizontally (with <code>vbox</code> or <code>hbox</code>, see the example below).</p>

<p>To allow a widget to be expanded on window resize, use <code>:expand
:yes</code> (or <code>:horizontal</code> and <code>:vertical</code>).</p>

<p>Use also the <code>:alignement</code> properties.</p>

<p><strong>How to get and set a widget&rsquo;s attributes</strong></p>

<p>Use <code>(iup:attribute widget attribute)</code> to get the attribute&rsquo;s value,
and use <code>setf</code> on it to set it.</p>

<h3 id="reacting-to-events">Reacting to events</h3>

<p>Most widgets take an <code>:action</code> parameter that takes a lambda function
with one parameter (the handle).</p>

<pre><code class="language-lisp">(iup:button :title &quot;Test &amp;1&quot;
            :expand :yes
            :tip &quot;Callback inline at control creation&quot;
            :action (lambda (handle)
                      (iup:message &quot;title&quot; &quot;button1's action callback&quot;)
                      iup:+default+))
</code></pre>

<p>Below we create a label and put a button below it. We display a
message dialog when we click on the button.</p>

<pre><code class="language-lisp">(defun click-button ()
  (iup:with-iup ()
    (let* ((label (iup:label :title (format nil &quot;Hello, World!~%IUP ~A~%~A ~A&quot;
                                            (iup:version)
                                            (lisp-implementation-type)
                                            (lisp-implementation-version))))
           (button (iup:button :title &quot;Click me&quot;
                               :expand :yes
                               :tip &quot;yes, click me&quot;
                               :action (lambda (handle)
                                         (declare (ignorable handle))
                                         (iup:message &quot;title&quot; &quot;button clicked&quot;)
                                         iup:+default+)))
           (vbox
            (iup:vbox (list label button)
                      :gap &quot;10&quot;
                      :margin &quot;10x10&quot;
                      :alignment :acenter))
           (dialog (iup:dialog vbox :title &quot;Hello, World!&quot;)))
      (iup:show dialog)
      (iup:main-loop))))

#+sbcl
(sb-int:with-float-traps-masked
      (:divide-by-zero :invalid)
    (click-button))
</code></pre>

<p>Here&rsquo;s a similar example to make a counter of clicks.  We use a label
and its title to hold the count. The title is an integer.</p>

<pre><code class="language-lisp">(defun counter ()
  (iup:with-iup ()
    (let* ((counter (iup:label :title 0))
           (label (iup:label :title (format nil &quot;The button was clicked ~a time(s).&quot;
                                            (iup:attribute counter :title))))
           (button (iup:button :title &quot;Click me&quot;
                               :expand :yes
                               :tip &quot;yes, click me&quot;
                               :action (lambda (handle)
                                         (declare (ignorable handle))
                                         (setf (iup:attribute counter :title)
                                               (1+ (iup:attribute counter :title 'number)))
                                         (setf (iup:attribute label :title)
                                               (format nil &quot;The button was clicked ~a times.&quot;
                                                       (iup:attribute counter :title)))
                                         iup:+default+)))
           (vbox
            (iup:vbox (list label button)
                      :gap &quot;10&quot;
                      :margin &quot;10x10&quot;
                      :alignment :acenter))
           (dialog (iup:dialog vbox :title &quot;Counter&quot;)))
      (iup:show dialog)
      (iup:main-loop))))

(defun run-counter ()
  #-sbcl
  (counter)
  #+sbcl
  (sb-int:with-float-traps-masked
      (:divide-by-zero :invalid)
    (counter)))
</code></pre>

<h3 id="list-widget-example">List widget example</h3>

<p>Below we create three list widgets with simple and multiple selection, we
set their default value (the pre-selected row) and we place them
horizontally side by side.</p>

<pre><code class="language-lisp">(defun list-test ()
  (iup:with-iup ()
    (let*  ((list-1 (iup:list :tip &quot;List 1&quot;  ;; tooltip
                              ;; multiple selection
                              :multiple :yes
                              :expand :yes))
            (list-2 (iup:list :value 2   ;; default index of the selected row
                              :tip &quot;List 2&quot; :expand :yes))
            (list-3 (iup:list :value 9 :tip &quot;List 3&quot; :expand :yes))
            (frame (iup:frame
                    (iup:hbox
                     (progn
                       ;; populate the lists: display integers.
                       (loop for i from 1 upto 10
                          do (setf (iup:attribute list-1 i)
                                   (format nil &quot;~A&quot; i))
                          do (setf (iup:attribute list-2 i)
                                   (format nil &quot;~A&quot; (+ i 10)))
                          do (setf (iup:attribute list-3 i)
                                   (format nil &quot;~A&quot; (+ i 50))))
                       ;; hbox wants a list of widgets.
                       (list list-1 list-2 list-3)))
                    :title &quot;IUP List&quot;))
            (dialog (iup:dialog frame :menu &quot;menu&quot; :title &quot;List example&quot;)))

      (iup:map dialog)
      (iup:show dialog)
      (iup:main-loop))))

(defun run-list-test ()
  #-sbcl (hello)
  #+sbcl
  (sb-int:with-float-traps-masked
      (:divide-by-zero :invalid)
    (list-test)))
</code></pre>

<p>Next is a different toolkit very well suited for games and that enables fully interactive development: Nuklear.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://vindarel.github.io/cl-cookbook/assets/gui/gtk3-hello-buttons.png" alt="GUI Programming in Common Lisp, part 3/5: Gtk3">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">GUI Programming in Common Lisp, part 3/5: Gtk3</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">27 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>We continue our tour of GUI toolkits for CL with Gtk+3 and cl-cffi-gtk.</p>

<p>The previosu posts are:</p>

<ul>
<li><a href="/blog/gui-programming-in-common-lisp-part-1-of-5-tk/">part 1: Ltk</a></li>
<li><a href="/blog/gui-programming-in-common-lisp-part-2-of-5-qt4-qtools/">part 2: Qt4</a></li>
</ul>

<p><strong>This blog post series was initially written for the Common Lisp
Cookbook, you can (and should) read it there:</strong></p>

<p><a href="https://lispcookbook.github.io/cl-cookbook/gui.html">https://lispcookbook.github.io/cl-cookbook/gui.html</a></p>

<h2 id="gtk-3-cl-cffi-gtk">Gtk+3 (cl-cffi-gtk)</h2>

<p><a href="https://www.gtk.org/">Gtk+3</a> is the primary library used to build <a href="https://www.gnome.org/">GNOME</a>
applications. Its (currently most advanced) lisp bindings is
<a href="https://github.com/Ferada/cl-cffi-gtk/">cl-cffi-gtk</a>. While primarily created for GNU/Linux, Gtk
works fine under macOS and can now also be used on Windows.</p>

<ul>
<li><strong>Framework written in</strong>: C</li>

<li><p><strong>Portability</strong>: GNU/Linux and macOS, also Windows.</p></li>

<li><p><strong>Widgets choice</strong>: large.</p></li>

<li><p><strong>Graphical builder</strong>: yes: Glade.</p></li>

<li><p><strong>Other features</strong>: web browser (WebKitGTK)</p></li>

<li><p><strong>Bindings documentation</strong>: very good: <a href="http://www.crategus.com/books/cl-gtk/gtk-tutorial.html">http://www.crategus.com/books/cl-gtk/gtk-tutorial.html</a></p></li>

<li><p><strong>Bindings stability</strong>: stable</p></li>

<li><p><strong>Bindings activity</strong>: low activity, active development.</p></li>

<li><p><strong>Licence</strong>: LGPL</p></li>

<li><p>Example applications:</p>

<ul>
<li>an <a href="https://github.com/ralph-schleicher/atmosphere-calculator">Atmosphere Calculator</a>, built with Glade.</li>
</ul></li>
</ul>

<h2 id="getting-started">Getting started</h2>

<p>The
<a href="http://www.crategus.com/books/cl-gtk/gtk-tutorial.html">documentation</a>
is exceptionally good, including for beginners.</p>

<p>The library to quickload is <code>cl-cffi-gtk</code>. It is made of numerous
ones, that we have to <code>:use</code> for our package.</p>

<pre><code class="language-lisp">(ql:quickload :cl-cffi-gtk)

(defpackage :gtk-tutorial
  (:use :gtk :gdk :gdk-pixbuf :gobject
   :glib :gio :pango :cairo :common-lisp))

(in-package :gtk-tutorial)
</code></pre>

<p><strong>How to run the main loop</strong></p>

<p>As with the other libraries, everything happens inside the main loop
wrapper, here <code>with-main-loop</code>.</p>

<p><strong>How to create a window</strong></p>

<p><code>(make-instance 'gtk-window :type :toplevel :title &quot;hello&quot; ...)</code>.</p>

<p><strong>How to create a widget</strong></p>

<p>All widgets have a corresponding class. We can create them with
<code>make-instance 'widget-class</code>, but we preferably use the constructors.</p>

<p>The constructors end with (or contain) &ldquo;new&rdquo;:</p>

<pre><code class="language-lisp">(gtk-label-new)
(gtk-button-new-with-label &quot;Label&quot;)
</code></pre>

<p><strong>How to create a layout</strong></p>

<pre><code class="language-lisp">(let ((box (make-instance 'gtk-box :orientation :horizontal :spacing 6))) ...)
</code></pre>

<p>then pack a widget onto the box:</p>

<pre><code class="language-lisp">(gtk-box-pack-start box mybutton-1)
</code></pre>

<p>and add the box to the window:</p>

<pre><code class="language-lisp">(gtk-container-add window box)
</code></pre>

<p>and display them all:</p>

<pre><code class="language-lisp">(gtk-widget-show-all window)
</code></pre>

<h3 id="reacting-to-events">Reacting to events</h3>

<p>Use <code>g-signal-connect</code> + the concerned widget + the event name (as a
string) + a lambda, that takes the widget as argument:</p>

<pre><code class="language-lisp">(g-signal-connect window &quot;destroy&quot;
  (lambda (widget)
    (declare (ignore widget))
    (leave-gtk-main)))
</code></pre>

<p>Or again:</p>

<pre><code class="language-lisp">(g-signal-connect button &quot;clicked&quot;
  (lambda (widget)
    (declare (ignore widget))
    (format t &quot;Button was pressed.~%&quot;)))
</code></pre>

<h3 id="full-example">Full example</h3>

<pre><code class="language-lisp">(defun hello-world ()
  ;; in the docs, this is example-upgraded-hello-world-2.
  (within-main-loop
    (let ((window (make-instance 'gtk-window
                                 :type :toplevel
                                 :title &quot;Hello Buttons&quot;
                                 :default-width 250
                                 :default-height 75
                                 :border-width 12))
          (box (make-instance 'gtk-box
                              :orientation :horizontal
                              :spacing 6)))
      (g-signal-connect window &quot;destroy&quot;
                        (lambda (widget)
                          (declare (ignore widget))
                          (leave-gtk-main)))
      (let ((button (gtk-button-new-with-label &quot;Button 1&quot;)))
        (g-signal-connect button &quot;clicked&quot;
                          (lambda (widget)
                            (declare (ignore widget))
                            (format t &quot;Button 1 was pressed.~%&quot;)))
        (gtk-box-pack-start box button))
      (let ((button (gtk-button-new-with-label &quot;Button 2&quot;)))
        (g-signal-connect button &quot;clicked&quot;
                          (lambda (widget)
                            (declare (ignore widget))
                            (format t &quot;Button 2 was pressed.~%&quot;)))
        (gtk-box-pack-start box button))
      (gtk-container-add window box)
      (gtk-widget-show-all window))))
</code></pre>

<p><img src="https://vindarel.github.io/cl-cookbook/assets/gui/gtk3-hello-buttons.png" alt="" /></p>

<p>Next is IUP, a not very famous but really great toolkit!</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://vindarel.github.io/cl-cookbook/assets/gui/qtools-intro.png" alt="GUI Programming in Common Lisp, part 2/5: Qt4 with Qtools">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">GUI Programming in Common Lisp, part 2/5: Qt4 with Qtools</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">27 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>Here&rsquo;s the second part of our exploration of GUI toolkits for Common Lisp.</p>

<p>The first part and introduction is accessible here:</p>

<ul>
<li><a href="/blog/gui-programming-in-common-lisp-part-1-of-5-tk/">part 1: Ltk</a></li>
</ul>

<p><strong>This blog post series was initially written for the Common Lisp
Cookbook, you can (and should) read it there:</strong></p>

<p><a href="https://lispcookbook.github.io/cl-cookbook/gui.html">https://lispcookbook.github.io/cl-cookbook/gui.html</a></p>

<h2 id="qt4-qtools">Qt4 (Qtools)</h2>

<p>Do we need to present Qt and <a href="https://doc.qt.io/archives/qt-4.8/index.html">Qt4</a>? Qt is huge and contains
everything and the kitchen sink. Qt not only provides UI widgets, but
numerous other layers (networking, D-BUS…).</p>

<p>Qt is free for open-source software, however you&rsquo;ll want to check the
conditions to ship proprietary ones.</p>

<p>The <a href="https://github.com/Shinmera/qtools">Qtools</a> bindings target Qt4. The Qt5 Lisp bindings are
yet to be created.</p>

<!-- possible future: gobject-introspection -->

<ul>
<li><strong>Framework written in</strong>: C++</li>
<li><strong>Framework Portability</strong>: multi-platform, Android, embedded systems, WASM.</li>

<li><p><strong>Bindings Portability</strong>: Qtools runs on x86 desktop platforms on Windows, macOS and GNU/Linux.</p></li>

<li><p><strong>Widgets choice</strong>: large.</p></li>

<li><p><strong>Graphical builder</strong>: yes.</p></li>

<li><p><strong>Other features</strong>: Web browser, a lot more.</p></li>

<li><p><strong>Bindings documentation</strong>: lengthy explanations, a few examples. Prior Qt knowledge is required.</p></li>

<li><p><strong>Bindings stability</strong>: stable</p></li>

<li><p><strong>Bindings activity</strong>: active</p></li>

<li><p><strong>Qt Licence</strong>: both commercial and open source licences.</p></li>

<li><p>Example applications:</p>

<ul>
<li><a href="https://github.com/Shinmera/qtools/tree/master/examples">https://github.com/Shinmera/qtools/tree/master/examples</a></li>
<li><a href="https://github.com/Shirakumo/lionchat">https://github.com/Shirakumo/lionchat</a></li>
<li><a href="https://github.com/shinmera/halftone">https://github.com/shinmera/halftone</a> - a simple image viewer</li>
</ul></li>
</ul>

<h2 id="getting-started">Getting started</h2>

<pre><code class="language-lisp">(ql:quickload '(:qtools :qtcore :qtgui))
</code></pre>

<pre><code class="language-lisp">(defpackage #:qtools-test
  (:use #:cl+qt)
  (:export #:main))
(in-package :qtools-test)
(in-readtable :qtools)
</code></pre>

<p>We create our main widget that will contain the rest:</p>

<pre><code class="language-lisp">(define-widget main-window (QWidget)
  ())
</code></pre>

<p>We create an input field and a button inside this main widget:</p>

<pre><code class="language-lisp">(define-subwidget (main-window name) (q+:make-qlineedit main-window)
  (setf (q+:placeholder-text name) &quot;Your name please.&quot;))
</code></pre>

<pre><code class="language-lisp">(define-subwidget (main-window go-button) (q+:make-qpushbutton &quot;Go!&quot; main-window))
</code></pre>

<p>We stack them horizontally:</p>

<pre><code class="language-lisp">(define-subwidget (main-window layout) (q+:make-qhboxlayout main-window)
  (q+:add-widget layout name)
  (q+:add-widget layout go-button))
</code></pre>

<p>and we show them:</p>

<pre><code class="language-lisp">(with-main-window
  (window 'main-window))
</code></pre>

<p><img src="https://vindarel.github.io/cl-cookbook/assets/gui/qtools-intro.png" alt="" /></p>

<p>That&rsquo;s cool, but we don&rsquo;t react to the click event yet.</p>

<h3 id="reacting-to-events">Reacting to events</h3>

<p>Reacting to events in Qt happens through signals and slots. <strong>Slots</strong> are
functions that receive or &ldquo;connect to&rdquo; signals, and <strong>signals</strong> are event carriers.</p>

<p>Widgets already send their own signals: for example, a button sends a
&ldquo;pressed&rdquo; event. So, most of the time, we only need to connect to them.</p>

<p>However, had we extra needs, we can create our own set of signals.</p>

<h4 id="built-in-events">Built-in events</h4>

<p>We want to connect our <code>go-button</code> to the <code>pressed</code> and
<code>return-pressed</code> events and display a message box.</p>

<ul>
<li>we need to do this inside a <code>define-slot</code> function,</li>
<li>where we establish the connection to those events,</li>
<li>and where we create the message box. We grab the text of the <code>name</code>
input field with <code>(q+:text name)</code>.</li>
</ul>

<pre><code class="language-lisp">(define-slot (main-window go-button) ()
  (declare (connected go-button (pressed)))
  (declare (connected name (return-pressed)))
  (q+:qmessagebox-information main-window
                              &quot;Greetings&quot;  ;; title
                              (format NIL &quot;Good day to you, ~a!&quot; (q+:text name))))
</code></pre>

<p>And voilà. Run it with</p>

<pre><code class="language-lisp">(with-main-window (window 'main-window))
</code></pre>

<h4 id="custom-events">Custom events</h4>

<p>We&rsquo;ll implement the same functionality as above, but for demonstration
purposes we&rsquo;ll create our own signal named <code>name-set</code> to throw when
the button is clicked.</p>

<p>We start by defining the signal, which happens inside the
<code>main-window</code>, and which is of type <code>string</code>:</p>

<pre><code class="language-lisp">(define-signal (main-window name-set) (string))
</code></pre>

<p>We create a <strong>first slot</strong> to make our button react to the <code>pressed</code>
and <code>return-pressed</code> events. But instead of creating the message box
here, as above, we send the <code>name-set</code> signal, with the value of our
input field..</p>

<pre><code class="language-lisp">(define-slot (main-window go-button) ()
  (declare (connected go-button (pressed)))
  (declare (connected name (return-pressed)))
  (signal! main-window (name-set string) (q+:text name)))
</code></pre>

<p>So far, nobody reacts to <code>name-set</code>. We create a <strong>second slot</strong> that
connects to it, and displays our message. Here again, we precise the
parameter type.</p>

<pre><code class="language-lisp">(define-slot (main-window name-set) ((new-name string))
  (declare (connected main-window (name-set string)))
  (q+:qmessagebox-information main-window &quot;Greetings&quot; (format NIL &quot;Good day to you, ~a!&quot; new-name)))
</code></pre>

<p>and run it:</p>

<pre><code class="language-lisp">(with-main-window (window 'main-window))
</code></pre>

<h3 id="building-and-deployment">Building and deployment</h3>

<p>It is possible to build a binary and bundle it together with all the
necessary shared libraries.</p>

<p>Please read <a href="https://github.com/Shinmera/qtools#deployment">https://github.com/Shinmera/qtools#deployment</a>.</p>

<p>You might also like <a href="https://github.com/phoe-trash/furcadia-post-splitter/blob/master/.travis.yml">this Travis CI script</a> to build a self-contained binary for the three OSes.</p>

<p>Next, we&rsquo;ll have a look at Gtk+3.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://vindarel.github.io/cl-cookbook/assets/gui/ltk-on-macos.png" alt="GUI Programming in Common Lisp, part 1/5: Tk">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">GUI Programming in Common Lisp, part 1/5: Tk</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">27 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>Lisp has a long and rich history and so does the development of
Graphical User Interfaces in Lisp. In fact, the first GUI builder was
written in Lisp (and sold to Apple. It is now Interface Builder).</p>

<p>Lisp is also famous and unrivaled for its interactive development
capabilities, a feature even more worth having to develop GUI
applications. Can you imagine compiling one function and seeing your
GUI update instantly? We can do this with many GUI frameworks today,
even though the details differ from one to another.</p>

<p>Finally, a key part in building software is how to build it and ship
it to users. Here also, we can build self-contained binaries, for
the three main operating systems, that users can run with a double
click.</p>

<p>We aim here to give you the relevant information to help you choose
the right GUI framework and to put you on tracks. Don&rsquo;t hesitate to
<a href="https://github.com/LispCookbook/cl-cookbook/issues/">contribute</a>, to
send more examples and to furnish the upstream documentations.</p>

<p><strong>This blog post series was initially written for the Common Lisp
Cookbook, you can (and should) read it there:</strong></p>

<p><a href="https://lispcookbook.github.io/cl-cookbook/gui.html">https://lispcookbook.github.io/cl-cookbook/gui.html</a></p>

<h1 id="introduction">Introduction</h1>

<p>In this article series, we&rsquo;ll present the following GUI toolkits:</p>

<ul>
<li><a href="https://www.tcl.tk">Tk</a> with <a href="http://www.peter-herth.de/ltk/ltkdoc/">Ltk</a></li>
<li><a href="https://doc.qt.io/archives/qt-4.8/index.html">Qt4</a> with <a href="https://github.com/Shinmera/qtools">Qtools</a></li>
<li><a href="http://webserver2.tecgraf.puc-rio.br/iup/">IUP</a> with <a href="https://github.com/lispnik/iup/">lispnik/iup</a></li>
<li><a href="https://www.gtk.org/">Gtk3</a> with <a href="https://github.com/Ferada/cl-cffi-gtk/">cl-cffi-gtk</a></li>
<li><a href="https://github.com/Immediate-Mode-UI/Nuklear">Nuklear</a> with <a href="https://github.com/borodust/bodge-nuklear">Bodge-Nuklear</a></li>
</ul>

<p>In addition, you might want to have a look to:</p>

<ul>
<li>the <a href="http://www.lispworks.com/products/capi.html">CAPI</a> toolkit (Common Application Programming Interface),
which is proprietary and made by LispWorks. It is a complete and cross-platform
toolkit (Windows, Gtk+, Cocoa), very praised by its users. LispWorks
also has <a href="http://www.lispworks.com/products/lw4mr.html">iOS and Android
runtimes</a>. Example
software built with CAPI include <a href="https://opusmodus.com/">Opusmodus</a>
or again <a href="https://scorecloud.com/">ScoreCloud</a>. It is possible to
try it with the LispWorks free demo.</li>
<li><a href="https://github.com/plkrueger/CocoaInterface/">CocoaInterface</a>, a
Cocoa interface for Clozure Common Lisp. Build Cocoa user interface
windows dynamically using Lisp code and bypass the typical Xcode
processes.</li>
<li><a href="https://common-lisp.net/project/mcclim/">McCLIM</a>, a toolkit in 100% Common Lisp.</li>
<li><a href="https://github.com/Shirakumo/alloy">Alloy</a>, another very new toolkit in 100% Common Lisp, used for example in the <a href="https://github.com/shinmera/kandria">Kandria</a> game.</li>
<li><a href="https://notabug.org/cage/nodgui">nodgui</a>, a fork of Ltk, with syntax sugar and additional widgets.</li>
<li><a href="https://gitlab.com/eql">eql, eql5, eql5-android</a>, embedded Qt4 and Qt5 Lisp, embedded in ECL, embeddable in Qt. Port of EQL5 to the Android platform.</li>
<li>this <a href="https://github.com/defunkydrummer/abcl-jazz">demo using Java Swing from ABCL</a></li>
<li>and, last but not least, <a href="http://ceramic.github.io/">Ceramic</a>, to ship a cross-platform web app with Electron.</li>
</ul>

<p>as well as the other ones listed on <a href="https://github.com/CodyReichert/awesome-cl#gui">awesome-cl#gui</a> and <a href="https://www.cliki.net/GUI">Cliki</a>.</p>

<h1 id="tk-ltk">Tk (Ltk)</h1>

<p><a href="https://www.tcl.tk">Tk</a> (or Tcl/Tk, where Tcl is the programming language) has the
infamous reputation of having an outdated look. This is not (so) true
anymore since its version 8 of 1997 (!). It is probably better than
you think:</p>

<p><img src="https://vindarel.github.io/cl-cookbook/assets/gui/ltk-on-macos.png" alt="Ltk looks ok now" /></p>

<p>Tk doesn&rsquo;t have a great choice of widgets, but it has a useful canvas,
and it has a couple of unique features: we can develop a graphical
interface <strong>fully interactively</strong> and we can run the GUI <strong>remotely</strong>
from the core app.</p>

<p>So, Tk isn&rsquo;t fancy, but it is an used and proven GUI toolkit (and
programming language) still used in the industry. It can be a great
choice to quickly create simple GUIs, to leverage its ease of deployment, or
when stability is required.</p>

<p>The Lisp binding is <a href="http://www.peter-herth.de/ltk/ltkdoc/">Ltk</a>.</p>

<ul>
<li><strong>Written in</strong>: Tcl</li>

<li><p><strong>Portability</strong>: cross-platform (Windows, macOS, Linux).</p></li>

<li><p><strong>Widgets</strong>: this is not the fort of Tk. It has a <strong>small set</strong> of
default widgets, and misses important ones, for example a calendar. We
can find some in extensions (such as in <strong>Nodgui</strong>), but they don&rsquo;t
feel native, at all.</p></li>

<li><p><strong>Interactive development</strong>: very much.</p></li>

<li><p><strong>Graphical builder</strong>: no</p></li>

<li><p><strong>Other features</strong>:</p>

<ul>
<li><strong>remote execution</strong>: the connection between Lisp and Tcl/Tk is
done via a stream. It is thus possible to run the Lisp program on
one computer, and to display the GUI on another one. The only
thing required on the client computer is tcl/tk installed and the
remote.tcl script. See <a href="http://www.peter-herth.de/ltk/ltkdoc/node46.html">Ltk-remote</a>.</li>
</ul></li>

<li><p><strong>Bindings documentation</strong>: short but complete. Nodgui too.</p></li>

<li><p><strong>Bindings stability</strong>: very stable</p></li>

<li><p><strong>Bindings activity</strong>: low to non-existent.</p></li>

<li><p><strong>Licence</strong>: Tcl/Tk is BSD-style, Ltk is LGPL.</p></li>

<li><p>Example applications:</p>

<ul>
<li><a href="https://notabug.org/cage/fulci/">Fulci</a> - a program to organize your movie collections.</li>
<li><a href="https://github.com/mijohnson99/ltk-small-games">Ltk small games</a> - snake and tic-tac-toe.</li>
<li><a href="https://github.com/vindarel/cl-torrents">cl-torrents</a> - searching torrents on popular trackers. CLI, readline and a simple Tk GUI.</li>
</ul></li>
</ul>

<p><strong>List of widgets</strong></p>

<p>(please don&rsquo;t suppose the list exhaustive)</p>

<pre><code>Button Canvas Check-button Entry Frame Label Labelframe Listbox
Menu Menubutton Message
Paned-window
Radio-button Scale
Scrollbar Spinbox Text
Toplevel Widget Canvas

Ltk-megawidgets:
    progress
    history-entry
    menu-entry
</code></pre>

<p>Nodgui adds:</p>

<pre><code>treelist tooltip searchable-listbox date-picker calendar autocomplete-listbox
password-entry progress-bar-star notify-window
dot-plot bar-chart equalizer-bar
swap-list
</code></pre>

<h1 id="getting-started">Getting started</h1>

<p>Ltk is quick and easy to grasp.</p>

<pre><code class="language-lisp">(ql:quickload :ltk)
(in-package :ltk-user)
</code></pre>

<p><strong>How to create widgets</strong></p>

<p>All widgets are created with a regular <code>make-instance</code> and the widget name:</p>

<pre><code class="language-lisp">(make-instance 'button)
(make-instance 'treeview)
</code></pre>

<p>This makes Ltk explorable with the default symbol completion.</p>

<p><strong>How to start the main loop</strong></p>

<p>As with most bindings, the GUI-related code must be started inside a macro that
handles the main loop, here <code>with-ltk</code>:</p>

<pre><code class="language-lisp">(with-ltk ()
  (let ((frame (make-instance 'frame)))
    …))
</code></pre>

<p><strong>How to display widgets</strong></p>

<p>After we created some widgets, we must place them on the layout. There
are a few Tk systems for that, but the most recent one and the one we
should start with is the <code>grid</code>. <code>grid</code> is a function that takes as
arguments the widget, its column, its row, and a few optional
parameters.</p>

<p>As with any Lisp code in a regular environment, the functions&rsquo;
signatures are indicated by the editor. It makes Ltk explorable.</p>

<p>Here&rsquo;s how to display a button:</p>

<pre><code class="language-lisp">(with-ltk ()
  (let ((button (make-instance 'button :text &quot;hello&quot;)))
    (grid button 0 0)))
</code></pre>

<p>That&rsquo;s all there is to it.</p>

<h3 id="reacting-to-events">Reacting to events</h3>

<p>Many widgets have a <code>:command</code> argument that accept a lambda which is
executed when the widget&rsquo;s event is started. In the case of a button,
that will be on a click:</p>

<pre><code class="language-lisp">(make-instance 'button
  :text &quot;Hello&quot;
  :command (lambda ()
             (format t &quot;clicked&quot;)))
</code></pre>

<h3 id="interactive-development">Interactive development</h3>

<p>When we start the Tk process in the background with <code>(start-wish)</code>, we
can create widgets and place them on the grid interactively.</p>

<p>See <a href="http://www.peter-herth.de/ltk/ltkdoc/node8.html">the documentation</a>.</p>

<p>Once we&rsquo;re done, we can <code>(exit-wish)</code>.</p>

<h3 id="nodgui">Nodgui</h3>

<p>To try the Nodgui demo, do:</p>

<pre><code class="language-lisp">(ql:quickload :nodgui)
(nodgui.demo:demo)
</code></pre>

<p>Next, we&rsquo;ll have a look at a very different beast, Qt4, with Qtools.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ondahostil.files.wordpress.com/2018/08/yo.jpg?w=32" alt="Camino a la panificación: pan de pandemia">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Camino a la panificación: pan de pandemia</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Onda Hostil</a> <span class="article__date">27 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Me pilló el encierro sin harina blanca y con una pila de avellanas producidas en un huerto que no es el mío. Vista la locura que suponen las compras en un pueblo como el mío en el que el pequeño comercio hace años que murió, decidí panificar con lo que tenía a mano y no [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/170-acquisition.png" alt="Acquisition">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Acquisition</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">24 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/170-acquisition.png" alt="Acquisition" title="A period of doubt, anxiety, and dissatisfaction that some experience in middle age." /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Literate Programming in Lisp With Erudite</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">21 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p><a href="https://github.com/mmontone/erudite/">Erudite</a> is a Common Lisp library to write literate programs.
The latest release (march, 2020) brings cool new features, amongst which the
ability to capture and print code output.</p>

<p>This page was created with Erudite. You can follow along with its
source <a href="/blog/literate-erudite.lisp">here</a>. Blogging about a programming language in the language itself is
pretty awesome and convenient (no more copy-pasting of code snippets
and manual adjustements of the indentation, yay!). It brings us closer
to an interactive notebook, even if it isn&rsquo;t the first goal.</p>

<h1 id="basic-usage">Basic usage</h1>

<p>You write a lisp program, as usual. There is no extra step to produce the program sources,
since we are inside the sources. This is different than the Org-mode approach for example.</p>

<p>The comments will be the documentation. Comments inside a function are
also extracted and cut the function in two.</p>

<p>Erudite can export to Latex, RestructuredText, Markdown, HTML… and
actually to and from any format by using a &ldquo;pass-through&rdquo; directive.</p>

<p><br>
Top level comments are shown like this. Here&rsquo;s code:</p>

<pre><code class="language-lisp">(defun fibonacci (n &amp;aux (f0 0) (f1 1))
  &quot;docstring&quot;
  (case n
    (0 f0)
    (1 f1)
</code></pre>

<p>this is an inline comment (there might be settings to control how it is rendered)</p>

<pre><code class="language-lisp">    (t (loop for n from 2 to n
          for a = f0 then b and b = f1 then result
          for result = (+ a b)
          finally (return result)))))

</code></pre>

<p>Erudite defines directives to play with the output, such as <code>ignore</code> and <code>eval</code>. Note that directives start with a <code>@</code> sign, which I cannot use here.</p>

<p>With <code>ignore</code>, we can write lisp code but hide it from the output. And with <code>eval</code>, Erudite connects to a Swank server, captures and prints the output.</p>

<p>There&rsquo;s also the handy <code>code</code>, to write a snippet inside comments (so it is not part of
the Lisp source) and make it appear in the generated document.</p>

<p>For the text markup, we can use Erudite&rsquo;s
syntax (&ldquo;link&rdquo;, &ldquo;section&rdquo;, &ldquo;subsection&rdquo;, &ldquo;emph&rdquo;…), or the markup of
the output file format.</p>

<h1 id="evaluating-code">Evaluating code</h1>

<p>With the latest Erudite, we can evaluate code. Note that it&rsquo;s a work
in progress.</p>

<p>The code snippet must be inside the comments too.</p>

<p>Here I call Fibonacci defined above: Fibonacci of 10 is…
<br>
55
<br></p>

<p>You might need to create a Swank server first with</p>

<pre><code class="language-lisp">
(swank:create-server :dont-close t)
</code></pre>

<p>and tell Erudite its port if it isn&rsquo;t 4005.</p>

<pre><code class="language-lisp">
(setf erudite::*swank-port* 4005)
</code></pre>

<h1 id="rendering-the-document">Rendering the document</h1>

<p>Call Erudite like so:</p>

<pre><code class="language-lisp">
(erudite:erudite #p&quot;literal.md&quot; &quot;literal-erudite.lisp&quot; :output-type :markdown)

</code></pre>

<p>We can also use a binary from the shell.</p>

<h1 id="live-rendering">Live rendering</h1>

<p>I don&rsquo;t want to re-run this command everytime I want to see the generated document.
I use this snippet to automatically export my document when I save the Lisp source:</p>

<pre><code class="language-lisp">
(ql:quickload :cl-inotify)

(bt:make-thread
 (lambda ()
   (cl-inotify:with-inotify (inotify t (&quot;literal-erudite.lisp&quot; :close-write))
     (cl-inotify:do-events (event inotify :blocking-p t)
       (format t &quot;~a~&amp;&quot; event)
       (erudite:erudite #p&quot;literal.md&quot; &quot;literal-erudite.lisp&quot; :output-type :markdown))))
 :name &quot;inotify-erudite&quot;)

</code></pre>

<p>And then I make the markdown file to be live-rendered in the browser.
I used impatient-mode for Emacs (see <a href="http://wikemacs.org/wiki/Markdown#Live_preview_as_you_type">Wikemacs</a>) with the help of <code>M-x auto-revert-mode</code>.</p>

<p>Kuddos to Mariano Montone!</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="El papel de internet en estos tiempos de crisis">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">El papel de internet en estos tiempos de crisis</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">20 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Queremos dedicar este episodio a todas las personas que están enfrentándose a esta emergencia en primera línea. Son tiempos complicados que exigen unión y sólo nuestra determinación por hacer las cosas juntos nos hará superar esta situación. Mucho ánimo para todos.</p>
<p>En este episodio hablamos sobre cómo internet está ayudando a sobrellevar esta crisis global y también la forma en la que el acceso a la red supone un alivio en la parte personal y profesional. El avance espectacular del virus ha obligado a aplicar restricciones sin precedentes y en este escenario de aislamiento social, internet está jugando un papel fundamental. Aspectos tan cotidianos como trabajar, estudiar o dedicar tiempo al ocio están siendo posibles gracias a nuestras conexiones a la red.</p>
<p>Entre las cuestiones que discutimos en el episodio:</p>
<ul>
<li>Cómo estamos llevando estos días en la parte profesional.</li>
<li>Servicios que estamos usando más en la parte de trabajo en remoto.</li>
<li>Lo que nos sugiere que en muchos guiones apocalípticos se apuntaba a un fallo de la tecnología o de internet, como el fin de una era.¿No debería ser un derecho el acceso?.</li>
<li>Gestos de solidaridad por parte de muchas empresas que ponen a su disposición sus productos digitales.</li>
<p>¿Algún caso que os gustaría reseñar?</p>
<li>¿Supone esta crisis un cambio cultural definitivo con respecto al trabajo en remoto?.</li>
<li>Cómo pensamos que esta crisis va a afectar a nuestro trabajo.</li>
</ul>
<p>Por últimos dos grandes oyentes del podcast Cristóbal y Carlos nos han mandado su opinión acerca de las cuestiones hemos tratado en el episodio. Como siempre encantados de contar con vuestras aportaciones al podcast.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/169-levels-of-satisfaction.png" alt="Levels Of Satisfaction">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Levels Of Satisfaction</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">17 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/169-levels-of-satisfaction.png" alt="Levels Of Satisfaction" title="Programmers will tell you the best part is writing code, they're lying" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Radar Extendido con herramientas, artículos y recursos de desarrollo web">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Radar Extendido con herramientas, artículos y recursos de desarrollo web</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">13 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Tras varias entrevistas y episodios temáticos aprovechamos este episodio del podcast para hacer un radar extendido con recursos y herramientas de interés para el desarrollo web. Recopilamos algunos de los recursos que teníamos apuntados para aportar entre los tres, una lista extendida de nuestra frecuente sección Radar. Cada uno de nosotros se ha preparado unos cuantos enlaces para discutir en este episodio.</p>
<p>Es inevitable que en este episodio hagamos mención de la crisis del Coronavirus, y hablamos sobre como estamos afrontando los próximos días tanto a nivel personal como profesional. Esta crisis está poniendo a prueba gran parte de los aspectos más esenciales de nuestra vida y casi nadie se escapará de sus efectos en el ámbito profesional.</p>
<h2>Recursos web discutidos en el episodio</h2>
<p>Alpine.js: A Tiny JavaScript Framework (Caleb Porzio)<br />
Diminuta librería para generar interacciones de usuario listas para usar, sin necesidad de otras opciones más completas. <a href="https://www.smashingmagazine.com/2020/03/introduction-alpinejs-javascript-framework/" rel="noopener noreferrer" target="_blank">Artículo de Alpine.js en Smashing Magazine.</a></p>
<p><a href="https://tailwindui.com/" rel="noopener noreferrer" target="_blank">TailwindUI:</a> Completa colección de snippets de HTML listos para integrar en tu proyecto hecho con TailwindCSS.</p>
<p><a href="https://capitanswing.com/libros/comerciantes-de-atencion/" rel="noopener noreferrer" target="_blank">Libro Comerciantes de Atención por Tim Wu, publicado en español por Capitán Swing</a>, un ensayo fundamental para comprender como las empresas de comunicación y publicidad comercian con nuestra atención. Tim Wu es profesor de la Universidad de Columbia y columnista habitual del New York Times. </p>
<p><a href="https://tribucasters.com/" rel="noopener noreferrer" target="_blank">Podcast Tribucasters</a> de Pol Rodríguez y José Carlos Cortizo, un podcast para podcasters con un enfoque especial en todo lo relacionado con producir y captar audiencia en el mundo del podcast.</p>
<p><a href="https://place-image.andros.dev/" rel="noopener noreferrer" target="_blank">Place Image, una aplicación de Andros</a> para facilitar una colección de imágenes aleatorias y en diferentes tamaños, destinado a facilitar el trabajo del desarrollo y diseño web. </p>
<p><a href="https://localwp.com/" rel="noopener noreferrer" target="_blank">LocalWP por Flywheel</a>, ofrece un entorno de trabajo local con soporte SSL, dominios locales, Mailhog, instalación en un clic, refresco automático, wp cli, acceso SSH, últimas versiones de MySQL y PHP, configurar entorno de desarrollo o producción, extensiones….</p>
<p><a href="https://retool.com/" rel="noopener noreferrer" target="_blank">Retool</a>, una aplicación que promete recortar el tiempo que lleva construir herramientas internas. </p>
<p><a href="https://www.anayamultimedia.es/libro.php?id=5629095" rel="noopener noreferrer" target="_blank">Libro Algoritmos, Guía ilustrada para programadores y curiosos por Aditya Y. Bhargava.</a> Una guía muy bien ilustrada que enseña cómo aplicar algoritmos comunes a problemas prácticos que enfrentan a diario los programadores. </p>
<p>Podcast de formación por David Vaquero y José Jiménez, Formadores en tiempos revueltos <a href="https://www.ivoox.com/formadores-tiempos-revueltos_fg_f1852501_filtro_1.xml" rel="noopener noreferrer" target="_blank">iVoox</a>, <a href="https://anchor.fm/s/13cc5df4/podcast/rss" rel="noopener noreferrer" target="_blank">Anchor.fm. </a><br />
anchor.fm https://anchor.fm/s/13cc5df4/podcast/rss</p>
<p><a href="https://cursosdedesarrollo.com/2020/02/gadgets-para-el-formado-itinerante-router-wifi-de-viaje/" rel="noopener noreferrer" target="_blank">Gadgets para freelance itinerantes o nómadas digitales </a></p>
<p><a href="https://www.drupal.org/project/devel_image_provider" rel="noopener noreferrer" target="_blank">Generador contenidos Drupal</a></p>
<p><a href="https://slimbook.es/tutoriales/aplicaciones-slimbook/100-slimbook-battery-3-app-optimizar-bateria-portatil" rel="noopener noreferrer" target="_blank">Slimbook Battery.</a></p>
<p><a href="https://cursosdedesarrollo.com/2020/03/novedades-de-angular-9/" rel="noopener noreferrer" target="_blank">Artículo de David Vaquero sobre Angular 9 nueva release </a></p>
<p><a href="https://cursosdedesarrollo.com/2020/03/novedades-y-actualizacion-a-ionic-5/" rel="noopener noreferrer" target="_blank">Artículo de David Vaquero sobre Ionic 5 nueva release</a></p>
<p>Muchísimas gracias a nuestra querida Sonia Sánchez por hacernos la presentación de este episodio.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Fusión Reactiva, compartiendo experiencias profesionales junto a Daniel Primo">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Fusión Reactiva, compartiendo experiencias profesionales junto a Daniel Primo</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">10 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Para este episodio especial compartimos micrófono con nuestro colega <a href="https://www.danielprimo.io/podcast">podcaster Daniel Primo de Web Reactiva.</a> Aunque alguno ya hemos compartido con Daniel micrófono tanto en su podcast, como en el nuestro, es la primera vez que podemos hablar los cuatro juntos en un episodio. Con Dani aprovechamos para compartir nuestras experiencias profesionales, hablando de cuestiones aprendidas con los años, alguno de nuestros logros recientes y la percepción que tenemos de nuestra profesión.</p>
<p>Se trata de un episodio que publicará Dani en su programa Web Reactiva y que nosotros hemos decidido publicar como bonus en nuestro feed oficial. En este episodio también hay espacio para hablar sobre proyectos de futuro y lo que tenemos cada uno entre manos. Un episodio en modo tertulia entre amigos y colegas, y que pensamos puede resultar de interés a nuestros respectivos oyentes.</p>
<p>Entre las cuestiones que tratamos en el episodio se encuentran:</p>
<ul>
<li>¿Qué es lo mejor que habéis hecho a nivel profesional los últimos 2 ó 3 años?</li>
<li>¿De qué tecnología, hábito o disciplina profesional estás más orgulloso?</li>
<li>¿De qué forma ha cambiado vuestra percepción de la profesión con los años?</li>
<li>Un buen consejo que os hayan dado a nivel profesional y que se haya demostrado efectivo.</li>
<li>Objetivos y proyectos de futuro.</li>
</ul>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/168-early-contributor.png" alt="Early Contributor">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Early Contributor</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">10 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/168-early-contributor.png" alt="Early Contributor" title="At least you tried!" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Generate an SEO-Friendly Sitemap for your Gatsby Site</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">09 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        If you maintain a blog, documentation, or any other sort of writing-based Gatsby site, you know how much work goes into content creation. Help users find your work by ensuring that it's properly indexed by Google!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Infraestructura para proyectos web con Iván Expósito de Dinahosting">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Infraestructura para proyectos web con Iván Expósito de Dinahosting</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">06 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Para este episodio David Vaquero habla con Iván Expósito de Dinahosting, uno de los proveedores de infraestructura de alojamiento, dominios y servicios web más importantes de España. David aprovecha que es cliente de larga trayectoria de Dinahosting para conversar <strong>sobre los servicios que ofrecen, sus puntos de diferenciales y los nuevos proyectos que tienen para el futuro.</strong></p>
<p><a href="https://dinahosting.com/">Dinahosting</a> ofrece desde el año 2001 un catálogo amplísimo de servicios que van desde el registro de dominios, el hosting web y servidores VPS / dedicados. Con sedes en Santiago de Compostela y Madrid (datacenter), Dinahosting ofrece todo lo necesario para lanzar proyectos web y garantizar su crecimiento, desde alojamientos compartidos y soluciones más avanzadas. Con Iván Expósito hablamos de la personalidad de Dinahosting y su cultura de atención al cliente.</p>
<p>También hay espacio para hablar de proyectos paralelos dentro de la empresa, migraciones a VPS, código abierto, cloud privadas y requerimientos para lanzar proyectos y soporte personalizado a clientes. Dinahosting es una solución perfecta para poder crecer proyectos web con todo lo necesario para garantizar el acceso a nuestros servicios, sin contar con un personal técnico en las empresas.</p>
<p>Por último también hablamos de <a href="https://dinahosting.com/ayuda/que-es-dinaip-y-como-lo-uso/" rel="noopener noreferrer" target="_blank">DinaIP</a>, una solución desarrollada por Dinahosting para configurar direcciones dinámicas.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Writing a bytecode interpreter - in C</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Danny van Kooten</a> <span class="article__date">05 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Some time during 2016 I got my hands on the book <a href="http://interpreterbook.com/">Writing an interpreter in Go</a> by <a href="https://thorstenball.com/">Thorsten Ball</a>. I skimmed through the first few chapters, liked what I read and then… life happened and I never actually got around to building an interpreter. :(</p>

<p>Until last month, that is. I cleared out my schedule and finally started going through the book.</p>

<p>For double the fun, I picked C as my programming language of choice instead of Go. This turned out to be a great decision as it really forced me to understand what was going on, instead of always having the easy option of just copying the author’s code.</p>

<p>I codenamed my implementation <a href="https://github.com/dannyvankooten/monkey-c-monkey-do">Monkey-C Monkey-Do</a>.</p>

<p>The book takes you through all the stages to get an interpreter for the <a href="https://monkeylang.org/">Monkey programming language</a> up and running:</p>

<ul>
  <li>Tokenize the input</li>
  <li>Parse the tokens into an Abstract Syntax Tree (AST)</li>
  <li>Evaluate the tree</li>
</ul>

<p>This tree-walking evaluator needs about 6 seconds to calculate the 35th fibonacci number using <a href="https://github.com/dannyvankooten/monkey-c-monkey-do/blob/946311e77d33d584e6fcfd9f87d0199242973947/examples/fib35.monkey">a very sub-optimal algorithm with lots of recursion</a>. That is certainly not bad, but it’s also not great compared to any of today’s production-grade interpreted languages.</p>

<p>For comparison, on the same machine Python 3.7 needs 2.3 seconds for that exact same algorithm and Node 15 only needs a whopping 200 miliseconds (due to its JIT compilation).</p>

<p>Can we do better, without talking to the hardware directly?</p>

<h3 id="writing-a-bytecode-compiler-and-virtual-machine">Writing a bytecode compiler and virtual machine</h3>

<p>Luckily, the author of the book didn’t stop there. In his second book (<a href="https://compilerbook.com/">Writing a compiler in Go</a>) the author walks you through the steps of building a bytecode interpreter.</p>

<p>Reusing the AST from the first book, it shows you how to build a compiler outputting bytecode. Simultaneously, you start building a virtual machine capable of executing that bytecode.</p>

<p>After getting the virtual machine up and running, calculating the 35th fibonacci number now only takes 0.82 seconds. That’s much closer or even faster than some other interpreted languages already.</p>

<p>I wholeheartedly recommend the two books. Not only is it a lot of fun to write your own interpreter, it also cleared up a lot of the magic for me surrounding how interpreters actually work and what happens behind the scene when a program is evaluated by an interpreter.</p>

<h3 id="programming-in-c">Programming in C</h3>

<p>This was my first experience programming in C and it surprised me to discover that I really enjoyed using it. Because of the small language specification very little time was spent reading documentation.</p>

<p>That’s not to say I did not shoot myself in the foot a good few times or struggled with memory management. Using C really cemented my understanding of some of the languages that came after it though. And what problems they attempt to solve or improve upon over C.</p>

<p>Given the right tooling, I’ve grown quite fond of C… Sorry, not sorry.</p>

<h4 id="resources">Resources</h4>

<ul>
  <li>Book: <a href="https://en.wikipedia.org/wiki/The_C_Programming_Language">The C Programming Language</a> by Kernighan &amp; Ritchie. Still the best resource for learning C.</li>
  <li>Tools: <a href="https://valgrind.org/">Valgrind</a>, <a href="https://sourceware.org/binutils/docs/gprof/">Gprof</a>, <a href="https://www.gnu.org/software/make/manual/make.html">GNU make</a>, <a href="https://www.gnu.org/software/gdb/">GNU Debugger</a></li>
  <li><a href="https://github.com/python/cpython/blob/master/Python/ceval.c#L775">This comment in the CPython source</a> explaining the use of computed GOTO’s in the VM for a performance gain due to better CPU branch prediction over using a switch statement.</li>
  <li><a href="https://www.gingerbill.org/series/memory-allocation-strategies/">Memory allocation strategies</a> by Ginger Bill.</li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">February 2020 Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">04 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Read updates from Expound, Oz, Ring, Calva, and Reagent
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://img.youtube.com/vi/ygKXeLKhiTI/0.jpg" alt="Common Lisp Macros By Example Tutorial">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Common Lisp Macros By Example Tutorial</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">02 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>I have recently edited and somewhat expanded the macros page on the
Common Lisp Cookbook. I find it may more legible and reader friendly,
so I reproduce it below (however, I cut two parts so than you get the essential).</p>

<p>You&rsquo;d better read it on the Cookbook: <a href="https://lispcookbook.github.io/cl-cookbook/macros.html">https://lispcookbook.github.io/cl-cookbook/macros.html</a></p>

<hr />

<p>The word <em>macro</em> is used generally in computer science to mean a syntactic extension to a programming language. (Note: The name comes from the word &ldquo;macro-instruction,&rdquo; which was a useful feature of many second-generation assembly languages. A macro-instruction looked like a single instruction, but expanded into a sequence of actual instructions. The basic idea has since been used many times, notably in the C preprocessor. The name &ldquo;macro&rdquo; is perhaps not ideal, since it connotes nothing relevant to what it names, but we&rsquo;re stuck with it.) Although many languages have a macro facility, none of them are as powerful as Lisp&rsquo;s. The basic mechanism of Lisp macros is simple, but has subtle complexities, so learning your way around it takes a bit of practice.</p>

<h1 id="how-macros-work">How Macros Work</h1>

<p>A macro is an ordinary piece of Lisp code that operates on <em>another piece of putative Lisp code,</em> translating it into (a version closer to) executable Lisp. That may sound a bit complicated, so let&rsquo;s give a simple example. Suppose you want a version of <a href="http://www.lispworks.com/documentation/HyperSpec/Body/s_setq.htm"><code>setq</code></a> that sets two variables to the same value. So if you write</p>

<pre><code class="language-lisp">(setq2 x y (+ z 3))
</code></pre>

<p>when <code>z</code>=8 then both <code>x</code> and <code>y</code> are set to 11. (I can&rsquo;t think of any use for this, but it&rsquo;s just an example.)</p>

<p>It should be obvious that we can&rsquo;t define <code>setq2</code> as a function. If <code>x</code>=50 and <code>y</code>=<em>-5</em>, this function would receive the values 50, <em>-5</em>, and 11; it would have no knowledge of what variables were supposed to be set. What we really want to say is, When you (the Lisp system) see:</p>

<pre><code class="language-lisp">(setq2 v1 v2 e)
</code></pre>

<p>then treat it as equivalent to:</p>

<pre><code class="language-lisp">(progn
  (setq v1 e)
  (setq v2 e))
</code></pre>

<p>Actually, this isn&rsquo;t quite right, but it will do for now. A macro allows us to do precisely this, by specifying a program for transforming the input pattern <code>(setq2 <i>v<sub>1</sub></i> <i>v<sub>2</sub></i> <i>e</i>)</code> into the output pattern <code>(progn ...)</code>.</p>

<h2 id="quote">Quote</h2>

<p>Here&rsquo;s how we could define the <code>setq2</code> macro:</p>

<pre><code class="language-lisp">(defmacro setq2 (v1 v2 e)
  (list 'progn (list 'setq v1 e) (list 'setq v2 e)))
</code></pre>

<p>It takes as parameters two variables and one expression.</p>

<p>Then it returns a piece of code. In Lisp, because code is represented
as lists, we can simply return a list that represents code.</p>

<p>We also use the <em>quote</em>: each <em>quoted</em> symbol evaluates to itself, aka
it is returned as is:</p>

<ul>
<li><code>(quote foo bar baz)</code> returns <code>(foo bar baz)</code></li>
<li>the quote character, <code>'</code>, is a shortcut for <code>quote</code>, a <em>special operator</em> (not a function nor a macro, but one of a few special operators forming the core of Lisp).</li>
<li>so, <code>'foo</code> evaluates to <code>foo</code>.</li>
</ul>

<p>So, our macro retourns the following bits:</p>

<ul>
<li>the symbol <code>progn</code>,</li>
<li>a second list, that contains

<ul>
<li>the symbol <code>setq</code></li>
<li>the variable <code>v1</code>: note that the variable is not evaluated inside the macro!</li>
<li>the expression <code>e</code>: it is not evaluated either!</li>
</ul></li>
<li>a second list, with <code>v2</code>.</li>
</ul>

<p>We can use it like this:</p>

<pre><code class="language-lisp">(defparameter v1 1)
(defparameter v2 2)
(setq2 v1 v2 3)
;; 3
</code></pre>

<p>We can check, <code>v1</code> and <code>v2</code> were set to <code>3</code>.</p>

<h2 id="macroexpand">Macroexpand</h2>

<p>We must start writing a macro when we know what code we want to
generate. Once we&rsquo;ve begun writing one, it becomes very useful to
check effectively what code does the macro generate. The function for
that is <code>macroexpand</code>. It is a function, and we give it some code, as
a list (so, we quote the code snippet we give it):</p>

<pre><code class="language-lisp">(macroexpand '(setq2 v1 v2 3))
;; (PROGN (SETQ V1 3) (SETQ V2 3))
;; T
</code></pre>

<p>Yay, our macro expands to the code we wanted!</p>

<p>More interestingly:</p>

<pre><code class="language-lisp">(macroexpand '(setq2 v1 v2 (+ z 3)))
;; (PROGN (SETQ V1 (+ z 3)) (SETQ V2 (+ z 3)))
;; T
</code></pre>

<p>We can confirm that our expression <code>e</code>, here <code>(+ z 3)</code>, was not
evaluated. We will see how to control the evaluation of arguments with
the comma: <code>,</code>.</p>

<p>Note: with Slime, you can call macroexpand by putting the cursor at
the left of the parenthesis of the s-expr to expand and call the function<code>M-x
slime-macroexpand-[1,all]</code>, or <code>C-c M-m</code>:</p>

<pre><code class="language-lisp">[|](setq2 v1 v2 3)
;^ cursor
; C-c M-m
; =&gt;
; (PROGN (SETQ V1 3) (SETQ V2 3))
</code></pre>

<h2 id="macros-vs-functions">Macros VS functions</h2>

<p>Our macro is very close to the following function definition:</p>

<pre><code class="language-lisp">(defun setq2-function (v1 v2 e)
  (list 'progn (list 'setq v1 e) (list 'setq v2 e)))
</code></pre>

<p>If we evaluated <code>(setq2-function 'x 'y '(+ z 3))</code> (note that each
argument is <em>quoted</em>, so it isn&rsquo;t evaluated when we call the
function), we would get</p>

<pre><code class="language-lisp">(progn (setq x (+ z 3)) (setq y (+ z 3)))
</code></pre>

<p>This is a perfectly ordinary Lisp computation, whose sole point of interest is that its output is a piece of executable Lisp code. What <code>defmacro</code> does is create this function implicitly and make sure that whenever an expression of the form <code>(setq2 x y (+ z 3))</code> is seen, <code>setq2-function</code> is called with the pieces of the form as arguments, namely <code>x</code>, <code>y</code>, and <code>(+ z 3)</code>. The resulting piece of code then replaces the call to <code>setq2</code>, and execution resumes as if the new piece of code had occurred in the first place. The macro form is said to <em>expand</em> into the new piece of code.</p>

<h2 id="evaluation-context">Evaluation context</h2>

<p>This is all there is to it, except, of course, for the myriad subtle consequences. The main consequence is that <em>run time for the <code>setq2</code> macro</em> is <em>compile time for its context.</em> That is, suppose the Lisp system is compiling a function, and midway through it finds the expression <code>(setq2 x y (+ z 3))</code>. The job of the compiler is, of course, to translate source code into something executable, such as machine language or perhaps byte code. Hence it doesn&rsquo;t execute the source code, but operates on it in various mysterious ways. However, once the compiler sees the <code>setq2</code> expression, it must suddenly switch to executing the body of the <code>setq2</code> macro. As I said, this is an ordinary piece of Lisp code, which can in principle do anything any other piece of Lisp code can do. That means that when the compiler is running, the entire Lisp (run-time) system must be present.</p>

<p>We&rsquo;ll stress this once more: at compile-time, you have the full language at your disposal.</p>

<p>Novices often make the following sort of mistake. Suppose that the <code>setq2</code> macro needs to do some complex transformation on its <code>e</code> argument before plugging it into the result. Suppose this transformation can be written as a Lisp procedure <code>some-computation</code>. The novice will often write:</p>

<pre><code class="language-lisp">(defmacro setq2 (v1 v2 e)
  (let ((e1 (some-computation e)))
    (list 'progn (list 'setq v1 e1) (list 'setq v2 e1))))

(defmacro some-computation (exp) ...) ;; _Wrong!_
</code></pre>

<p>The mistake is to suppose that once a macro is called, the Lisp system enters a &ldquo;macro world,&rdquo; so naturally everything in that world must be defined using <code>defmacro</code>. This is the wrong picture. The right picture is that <code>defmacro</code> enables a step into the <em>ordinary Lisp world</em>, but in which the principal object of manipulation is Lisp code. Once that step is taken, one uses ordinary Lisp function definitions:</p>

<pre><code class="language-lisp">(defmacro setq2 (v1 v2 e)
  (let ((e1 (some-computation e)))
    (list 'progn (list 'setq v1 e1) (list 'setq v2 e1))))

(defun some-computation (exp) ...) ;; _Right!_
</code></pre>

<p>One possible explanation for this mistake may be that in other languages, such as C, invoking a preprocessor macro <em>does</em> get you into a different world; you can&rsquo;t run an arbitrary C program. It might be worth pausing to think about what it might mean to be able to.</p>

<p>Another subtle consequence is that we must spell out how the arguments to the macro get distributed to the hypothetical behind-the-scenes function (called <code>setq2-function</code> in my example). In most cases, it is easy to do so: In defining a macro, we use all the usual <code>lambda</code>-list syntax, such as <code>&amp;optional</code>, <code>&amp;rest</code>, <code>&amp;key</code>, but what gets bound to the formal parameters are pieces of the macro form, not their values (which are mostly unknown, this being compile time for the macro form). So if we defined a macro thus:</p>

<pre><code class="language-lisp">(defmacro foo (x &amp;optional y &amp;key (cxt 'null)) ...)
</code></pre>

<p>then</p>

<table>
<thead>
<tr>
<th><em>If we call it thus &hellip;</em></th>
<th><em>The parameters&rsquo; values are &hellip;</em></th>
</tr>
</thead>

<tbody>
<tr>
<td><code>(foo a)</code></td>
<td><code>x=a</code>, <code>y=nil</code>, <code>cxt=null</code></td>
</tr>

<tr>
<td><code>(foo (+ a 1) (- y 1))</code></td>
<td><code>x=(+ a 1)</code>, <code>y=(- y 1)</code>, <code>cxt=null</code></td>
</tr>

<tr>
<td><code>(foo a b :cxt (zap zip))</code></td>
<td><code>x=a</code>, <code>y=b</code>, <code>cxt=(zap zip)</code></td>
</tr>
</tbody>
</table>

<p><br></p>

<p>Note that the values of the variables are the actual expressions <code>(+ a 1)</code> and <code>(zap zip)</code>. There is no requirement that these expressions&rsquo; values be known, or even that they have values. The macro can do anything it likes with them. For instance, here&rsquo;s an even more useless variant of <code>setq</code>: <code>(setq-reversible <i>e<sub>1</sub></i> <i>e<sub>2</sub></i> <i>d</i>)</code> behaves like <code>(setq <i>e<sub>1</sub></i> <i>e<sub>2</sub></i>)</code> if <i>d=</i><code>:normal</code>, and behaves like <code>(setq <i>e<sub>2</sub></i> <i>e<sub>1</sub></i>)</code> if <em>d=</em><code>:backward</code>. It could be defined thus:</p>

<pre><code class="language-lisp">(defmacro setq-reversible (e1 e2 direction)
  (case direction
    (:normal (list 'setq e1 e2))
    (:backward (list 'setq e2 e1))
    (t (error &quot;Unknown direction: ~a&quot; direction))))
</code></pre>

<p>Here&rsquo;s how it expands:</p>

<pre><code class="language-lisp">(macroexpand '(setq-reversible x y :normal))
(SETQ X Y)
T
(macroexpand '(setq-reversible x y :backward))
(SETQ Y X)
T
</code></pre>

<p>And with a wrong direction:</p>

<pre><code class="language-lisp">(macroexpand '(setq-reversible x y :other-way-around))
</code></pre>

<p>We get an error and are prompted into the debugger!</p>

<p>We&rsquo;ll see the backquote and comma mechanism in the next section, but
here&rsquo;s a fix:</p>

<pre><code class="language-lisp">(defmacro setq-reversible (v1 v2 direction)
  (case direction
    (:normal (list 'setq v1 v2))
    (:backward (list 'setq v2 v1))
    (t `(error &quot;Unknown direction: ~a&quot; ,direction))))
    ;; ^^ backquote                    ^^ comma: get the value inside the backquote.

(macroexpand '(SETQ-REVERSIBLE v1 v2 :other-way-around))
;; (ERROR &quot;Unknown direction: ~a&quot; :OTHER-WAY-AROUND)
;; T
</code></pre>

<p>Now when we call <code>(setq-reversible v1 v2 :other-way-around)</code> we still get the
error and the debugger, but at least not when using <code>macroexpand</code>.</p>

<p><a name="2-backquote"></a></p>

<h1 id="backquote-and-comma">Backquote and comma</h1>

<p>Before taking another step, we need to introduce a piece of Lisp notation that is indispensable to defining macros, even though technically it is quite independent of macros. This is the <em>backquote facility</em>. As we saw above, the main job of a macro, when all is said and done, is to define a piece of Lisp code, and that means evaluating expressions such as <code>(list 'prog (list 'setq ...) ...)</code>. As these expressions grow in complexity, it becomes hard to read them and write them. What we find ourselves wanting is a notation that provides the skeleton of an expression, with some of the pieces filled in with new expressions. That&rsquo;s what backquote provides. Instead of the the <code>list</code> expression given above, one writes</p>

<pre><code class="language-lisp">  `(progn (setq ,v1 ,e) (setq ,v2 ,e))
;;^ backquote   ^   ^         ^   ^ commas
</code></pre>

<p>The backquote (`) character signals that in the expression that follows, every subexpression <em>not</em> preceded by a comma is to be quoted, and every subexpression preceded by a comma is to be evaluated.</p>

<p>You can think of it, and use it, as data interpolation:</p>

<pre><code class="language-lisp">`(v1 = ,v1) ;; =&gt; (V1 = 3)
</code></pre>

<p>That&rsquo;s mostly all there is to backquote. There are just two extra items to point out.</p>

<h3 id="comma-splice">Comma-splice ,@</h3>

<p>First, if you write &ldquo;<code>,@e</code>&rdquo; instead of &ldquo;<code>,e</code>&rdquo; then the value of <em>e</em> is <em>spliced</em> (or &ldquo;joined&rdquo;, &ldquo;combined&rdquo;, &ldquo;interleaved&rdquo;) into the result. So if <code>v</code> equals <code>(oh boy)</code>, then</p>

<pre><code class="language-lisp">(zap ,@v ,v)
</code></pre>

<p>evaluates to</p>

<pre><code class="language-lisp">(zap oh boy (oh boy))
;;   ^^^^^ elements of v (two elements), spliced.
;;          ^^ v itself (a list)
</code></pre>

<p>The second occurrence of <code>v</code> is replaced by its value. The first is replaced by the elements of its value. If <code>v</code> had had value <code>()</code>, it would have disappeared entirely: the value of <code>(zap ,@v ,v)</code> would have been <code>(zap ())</code>, which is the same as <code>(zap nil)</code>.</p>

<h3 id="quote-comma">Quote-comma &lsquo;,</h3>

<p>When we are inside a backquote context and we want to print an
expression literally, we have no choice but to use the combination of
quote and comma:</p>

<pre><code class="language-lisp">(defmacro explain-exp (exp)
  `(format t &quot;~S = ~S&quot; ',exp ,exp))
  ;;                   ^^

(explain-exp (+ 2 3))
;; (+ 2 3) = 5
</code></pre>

<p>See by yourself:</p>

<pre><code class="language-lisp">;; Defmacro with no quote at all:
(defmacro explain-exp (exp)
  (format t &quot;~a = ~a&quot; exp exp))
(explain-exp v1)
;; V1 = V1

;; OK, with a backquote and a comma to get the value of exp:
(defmacro explain-exp (exp)
  ;; WRONG example
  `(format t &quot;~a = ~a&quot; exp ,exp))
(explain-exp v1)
;; =&gt; error: The variable EXP is unbound.

;; We then must use quote-comma:
(defmacro explain-exp (exp)
  `(format t &quot;~a = ~a&quot; ',exp ,exp))
(explain-exp (+ 1 2))
;; (+ 1 2) = 3
</code></pre>

<h3 id="nested-backquotes">Nested backquotes</h3>

<p>Second, one might wonder what happens if a backquote expression occurs inside another backquote. The answer is that the backquote becomes essentially unreadable and unwriteable; using nested backquote is usually a tedious debugging exercise. The reason, in my not-so-humble opinion, is that backquote is defined wrong. A comma pairs up with the innermost backquote when the default should be that it pairs up with the outermost. But this is not the place for a rant; consult your favorite Lisp reference for the exact behavior of nested backquote plus some examples.</p>

<h3 id="building-lists-with-backquote">Building lists with backquote</h3>

<p>[…]</p>

<h1 id="getting-macros-right">Getting Macros Right</h1>

<p>I said in the first section that my definition of <code>setq2</code> wasn&rsquo;t quite right, and now it&rsquo;s time to fix it.</p>

<p>Suppose we write <code>(setq2 x y (+ x 2))</code>, when <code>x</code><em>=8</em>. Then according to the definition given above, this form will expand into</p>

<pre><code class="language-lisp">(progn
  (setq x (+ x 2))
  (setq y (+ x 2)))
</code></pre>

<p>so that <code>x</code> will have value 10 and <code>y</code> will have value 12. Indeed, here&rsquo;s its macroexpansion:</p>

<pre><code class="language-lisp">(macroexpand '(setq2 x y (+ x 2)))
;;(PROGN (SETQ X (+ X 2)) (SETQ Y (+ X 2)))
</code></pre>

<p>Chances are that isn&rsquo;t what the macro is expected to do (although you never know). Another problematic case is <code>(setq2 x y (pop l))</code>, which causes <code>l</code> to be popped twice; again, probably not right.</p>

<p>The solution is to evaluate the expression <code>e</code> just once, save it in a temporary variable, and then set <code>v1</code> and <code>v2</code> to it.</p>

<h2 id="gensym">Gensym</h2>

<p>To make temporary variables, we use the <code>gensym</code> function, which returns a fresh variable guaranteed to appear nowhere else. Here is what the macro should look like:</p>

<pre><code class="language-lisp">(defmacro setq2 (v1 v2 e)
  (let ((tempvar (gensym)))
    `(let ((,tempvar ,e))
       (progn (setq ,v1 ,tempvar)
              (setq ,v2 ,tempvar)))))
</code></pre>

<p>Now <code>(setq2 x y (+ x 2))</code> expands to</p>

<pre><code class="language-lisp">(let ((#:g2003 (+ x 2)))
  (progn (setq x #:g2003) (setq y #:g2003)))
</code></pre>

<p>Here <code>gensym</code> has returned the symbol <code>#:g2003</code>, which prints in this funny way because it won&rsquo;t be recognized by the reader. (Nor is there any need for the reader to recognize it, since it exists only long enough for the code that contains it to be compiled.)</p>

<p>Exercise: Verify that this new version works correctly for the case <code>(setq2 x y (pop l1))</code>.</p>

<p>Exercise: Try writing the new version of the macro without using backquote. If you can&rsquo;t do it, you have done the exercise correctly, and learned what backquote is for!</p>

<p>The moral of this section is to think carefully about which expressions in a macro get evaluated and when. Be on the lookout for situations where the same expression gets plugged into the output twice (as <code>e</code> was in my original macro design). For complex macros, watch out for cases where the order that expressions are evaluated differs from the order in which they are written. This is sure to trip up some user of the macro - even if you are the only user.<a name="LtohTOCentry-4"></a></p>

<h1 id="what-macros-are-for">What Macros are For</h1>

<p>[…]</p>

<h1 id="see-also">See also</h1>

<p><a href="https://medium.com/@MartinCracauer/a-gentle-introduction-to-compile-time-computing-part-1-d4d96099cea0">A gentle introduction to Compile-Time Computing — Part 1</a></p>

<p><a href="https://medium.com/@MartinCracauer/a-gentle-introduction-to-compile-time-computing-part-3-scientific-units-8e41d8a727ca">Safely dealing with scientific units of variables at compile time (a gentle introduction to Compile-Time Computing — part 3)</a></p>

<p>The following video, from the series
<a href="https://www.youtube.com/user/CBaggers/playlists">&ldquo;Little bits of Lisp&rdquo;</a>
by <a href="https://github.com/cbaggers/">cbaggers</a>, is a two hours long talk
on macros, showing simple to advanced concepts such as compiler
macros:
<a href="https://www.youtube.com/watch?v=ygKXeLKhiTI">https://www.youtube.com/watch?v=ygKXeLKhiTI</a>
It also shows how to manipulate macros (and their expansion) in Emacs.</p>

<p><a href="https://www.youtube.com/watch?v=ygKXeLKhiTI"><img src="http://img.youtube.com/vi/ygKXeLKhiTI/0.jpg" alt="video" /></a></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Yes Google Uses and Hacks on Common Lisp</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">02 03 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><a href="https://en.wikipedia.org/wiki/ITA_Software">ITA Software</a>, owned by
Google, the airfare search and pricing system that is still used by
companies such as Kayak.com or Orbitz, is a well-known example of a
successful industrial and large Common Lisp software.</p>

<p>We&rsquo;re legitimate to wonder if they still run it (they do), if Google
develops more CL software (I don&rsquo;t know), or if they put resources to
improve a CL implementation: they do.</p>

<p>According to <a href="https://mstmetent.blogspot.com/2020/01/sbcl20-in-vienna-last-month-i-attended.html:">https://mstmetent.blogspot.com/2020/01/sbcl20-in-vienna-last-month-i-attended.html:</a></p>

<blockquote>
<p>Doug Katzman talked about his work at Google getting SBCL to work with Unix better. For those of you who don&rsquo;t know, he&rsquo;s done a lot of work on SBCL over the past couple of years, not only adding a lot of new features to the GC and making it play better with applications which have alien parts to them, but also has done a tremendous amount of cleanup on the internals and has helped SBCL become even more Sanely Bootstrappable. That&rsquo;s a topic for another time, and I hope Doug or Christophe will have the time to write up about the recent improvements to the process, since it really is quite interesting.</p>

<p>Anyway, what Doug talked about was his work on making SBCL more amenable to external debugging tools, such as gdb and external profilers. It seems like they interface with aliens a lot from Lisp at Google, so it&rsquo;s nice to have backtraces from alien tools understand Lisp. It turns out a lot of prerequisite work was needed to make SBCL play nice like this, including implementing a non-moving GC runtime, so that Lisp objects and especially Lisp code (which are normally dynamic space objects and move around just like everything else) can&rsquo;t evade the aliens and will always have known locations.</p>
</blockquote>

<p>So now that&rsquo;s in the wild, Common Lisp can go trendy again: Google uses and dedicates resources for Common Lisp!</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2020/02/episodio-accesibilidad.jpg" alt="Accesibilidad y web inclusiva con Javier Hernández y Vicent Sanchis">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Accesibilidad y web inclusiva con Javier Hernández y Vicent Sanchis</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">29 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Nos acompañan para este episodio Javier Hernández y Vicent Sanchis, dos profesionales del mundo web y especialistas en accesibilidad y web inclusiva. Aunque sobre el papel muchos profesionales simpatizan, son pocos los que le prestan una atención especial y tiempo. En su origen uno de los objetivos de la web era conseguir un acceso universal a la información por cualquier persona, sin que sus dificultades físicas o cognitivas se lo impidan. No obstante, por desconocimiento o falta de empatía, la accesibilidad pasa por ser un asunto menor, al que ni siquiera muchos proyectos dedican atención.</p>
<p><img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2020/02/episodio-accesibilidad.jpg" alt="Episodio de accesibilidad web en Idecrea" width="1284" height="933" class="img-responsive aligncenter size-full wp-image-2292" srcset="https://republicaweb.es/wp-content/uploads/2020/02/episodio-accesibilidad.jpg 1284w, https://republicaweb.es/wp-content/uploads/2020/02/episodio-accesibilidad-300x218.jpg 300w, https://republicaweb.es/wp-content/uploads/2020/02/episodio-accesibilidad-1024x744.jpg 1024w, https://republicaweb.es/wp-content/uploads/2020/02/episodio-accesibilidad-768x558.jpg 768w" sizes="(max-width: 1284px) 100vw, 1284px" /></p>
<h2>La experiencia de Javier Hernández en Estudio Inclusivo</h2>
<p>Javier es socio fundador de <a href="https://estudioinclusivo.com/">Estudio Inclusivo, </a>un singular estudio de diseño web especializado en accesibilidad web. Su equipo cuenta con personas con diversas discapacidades y ha desarrollado multitud de proyectos web, con la accesibilidad como objetivo fundamental. El equipo de Estudio Inclusivo también ha desarrollado un plugin para WordPress que ayuda a implantar soluciones de accesibilidad en los sitios web. En esta entrevista Javier nos habla de su experiencia, de la actualidad del mundo de la accesibilidad y su visión acerca de cómo llevarla a cabo.</p>
<h2>Vicent Sanchis, un especialista en visión y desarrollo accesible</h2>
<p><a href="https://vicentsanchis.com">Vicent Sanchis</a> es especialista en visión y Doctorado en Ciencias de la Visión. Además combina su actividad profesional como desarrollador web y técnico en accesibilidad. Vicent es un ponente habitual en los meetups de WordPress, donde suele ofrecer información de interés sobre accesibilidad. Vicent nos cuenta unos detalles de gran interés y que nos ayudan a entender mejor las necesidades de las personas con dificultades de acceso a los contenidos. </p>
<p>Entre las cuestiones que discutimos con ellos:</p>
<ul>
<li>¿Qué porcentaje de usuarios de internet se calcula que pueden tener necesidades especiales de accesibilidad y qué tipo de dificultades existen para acceder a la información? ¿Qué tipos de minusvalías afectan a la navegación?</li>
<li>¿Cuál es la mejor forma de afrontar un proyecto web accesible?.</li>
<li>¿Cómo está actualmente la legislación en materia de accesibilidad web y qué se le puede exigir al propietario de un sitio web?.</li>
<li>¿Qué buenas prácticas le recomendarías a un desarrollador web para tener un sitio web mínimamente accesible?</li>
</ul>
<p>Agradecimiento a nuestra amiga<a href="https://www.igakurowska.com/home"> Iga Kurowska</a> por grabarnos la intro del episodio y darle un toque más femenino a este programa.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ondahostil.files.wordpress.com/2018/08/yo.jpg?w=32" alt="En que ando: febrero">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">En que ando: febrero</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Onda Hostil</a> <span class="article__date">29 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Febrero es un mes corto pero se me ha hecho muy largo. ¿Tendrá que ver esto con que haya dedicado casi todo el mes a la papelada para acreditarme como profesora (ayudante) de universidad? Nah, seguro que no. ¡Aunque este proceso me hizo aprender cosas! Ahora sé manipular pdfs desde la terminal. Me faltan trámites [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure Homebrew Tap</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">28 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>For Mac or Linux users using Homebrew, Clojure now has its own <a href="https://github.com/clojure/homebrew-tools">Homebrew tap</a>, <code>clojure/tools</code>. Creating an official Clojure tap has the following advantages:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Clojure team controls formula contents</p>
</li>
<li>
<p>Clojure team controls release timing</p>
</li>
<li>
<p>Freedom to keep an archive of older versioned releases that would be too much for the core tap</p>
</li>
<li>
<p>Easier to automate releases</p>
</li>
</ol>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_dependencies"><a class="anchor" href="#_dependencies"></a>Dependencies</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Clojure requires Java. Clojure officially supports Java LTS releases (currently Java 8 and Java 11), but also tries to ensure interim versions work as well. You can use any Java installation, whether it&#8217;s a commercial release from Oracle or an open source version based on OpenJDK (like adoptopenjdk).</p>
</div>
<div class="paragraph">
<p>The Clojure tools require that either the <code>java</code> command is on the path or that the <code>JAVA_HOME</code> environment variable is set.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_how_do_i_use_it"><a class="anchor" href="#_how_do_i_use_it"></a>How do I use it?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Using an external homebrew tap just requires combining the tap location and the formula name:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="shell">brew install clojure/tools/clojure</code></pre>
</div>
</div>
<div class="paragraph">
<p>for a new install or:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="shell">brew upgrade clojure/tools/clojure</code></pre>
</div>
</div>
<div class="paragraph">
<p>to upgrade your current install. For more detailed information, see the <a href="https://github.com/clojure/homebrew-tools/blob/master/README.md">docs at the tap</a>. Other pages on the Clojure site have been updated appropriately.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_development_stable_and_archived_releases"><a class="anchor" href="#_development_stable_and_archived_releases"></a>Development, stable, and archived releases</h2>
<div class="sectionbody">
<div class="paragraph">
<p>As those docs describe, there are now three flavors of release available:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Stable releases (obtained with the commands above) - this is what most people should use and we expect to update these on the frequency of every 1-3 months.</p>
</li>
<li>
<p>Development releases (using the --devel flag) - the latest bits, probably best for tools developers and those evaluating new bug fixes or functionality. New development releases may come out as frequently as multiple times per week during active periods.</p>
</li>
<li>
<p>Archived version releases - occasionally, it may be useful to install a specific older release, and there will now be an archive of these release formulas available. See the tap docs for how to use.</p>
</li>
</ol>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_what_about_the_core_tap"><a class="anchor" href="#_what_about_the_core_tap"></a>What about the core tap?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The Homebrew core tap still has a clojure formula for the Clojure tools. You should now consider that unofficial and likely to lag behind the Clojure tap, which should be preferred. Anyone can update it, or we may periodically bump it for big releases, but we will not be actively updating it as of now.</p>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/167-planned-vs-bugeted.png" alt="Planned vs Budgeted">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Planned vs Budgeted</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">25 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/167-planned-vs-bugeted.png" alt="Planned vs Budgeted" title="At least it works - kinda" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Persisting React State in localStorage</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">24 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A common thing in React development is that we want to store a bit of React state in localStorage, and re-initialize from that value on the next page-load. This quick tutorial shows you how we can build a custom hook that does exactly this!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ondahostil.files.wordpress.com/2018/08/yo.jpg?w=32" alt="Lo que he aprendido: pdfjam y la ANECA">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Lo que he aprendido: pdfjam y la ANECA</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Onda Hostil</a> <span class="article__date">24 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Estoy en plena diversión de la ANECA. Llevo dos semanas pidiendo certificados para justificar todas las actividades que he llevado a cabo en la universidad y añadiéndolas una a una a un formulario. Luego diremos que si endogamia en la academia y cosas, pero ¿qué esperamos si la manera de acreditarse como profesora pasa por [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2020/02/nestor-angulo-andros-republicaweb.jpg" alt="Seguridad en WordPress con Néstor Angulo de Ugarte">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Seguridad en WordPress con Néstor Angulo de Ugarte</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">22 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Seguimos con la racha de invitados en el podcast y esta semana contamos con <a href="https://about.me/pharar">Néstor Angulo de Ugarte</a>, especialista en <a href="https://sucuri.net/" rel="noopener noreferrer" target="_blank">seguridad web de la empresa Sucuri,</a> integrada ahora en la compañía GoDaddy.  Néstor trabaja en remoto para Sucuri investigando casos de hackeo en entornos web y dando respuesta a los problemas de seguridad de los clientes.</p>
<p><img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2020/02/nestor-angulo-andros-republicaweb.jpg" alt="Nestor Angulo y Andros Fenollosa episodio República Web Podcast" width="1280" height="960" class="img-responsive aligncenter size-full wp-image-2287" srcset="https://republicaweb.es/wp-content/uploads/2020/02/nestor-angulo-andros-republicaweb.jpg 1280w, https://republicaweb.es/wp-content/uploads/2020/02/nestor-angulo-andros-republicaweb-300x225.jpg 300w, https://republicaweb.es/wp-content/uploads/2020/02/nestor-angulo-andros-republicaweb-1024x768.jpg 1024w, https://republicaweb.es/wp-content/uploads/2020/02/nestor-angulo-andros-republicaweb-768x576.jpg 768w" sizes="(max-width: 1280px) 100vw, 1280px" /></p>
<p>Como nuestro último invitado, Guillermo, Néstor también estuvo en la WordCamp con Andros como ponente <a href="https://wordpress.tv/2020/01/21/nestor-angulo-de-ugarte-hacking-wordpress/" rel="noopener noreferrer" target="_blank">donde ofreció una charla sobre seguridad en WordPress. </a>Con Néstor queremos hablar precisamente de esto de seguridad WordPress, o más específicamente de la forma en la que se puede comprometer una instalación de WordPress y las cuestiones a tener en cuenta para ofrecer más seguridad. Además tenemos la suerte de haber contado con él para grabar en las instalaciones de Idecrea y eso ha hecho si cabe más amena la entrevista.</p>
<p>Entre las cuestiones que hablamos con Néstor:</p>
<ul>
<li>Motivaciones más habituales de un atacante a un sitio web con WordPress.</li>
<li>Los ataques más comunes en sitios web con WordPress.</li>
<li>Medidas básicas para proteger nuestro WordPress.</li>
<li>Limpiar correctamente un WordPress infectado.</li>
<li>Soporte y mantenimiento de sitios web.</li>
<li>Fuentes y medios de información para estar al día.</li>
<li>Certificados y auditorias de seguridad para plugins y temas.</li>
</ul>
<h2>Descuentos para licencias de JetBrains.</h2>
<p>David Vaquero ofrece una clave para aprovecharse del 20% de descuento en licencias de productos de JetBrains. Es válido hasta 10 licencias de uso, con lo que los primeros que compren, son las que se lo llevan.</p>
<p>Código: MGLGX-9Y9J9-LX3XZ-YCQU6-UTYED</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Cómo cohabitan la vida salvaje y el ser humano en el lugar más frío de Grecia">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cómo cohabitan la vida salvaje y el ser humano en el lugar más frío de Grecia</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">21 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        La Comisión Europea financia con más de 5,7 millones de euros un plan para proteger la fauna silvestre
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="“Bueno, ya no piso ningún bicho”">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">“Bueno, ya no piso ningún bicho”</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">21 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Un experimento con abejorros plantea la cuestión de la consciencia de los insectos
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Setting up Syncthing to synchronise files between computers</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">21 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I&rsquo;ve just set up Syncthing on my home computers. It&rsquo;s a program which keeps directories on different computers synchronised. It&rsquo;s like Dropbox, but your data isn&rsquo;t shared with any third parties.
What&rsquo;s it for? I&rsquo;m currently using it to synchronise documents from my laptop to my home server, which gives a bit of redundancy if my laptop breaks or gets lost. We should note that Syncthing isn&rsquo;t suitable as a proper backup application, because changes (including deletions) are propagated to all machines.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/images/content/news/2020-02-20/use.png" alt="State of Clojure 2020 Results">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">State of Clojure 2020 Results</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">20 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Ten years ago, Chas Emerick ran the first State of Clojure survey. In 2010, most users had been using Clojure for just weeks or months, and few were using it as a language for serious work. <a href="https://www.surveymonkey.com/results/SM-CDBF7CYT7/">This year</a>, we see consistent and growing use for <a href="#work">work</a>, steady interest in the key <a href="#values">value</a> propositions of Clojure, and an ever-evolving <a href="#community">community</a> of users.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="work"><a class="anchor" href="#work"></a>Clojure at Work</h2>
<div class="sectionbody">
<div class="paragraph">
<p>One of the questions we have been asking since 2010 is whether respondents are using Clojure for work, hobby projects, tinkering, or studies. This year, we saw the highest percentage yet of Clojure use at work:</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="/images/content/news/2020-02-20/use.png" alt="Clojure uses">
</div>
</div>
<div class="paragraph">
<p>Additionally, we saw a small shift in company size to bigger companies - an increase of 3% in companies of size 1000+ (and reduction in companies size 1-10).</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="/images/content/news/2020-02-20/org-size.png" alt="Clojure organization size">
</div>
</div>
<div class="paragraph">
<p>We also asked respondents for the first time how many people were using Clojure at their organization. As expected, many Clojure teams are small. As a high-leverage tool, Clojure is a great fit for small highly-productive teams. However, it was also great to see many respondents at companies with 40 or even 100+ Clojure developers.</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="/images/content/news/2020-02-20/at-org.png" alt="Clojure devs at organization">
</div>
</div>
<div class="paragraph">
<p>A question we&#8217;ve been asking since 2010 (with some variation in wording and choices), is in what domains Clojure is being used. The top results have not changed too much over the years but we did see a noticeable increase this year in "enterprise applications", to its highest level ever.</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="/images/content/news/2020-02-20/domains.png" alt="Clojure domains">
</div>
</div>
<div class="paragraph">
<p>Feedback comments indicate Clojure is a tool yielding high leverage for both companies and teams:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>"Clojure continues to be a force multiplier and a vital enabler for our production system."</p>
</li>
<li>
<p>"Clojure enables our small team to do more with less."</p>
</li>
<li>
<p>"Clojure is by far the best language I have to use at work, and it is a pleasure to solve problems using it. It is almost perfect."</p>
</li>
<li>
<p>"Clojure is powering our data driven insurance ERP. I cannot think of a better approach. Many thanks!"</p>
</li>
<li>
<p>"Hard to find too many complaints about Clojure: it&#8217;s a wonderful language with a great community. I plan to stay with this language + community for a long time. We have basically bet the company&#8217;s technical strategy on it."</p>
</li>
<li>
<p>"I love using Clojure and ClojureScript and have moved all our development projects using various different languages (PHP, Python, C#, Javascript) to only using Clojure and ClojureScript"</p>
</li>
<li>
<p>"Our startup is built solely on Clojure and Clojurescript and we are very happy with it."</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Clojure&#8217;s use continues to grow at hundreds of <a href="xref/../../../../../community/companies">companies</a>, with an ever higher percentage of developers using it at work for their core business.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="values"><a class="anchor" href="#values"></a>Values</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Since 2015, we have asked a question about which aspects of Clojure users valued the most. The weighted ranking of those answers has remained virtually identical since 2015. The most important things to Clojure users are: functional programming, the REPL, immutable data, ease of development, and host interop. Indeed these are all things intrinsic to the Clojure experience and align strongly with the reasons Clojure exists.</p>
</div>
<div class="paragraph">
<p>The open feedback comments often praised the steady arc of Clojure’s development and tradition for growing without breaking:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>"Clojure is an awesome lisp, lovingly created with taste and refinement.  It is a pleasure to think and implement in the abstractions provided."</p>
</li>
<li>
<p>"Great work, team! This is the most stable technology I&#8217;ve used in my many years doing software development."</p>
</li>
<li>
<p>"I love what you are doing with the language and community. In the world of churn and constantly pumping changes just to create 'buzz' clojure is like a safe zone where my sanity is kept alive."</p>
</li>
<li>
<p>"I really like the simplicity of Clojure and the functional nature of it. I also like the fact that the team doesn&#8217;t slap on a ton of features like every other language out there."</p>
</li>
<li>
<p>"Thanks for sticking to the principles: lean, conservative, essential, no frills, production grade software that brought back Lisp to the mainstream."</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="community"><a class="anchor" href="#community"></a>Community</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Again this year we surveyed the most popular forums where Clojurists interact with each other. Some new and/or rising entries included in-person Clojure conferences (we saw many new ones this year!), the new <a href="https://ask.clojure.org">Ask Clojure</a> site, Telegram chats, and Discord.</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="/images/content/news/2020-02-20/forums.png" alt="Clojure forums">
</div>
</div>
<div class="paragraph">
<p>We also collect information on how users are involved in the Clojure ecosystem. The response this year were very similar to last year but we did see mild upticks in helping new Clojure users, advocating for Clojure in their organization, and maintaining open source libraries, all great contributions!</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="/images/content/news/2020-02-20/ecosystem.png" alt="Clojure involvement">
</div>
</div>
<div class="paragraph">
<p>In feedback comments, many people enjoyed the kind and responsive Clojure community:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>"The Clojure community is absolutely fantastic. Being able to post a question and get thoughtful &amp; insightful answers quickly is immensely valuable. Thank you for fostering such an incredible community."</p>
</li>
<li>
<p>"Clojure (Script) is a great, well-thought out language that has helped me tremendously in my work. However, it also exposed me to a wonderful community of thoughtful developers who have given me wonderful new insights, while remaining a friendly and welcoming community"</p>
</li>
<li>
<p>"Wonderful language and a uniquely insightful community. It has helped me rediscover my love for programming."</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_deep_dives"><a class="anchor" href="#_deep_dives"></a>Deep Dives</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Clojure developers will be particularly interested in the version and tooling related questions in the survey.</p>
</div>
<div class="paragraph">
<p>One new question we asked this year was about the primary developer operating system to give us better guidance about tool-related work. As expected, MacOS was the leader (55%), followed by Linux (35%) and Windows (9%):</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="/images/content/news/2020-02-20/os.png" alt="Clojure developer operating system">
</div>
</div>
<div class="paragraph">
<p>For primary development tool, there were only minor updates this year. Emacs dropped slightly to 43%, IntelliJ/Cursive rose slightly to 32%, and VS Code with Calva had the biggest increase to 10%.</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="/images/content/news/2020-02-20/tool.png" alt="Clojure development environment">
</div>
</div>
<div class="paragraph">
<p>Clojure users have a wealth of fine development environments, each suited to different communities and tastes, and we’re glad to see them all getting better day by day.</p>
</div>
<div class="paragraph">
<p>For many years, the survey has included a question about "build tools", but this idea of a single monolithic tool has become increasingly less reflective of how people are managing Clojure projects, where they may use multiple tools for different parts of their process, particularly in mixed Clojure/ClojureScript projects. In response to this, we tailored this question more tightly to dependency management and made it multi-select this year:</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="/images/content/news/2020-02-20/deps.png" alt="Clojure dependency management">
</div>
</div>
<div class="paragraph">
<p>Looking at previous years, we continue to see strong (but slightly reduced) use of Leiningen, and a steady increase in use of clj/deps.edn. For ClojureScript work, shadow-cljs has made big strides over the last couple years, with big support from Clojurists Together.</p>
</div>
<div class="paragraph">
<p>In the greater world of Java and the JVM, Java has migrated to a new release strategy where releases come out every spring and fall, and every 3 years there is a "long term support" (LTS) release - 8, 11, and (presumably) 17. Java 9 introduced a major change with the module system and in all JVM communities this has caused a significant user base to remain on Java 8. Clojure reflects this as well (although probably shows more shift to Java 11 than other language communities):</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="/images/content/news/2020-02-20/java.png" alt="Java versions">
</div>
</div>
<div class="paragraph">
<p>Releases like Java 9, 10, 12, and soon 13 are effectively dead when the next release comes out and we would recommend sticking primarily to the LTS releases and maybe the latest release, if it’s not an LTS release.</p>
</div>
<div class="paragraph">
<p>One aspect of Java 11 that is underappreciated is significant work to make Java work better in containers like Docker. If you are deploying in containerized environments with Java 8, you should really be looking closely at the changes in Java 11 and considering an upgrade.</p>
</div>
<div class="paragraph">
<p>Clojure itself has been using Java 8 as the baseline JVM for a couple years and will continue to do so (while also supporting newer versions of Java). When running Clojure, we recommend Java 8 or 11 right now.</p>
</div>
<div class="paragraph">
<p>Since last year, we’ve seen strong uptake of Clojure 1.10.0 and 1.10.1. The latter was a maintenance release this year with error handling improvements building on the changes in Clojure 1.10.0 and mitigations for some Java performance regressions in their service releases after Java 8u201. Use of Clojure 1.8 and earlier continues to dwindle:</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="/images/content/news/2020-02-20/clojure.png" alt="Clojure versions">
</div>
</div>
<div class="paragraph">
<p>In addition to the prior dependency management question, we also added a new question on how respondents are starting their apps in production. Based on feedback, it’s likely the wording and answer choices will need some fine-tuning next year, but there is some interesting feedback in the results:</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="/images/content/news/2020-02-20/run-app.png" alt="Running production apps">
</div>
</div>
<div class="paragraph">
<p>The majority of users are using launchers like Leiningen or clj to start their production apps, more so than by building jars or uberjars and launching them directly with Java. We do see a small group also experimenting with Graal native images (particularly common with smaller scripting apps).</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_full_results"><a class="anchor" href="#_full_results"></a>Full Results</h2>
<div class="sectionbody">
<div class="paragraph">
<p>If you’d like to dig into the full results, you can find the complete set of data from this and former years here:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://www.surveymonkey.com/results/SM-CDBF7CYT7/">2020</a></p>
</li>
<li>
<p><a href="https://www.surveymonkey.com/results/SM-S9JVNXNQV/">2019</a></p>
</li>
<li>
<p><a href="https://www.surveymonkey.com/results/SM-9BC5FNJ68/">2018</a></p>
</li>
<li>
<p><a href="https://www.surveymonkey.com/results/SM-7K6NXJY3/">2016</a></p>
</li>
<li>
<p><a href="http://blog.cognitect.com/blog/2016/1/28/state-of-clojure-2015-survey-results">2015</a></p>
</li>
<li>
<p><a href="http://blog.cognitect.com/blog/2014/10/20/results-of-2014-state-of-clojure-and-clojurescript-survey">2014</a></p>
</li>
<li>
<p><a href="http://cemerick.com/2013/11/18/results-of-the-2013-state-of-clojure-clojurescript-survey/">2013</a></p>
</li>
<li>
<p><a href="http://cemerick.com/2012/08/06/results-of-the-2012-state-of-clojure-survey/">2012</a></p>
</li>
<li>
<p><a href="http://cemerick.com/2011/07/11/results-of-the-2011-state-of-clojure-survey/">2011</a></p>
</li>
<li>
<p><a href="http://cemerick.com/2010/06/07/results-from-the-state-of-clojure-summer-2010-survey/">2010</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Thanks again for using Clojure and ClojureScript and participating in the survey!</p>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/166-presale.png" alt="Presale">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Presale</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">18 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/166-presale.png" alt="Presale" title="It might require a few minor adjustments" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Home server and Pi-hole</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">17 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I recently bought a small (10 by 10cm), cheap (~£100) computer to use as a home server. It&rsquo;s got 4GB of RAM and 60GB of disk, so not very powerful, but not terrible either. I got it to get some experience with classical system administration. At work everything is containerised and runs in Kubernetes, so I don&rsquo;t actually have much experience managing linux servers the traditional way.
Operating system I installed Ubuntu Server 18.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to write things people actually want to read</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">17 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Staring at a blank screen can be scary. And writing is hard work. Don’t let anyone tell you different. It takes extended periods of concentration to write anything significant. And that's a rare commodity these days. And even if you manage to beat your attention into submission, the craft of writing is still complex. It can be tough to know where to start. What if my writing turns out to be boring? What if nobody reads it? What if people hate it? Or worse, they start reading and get so bored they quit?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Analytics server</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">16 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        This website runs as a static site hosted on GitHub pages. I don&rsquo;t currently have any way of telling how many people are reading it, or what pages they&rsquo;re reading etc.
The simple way to get this data would be to add Google Analytics to the website. However, I think it&rsquo;s an interesting exercise to work out how to implement something similar ourselves. This would let us specify the amount of information we&rsquo;d like to log about each visitor and we&rsquo;d also have control of the data ourselves, rather than shipping it to a third party.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="PWA y aplicaciones móviles con Guillermo Tamborero">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">PWA y aplicaciones móviles con Guillermo Tamborero</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">15 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Para este episodio contamos con la compañía de Guillermo Tamborero, desarrollador y socio fundador de la <a href="https://www.iproject.cat/" rel="noopener noreferrer" target="_blank">empresa iproject.cat,</a> especialistas en desarrollo proyectos web a medida, Progressive Web Apps y soluciones basadas en PHP, WordPress, Laravel y VueJS. Con Guillermo hablamos de las Aplicaciones Web Progresivas (PWA), en qué consisten y cómo encajan en el ecosistema de desarrollo web. Hablamos de las ventajas que ofrecen, cómo empezar tu propia PWA y también los inconvenientes que puedes tener en su desarrollo.</p>
<p>En el episodio hablamos <strong>sobre el escaso interés de Apple</strong> en desarrollar junto con Google, soluciones estándar para PWA. Y es que Apple a pesar de ser una de las primeras compañías en apoyar la tecnología, ha decidido desmarcarse ofreciéndole un soporte limitado. Trabajar con una Aplicación Web Progresiva <strong>ofrece una experiencia muy similar a realizarlo con una aplicación nativa,</strong> pero con la ventaja de estar en un entorno idéntico al del navegador web. Como explica Guillermo, empezar a realizar tu propia PWA es tan fácil como instalar un plugin de WordPress. Otra característica de las PWA es que es posible instalarlas en casi cualquier dispositivo que admita un navegador web (en especial los basados en Chromium).</p>
<p>Por último hablamos de <strong>las diferentes opciones</strong> que tenemos para desarrollar una aplicación móvil, con soluciones que van desde las opciones nativas para Android y iOS, a soluciones híbridas (Cordova, Ionic​… Capacitor) o «pseudo nativas» como Xamarin, React Native, Flutter o NativeScript.</p>
<p>Andros tuvo la oportunidad de coincidir con Guillermo en la pasada WordCamp de Zaragoza donde ofreció una charla <a href="https://2020.zaragoza.wordcamp.org/session/introduccion-a-blocklab-crea-bloques-del-nuevo-editor-de-wordpress-facilmente/" rel="noopener noreferrer" target="_blank">sobre la edición con bloques en WordPress usando BlockLab.</a></p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Mobile viewports</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">15 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Yesterday, I wrote about how this website looks small on Firefox on mobile. It turns out, this is a viewport issue, which is fixed by adding the following line to each page&rsquo;s &lt;head&gt;:
&lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1&#34; /&gt; What&rsquo;s going on? A browser&rsquo;s viewport is the area of the page which can currently be seen.
When smartphones were first introduced, most web pages weren&rsquo;t optimised for mobile and would have looked broken when viewed from mobile devices, because mobiles have much smaller viewports than desktop browsers.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">This website has small text on Firefox for mobile</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">14 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        This website is currently rendered with very small text in Firefox on mobile. Here&rsquo;s a screenshot of what it looks like on a Pixel 2:
While debugging this, I tried removing all CSS from my website. It turns out that the issue isn&rsquo;t to do with anything I&rsquo;ve written (I think), but the way Firefox displays unstyled HTML on mobile:
I&rsquo;m a bit surprised by this - I would have assumed that rendering unstyled HTML would be legible in any browser.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Kairos, patrocinador Gold de FrontFest 2020</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FrontFest</a> <span class="article__date">14 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ¿TE VIENES CON NOSOTROS? ¡#IT’S YOUR TIME!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How do .epubs work?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">13 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        There are a couple of different file formats that e-books are distributed in. The one I most commonly see is the EPUB format, which has the .epub file extension. Let&rsquo;s take a look at the internals of this file this format.
An example EPUB In this article, we&rsquo;ll be looking at a copy of Moby Dick, published by the website Planet Ebook. You can download the EPUB from this page. N.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Introducción al testing web por David Vaquero">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Introducción al testing web por David Vaquero</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">12 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>El audio de este episodio está extraído de una clase que realizó David Vaquero en un curso sobre Python. En la clase se ofrece una introducción a la teoría del testing y herramientas que se utilizan para probar el código de un sitio web. Es un contenido que te ayudará a entender en qué consiste el testing y cómo encaja en el desarrollo web.</p>
<p>Puedes ver la charla en el<a href="https://www.youtube.com/channel/UChE59MSKV-eEFyS-0_wqrFg" rel="noopener noreferrer" target="_blank"> canal de YouTube de Cursos de Desarrollo</a> y acceder a más contenido incluyendo cursos gratuitos, en la página web de David Vaquero <a href="https://cursosdedesarrollo.com/">https://cursosdedesarrollo.com/</a></p>
<p></p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A gratitude journal design</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">12 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I&rsquo;ve been thinking about how I&rsquo;d design a gratitude journal product. A gratitude journal lets you keep a record of things you&rsquo;re grateful for. Proponents say gratitude journaling offers a number of mental health benefits.
Why build a product?  Habit building. One of the common issues with starting a gratitude journal is developing the habit of writing consistently. Products can help develop habits by reminding users to write. There&rsquo;s a dark side to habit building products, so we&rsquo;d want to stay away from being too intrusive.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">January 2020 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">11 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Read updates from Expound, Oz, and Deep Diamond
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Building an IVR System with Python, Django and Twilio</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">11 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Last year my team and I worked on a very challenging IVR system. After almost a year in production and thousands of processed transactions, I teamed up with the great people over at the Twilio blog to write an introductory tutorial for developing IVR systems using Django and Twilio IVR.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Paradigma Digital, tecnología con un propósito para un mundo mejor</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FrontFest</a> <span class="article__date">11 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        En Paradigma somos conscientes de que en el mundo digital la tecnología es la fuerza más transformadora que existe. Combinamos tecnología, talento y metodología para reinventar el futuro digital de las grandes compañías, y para conseguirlo es imprescindible estar siempre a la vanguardia, tanto tecnológica como metodológica y de negocio.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/165-minor-change.png" alt="Minor Change">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Minor Change</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">11 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/165-minor-change.png" alt="Minor Change" title="git commit -m 'Hey, don't worry about it'." /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Understand Group by in Django with SQL</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">10 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Understand GROUP BY in Django ORM by comparing QuerySets and SQL side by side. If SQL is where you are most comfortable, this is the Django GROUP BY tutorial for you.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Geografía de la muerte">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Geografía de la muerte</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">09 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Las desigualdades regionales en salud pública deben marcar el norte para los políticos
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">mmv, a tool for batch renaming files</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">09 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A couple of months a go, I wrote a command-line tool called mmv, which lets you batch rename files. You can find its source code on GitHub.
mmv takes a single argument, a path to a directory. It opens a list of the files in that directory in the text editor of your choice. You can edit the file names and when you save and exit your editor, it&rsquo;ll rename the files.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2020/02/visita-slimbook-podcast-republicaweb.jpg" alt="Innovando en ordenadores personales con Alejandro López CEO de Slimbook">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Innovando en ordenadores personales con Alejandro López CEO de Slimbook</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">08 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Nos trasladamos a las instalaciones de la empresa valenciana Slimbook, fabricante de excelentes ordenadores personales especializados en GNU/Linux. Para ello nos recibe Alejandro López, CEO de <a href="https://slimbook.es" rel="noopener noreferrer" target="_blank">Slimbook</a> para explicarnos con detalle la filosofía de la empresa, basada en ofrecer productos de excelente calidad, combinados con un soporte cercano y profesional. A pesar de su juventud, Slimbook cuenta con un catálogo muy completo de productos, que incluyen portátiles ultrabooks, equipos de escritorio y compactos. Slimbook proporciona un cuidado montaje de los componentes y trabaja con marcas líderes como Intel y Samsung para la fabricación de sus equipos.</p>
<p><img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2020/02/visita-slimbook-podcast-republicaweb.jpg" alt="Visita a Slimbook " width="900" height="675" class="img-responsive aligncenter size-full wp-image-2277" srcset="https://republicaweb.es/wp-content/uploads/2020/02/visita-slimbook-podcast-republicaweb.jpg 900w, https://republicaweb.es/wp-content/uploads/2020/02/visita-slimbook-podcast-republicaweb-300x225.jpg 300w, https://republicaweb.es/wp-content/uploads/2020/02/visita-slimbook-podcast-republicaweb-768x576.jpg 768w" sizes="(max-width: 900px) 100vw, 900px" /></p>
<p>Con Alejandro hablamos también de la vocación de comunidad de la empresa y su Linux Center, una aula dedicada a fomentar el código abierto y el entorno GNU/Linux. Slimbook ofrece una combinación excelente de software y hardware, lo que garantiza que sus equipos tengan una experiencia de usuario muy elevada. Finalmente nos cuentan sus planes de futuro, las mejoras que tienen en mente y alguna colaboración que pactamos para el futuro. </p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Writing daily, one week in</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">08 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        This February, I&rsquo;m trying to write a blog post every day. I&rsquo;m now a week in - how are things going?
Positives:
 I&rsquo;m finding it easier coming up with things to write about. I&rsquo;ve started noting down interesting things I come across through my day as potential blog posts. I feel more comfortable writing shorter posts, which has opened up the range of topics I&rsquo;m happy to write about. I&rsquo;m having fun!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Breadcrumbs</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">07 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I just implemented breadcrumb navigation for this blog. How it works is quite neat - we iterate over the sections of the path, and store our current position using a Hugo Scratch variable:
&lt;nav&gt; &lt;ul&gt; &lt;!-- Initialise a scratch variable &#34;path&#34; to an empty string --&gt; {{ $.Scratch.Set &#34;path&#34; &#34;&#34; }} &lt;li&gt;&lt;a href=&#34;/&#34;&gt;Home&lt;/a&gt;&lt;/li&gt; &lt;!-- For each non-empty item in the URL path --&gt; {{ range $element := split .RelPermalink &#34;/&#34; }}{{ if ne $element &#34;&#34; }} &lt;!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Plain Concepts, patrocinador Platinum FrontFest 2020</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FrontFest</a> <span class="article__date">07 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Fundada en 2006 por 4 MVPS de Microsoft, Plain Concepts nace con el objetivo de desarrollar y facilitar a todo tipo de compañías la adopción de nuevas tecnologías destinadas a mejorar su productividad y procesos.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Blog UI updates</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">06 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I&rsquo;ve just updated by blog UI with a couple of things:
 Centered the header and date Added a footer to blog posts with a photo and bio. Sidenote - Firefox&rsquo;s flexbox developer tools look amazing:  Updated the body font to Nanum Myeongjo Reduced the code font size to 14px so the letter size matches the body font size  Here&rsquo;s what it looks like:
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Vim diff</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">05 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I was digging through Vim&rsquo;s documentation, and came across the help article diff.txt. It turns out that Vim implements a visual diff feature, which shows the &lsquo;difference between two to eight versions of the same file&rsquo;.
I occasionally need to find the differences between two files, and have historically used diff for this. Unfortunately, I find the output quite hard to parse:
$ diff file_1 file_2 32c32 &lt; TODO: screenshot of diff --- &gt; !
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2020/02/launchyoo-logo.jpg" alt="Lanzando Launchyoo una red social alternativa con Vicente Pechuán">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Lanzando Launchyoo una red social alternativa con Vicente Pechuán</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">05 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>El mundo de las redes sociales está dominado por grandes empresas tecnológicas, con audiencias  de millones de personas y presupuestos gigantes. Estas redes sociales están diseñadas para explotar la atención, los datos y el tiempo de los usuarios. En este escenario ha surgido hace poco una red social llamada <a href="https://launchyoo.com" rel="noopener noreferrer" target="_blank">Launchyoo</a> y que se presenta como una red social alternativa y pensada con el usuario en el centro.</p>
<p><img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2020/02/launchyoo-logo.jpg" alt="Launchyoo Logo" width="640" height="640" class="aligncenter img-responsive block mx-auto size-full wp-image-2275" srcset="https://republicaweb.es/wp-content/uploads/2020/02/launchyoo-logo.jpg 640w, https://republicaweb.es/wp-content/uploads/2020/02/launchyoo-logo-300x300.jpg 300w, https://republicaweb.es/wp-content/uploads/2020/02/launchyoo-logo-150x150.jpg 150w" sizes="(max-width: 640px) 100vw, 640px" /></p>
<p>Hablamos con<a href="https://www.linkedin.com/in/vicente-pechuan-vilar-65927437/" rel="noopener noreferrer" target="_blank"> Vicente Pechuán</a>, un valenciano que tras pasar por el mundo del motociclismo, decidió crear desde cero la red social que le gustaría. Vicente nos cuenta en esta entrevista los orígenes de Launchyoo, sus motivaciones y lo que le hace diferente a las redes sociales existentes. Con Vicente hablamos de la dificultad de lanzar un proyecto en un mercado tan maduro y también de cómo han orientado la aplicación de una forma integral, integrando originales funcionalidades y pensando en nuevas formas de organizar tu contenido.</p>
<blockquote>
<p>Launchyoo es otro ejemplo de empresa con base tecnológica que puede lanzar su producto gracias a las tecnologías en la nube, que facilitan el despliegue y la flexibilidad de recursos. También de una empresa distribuida en un equipo en remoto.</p></blockquote>
<p>Con Vicente también hablamos del futuro de Launchyoo y cómo afrontan los próximos meses. Launchyoo es una red social con un equipo distribuido y orientado al mercado hispanohablante, aunque también está disponible en varios idiomas. Dispone de un soporte para varios tipo de contenido, grupos, páginas de marcas y empresas y también permite diferenciar entre contactos.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="¿La actividad física puede regenerar neuronas?">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">¿La actividad física puede regenerar neuronas?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">05 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Con independencia de que se produzca o no neurogénesis, el ejercicio puede mejorar el cerebro
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ondahostil.files.wordpress.com/2018/08/yo.jpg?w=32" alt="Lo que he aprendido: la clase standalone">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Lo que he aprendido: la clase standalone</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Onda Hostil</a> <span class="article__date">04 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ¡He aprendido nuevas cosas LaTeXianas! El tema es que quería hacer un diagrama de flujo con unas ecuaciones y cosas y después de dedicarle quince minutos en el Draw me di cuenta de que estaba perdiendo el tiempo. ¡Cuánto mejor se hacen esas cosas en LaTeX! Encontré un bicho que me molaba en TeXample y [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Real vs percieved simplicity</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">04 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        There are certain command line tasks I need to do every few weeks or months, which is infrequently enough that I need to look up the syntax every time I do them. For example:
 Undoing a commit Getting ripgrep to return only the text which matches a regular expression, not the whole line Executing a command against all files in a directory  A solution To save time searching for how to do these things, I decided to create my own command line tool, cookbook, which would let me save examples (or &lsquo;recipes&rsquo;) for these tasks.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Cuando el enfermo paga la investigación de su dolencia">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cuando el enfermo paga la investigación de su dolencia</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">04 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Las asociaciones de pacientes de patologías raras subvencionan los estudios científicos, ofrecen apoyo y muestran su lucha a la sociedad y a los políticos
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">ING, patrocinador Gold en FrontFest 2020</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FrontFest</a> <span class="article__date">04 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ING, un banco con alma de startup en el que trabajamos más de mil profesionales. A través de metodologías Agile tenemos el objetivo de poner a disposición de nuestros clientes los mejores productos y servicios en el menor tiempo posible.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">CO2 emissions on the web</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Danny van Kooten</a> <span class="article__date">03 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I’ve spent the last month trying to reduce the carbon footprint of the websites I have (some) control over. When talking about this with other people they often look at me blankly before asking “aren’t you taking this a little too far?”.</p>

<p>The simple answer is no. In fact, it is probably the most effective use of my time when it comes to reducing carbon dioxide emissions.</p>

<p>Just last week I reduced global emissions by an estimated 59.000 kg CO<sub>2</sub> per month by removing a 20 kB JavaScript dependency in <a href="https://www.mc4wp.com/">Mailchimp for WordPress</a>. There’s no way I can have that kind of effect in other areas of my life.</p>

<h3 id="co2-emissions-from-distributed-code">CO2 emissions from distributed code</h3>

<p>All of <a href="https://dannyvankooten.com/wordpress-plugins/">my WordPress plugins</a> combined run on well over 2 million different websites, each website receiving who knows how many visitors.</p>

<p>At an average energy expenditure of <a href="#f1">0,5 kWh per GB <sup>1</sup></a> of data transfer this means that every kB equals <code class="language-plaintext highlighter-rouge">0,5 kWh / 1.000.000 kB * 2.000.000 websites = 1 kWh</code> if each of these websites received exactly 1 visitor.</p>

<p>Let’s assume the average website receives about 10.000 unique visitors per month and serves files from cache for returning visitors. The total amount of energy saved by shaving off a single kilobyte is then <code class="language-plaintext highlighter-rouge">1 kWh * 10.000 visitors = 10.000 kWh</code>.</p>

<p>10.000 kWh of energy produced by the <a href="https://www.eea.europa.eu/data-and-maps/indicators/overview-of-the-electricity-production-2/assessment-4">current European electricity grid</a> equals about <code class="language-plaintext highlighter-rouge">10.000 * 0,295 = 2950 kg of CO2</code>.</p>

<blockquote>
  <p><strong>Shaving off a single kilobyte in a file that is being loaded on 2 million websites reduces CO<sub>2</sub> emissions by an estimated 2950 kg per month.</strong></p>
</blockquote>

<p>To put this into perspective, that is the same amount of CO<sub>2</sub> saved each month as:</p>

<ul>
  <li>Driving my Toyota Yaris for 18.670 kilometers. (<a href="https://car-emissions.com/cars/index/toyota%20yaris%201.3%20vvt-i%20tr/">158 g CO<sub>2</sub> per km</a>)</li>
  <li>5 flights from Amsterdam to New York. (<a href="https://www.costtotravel.com/flight/from-new-york-to-amsterdam">679 kg CO<sub>2</sub> per flight</a>)</li>
  <li>Eating 118 kg of beef (<a href="https://eprints.lancs.ac.uk/79432/4/1_s2.0_S0959652616303584_main.pdf">25 kg CO<sub>2</sub> per kg of beef</a>)</li>
</ul>

<p>I already work from home, am a vegetarian and didn’t take any flights in the last 3 years so it seems I am stuck trying to make the web more efficient.</p>

<h3 id="what-can-we-do">What can we do?</h3>

<p>According to <a href="https://httparchive.org/reports/page-weight?start=earliest&amp;end=latest">httparchive.org</a>, the average website on desktop is about 4 times as large as in 2010. On mobile, where data transfer is way more expensive in terms of energy usage, the numbers look even worse: from 200 kB up to a whopping 1,9 MB!</p>

<p>As web developers we have a responsibility to stop this madness. Did websites really get 4 times as good? Is this <a href="https://motherfuckingwebsite.com/">motherfuckingwebsite.com</a> clocking in at 5 kB in total really that bad in comparison? I don’t think so.</p>

<p>Whenever you are adding to a website, ask yourself: is this necessary? If not, consider leaving it out.</p>

<p>Your content site probably <a href="https://github.com/you-dont-need/You-Dont-Need-Javascript">doesn’t need JavaScript</a>. You probably <a href="https://hacks.mozilla.org/2016/04/you-might-not-need-a-css-framework/">don’t need a CSS framework</a>. You probably don’t need a custom font. Use <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">responsive images</a>. Extend your <a href="https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching">HTTP cache</a> lifetimes. Use a <a href="https://www.staticgen.com/">static site generator</a> or <a href="https://wp2static.com/">wp2static.com</a> instead of dynamically generating each page on the fly, despite never changing. Consider ditching that third-party analytics service that you never look at anyway, especially if they also happen to sell ads. Run your website through <a href="https://www.websitecarbon.com/">websitecarbon.com</a>. Choose a <a href="https://www.thegreenwebfoundation.org/">green web host</a>.</p>

<p>I’m sorry if that turned into a bit of a rambling, but I hope you see where I am going with this.</p>

<p>Personally I constrained myself to not use more than 1 kB of CSS for the website you are reading this on. And I really liked making that work, it <a href="https://www.inc.com/thomas-oppong/for-a-more-creative-brain-embrace-constraints.html">sparked creativity</a>.</p>

<p>Let’s do our share as web developers and stop bloating the web.</p>

<hr />

<p><small>
 Energy costs of data transfer varies a lot depending on the type of network that is used. The range seems to be from 0,08 kWh per GB for fixed broadband connections to 37 kWh per GB for 2G networks.</small></p>

<p><small>I initially went with a global estimate of 2,9 kWh per GB in this post (the average cost per GB for 3G networks), but later changed it to 0,50 kWh per GB as I believe that is a better estimate for 2020 <sup><a href="#f2">2</a></sup>. It’s hard to come up with a good estimate that works globally, but I didn’t mean for this post to be about exact numbers anyway.</small></p>

<p><small>
The most important thing I attempted to convey is that the choices we make in developing for the web have consequences that really add up at scale.
</small></p>

<hr />

<p><small><strong>References</strong></small></p>

<p><small>
</small></p>

<p><small><sup id="f1">1</sup> Pihkola, H., Hongisto, M., Apilo, O., &amp; Lasanen, M. (2018). Evaluating the energy consumption of mobile data transfer-from technology development to consumer behaviour and life cycle thinking. <a href="https://doi.org/10.3390/su10072494">https://doi.org/10.3390/su10072494</a>
</small></p>

<p><small>
	<sup id="f2">2</sup>
	Aslan, Joshua &amp; Mayers, Kieren &amp; Koomey, Jonathan &amp; France, Chris. (2017). Electricity Intensity of Internet Data Transmission: Untangling the Estimates: Electricity Intensity of Data Transmission. Journal of Industrial Ecology. <a href="https://doi.org/10.1111/jiec.12630">https://doi.org/10.1111/jiec.12630</a> 
</small></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How I make coffee</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">03 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        This post covers how I currently make coffee at home. I&rsquo;ll update it if anything changes
Aeropress Equipment:
 Porlex hand grinder (I have the &lsquo;tall&rsquo; version) Aeropress Weighing scale Timer  Technique:
 Grind 15g coffee to a medium grind (7-8 &lsquo;clicks&rsquo; from closed on the Porlex) Insert the Aeropress plunger into the main body, to the &lsquo;4&rsquo; mark. Place the Aeropress upside down onto a weighing scale, so the end of the plunger is on the scale, and the open end of the main body is facing up Place the filter paper into the lid of the Aeropress, and wash it through with water, boil about 400g of water Add the coffee to the Aeropress, tare the scale, Add 200g of water just off the boil, start the timer, add the rest of the water to your cup to heat it up After about 20 seconds, a crust of coffee grounds will form at the top of the Aeropress.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Qué tiene que decir la ciencia sobre el Apocalipsis">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Qué tiene que decir la ciencia sobre el Apocalipsis</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">02 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Amenazas como la guerra nuclear o el cambio climático pueden provocar un sufrimiento extremo a la humanidad, pero es improbable que causen su extinción
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ondahostil.files.wordpress.com/2018/08/yo.jpg?w=32" alt="En qué ando: enero">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">En qué ando: enero</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Onda Hostil</a> <span class="article__date">02 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        No es ya enero, he estado haciendo tantas cosas que se me ha ido el mes. Estoy leyendo, aprendiendo y escribiendo, aunque no en el blog. En el ámbito del aprendizaje, estoy siguiendo un curso de esperanto y otro de metafísica. También he estado jugando con TikZ y con cron, espero escribir pronto sobre ambos [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Thoughts on a scheduling todo list</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">02 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Some issues with todo lists Todo lists store a number of tasks, but don&rsquo;t offer any advice on which order to tackle the tasks in. This system works well - it&rsquo;s simple, and people are generally pretty good at quickly working out what to work on next. However, I&rsquo;ve noticed a couple of issues with the system:
 When there are lots of tasks, working out the next task can be complicated.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Bulletin Board Systems: The VICE Exposé</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Two-Bit History</a> <span class="article__date">02 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        By now, you have almost certainly heard of the dark web. On sites unlisted by any search engine, in forums that cannot be accessed without special passwords or protocols, criminals and terrorists meet to discuss conspiracy theories and trade child pornography. We here at VICE headquarters have reported before on the dark web’s “hurtcore” communities, its human trafficking markets, its rent-a-hitman websites. We have explored the challenges the dark web presents to regulators, the rise of dark web revenge porn, and the frightening size of the dark web gun trade. We have kept you informed about that one dark web forum where you can make like Walter White and learn how to manufacture your own drugs, and also about—thanks to our foreign correspondent—the Chinese dark web. We have even attempted to catalog every single location on the dark web. Our coverage of the dark web has been nothing if not comprehensive. But I wanted to go deeper.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2020/02/juan-simon-garcia-republica-web-podcast.jpeg" alt="Gestionar meetups y desvirtualizar comunidades con Juan Simón García">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Gestionar meetups y desvirtualizar comunidades con Juan Simón García</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">01 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Los foros y las comunidades virtuales forman parte de internet desde casi sus inicios. La capacidad de formar parte de un grupo de manera virtual, con o sin tu nombre real, ha propiciado la interacción y el intercambio de ideas de una forma antes desconocida. Si bien internet, por su facilidad y conveniencia, es una herramienta ideal para crear comunidades, la cosa se complica cuando se desea trasladar ese dinamismo digital al mundo físico.</p>
<p>En este episodio queremos hablar de experiencias creando y desvirtualizando comunidades en internet. Para ello nos acompaña de nuevo en el podcast Juan Simón García, consultor y formador en nuevas tecnologías y presidente de la <a href="https://avre.tech/">Asociación Valenciana de Realidad Extendida (AVRE).</a></p>
<p><img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2020/02/juan-simon-garcia-republica-web-podcast.jpeg" alt="Juan Simón García en el podcast República Web" width="600" height="627" class="aligncenter mx-auto img-responsive size-full wp-image-2270" srcset="https://republicaweb.es/wp-content/uploads/2020/02/juan-simon-garcia-republica-web-podcast.jpeg 600w, https://republicaweb.es/wp-content/uploads/2020/02/juan-simon-garcia-republica-web-podcast-287x300.jpeg 287w" sizes="(max-width: 600px) 100vw, 600px" /></p>
<p>Juan lanzó hace un tiempo una comunidad alrededor de la realidad virtual en Valenccia, con un grupo de meetup y Telegram . Con él hablaremos de esto de desvirtualizar comunidades creadas en internet, algunas experiencias y por supuesto nuestra opinión alrededor de este tema. Juan comparte los puntos positivos de crear comunidades pero tampoco oculta, la responsabilidad personal que involucra dedicarte a proyectos abiertos.</p>
<p>Entre las cuestiones discutidas en el episodio del podcast se incluyen:</p>
<ul>
<li>Experiencia de Juan con el grupo de Valencia Virtual. Puntos positivos y negativos.</li>
<li>Dificultad de llevar a la gente hacia planos presenciales y formas de hacerlo mejor.</li>
<li>Organización de eventos presenciales (trabajo personal y dedicación).</li>
<li>Motivaciones de la gente para unirse a grupos y si son conscientes de lo que implica.</li>
<li>¿Se debería cobrar por las membresías o establecer límites?.</li>
<li>¿Deben las empresas mantenerse al margen de ciertas comunidades?</li>
</ul>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://slimbook.es/images/imagetuto/htop-top.png" alt="Conociendo HTOP">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Conociendo HTOP</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Soporte - SLIMBOOK: ultrabooks, portátiles y ordenadores GNU/Linux</a> <span class="article__date">01 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>El comando top es conocido por muchos, por listarnos los procesos activos y la carga del sistema, y su primo el comando htop, es aún más completo.</p>
<p>Si deseas instalarlo:</p>
<pre xml:lang="bash" lines="false">[code]sudo apt install htop[/code]</pre>
<p>Vía <a href="https://codeahoy.com/2017/01/20/hhtop-explained-visually/" target="_blank" rel="nofollow">codeahoy</a> os dejamos 2 imagenes que valen más que mil palabras:</p>
<p><img src="https://slimbook.es/images/imagetuto/htop-top.png" alt="htop top" width="1100" height="262" /></p>
<p><img src="https://slimbook.es/images/imagetuto/htop-bottom.png" alt="htop bottom" width="1100" height="381" /></p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Writing daily</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">01 02 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Over the month of February, I&rsquo;m going to try and write a blog post each day. I&rsquo;m hoping that this high cadence will have a couple of benefits:
 I&rsquo;ll get back into the habit of writing I&rsquo;ll learn to write faster The act of writing every day will help my focus my thoughts, and I&rsquo;ll end up having ideas or insights I wouldn&rsquo;t have had otherwise  I expect the format of my posts to change, to become shorter and less fleshed out, but I think that&rsquo;s fine for now.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">What’s more fantastic than fantasy land? An Introduction to Static land</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">29 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Fantasy land is great. It opens up a whole world of interoperable functions and structures. And the title, though originally a joke, is quite fitting. But Fantasy land isn’t perfect. And it’s not the only way to do algebraic structures in JavaScript.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">What’s more fantastic than fantasy land? An Introduction to Static land</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">29 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Fantasy land is great. It opens up a whole world of interoperable functions and structures. And the title, though originally a joke, is quite fitting. But Fantasy land isn’t perfect. And it’s not the only way to do algebraic structures in JavaScript.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/163-open-space.png" alt="Open Space">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Open Space</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">28 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/163-open-space.png" alt="Open Space" title="Big brother is watching!" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/164-next-level.png" alt="Next Level">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Next Level</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">28 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/164-next-level.png" alt="Next Level" title="This can only be fixed with therapy." /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Los satélites que vigilan el mar">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Los satélites que vigilan el mar</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">26 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        El CSIC presenta ante la Comisión Europea un programa para el control y el seguimiento del litoral a partir de las revolucionarias imágenes de los 'Sentinel'
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Ingenieros de hace 1,8 millones de años">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Ingenieros de hace 1,8 millones de años</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">26 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Un estudio demuestra que los homínidos de la Garganta de Olduvai (Tanzania) fabricaban herramientas de piedra específicas en función de su uso, dureza, capacidad y vida útil
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q1 2020 Funding Announcement</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">25 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        This quarter we are funding Reagent, Ring, Fireplace, and Calva!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Sitesauce, convertir sitios dinámicos en estáticos con Miguel Piedrafita">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Sitesauce, convertir sitios dinámicos en estáticos con Miguel Piedrafita</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">25 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Volvemos a contar de nuevo para este episodio con el «indie hacker» <a href="https://miguelpiedrafita.com/">Miguel Piedrafita,</a> que ya estuvo con nosotros en un episodio y que hoy vuelve para contarnos su último proyecto, <a href="https://sitesauce.app/" rel="noopener noreferrer" target="_blank">Sitesauce.</a> Este innovador servicio web que permite transformar un sitio dinámico basada en servidor, como por ejemplo un CMS hecho con WordPress, en un servicio estático. Esto permite aprovechar las ventajas de velocidad y seguridad que ofrecen los sitios estáticos, pero al mismo tiempo manteniendo el panel de control y la organización de los sitios basados en gestores de contenido.</p>
<p>El SSR o server side rendering consiste en alojar archivos estáticos listos para servir y sin intervención de base de datos o una lógica de procesamiento. Miguel viene a contarnos más sobre su proyecto, cómo se le ocurrió este servicio y los casos específicos donde su solución puede ser más interesante. Miguel habla de las tecnologías usadas y además nos cuenta detalles sobre el proyecto. También le preguntamos consejos sobre como arrancar tu propio proyecto en internet.</p>
<p>En la segunda parte del podcast volvemos con la sección Radar donde hablamos de recursos, herramientas y tecnologías interesantes en el mundo del desarrollo web.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="La banquera que salva vidas">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">La banquera que salva vidas</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">24 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        María Ángeles Muñoz ha pasado de ver morir niños con sida a construir cerebros en miniatura con células madre. Así se trabaja en la red española de biobancos
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Las mejores imágenes científicas del año">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Las mejores imágenes científicas del año</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">24 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        El Consejo Superior de Investigaciones Científicas (CSIC) y Fundación Española para la Ciencia y la Tecnología han elegido siete fotografías que reflejan fenómenos que nos rodean para acercar la ciencia a la sociedad.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="“Muy pocos políticos se interesan de forma auténtica por la ciencia”">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">“Muy pocos políticos se interesan de forma auténtica por la ciencia”</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">23 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        El académico uruguayo defiende la investigación como única manera de garantizar "una política basada en la evidencia" para afrontar desafíos como el envejecimiento de la población o el cambio climático
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="APP en VueJS con la ayuda del API REST de WordPress – Andros Fenollosa en WordCamp Zaragoza 2020">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">APP en VueJS con la ayuda del API REST de WordPress – Andros Fenollosa en WordCamp Zaragoza 2020</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">22 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>En el evento de <a href="https://2020.zaragoza.wordcamp.org/" rel="noopener noreferrer" target="_blank">WordPress WordCamp Zaragoza</a> nuestro compañero Andros Fenollosa tuvo la oportunidad de participar con dos charlas. En esta charla Andros demuestra las bondades del API REST de WordPress para agilizar la ejecución de proyectos web. En este caso Andros cuenta como la API de WordPress le ayudó a alimentar una APP que tuvo que realizar en su estudio en poco tiempo.</p>
<p>En la charla Andros también cuenta como se ayudó de VueJS y de las herramientas que incorpora, además de detalles sobre como construir la aplicación.</p>
<p>Audio extraído del <a href="https://wordpress.tv/2020/01/22/andros-fenollosa-app-en-vuejs-con-la-ayuda-del-api-rest-de-wordpress/" rel="noopener noreferrer" target="_blank">vídeo de la charla disponible</a> WordPress.tv.</p>
<p><br />
<script src="https://videopress.com/videopress-iframe.js"></script></p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="¿Es seguro que existe la materia oscura?">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">¿Es seguro que existe la materia oscura?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">22 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        La prueba más clara llegó con los estudios de la astrofísica estadounidense Vera Rubin sobre los movimientos de las galaxias espirales
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Effective Collaboration with Product and Design</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">21 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        How we work with design can have a tremendous impact on our overall output, and yet we don't always treat it as very important. A look at how collaborating with design can supercharge our own productivity.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/162-user-story.png" alt="User Story">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">User Story</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">21 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/162-user-story.png" alt="User Story" title="Also consider using messenger pigeon" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://javierarcheni.com/wp-content/uploads/2021/04/cropped-favicon-javierarcheni-32x32.png" alt="Charla sobre podcasting en la meetup de WordPress Valencia">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Charla sobre podcasting en la meetup de WordPress Valencia</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Javier Archeni</a> <span class="article__date">20 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        EL pasado 15 de enero tuve la oportunidad de participar en el meetup mensual del grupo WordPress Valencia. La charla que presenté tuvo como protagonistas al podcasting y a las posibilidades que ofrece WordPress para publicar tu propio podcast. Tanto el podcasting como la publicación con WordPress ponen acento en la libertad y el acceso &#8230; <a href="https://javierarcheni.com/blog/charla-sobre-podcasting-en-la-meetup-de-wordpress-valencia/">Ver más</a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="El espacio, parque de atracciones de los milmillonarios">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">El espacio, parque de atracciones de los milmillonarios</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">19 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Los ultrarricos impulsan la carrera espacial a través de empresas con programas espaciales propios y como turistas que ven estos viajes como el último producto exclusivo
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Clouding.io, el cloud también habla español con Patricia Armesto">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clouding.io, el cloud también habla español con Patricia Armesto</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">18 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>El cloud sigue imparable y cada vez son más los proveedores que ofrecen soluciones de calidad con grandes prestaciones a un precio muy competitivo. <a href="http://clouding.io/" rel="noopener noreferrer" target="_blank">Clouding.io</a> es una empresa que ofrece servidores cloud vps con sello español desde su centro de datos en Barcelona. Para este episodio contamos con <strong>Patricia Armesto,</strong> del equipo de comunicación, marketing y comunicación con el cliente de Clouding.io. Con Patricia hablamos sobre lo que ofrece desde España clouding.io en el mercado del cloud, sus características más destacables y cuestiones como el tipo de proyectos que se lanzan desde su infraestructura.</p>
<p>El nombre de Clouding ya ha surgido en alguno de nuestros episodios y hay que destacar los excelentes resultados que obtiene en rendimiento. Clouding se caracteriza por un <strong>acento especial en la atención al cliente</strong> y en una infraestructura de primer nivel 100% en Barcelona. A destacar también su facilidad de uso y la opción de comenzar gratuitamente con un acceso abierto para probar su servicio con 5 euros de crédito. Además clouding.io no sólo opera con clientes en España, sino que sus servicios también son contratados por clientes internacionales.</p>
<p>Con Patricia Armesto tratamos las siguientes cuestiones:</p>
<ul>
<li>Orígenes de clouding.io</li>
<li>Como están viviendo el auge del cloud en la empresa española.</li>
<li>Características más destacables que ofrece clouding a sus clientes.</li>
<li>Tipo de cliente que confía en sus servicios y qué tipo de proyectos suelen montar.</li>
<li>Su servicio de administración y soporte Cloud Pro.</li>
<li>Planes de futuro.</li>
</ul>
<p>Estamos agradecidos al equipo de clouding.io por la atención prestada desde el primer momento y como se comenta en la entrevista, les emplazamos a nuevas colaboraciones que ayuden a conocer las posibilidades del cloud español para los desarrolladores y proyectos empresariales.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Una tinta de oro y azúcar fundamental para tratar el cáncer">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Una tinta de oro y azúcar fundamental para tratar el cáncer</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">17 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Científicos de la Universidad de Sevilla y Nottingham desarrollan una fórmula para impresoras 3D que abre la puerta al diagnóstico y tratamiento de tumores
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Meetup WordPress Valencia – Hola soy WordPress y he venido a salvar al podcasting">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Meetup WordPress Valencia – Hola soy WordPress y he venido a salvar al podcasting</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">16 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Como episodio especial del podcast, subimos la grabación de la intervención de Javier Archeni en el <a href="https://www.meetup.com/es-ES/wordpress-valencia-meetup/events/267713810/?isFirstPublish=true" rel="noopener noreferrer" target="_blank">Meetup de WordPress Valencia </a>celebrado este miércoles 15 de enero en las instalaciones de <a href="https://iembs.com/" rel="noopener noreferrer" target="_blank">IEM Business School.</a> La charla tuvo como objetivo presentar las oportunidades que ofrece el podcasting y cómo garantizar la independencia de tus contenidos, sin renunciar a la exposición que ofrecen las plataformas de streaming. </p>
<p>En la charla se destacó el crecimiento sostenido que ha venido experimentando el podcasting y los diferentes actores que protagonizan al medio. Debido a que se trata de una presentación en el Meetup de WordPress Valencia, se explica los puntos básicos a tener en cuenta para crear tu podcast con este software. Además se ofrece una visión del futuro del podcasting y el escenario que afrontamos como productores de contenido.</p>
<p></p>
<p><a href="https://mega.nz/#!aTRQwIwZ!wIgZazg2ydQGJ1eZUZ-ZgpzHV4WsNdc2EduVrseqq-g" rel="noopener noreferrer" target="_blank">Descargar presentación en formato PPTX editable (Mega).</a></p>
<p>Desde aquí agradecer al equipo de organización del evento, con Ricardo Vilar a la cabeza la oportunidad para participar en el encuentro. También a los patrocinadores del evento por el apoyo brindado para su celebración (<a href="https://siteground.es" rel="noopener noreferrer" target="_blank">Siteground</a>,<a href="https://weglot.com/" rel="noopener noreferrer" target="_blank"> Weglot</a>) Confiamos poder seguir colaborando con nuevos eventos que acerquen la tecnología a los profesionales de los contenidos y el desarrollo web.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="El ídolo de Pachacámac, un caso excepcional de pintura policromática">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">El ídolo de Pachacámac, un caso excepcional de pintura policromática</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">15 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Una investigación descubre que la estatua prehispánica andina de más de dos metros preserva trazos amarillos, blancos y rojos
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Andar rápido modifica el ADN y reduce el riesgo cardiovascular">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Andar rápido modifica el ADN y reduce el riesgo cardiovascular</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">14 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Investigadores del Hospital del Mar de Barcelona hallan que el ejercicio físico moderado está relacionado con cambios en la estructura de un gen que participa en la regulación de los triglicéridos
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Hallado un material más antiguo que la Tierra dentro de un meteorito">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hallado un material más antiguo que la Tierra dentro de un meteorito</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">14 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Un equipo de científicos analiza el compuesto más viejo que se haya detectado. Tiene hasta 7.000 millones de años y se formó antes que existiesen el Sol y los planetas del sistema solar
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-d-PjZ820mbA/Xhy5rxCi_5I/AAAAAAAAnRc/_RYOlh1QViABmDZ67yF-NFTACfKxhbpsgCLcBGAsYHQ/s640/32%2Bconsejos%2Bpara%2Bdevelopers.jpg" alt="32 consejos para web developers">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">32 consejos para web developers</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">14 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="separator" style="clear: both; text-align: left;"><img border="0" data-original-height="720" data-original-width="1280" height="360" src="https://1.bp.blogspot.com/-d-PjZ820mbA/Xhy5rxCi_5I/AAAAAAAAnRc/_RYOlh1QViABmDZ67yF-NFTACfKxhbpsgCLcBGAsYHQ/s640/32%2Bconsejos%2Bpara%2Bdevelopers.jpg" width="640" /></div><div class="separator" style="clear: both; text-align: left;">¿Qué consejo le darías a un desarrollador web? seguramente si tienes ya un poco de experiencia sabrás que hoy en día un developer no solo debe centrarse en el tema del código como tal, hay varias habilidades adicionales que se necesitan para tener en cuenta que un desarrollador web tiene un perfil más completo.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">En este video les comparto <b>32 consejos para web developers</b>, consejos muy rápidos y sencillos de seguir si tu ruta de carrera conlleva tener un puesto de este tipo, pues temas de colaboración, de apoyo a la comunidad, de tener presencia en internet y de estar constantemente actualizándose con las nuevas tecnologías son temas importantes que necesitas cumplir para tener un perfil completo.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><br /></div><br /><iframe allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/oqsA3boY82k" width="560"></iframe><br /><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=cL5LPvRz0nI:Ri6Lh2bWNlk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=cL5LPvRz0nI:Ri6Lh2bWNlk:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=cL5LPvRz0nI:Ri6Lh2bWNlk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=cL5LPvRz0nI:Ri6Lh2bWNlk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=cL5LPvRz0nI:Ri6Lh2bWNlk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=cL5LPvRz0nI:Ri6Lh2bWNlk:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=cL5LPvRz0nI:Ri6Lh2bWNlk:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=cL5LPvRz0nI:Ri6Lh2bWNlk:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=cL5LPvRz0nI:Ri6Lh2bWNlk:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=cL5LPvRz0nI:Ri6Lh2bWNlk:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=cL5LPvRz0nI:Ri6Lh2bWNlk:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=cL5LPvRz0nI:Ri6Lh2bWNlk:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=cL5LPvRz0nI:Ri6Lh2bWNlk:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=cL5LPvRz0nI:Ri6Lh2bWNlk:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/cL5LPvRz0nI" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/161-fix.png" alt="Fix">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Fix</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">14 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/161-fix.png" alt="Fix" title="It was a feature!" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Un coágulo en la yugular de un astronauta obliga a la NASA a improvisar una cura en órbita">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Un coágulo en la yugular de un astronauta obliga a la NASA a improvisar una cura en órbita</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">13 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        El primer trombo detectado en el espacio, para el que no se contaba con el tratamiento adecuado, reabre el debate sobre los riesgos físicos de los futuros viajes espaciales
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Cómo se hace un biobot">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cómo se hace un biobot</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">13 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Los autores de las primeras “máquinas vivientes” creen que tendrán aplicaciones en la medicina y en el cuidado del medio ambiente
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-krW7P82_yNs/Xhy254xJQrI/AAAAAAAAnQ0/jMxkpXEvx-UMP09ha8VexLhskHBfuhBiQCLcBGAsYHQ/s640/musica-08.jpg" alt="10 ejemplos de diseños web enfocados a la música">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">10 ejemplos de diseños web enfocados a la música</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">13 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-krW7P82_yNs/Xhy254xJQrI/AAAAAAAAnQ0/jMxkpXEvx-UMP09ha8VexLhskHBfuhBiQCLcBGAsYHQ/s1600/musica-08.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="481" data-original-width="1000" height="305" src="https://1.bp.blogspot.com/-krW7P82_yNs/Xhy254xJQrI/AAAAAAAAnQ0/jMxkpXEvx-UMP09ha8VexLhskHBfuhBiQCLcBGAsYHQ/s640/musica-08.jpg" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div></div><div>Hace tiempo que no comparto diseños de sitios web. En esta ocasión les comparto una galería de diseños de sitios web con estilo enfocado a la música. Muchos de estos sitios obviamente tienen que ver con artistas o la fuente hace referencia mucho al tipo de música que vas a encontrar. Sitios que se enfocan en colecciones de música o servicios de streaming están enfocados en dar a conocer los éxitos más populares alrededor del mundo, por lo que son varios los tips que pueden tomar como referencia si su próximo proyecto va a ir enfocado a la música.</div><div><h2 style="background-color: white; box-sizing: border-box; font-family: Roboto, sans-serif; font-size: 20px; margin: 0px 0px 10px; padding: 10px 0px 0px;"><a href="https://themeforest.net/item/snakepit-a-rock-and-metal-oriented-music-wordpress-theme/23418267?ref=webdesigndev" style="box-sizing: border-box; color: #f8800c; margin: 0px; outline: 0px; padding: 0px; text-decoration-line: none;" target="_blank">1. Snakepit:</a></h2></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-U012u3r7f_Y/Xhy23l_kSrI/AAAAAAAAnQg/msQox1AFLh0f9ZDkJPko2bm4mppuojMXACLcBGAsYHQ/s1600/musica-01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="485" data-original-width="1000" height="307" src="https://1.bp.blogspot.com/-U012u3r7f_Y/Xhy23l_kSrI/AAAAAAAAnQg/msQox1AFLh0f9ZDkJPko2bm4mppuojMXACLcBGAsYHQ/s640/musica-01.jpg" width="640" /></a></div><h2 style="background-color: white; box-sizing: border-box; font-family: Roboto, sans-serif; font-size: 20px; margin: 0px 0px 10px; padding: 10px 0px 0px;"><a href="https://themeforest.net/item/slide-music-wordpress-theme/21680152?ref=webdesigndev" style="box-sizing: border-box; color: #f8800c; margin: 0px; outline: 0px; padding: 0px; text-decoration-line: none;" target="_blank">2. Slide:</a></h2><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-OlpvEhcmVoA/Xhy23YDTeZI/AAAAAAAAnQc/OxNuazaGV10CSGStQOmm5yzuJgtxgBcCgCLcBGAsYHQ/s1600/musica-02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="462" data-original-width="1000" height="292" src="https://1.bp.blogspot.com/-OlpvEhcmVoA/Xhy23YDTeZI/AAAAAAAAnQc/OxNuazaGV10CSGStQOmm5yzuJgtxgBcCgCLcBGAsYHQ/s640/musica-02.jpg" width="640" /></a></div><h2 style="background-color: white; box-sizing: border-box; font-family: Roboto, sans-serif; font-size: 20px; margin: 0px 0px 10px; padding: 10px 0px 0px;"><a href="https://themeforest.net/item/mixtape-a-fresh-music-theme-for-artists-bands-and-festivals/19984384?ref=webdesigndev" style="box-sizing: border-box; color: #f8800c; margin: 0px; outline: 0px; padding: 0px; text-decoration-line: none;" target="_blank">3. Mixtape:</a></h2><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-p68_vqr1zqg/Xhy23TTe2AI/AAAAAAAAnQY/MkKhY3qR4KA04PwPhh7PZlB3MyFG7esYwCLcBGAsYHQ/s1600/musica-03.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="483" data-original-width="1000" height="307" src="https://1.bp.blogspot.com/-p68_vqr1zqg/Xhy23TTe2AI/AAAAAAAAnQY/MkKhY3qR4KA04PwPhh7PZlB3MyFG7esYwCLcBGAsYHQ/s640/musica-03.jpg" width="640" /></a></div><h2 style="background-color: white; box-sizing: border-box; font-family: Roboto, sans-serif; font-size: 20px; margin: 0px 0px 10px; padding: 10px 0px 0px;"><a href="https://themeforest.net/item/milando-music-portal-html-template/21781034?ref=webdesigndev" style="box-sizing: border-box; color: #f8800c; margin: 0px; outline: 0px; padding: 0px; text-decoration-line: none;" target="_blank">4. Milando:</a></h2><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-wXYyss1V2gA/Xhy236xRhOI/AAAAAAAAnQk/p5LnKLgEkSU1kvzeCbDVQeu0ArhSj95PACLcBGAsYHQ/s1600/musica-04.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="486" data-original-width="1000" height="308" src="https://1.bp.blogspot.com/-wXYyss1V2gA/Xhy236xRhOI/AAAAAAAAnQk/p5LnKLgEkSU1kvzeCbDVQeu0ArhSj95PACLcBGAsYHQ/s640/musica-04.jpg" width="640" /></a></div><h2 style="background-color: white; box-sizing: border-box; font-family: Roboto, sans-serif; font-size: 20px; margin: 0px 0px 10px; padding: 10px 0px 0px;"><a href="https://themeforest.net/item/beatswave-creative-music-template/22620047?ref=webdesigndev" style="box-sizing: border-box; color: #f8800c; margin: 0px; outline: 0px; padding: 0px; text-decoration-line: none;" target="_blank">5. BeatsWave:</a></h2><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-xkBBZS08wYw/Xhy24OEr4-I/AAAAAAAAnQo/3SMYnnWz7Dw424uag8_UX1anfIbmpUQhgCLcBGAsYHQ/s1600/musica-05.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="489" data-original-width="1000" height="312" src="https://1.bp.blogspot.com/-xkBBZS08wYw/Xhy24OEr4-I/AAAAAAAAnQo/3SMYnnWz7Dw424uag8_UX1anfIbmpUQhgCLcBGAsYHQ/s640/musica-05.jpg" width="640" /></a></div><h2 style="background-color: white; box-sizing: border-box; font-family: Roboto, sans-serif; font-size: 20px; margin: 0px 0px 10px; padding: 10px 0px 0px;"><a href="https://themeforest.net/item/soundflare-hifi-audio-repair-service-landing-page-html5-template/21285766?ref=webdesigndev" style="box-sizing: border-box; color: #f8800c; margin: 0px; outline: 0px; padding: 0px; text-decoration-line: none;" target="_blank">6. SoundFlare:</a></h2><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-qXJXHoztIAw/Xhy24qhEgTI/AAAAAAAAnQs/5UZ7nvdacMs-I-qxNx8RqL5G7TfxWDD-QCLcBGAsYHQ/s1600/musica-06.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="486" data-original-width="1000" height="308" src="https://1.bp.blogspot.com/-qXJXHoztIAw/Xhy24qhEgTI/AAAAAAAAnQs/5UZ7nvdacMs-I-qxNx8RqL5G7TfxWDD-QCLcBGAsYHQ/s640/musica-06.jpg" width="640" /></a></div><h2 style="background-color: white; box-sizing: border-box; font-family: Roboto, sans-serif; font-size: 20px; margin: 0px 0px 10px; padding: 10px 0px 0px;"><a href="https://themeforest.net/item/bepop-nonstop-music-wordpress-theme/24075935?ref=webdesigndev" style="box-sizing: border-box; color: #f8800c; margin: 0px; outline: 0px; padding: 0px; text-decoration-line: none;" target="_blank">7. Bepop:</a></h2><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-ZGCM5LCCZAI/Xhy25f_XYoI/AAAAAAAAnQw/VCX6lKnGlV8TDnxfknW5RUC9KzwVRqNeQCLcBGAsYHQ/s1600/musica-07.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="486" data-original-width="1000" height="308" src="https://1.bp.blogspot.com/-ZGCM5LCCZAI/Xhy25f_XYoI/AAAAAAAAnQw/VCX6lKnGlV8TDnxfknW5RUC9KzwVRqNeQCLcBGAsYHQ/s640/musica-07.jpg" width="640" /></a></div><br /><h2 style="background-color: white; box-sizing: border-box; font-family: Roboto, sans-serif; font-size: 20px; margin: 0px 0px 10px; padding: 10px 0px 0px;"><a href="https://themeforest.net/item/mousiqua-music-band-and-musician-template/21699925?ref=webdesigndev" style="box-sizing: border-box; color: #f8800c; margin: 0px; outline: 0px; padding: 0px; text-decoration-line: none;" target="_blank">8. Mousiqua:</a></h2><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-tmBu2lVBOEU/Xhy26aSugKI/AAAAAAAAnQ4/IkG0GNiGPYgW1uUMWvIsexDADqMyqMg7gCLcBGAsYHQ/s1600/musica-09.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="489" data-original-width="1000" height="312" src="https://1.bp.blogspot.com/-tmBu2lVBOEU/Xhy26aSugKI/AAAAAAAAnQ4/IkG0GNiGPYgW1uUMWvIsexDADqMyqMg7gCLcBGAsYHQ/s640/musica-09.jpg" width="640" /></a></div><h2 style="background-color: white; box-sizing: border-box; font-family: Roboto, sans-serif; font-size: 20px; margin: 0px 0px 10px; padding: 10px 0px 0px;"><a href="https://themeforest.net/item/bridge-creative-multipurpose-wordpress-theme/7315054?ref=webdesigndev" style="box-sizing: border-box; color: #f8800c; margin: 0px; outline: 0px; padding: 0px; text-decoration-line: none;" target="_blank">9. Bridge:</a></h2><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-6xH8qTVjuvg/Xhy264rmxmI/AAAAAAAAnQ8/2uquooX7bfEdmKKV6tKBxaGrZEfYhScigCLcBGAsYHQ/s1600/musica-10.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="485" data-original-width="1000" height="307" src="https://1.bp.blogspot.com/-6xH8qTVjuvg/Xhy264rmxmI/AAAAAAAAnQ8/2uquooX7bfEdmKKV6tKBxaGrZEfYhScigCLcBGAsYHQ/s640/musica-10.jpg" width="640" /></a></div><h2 style="background-color: white; box-sizing: border-box; font-family: Roboto, sans-serif; font-size: 20px; margin: 0px 0px 10px; padding: 10px 0px 0px;"><a href="https://themeforest.net/item/kentha-visionary-music-wordpress-theme/21148850?ref=webdesigndev" style="box-sizing: border-box; color: #f8800c; margin: 0px; outline: 0px; padding: 0px; text-decoration-line: none;" target="_blank">10. Kentha:</a></h2><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-krW7P82_yNs/Xhy254xJQrI/AAAAAAAAnQ0/jMxkpXEvx-UMP09ha8VexLhskHBfuhBiQCLcBGAsYHQ/s1600/musica-08.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="481" data-original-width="1000" height="305" src="https://1.bp.blogspot.com/-krW7P82_yNs/Xhy254xJQrI/AAAAAAAAnQ0/jMxkpXEvx-UMP09ha8VexLhskHBfuhBiQCLcBGAsYHQ/s640/musica-08.jpg" width="640" /></a></div><div></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=8fRjF4bmeYM:6t0ydEOC85w:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8fRjF4bmeYM:6t0ydEOC85w:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8fRjF4bmeYM:6t0ydEOC85w:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=8fRjF4bmeYM:6t0ydEOC85w:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8fRjF4bmeYM:6t0ydEOC85w:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=8fRjF4bmeYM:6t0ydEOC85w:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8fRjF4bmeYM:6t0ydEOC85w:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8fRjF4bmeYM:6t0ydEOC85w:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8fRjF4bmeYM:6t0ydEOC85w:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=8fRjF4bmeYM:6t0ydEOC85w:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8fRjF4bmeYM:6t0ydEOC85w:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8fRjF4bmeYM:6t0ydEOC85w:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=8fRjF4bmeYM:6t0ydEOC85w:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8fRjF4bmeYM:6t0ydEOC85w:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/8fRjF4bmeYM" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Magical Rainbow Gradients</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">13 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        If you've ever tried to animate a gradient, you've been met with a harsh reality—it isn't possible. At least, it wasn't! In this tutorial, we'll leverage bleeding-edge browser features to animate ANY CSS property, including background gradients, using CSS Houdini, CSS variables, and React.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Ciencia, las dudas de un ministerio amputado">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Ciencia, las dudas de un ministerio amputado</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">13 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        El nuevo mandato del astronauta Pedro Duque como ministro de Ciencia arranca con la hostilidad de la comunidad científica y el reconocimiento de alguno de sus logros
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Minerales con leyendas de deseos, amor y muerte">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Minerales con leyendas de deseos, amor y muerte</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">13 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        La Universidad de Sevilla recopila historias asociadas a piedras convertidas en símbolos para acercar la geología al público general
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="El viaje en el tiempo como truco cuántico">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">El viaje en el tiempo como truco cuántico</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">12 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        En una de sus novelas, Stephen King consideró los universos paralelos como un recurso para cambiar el futuro de la Historia
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Estudio sobre los frameworks de Front-end más utilizados">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Estudio sobre los frameworks de Front-end más utilizados</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">11 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Para este primer episodio del año, queremos continuar hablando del estudio de tecnologías web realizado por David Vaquero. En esta ocasión vamos a detenernos en los datos que ha conseguido David en relación a los frameworks de front-end. Veamos si hay sorpresas en las tecnologías más usadas y si podemos ver alguna tendencia clara <a href="https://cursosdedesarrollo.com/2020/01/que-frameworks-de-frontend-son-los-mas-utilizados-en-el-millon-de-paginas-del-top-de-alexa/" rel="noopener noreferrer" target="_blank">en los datos que ha obtenido David.</a></p>
<p>Antes de empezar el episodio 123, hablamos de la creación del <strong>grupo Malditos Webmasters en Telegram.</strong> Se trata de un espacio para todas aquellas personas interesadas en la creación y mantenimiento de un sitio web. También hablamos de nuestras próximas charlas en <a href="https://www.meetup.com/es-ES/wordpress-valencia-meetup/events/267713810/?isFirstPublish=true" rel="noopener noreferrer" target="_blank">meetup WordPress Valencia</a> y <a href="https://2020.zaragoza.wordcamp.org/" rel="noopener noreferrer" target="_blank">WordCamp Zaragoza</a>. Por último también comentamos nuestras expectativas y propósitos para el año que comenzamos.</p>
<p>Con respecto a las tecnologías de front-end, poca sorpresa al encontrarnos a jQuery como el dominador absoluto en este terreno. Una cuestión importante es advertir que son datos obtenidos de vistas públicas procedentes de dominios facilitados por Alexa. No se muestran los datos procedentes de sitios web protegidos por contraseña o que pueden estar detrás de algún proxy o cortafuegos. Hablamos sobre React, Vue y también sobre Angular. Ofrecemos también unos datos sobre las demandas laborales en este terreno.</p>
<p>En la segunda parte del episodio volvemos con la sección Radar, con interesantes recursos propios y de terceros. Disponibles los enlaces en la sección inferior.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Historia profunda del tomate">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Historia profunda del tomate</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">10 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        La agricultura empezó en el neolítico, pero se basó en materias primas muy anteriores
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Gusanos, microbios y desechos que resucitan suelos">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Gusanos, microbios y desechos que resucitan suelos</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">10 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Una investigación aplica en Aznalcóllar una forma de activar la tierra contaminada por metales pesados para que se regenere a partir de lombrices, microorganismos y residuos
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="El cambio climático avivará los incendios en la selva amazónica">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">El cambio climático avivará los incendios en la selva amazónica</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">10 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        La interacción entre deforestación y calentamiento doblará el área quemada para 2050
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Anillo de fuego">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Anillo de fuego</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">10 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ¿Por qué a veces en los eclipses solares se ve un anillo de fuego alrededor del disco lunar?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="El viaje de una fruta diminuta nacida en los Andes que conquistó el mundo">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">El viaje de una fruta diminuta nacida en los Andes que conquistó el mundo</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">10 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Un equipo científico reconstruye la evolución del tomate, desde que tenía el tamaño de un arándano, cómo alcanzó el tamaño de un cherry, volvió a encoger y acabó domesticado en México
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="¿Por qué nuestra galaxia tiene forma de espiral?">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">¿Por qué nuestra galaxia tiene forma de espiral?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">10 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Cuando el universo era más joven, la fracción de galaxias espirales era mucho mayor que ahora
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Las 10 especies de pájaros recién descubiertas que desaparecerán en 20 años">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Las 10 especies de pájaros recién descubiertas que desaparecerán en 20 años</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">10 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Un grupo de investigadores halla nuevas familias de aves en tres islas poco exploradas de Indonesia, pero su supervivencia está amenazada por la destrucción forestal
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://slimbook.es/images/imagetuto/hibernar.jpg" alt="Cómo hibernar en Ubuntu 18.04 LTS, 19.10, 20.04, o Linux Mint y derivadas.">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cómo hibernar en Ubuntu 18.04 LTS, 19.10, 20.04, o Linux Mint y derivadas.</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Soporte - SLIMBOOK: ultrabooks, portátiles y ordenadores GNU/Linux</a> <span class="article__date">09 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p id="aviso-dl-prem"><strong>AVISO IMPORTANTE: Las distintas distribuciones de GNU/Linux han quitado la opción de hibernar, porque genera muchos problemas. tanto de incompatibilidad con mucho ordenadores, como fallos puntuales. Nosotros hemos probado y ahora mismo funciona, pero no sabemos si después de una actualización de tu distribución linux, mañana por ejemplo, dejará de funcionar. Es por ello que deberás asegurarte cuando hibernes, que el ordenador está completamente apagado, antes de meterlo en un maletín y que se sobre-caliente.<br /></strong></p>
<p>Para poder activar la hibernación en tu portátil, lo primero que debes saber es que has de tener en la bios desactivado el <strong>Secure Boot</strong>, y has de haber instalado así el sisetma operativo, no se puede cambiar a las bravas. Y lo segundo que has de saber es que vas a perder un trozo de disco duro, ya que has de reservar el espacio. Aunque desde Ubuntu 18 ya no hay partición swap, si no un fichero pequeño y dinámico, ahora has de fijarle un tamaño, concretamente el tamaño de tu memoria RAM (o algo más por precaución).</p>
<p>Puedes mirar gráficamente cuanta RAM tiene tu ordenador, o puedes comprobarlo via terminal con:</p>
<pre xml:lang="bash" lines="false">[code]free[/code]</pre>
<p>Del comando de arriba quedarte con el primer valor de memoria, o si quieres usa este otro comando:</p>
<pre xml:lang="bash" lines="false">[code]vmstat -s | awk '{print int(($1 / 1024 / 1024)+0.51)}' | head -1[/code]</pre>
<p>Si tuvieras la swap ya activa, primero hemos de detenerla, para poder luego redimensionarla. Detenla con este comando:</p>
<pre xml:lang="bash" lines="false">[code]sudo swapoff -a[/code]</pre>
<p>Crea el fichero de swap con el tamañao de tu ram, yo pongo en mi ejemplo 16 GB, pero cambia el número por tu RAM o un poco más:</p>
<pre xml:lang="bash" lines="false">[code]sudo fallocate -l 16g /swapfile[/code]</pre>
<p>Dale permisos y añadelo al fichero fstab con:</p>
<pre xml:lang="bash" lines="false">[code]sudo chmod 600 /swapfile<br />sudo mkswap /swapfile<br />sudo swapon /swapfile[/code]</pre>
<p>Mira si ya tienes el el fichero /etc/fstab una linea que empiece por /swapfile, si no la tienes añadela con esto:</p>
<pre xml:lang="bash" lines="false">[code]echo '/swapfile swap swap defaults 0 0' | sudo tee -a /etc/fstab[/code]</pre>
<p>Montamos y verificamos:</p>
<pre xml:lang="bash" lines="false">[code]sudo findmnt -no SOURCE,UUID -T /swapfile[/code]</pre>
<p>Nos mostrará algo como esto: /dev/sda1 0c233fbb-f72e-470f-8460-4f2521bf3569 <br />La segunda parte después de sda1 (o nvme0n1p1 o tu lvm) es el UUID de la partición y tienes que apuntártela, o copiarla.</p>
<p>Ahora instalamos y configuramos uswsusp:</p>
<pre xml:lang="bash" lines="false">[code]sudo apt install uswsusp<br />sudo dpkg-reconfigure -pmedium uswsusp[/code]</pre>
<p>Te preguntará si quieres continuar sin valeidar swap, respondes "<strong>Sí</strong>".<br />Luego te dirá que selecciones la partición, y <strong>NO</strong> has de elegir /swapfile, y <strong>SÍ</strong> el UUID que has apuntado antes.<br />En cifrar la partición hibernada diremos NO para que no nos pide una contraseña adicional para desbloquarlo, con cerrar sesión que lo hace, es suficiente.</p>
<p>Por si acaso ahora:</p>
<pre xml:lang="bash" lines="false">[code]sudo update-initramfs -u[/code]</pre>
<p>Es hora de probar si la hibernación funciona con este comando (espera un minuto):</p>
<pre xml:lang="bash" lines="false">[code]sudo s2disk[/code]</pre>
<p><b>Estos pasos son solo para Linux Mint:</b><br />Si no ha vuelto a tu sesión después de hibernar, haz estos pasos, pero si ha ido bien, no lo hagas:</p>
<pre xml:lang="bash" lines="false">[code]sudo nano /etc/default/grub[/code]</pre>
<p>y añadir en la linea GRUB_CMDLINE_LINUX_DEFAULT="quiet splash", antes de cerrar las comillas resume=UUID= con el identificador de tu partición que hemos copiado antes, o sea en nuestro caso quedaría así:</p>
<pre xml:lang="bash" lines="false">[code]GRUB_CMDLINE_LINUX_DEFAULT="quiet splash resume=UUID=0c233fbb-f72e-470f-8460-4f2521bf3569"[/code]</pre>
<pre xml:lang="bash" lines="false">[code]sudo update-grub[/code]</pre>
<pre xml:lang="bash" lines="false">[code]reboot[/code]</pre>
<p><b>Fin de los pasos para Linux Mint</b></p>
<p>Ahora tenemos que editar el servicio de hibernación para que utilice el nuevo métido:</p>
<pre xml:lang="bash" lines="false">[code]sudo systemctl edit systemd-hibernate.service[/code]</pre>
<p>Y dentro pegamos:</p>
<pre xml:lang="bash" lines="false">[code][Service]<br />ExecStart=<br />ExecStart=/usr/sbin/s2disk <br />ExecStartPost=/bin/run-parts -a post /lib/systemd/system-sleep[/code]</pre>
<p>Volvemos a probar la hibernación, pero ahora con el servicio:</p>
<pre xml:lang="bash" lines="false">[code]systemctl hibernate[/code]</pre>
<p>Si no funciona puedes ver el estado y ver los errores que muestra:</p>
<pre xml:lang="bash" lines="false">[code]systemctl status systemd-hibernate.service[/code]</pre>
<p>Ahora que todo funciona correctamente, sólo tenemos que al apagar el ordenador, aparezca la opción de hibernar junto a la de reiniciar o suspender.<br />Vamos a crear un fichero nuevo con:</p>
<pre xml:lang="bash" lines="false">[code]sudo nano /etc/polkit-1/localauthority/50-local.d/com.ubuntu.enable-hibernate.pkla[/code]</pre>
<p>y dentro pagamos a pegar esto y guardar:</p>
<pre xml:lang="bash" lines="false">[code][Re-enable hibernate by default in upower]<br />Identity=unix-user:*<br />Action=org.freedesktop.upower.hibernate<br />ResultActive=yes<br />&#160;<br />[Re-enable hibernate by default in logind]<br />Identity=unix-user:*<br />Action=org.freedesktop.login1.hibernate;org.freedesktop.login1.hibernate-multiple-sessions<br />ResultActive=yes[/code]</pre>
<p>Ahora reiniciamos el ordenador y ya estará listo :) <br />Adicionalmente en Gnome Shell existen extensiones como <a href="https://extensions.gnome.org/extension/755/hibernate-status-button/" target="_blank" rel="nofollow">esta</a> para que el botón esté más accesible.</p>
<p>&#160;</p>
<p><img src="https://slimbook.es/images/imagetuto/hibernar.jpg" alt="hibernar" /></p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Cae la confianza de los españoles en la innovación, sobre todo en los colectivos vulnerables">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cae la confianza de los españoles en la innovación, sobre todo en los colectivos vulnerables</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">09 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        La encuesta sobre la percepción social de la innovación de Cotec revela que el número de personas sin estudios que temen el cambio digital ha aumentado un 32% en dos años
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="La mala calidad del sueño despierta al alzhéimer">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">La mala calidad del sueño despierta al alzhéimer</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">09 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Dos estudios sugieren un vínculo entre el insomnio y el aumento del riesgo de desarrollar esta demencia
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Primer avance en décadas en un problema aparentemente imposible">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Primer avance en décadas en un problema aparentemente imposible</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">09 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        El matemático Terence Tao obtiene un nuevo resultado significativo sobre la conjetura de Collatz, uno de los problemas matemáticos más fáciles de enunciar y difíciles de resolver
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="De Hércules de feria a ganador del Nobel">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">De Hércules de feria a ganador del Nobel</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">09 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Una gran exposición en Zaragoza recuerda la asombrosa vida de Santiago Ramón y Cajal
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="La primera especie extinguida de 2020: un pez de hasta siete metros de largo">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">La primera especie extinguida de 2020: un pez de hasta siete metros de largo</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">09 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        La construcción de represas bloqueó los hábitos migratorios del animal y su reproducción
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q1 2020 Survey Results</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">09 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        We surveyed our members on what they wanted us to support this round. The main things they were interested in were Error messages, Documentation, Developer experience tools, Build tooling, IDE support, Test tooling, Linters, Profilers, and Data analysis/processing frameworks
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Dos misiones para desentrañar el misterio de los agujeros negros">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Dos misiones para desentrañar el misterio de los agujeros negros</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">08 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        La Agencia Espacial Europea logra más fondos para el estudio de estos monstruos cósmicos
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Detectada la mayor colisión estelar del universo">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Detectada la mayor colisión estelar del universo</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">08 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        El experimento LIGO capta ondas gravitacionales producidas por la fusión de dos astros de extrema densidad
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">State of Clojure 2020 Survey</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">07 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div class="paragraph">
<p>It&#8217;s time for the annual State of Clojure Community Survey!</p>
</div>
<div class="paragraph">
<p>If you are a user of Clojure or ClojureScript, we are greatly interested in your responses to the following survey:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://www.surveymonkey.com/r/clojure2020">State of Clojure 2020</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The survey contains five pages:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>General info</p>
</li>
<li>
<p>Tool usage</p>
</li>
<li>
<p>Questions specific to JVM Clojure (skip if not applicable)</p>
</li>
<li>
<p>Questions specific to ClojureScript (skip if not applicable)</p>
</li>
<li>
<p>Final comments</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>The survey will close January 23rd, after which all of the data will be released with some analysis. We greatly appreciate your input!</p>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-4e5XOFYl8Uk/XhI6TEUNpkI/AAAAAAAAnDQ/75kGl9SocVUDcvrRE79Z5GwGXG0xFQ7awCLcBGAsYHQ/s1600/CORS_principle.png" alt="Qué es CORS y cómo usarlo en Node.js">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Qué es CORS y cómo usarlo en Node.js</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">07 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-4e5XOFYl8Uk/XhI6TEUNpkI/AAAAAAAAnDQ/75kGl9SocVUDcvrRE79Z5GwGXG0xFQ7awCLcBGAsYHQ/s1600/CORS_principle.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Qué es CORS y cómo usarlo en Node.js" border="0" data-original-height="643" data-original-width="925" src="https://1.bp.blogspot.com/-4e5XOFYl8Uk/XhI6TEUNpkI/AAAAAAAAnDQ/75kGl9SocVUDcvrRE79Z5GwGXG0xFQ7awCLcBGAsYHQ/s1600/CORS_principle.png" title="Qué es CORS y cómo usarlo en Node.js" /></a></div><br />CORS significa Cross-Origin Resource Sharing, y es una política a nivel de navegador web que se aplica para prevenir que el dominio A evite acceder a recursos del dominio B usando solicitudes del tipo AJAX como cuando usamos <code>fetch()</code> o <code>XMLHttpRequest</code>.<br />Un ejemplo básico de este comportamiento es cuando creas un archivo html y tratas de hacer una llamada AJAX a cualquier sitio en internet o servidor en tu equipo o red local. Vas a obtener un error como el siguiente:<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-XMoVr7Bnnls/XhI58Z8T8DI/AAAAAAAAnDI/EHPFNESgii4_2HmeMB0P729yxISbaWbmQCLcBGAsYHQ/s1600/font-origin-blocked.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Qué es CORS y cómo usarlo en Node.js" border="0" data-original-height="180" data-original-width="670" height="170" src="https://1.bp.blogspot.com/-XMoVr7Bnnls/XhI58Z8T8DI/AAAAAAAAnDI/EHPFNESgii4_2HmeMB0P729yxISbaWbmQCLcBGAsYHQ/s640/font-origin-blocked.png" title="Qué es CORS y cómo usarlo en Node.js" width="640" /></a></div><br />Puedes encontrar toda la información detallada en el <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS">sitio de Mozilla</a> pero en este tutorial vamos a ver cómo manejar este comportamiento con Node.js<br /><br />Lo primero que necesitamos saber es que si tenemos dos dominios: posco.com y contaro.com en principio no pueden comunicarse. Si nosotros queremos que por ejemplo contaro.com pueda permitir a otros dominios acceder a sus recursos, podemos hacerlo a través del módulo de cors. Lo primero es instalarlo<br /><br /><pre><code>$ npm <span class="hljs-keyword">install</span> cors<br /></code></pre><br />Después, vamos a incluirlo en nuestro archivo de Node.js<br /><pre><code><span class="hljs-keyword">var</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>)<br /><span class="hljs-keyword">var</span> cors = <span class="hljs-built_in">require</span>(<span class="hljs-string">'cors'</span>)<br /><span class="hljs-keyword">var</span> app = express()<br /><br />app.use(cors())<br /><br />app.get(<span class="hljs-string">'/products/:id'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">req, res, next</span>) </span>{<br />  res.json({<span class="hljs-attr">msg</span>: <span class="hljs-string">'This is CORS-enabled for all origins!'</span>})<br />})<br /><br />app.listen(<span class="hljs-number">80</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{<br />  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'CORS-enabled web server listening on port 80'</span>)<br />})<br /></code></pre>Con esto ya estamos permitiendo a nuestro dominio recibir solicitudes de otros dominios. Pero si queremos limitar solo a ciertos dominios de acceder a nuestros recursos podemos igual hacerlo a través de una lista blanca, en donde definimos los dominios y validamos que cada que haya una solicitud a una ruta específica se ejecute ese procedimiento de confirmación para aprobar o descargar el dominio.<br /><br /><pre><code><span class="hljs-keyword">var</span> whitelist = [<span class="hljs-string">'http://example1.com'</span>, <span class="hljs-string">'http://example2.com'</span>]<br /><span class="hljs-keyword">var</span> corsOptions = {<br />  origin: <span class="hljs-type">function </span>(origin, <span class="hljs-keyword">callback</span>) {<br />    <span class="hljs-keyword">if</span> (whitelist.indexOf(origin) !== <span class="hljs-number">-1</span>) {<br />      <span class="hljs-keyword">callback</span>(<span class="hljs-literal">null</span>, <span class="hljs-literal">true</span>)<br />    } <span class="hljs-keyword">else</span> {<br />      <span class="hljs-keyword">callback</span>(<span class="hljs-keyword">new</span> <span class="hljs-type">Error</span>(<span class="hljs-string">'Not allowed by CORS'</span>))<br />    }<br />  }<br />}<br /><br />...<br /><br />app.<span class="hljs-keyword">get</span>(<span class="hljs-string">'/products/:id'</span>, cors(corsOptions), <span class="hljs-function"><span class="hljs-keyword">function</span> </span>(req, res, next) {<br />  res.json({msg: <span class="hljs-type"></span>'This is CORS-enabled <span class="hljs-keyword">for</span> a whitelisted domain.<span class="hljs-string">'})<br />})</span><br /></code></pre>De esa forma podemos controlar de forma más granular quién puede o no acceder a nuestros recursos como una API sin tener que hacer otro esfuerzo adicional al momento de configurar nuestras aplicaciones web.<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=Yrq3N6fQZLQ:BELUhFmblqY:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Yrq3N6fQZLQ:BELUhFmblqY:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Yrq3N6fQZLQ:BELUhFmblqY:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=Yrq3N6fQZLQ:BELUhFmblqY:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Yrq3N6fQZLQ:BELUhFmblqY:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=Yrq3N6fQZLQ:BELUhFmblqY:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Yrq3N6fQZLQ:BELUhFmblqY:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Yrq3N6fQZLQ:BELUhFmblqY:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Yrq3N6fQZLQ:BELUhFmblqY:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=Yrq3N6fQZLQ:BELUhFmblqY:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Yrq3N6fQZLQ:BELUhFmblqY:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Yrq3N6fQZLQ:BELUhFmblqY:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=Yrq3N6fQZLQ:BELUhFmblqY:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Yrq3N6fQZLQ:BELUhFmblqY:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/Yrq3N6fQZLQ" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2020/160-features.png" alt="Features">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Features</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">07 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2020/160-features.png" alt="Features" title="Learn about Monkeyuser's 10 years tech debt repayment plan" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="“Si no te preocupas por las plantas, es posible que no sepas cuidar de otro ser humano”">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">“Si no te preocupas por las plantas, es posible que no sepas cuidar de otro ser humano”</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">06 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Cada año, 2.100 especies de plantas fascinan a las 250.000 personas que visitan el jardín botánico de la Universidad de Harvard en Boston. Su director confiesa que el mundo vegetal nunca dejará de sorprenderle
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="El yaguareté regresa al chaco argentino">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">El yaguareté regresa al chaco argentino</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">06 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A 70 años del avistamiento del último ejemplar, la Fundación Rewilding Argentina ultima la reinserción de cinco ejemplares en los Esteros del Iberá
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Localizado el estallido de radio más cercano a la Tierra">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Localizado el estallido de radio más cercano a la Tierra</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">06 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Este descubrimiento revoluciona las hipótesis que se tenían sobre el origen de estas señales
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="El ADN en el lugar del crimen se chiva del origen del asesino y de su color de piel, de ojos y de pelo">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">El ADN en el lugar del crimen se chiva del origen del asesino y de su color de piel, de ojos y de pelo</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">05 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Una comisión del Ministerio de Justicia alerta del vacío legal que rodea a las nuevas técnicas de análisis genético
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="2020: invasión en Marte">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">2020: invasión en Marte</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">05 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Las grandes potencias espaciales compiten para ser las primeras en encontrar indicios de vida en el planeta rojo
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Friend of a Friend: The Facebook That Could Have Been</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Two-Bit History</a> <span class="article__date">05 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The FOAF standard, or Friend of a Friend standard, is a now largely defunct/ignored/superseded web standard dating from the early 2000s that hints at what social networking might have looked like had Facebook not conquered the world. Before we talk about FOAF though, I want to talk about the New York City Subway.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Dionisio el Exiguo">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Dionisio el Exiguo</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">04 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ¿Qué tiene de especial el 2020? ¿Ha empezado una nueva década el 1 de enero de este año?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Feliz 2070">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Feliz 2070</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">03 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Para esa fecha sabremos si estamos solos en el cosmos, según un cazador de mundos
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="La física matemática que probó que el futuro del universo está bien definido">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">La física matemática que probó que el futuro del universo está bien definido</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">03 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Yvonne Choquet-Bruhat, que acaba de cumplir 96 años, encontró solución al llamado problema de Cauchy para las ecuaciones de Einstein de vacío
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="El mensaje galáctico">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">El mensaje galáctico</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">03 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        En unas placas agregadas a las sondas espaciales 'Pioneer' se indica nuestra posición en el universo, así como nuestro aspecto físico
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ondahostil.files.wordpress.com/2018/08/yo.jpg?w=32" alt="En qué ando: diciembre">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">En qué ando: diciembre</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Onda Hostil</a> <span class="article__date">01 01 2020</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Diciembre ha sido un mes raro. Muy raro. He publicado dos papers (cubriendo mis obligaciones académicas para este año y el próximo), he acabado mis últimas clases programadas y se ha terminado el seminario de Ingeniería Sin Fronteras. He podido volver a pintar después de un terrible bloqueo artístico y he trabajado en la huerta. [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">November/December 2019 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">31 12 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        November was the first month of our next funding round. libpython-clj and Deep Diamond started in November, Expound started in December, and Oz is starting in January. This is a combined update due to the holiday break.

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://dannyvankooten.com/media/2019/slovenia-climbing.jpg" alt="Personal goals for 2020">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Personal goals for 2020</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Danny van Kooten</a> <span class="article__date">30 12 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>My last blog post where I defined <a href="https://dannyvankooten.com/goals-for-2013/">goals for the upcoming year was back in 2013</a>.</p>

<p>It’s fun to go through that post. In a way I feel some shame of where I was back then (which is silly, but I feel it nonetheless). At the same time it’s a testament of how far I’ve come, so there is some proud as well.</p>

<p>Since this will be another post in which I will be defining my goals for the upcoming year, I hope to be looking at this post a few years from now with the same mix of feelings.</p>

<p>For the last few years I have been drifting, just taking life as it happened. Caring for my daughter (now daughters!), keeping <a href="https://ibericode.com/">the business</a> running, trying to stay healthy while attempting to enjoy life at the same time.</p>

<p>But I miss having clear and measurable goals. I like the feeling of moving closer to a set target each and every day, even if just a tiny bit. That’s why I came up with this list of what I would like to achieve in 2020.</p>

<hr />

<h3 id="hire-a-wordpress-developer">Hire a WordPress developer</h3>

<p>I’ve postponed this for years, only hiring to help reduce the burden of daily support.</p>

<p>Despite it being justified financially to bring on another WordPress developer to help me out with more advanced support questions and possibly some development, I’ve yet to take the plunge.</p>

<p>For 7 straight years I have been answering emails for the <a href="https://www.mc4wp.com/">Mailchimp for WordPress plugin</a> each and every day, with at most 48 hours of rest in between. This has certainly taken its toll, so I would like to get some help in this area or alternatively sell off the product in its entirety.</p>

<h3 id="learn-rust">Learn Rust</h3>

<p>After learning Go (and open-sourcing <a href="https://dannyvankooten.com/chrome-extension-for-pass/">Browserpass</a>) in 2016 and some C in 2019, I would like to gain a basic understanding of Rust in 2020.</p>

<p>This goal is a little vague as it is, so I will need to rephrase this goal by setting out to create a specific tool in Rust instead. More on that later.</p>

<h3 id="lead-climb-in-nature">Lead climb in nature</h3>

<p>In the spring of 2020 I will be taking lessons in lead climbing. The plan is to use our summer holiday to go lead climbing in nature. Slovenia is tempting, but I am not sure whether we are ready to make the 12-hour drive with 2 young kids aboard.</p>

<p>There are so many spots in Europe to go lead climbing that finding a beautiful place closer to home shouldn’t be an issue though.</p>

<p><img src="https://dannyvankooten.com/media/2019/slovenia-climbing.jpg" alt="Climbing in Bled, Slovenia" /></p>

<h3 id="send-a-bouldering-route-graded-6c-v6">Send a bouldering route graded 6C (V6)</h3>

<p>Another climbing related goal is to send an indoor bouldering route graded 6C. After just a few months of climbing I’m currently climbing 6B on a good day, so this should not be an issue if I put in consistent sessions and do not injure myself.</p>

<h3 id="get-my-chess-elo-rating-up-to-1600">Get my chess ELO rating up to 1600</h3>

<p>I have been slacking when it comes to chess lately, not playing any games at all for months. Perhaps having a clear goal will help.</p>

<p>My current ELO rating is about 1400, I would like to get this up to 1600 in 2020.</p>

<h3 id="not-buying-a-new-laptop">Not buying a new laptop</h3>

<p>My current laptop is a 2013 Macbook Pro, which is still running great. Despite that I have been feeling the urge to replace it lately, even though <a href="https://dannyvankooten.com/2016-year-in-review/#switched-back-to-linux">it is not even my daily driver</a>.</p>

<p>I gave in to the urge last month and bought a Dell XPS 15”, only to return it a week later because I realised it was an unnecessary purchase. So for 2020 (and beyond) the goal is to hold on to the Macbook Pro until it literally falls apart.</p>

<hr />

<p>If you’re still reading this far (and even if not), here’s to a wonderful 2020 for you and your loved ones.</p>

<p><a href="https://twitter.com/dannyvankooten">Send me a tweet</a> if you have written goals you would like me to remind you of as the year progresses, it would be good to keep each other accountable!</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Las Chimp Sisters">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Las Chimp Sisters</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">28 12 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        La danza de dos hembras chimpancés aporta un nuevo respiro a la brusquedad de la evolución humana
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Buscar fósiles humanos, ¿y eso para qué sirve?">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Buscar fósiles humanos, ¿y eso para qué sirve?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">28 12 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        El director de una investigación en Guinea para buscar el origen del bipedismo explica que buscan "saber dónde y cómo se produjo la transformación de los simios que dejaron paulatinamente la vida en los árboles"
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="¿Cómo se define la inteligencia en los seres vivos?">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">¿Cómo se define la inteligencia en los seres vivos?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">26 12 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        La definición de 'inteligencia' es esquiva pero incluye cosas como el uso de herramientas para modificar el entorno o el uso del lenguaje
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="Campana sobre campana (matemática)">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Campana sobre campana (matemática)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">23 12 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        El arte de tocar campanas anticipó la teoría de grupos, una disciplina matemática de gran importancia en la investigación actual
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Nuestros ganadores y perdedores del mundo web en 2020">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Nuestros ganadores y perdedores del mundo web en 2020</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">21 12 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Para finalizar el año proponemos un episodio clásico sobre tendencias para el año que entra. En esta ocasión en lugar de hacer un recorrido por las principales tendencias, vamos a hacerlo colocando a una tecnología en auge en relación a una que, por los motivos que sean, se encuentre en declive o en bajada. Cada uno de nosotros ha preparado una clasificación en dos categorías: ganadores y perdedores.</p>
<table style="margin-top:30px;margin-bottom:30px">
<thead>
<tr>
<th>
? Winners
</th>
<th>
? Losers
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
Python / Adobe
</td>
<td>
AMP
</td>
</tr>
<tr>
<td>
Infraestructura Cloud
</td>
<td>
Regulación de acceso a internet y privacidad
</td>
</tr>
<tr>
<td>
HTTP3 / Microservicios
</td>
<td>
MySQL / Chrome
</td>
</tr>
</tbody>
</table>
<h2>Personajes del año 2019 en la web</h2>
<p>En la segunda parte del programa destacaremos a los que para nosotros han sido los personajes del año, para lo bueno y para lo malo en esto del mundo de la web y de internet. </p>
<table style="margin-top:30px;margin-bottom:30px">
<thead>
<tr>
<th>
? Héroes del 2019
</th>
<th>
? Villanos
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
Guido Van Rossum
</td>
<td>
Project Manager de Safari
</td>
</tr>
<tr>
<td>
Quincy Larson
</td>
<td>
Mark Zuckerberg
</td>
</tr>
<tr>
<td>
Fernando Acero y Rasmus Lerdorf
</td>
<td>
Project Managers de IE6/Edge
</td>
</tr>
</tbody>
</table>
<p>Seguro que muchos tenéis vuestra propia lista de ganadores y perdedores para el 2019. Nos encantará conocerla y que la compartáis con nosotros. </p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Finding your first remote job</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">19 12 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        As remote work becomes increasingly popular, I am frequently asked how to get started. This article shares everything I know about landing that first remote gig.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://republicaweb.es/wp-content/uploads/2021/01/republica-web-cover-2000x2000-1.jpg" alt="Estudio de David Vaquero sobre tecnologías que más se usan en la web">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Estudio de David Vaquero sobre tecnologías que más se usan en la web</h1>
                            <h2 class="article__feed"><a target="_blank" href="">República Web</a> <span class="article__date">14 12 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Dedicamos este episodio a discutir sobre las tecnologías que triunfan en internet, y en especial hacerlo en el mundo del desarrollo web. Son muchas las tecnologías que están de moda, tanto en los eventos, como en la mayor parte de las empresas tecnológicas. Por eso nos gustaría hablar sobre cuál es la situación actual de la utilización de las tecnologías que se utilizan a día de hoy para que seamos conscientes de uso real en los principales sitios de internet. </p>
<p>Para ello nuestro compañero David ha estado realizando un extenso estudio <a href="https://cursosdedesarrollo.com/2019/12/estudio-de-uso-de-tecnologias-en-el-millon-de-paginas-mas-vistas-segun-alexa/" rel="noopener noreferrer" target="_blank">(datos disponibles en su sitio web)</a> durante el último mes, utilizando la base de los principales sitios web según Alexa, en el que analiza hasta 1.400.000 sitios web para saber qué tecnologías utilizan. En este episodio del podcast David nos explica la metodología que ha usado en su estudio, las herramientas usadas y cómo ha organizado la información en su informe.</p>
<p>En el episodio hablamos de tecnologías consolidadas, pero también nos han sorprendido ciertas librerías y tecnologías. Al final se trata un episodio de análisis de tecnologías web y su influencia en nuestro trabajo.</p>
<p><a href="https://republicaweb.es">Visita la web del podcast</a> donde encontrarás los enlaces de interés discutidos en el episodio. Estaremos encantados de recibir vuestros comentarios y reacciones.</p>
<p>Nos podéis encontrar en:</p>
<ul>
<li><a href="https://republicaweb.es">Web: republicaweb.es</a></li>
<li><a href="https://t.me/republicaweb">Canal Telegram: t.me/republicaweb</a></li>
<li><a href="https://t.me/joinchat/AMQL6U88Wo9ru3O2e9ctjQ">Grupo Telegram Malditos Webmasters</a></li>
<li><a href="https://twitter.com/republicawebes">Twitter: @republicawebes</a></li>
<li><a href="https://www.facebook.com/republicaweb">Facebook: https://www.facebook.com/republicaweb</a></li>
</ul>
<p>¡Contribuye a este podcast!. A través de la plataforma <a href="https://www.buymeacoffee.com/republicaweb">Buy me a coffee puedes realizar una mínima aportación</a> desde 3€ que ayude a sostener a este podcast. Tú eliges el importe y si deseas un pago único o recurrente. ¡Muchas gracias!</p>
<ul>
<li><a href="https://javierarcheni.com">Sitio web de Javier Archeni: https://javierarcheni.com</a></li>
<li><a href="https://programadorwebvalencia.com<">Sitio web de Andros Fenollosa https://programadorwebvalencia.com</a></li>
<li><a href="https://cursosdedesarrollo.com">Sitio web de David Vaquero https://cursosdedesarrollo.com</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">October 2019 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">06 12 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        October was our third and final month with this round of projects, check out their monthly update!

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="La cara y la cruz nutricional del café en cápsulas">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">La cara y la cruz nutricional del café en cápsulas</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">04 12 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Son iguales por fuera, pero nutricionalmente diferentes por dentro
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">My experience as a remote worker</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">02 12 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I've spent half of my career working remotely. This post chronicles those experiences, giving a real-world window into what it's like to work fully-remote as a software engineer.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://images.ponyfoo.com/uploads/Inside_Ad-087fe92d9d1b4ccca2dee1a78810a3ef.png" alt="ESM goes GA in Node 13.2.0, React Fiber, React Native, Expert Advice, CSS Architecture, &amp; Lighthouse! 🛰  — Pony Foo Weekly">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">ESM goes GA in Node 13.2.0, React Fiber, React Native, Expert Advice, CSS Architecture, &amp; Lighthouse! 🛰  — Pony Foo Weekly</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Pony Foo Weekly</a> <span class="article__date">28 11 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="f-core"><div class="md-markdown"><p>We&#x2019;re glad you could make it this week! </p> <p>With your help, we can make Pony Foo Weekly <em>even more</em> awesome: <a href="https://ponyfoo.com/weekly/submissions?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" target="_blank" rel="noopener noreferrer">send tips about cool resources</a>.</p> </div><div class="wy-section-header"><h3 class="md-markdown" style="color:#fcfcfc;background-color:#ff895c;padding:10px"><div>ECMAScript Modules! </div> </h3></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://medium.com/@nodejs/announcing-core-node-js-support-for-ecmascript-modules-c5d6dc29b663?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" style="color:#ff895c;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Node.js support for ESM goes GA</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/news" style="color:#1bc211;background-color:#e4f9e3" class="wy-link-tag">News</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Node.js 13.2.0 ships support for <a href="https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" target="_blank" rel="noopener noreferrer">ECMAScript modules</a>, known for their <code class="md-code md-code-inline">import</code> and <code class="md-code md-code-inline">export</code> statements. This support was previously behind the<code class="md-code md-code-inline">--experimental-module</code> flag, which is no longer required; however the implementation remains experimental and subject to change.</p> </div></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://github.com/billinghamj/fix-es-imports?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" style="color:#ff895c;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p><code>billinghamj/fix-es-imports</code></p> </a><a href="https://ponyfoo.com/weekly/links/tagged/code" style="color:#1a4d7f;background-color:#ffe270" class="wy-link-tag">Code</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Fixes your ES <code class="md-code md-code-inline">import</code> paths: from Node-style to explicit filenames.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/oolon?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>James Billingham</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-primary"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="http://go.tech/ponyfoo?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" style="color:#ff895c;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>.TECH Domain Black Friday Sale <strong>90% OFF!</strong></p> </a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>.TECH is the most definitive domain extension for the tech industry with the likes of Intel, CES and Viacom using it. Get your .TECH domain at 90% off this Black Friday and secure your online tech identity!</p> <p><a href="http://go.tech/ponyfoo?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" target="_blank" rel="noopener noreferrer">Buy Now</a> </p> </div></div><div class="wy-link-source-section"><a href="http://go.tech/ponyfoo?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>.TECH Domains</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/sponsored" class="wy-link-tag wy-link-sponsor">Sponsored</a></div></td><td class="wy-td wy-link-cell-image"><a href="http://go.tech/ponyfoo?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://images.ponyfoo.com/uploads/Inside_Ad-087fe92d9d1b4ccca2dee1a78810a3ef.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-header"><h3 class="md-markdown" style="color:#fcfcfc;background-color:#7d5cff;padding:10px"><div>Just React Things </div> </h3></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://pomb.us/build-your-own-react/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Build your Own React</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/deep-dive" style="color:#f7f0f5;background-color:#900070" class="wy-link-tag">Deep Dive</a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Learn how to rewrite React from scratch. Step by step. Following the architecture from the real React code but without all the whipped cream on top!</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/pomber?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Rodrigo Pombo</p> </a></div></td><td class="wy-td wy-link-cell-image"><a href="https://pomb.us/build-your-own-react/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://pomb.us/static/b4694e6041953e3cb16f6a889f0cbc59/25036/card.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-secondary"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://wallabyjs.com/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Wallaby</p> </a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Smart and fast integrated continuous test runner for JavaScript, TypeScript, CoffeeScript. It enables continuous testing, TDD and BDD with instant feedback and code coverage in your code editor.</p> </div></div><div class="wy-link-source-section"><span class="wy-link-source wy-link-source-plain md-markdown md-markdown-inline"><p>Wallaby.js</p> </span><a href="https://ponyfoo.com/weekly/links/tagged/sponsored" class="wy-link-tag wy-link-sponsor">Sponsored</a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://blog.logrocket.com/deep-dive-into-react-fiber-internals/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Deep dive into React Fiber internals</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/deep-dive" style="color:#f7f0f5;background-color:#900070" class="wy-link-tag">Deep Dive</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Since version 16, React has built the DOM tree with an algorithm called Fiber. To better grasp how it works, we explain exactly what goes on under the hood.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/karthikkalyan90?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Karthik Kalyanaraman</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://www.telerik.com/kendo-react-ui/react-best-practices-and-productivity-tips/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Expert Tips for React Productivity</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/best-practices" style="color:#900070;background-color:#ffe270" class="wy-link-tag">Best Practices</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>25 excellent productivity tips for React developers from 25 React and JavaScript experts &#x2013; dive in and enjoy!</p> </div></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-secondary"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://tinyurl.com/yeeee4st?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Developer Economics</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/survey" class="wy-link-tag">survey</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Developers, speak out! Take the survey and you can win amazing prizes: Surface Pro 6, iPhone 11, Chromebook 3, lots of dev swag and vouchers. Plus, you can earn up to $1,000 in cash through our referral program. Start here and tell us your opinion on tools you work with every day.</p> </div></div><div class="wy-link-source-section"><a href="https://ponyfoo.com/weekly/links/tagged/sponsored" class="wy-link-tag wy-link-sponsor">Sponsored</a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://medium.com/walmartlabs/a-new-beginning-for-react-native-at-walmartlabs-online-grocery-c30b27db57d3?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>React Native at Walmart</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/deep-dive" style="color:#f7f0f5;background-color:#900070" class="wy-link-tag">Deep Dive</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><blockquote> <p><em>&#x201C;Almost two years ago we launched our first React Native page, now we&#x2019;re close to having 90% of our Walmart Grocery App pages powered by RN.&#x201D;</em></p> </blockquote> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/anders462?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Anders Bengtsson</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-header"><h3 class="md-markdown" style="color:#fcfcfc;background-color:#3aca96;padding:10px"><div><code class="md-code md-code-inline">...rest</code> </div> </h3></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://medium.com/javascript-in-plain-english/i-created-the-exact-same-app-in-react-and-svelte-here-are-the-differences-c0bd2cc9b3f8?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" style="color:#3aca96;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Differences Writing an App in React and Svelte</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/deep-dive" style="color:#f7f0f5;background-color:#900070" class="wy-link-tag">Deep Dive</a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>A side-by-side code comparison of React vs Svelte.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/sunilsandhu?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Sunil Sandhu</p> </a></div></td><td class="wy-td wy-link-cell-image"><a href="https://medium.com/javascript-in-plain-english/i-created-the-exact-same-app-in-react-and-svelte-here-are-the-differences-c0bd2cc9b3f8?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://miro.medium.com/max/1200/1*9polCAouiiVgAEHpR2JKSA.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://engineering.q42.nl/making-a-lighthouse-plugin-work-with-lighthouse-ci?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" style="color:#3aca96;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Making a Lighthouse Plugin work with Lighthouse CI</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/tutorial" style="color:#5aa9bc;background-color:#333" class="wy-link-tag">Tutorial</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Learn how to do your custom page audits in GitHub Actions with Lighthouse CI.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/roelfjandevries?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Roelf-Jan de Vries</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://www.madebymike.com.au/writing/css-architecture-for-modern-web-applications/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" style="color:#3aca96;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>CSS Architecture for Modern JavaScript Applications</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/deep-dive" style="color:#f7f0f5;background-color:#900070" class="wy-link-tag">Deep Dive</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>An attempt to modernize CSS architecture and how to apply best practices in the context of modern JavaScript applications.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/MikeRiethmuller?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Mike Riethmuller</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://medium.com/javascript-in-plain-english/javascript-doesnt-need-to-be-replaced-bd01e2f12d51?source=friends_link&#38;sk=7b151cc6397ac9e83c14c99739b6c36f&#38;utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" style="color:#3aca96;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>JavaScript doesn&#x2019;t need to be replaced</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/point-of-view" style="color:#f3720d;background-color:#ffeada" class="wy-link-tag">Point of View</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Every now and then developers call for a replacement of JavaScript. But this is no solution, as other languages will face the same issues because of the Web&#x2019;s most important design principle: <a href="https://ponyfoo.com/articles/stop-breaking-the-web?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189">Don&#x2019;t break the web</a>.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/dannymoerkerke?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-189" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Danny Moerkerke</p> </a></div></td></tr></table></td></tr></table></div></div><style>html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;position:relative;vertical-align:baseline}sup{top:-.5em}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto;resize:vertical;min-height:280px;max-height:900px}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item;margin:-10px -20px;padding:10px;background-color:#f6f6f6;cursor:pointer;border-bottom:2px solid #ddd}[hidden],template{display:none}body,body:after,body:before,html,html:after,html:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*,:after,:before{-webkit-box-sizing:inherit;-moz-box-sizing:inherit;box-sizing:inherit}@-moz-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-webkit-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-o-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-moz-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@-webkit-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@-o-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}.f-core{font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}.f-mono{font-family:Consolas,Menlo,Monaco,'Lucida Console','Liberation Mono','DejaVu Sans Mono','Bitstream Vera Sans Mono','Courier New',monospace,serif}.ly-custom-heading .f-heading,.ly-custom-heading h1,.ly-custom-heading h2,.ly-custom-heading h3,.ly-custom-heading h4,.ly-custom-heading h5,.ly-custom-heading h6,.ly-lean .f-heading,.ly-lean h1,.ly-lean h2,.ly-lean h3,.ly-lean h4,.ly-lean h5,.ly-lean h6{font-family:Neuton,'Hoefler Text',Palatino,Baskerville,Georgia,'Times New Roman',serif}.ly-custom-subheading .f-subheading,.ly-lean .f-subheading{font-family:Merriweather,Georgia,serif}body{margin:0;font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif;background:#fcfcfc;color:#333}img{max-width:100%;border:none}.md-markdown figure:not(.twitter-tweet-figure){background-color:#f6f6f6}.md-markdown figure:not(.twitter-tweet-figure)>a{display:block}.md-markdown figure:not(.twitter-tweet-figure)>a>img,.md-markdown figure:not(.twitter-tweet-figure)>img{display:block;margin-left:auto;margin-right:auto}.md-markdown figcaption{padding:10px;font-style:italic;font-size:14px;background:-webkit-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-moz-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-o-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-ms-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:linear-gradient(to right,#fff9e2 33%,#fcf9ee 100%);color:#555}.md-markdown .figure-has-loaded{background:-webkit-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-moz-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-o-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-ms-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:linear-gradient(to bottom,rgba(255,255,255,0) 0,#fcf9ee 100%)}b,em,font-style italic,font-weight bold,i,ins,strong{text-decoration:none}del{text-decoration:line-through}sub,sup{bottom:0;line-height:18px}button,input{overflow:visible;border-radius:0}button{border:none;padding:6px 8px;font-size:1.2em;background:0 0}button[disabled]{color:#cbccbc!important}input,select,textarea{display:block;width:100%;padding:10px 8px;line-height:18px;border:none;font:inherit}select{height:38px}ol,ul{padding:0;margin:0;list-style-position:inside}li>ol,li>ul{margin-left:20px}hr{border:none;border-top:5px solid rgba(0,0,0,.05);margin:20px 0}kbd{display:inline-block;border:1px solid #ccc;margin:0 .1em;padding:.1em .6em;line-height:1.4;font-size:11px;background-color:#f7f7f7;-webkit-box-shadow:0 1px 0 #bbb,0 0 0 2px #fff inset;box-shadow:0 1px 0 #bbb,0 0 0 2px #fff inset;border-radius:3px;color:#333;text-shadow:0 1px 0 #fff;white-space:nowrap}iframe{display:inline-block;border:none;max-width:100%}summary:hover{opacity:.8}details{padding:10px 20px 20px;border-bottom:2px dashed #ddd}details[open] summary{margin-bottom:20px}blockquote{border:none;margin:0!important}ol,p,ul{line-height:35px}p{margin:35px 0}@media only screen and (min-width:768px){ol,p,ul{line-height:30px}}a,button,input[type=submit]{cursor:pointer;text-decoration:none}.lk-link{color:#e92c6c;border-bottom:1px solid transparent;background-color:rgba(255,255,255,.04)}.lk-link .md-code-inline{position:relative}.lk-link .md-code-inline:only-child{display:inline-block;line-height:17px}.lk-link .md-code-inline:before{content:'';position:absolute;background-color:#f1e05a;top:0;left:0;right:0;bottom:0;opacity:.04}.lk-link:visited{background-color:rgba(233,44,108,.04)}.lk-link:visited .md-code-inline:before{background-color:#e92c6c}.lk-link:hover{border-bottom:1px solid #e92c6c}.lk-rainbows{position:relative;color:#333;margin-bottom:5px}.lk-rainbows:hover:before{position:absolute;content:'';left:0;right:0;bottom:-8px;height:3px;opacity:.8;-webkit-transition:.1s ease-in-out;-moz-transition:.1s ease-in-out;-o-transition:.1s ease-in-out;-ms-transition:all .1s ease-in-out;transition:.1s ease-in-out;-webkit-animation:.5s infinite bg-rainbow;-moz-animation:.5s infinite bg-rainbow;-o-animation:.5s infinite bg-rainbow;-ms-animation:bg-rainbow .5s infinite;animation:.5s infinite bg-rainbow}.lk-icon{color:#333}.lk-icon:hover{color:#e92c6c}.lk-visitor{color:#333}.lk-visitor:after{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-left:5px}.lk-visitor.lk-visitor-large:after{font-size:1em}.lk-visitor:hover:after{color:#333;border-bottom-style:solid}.lk-visitor:visited:after{color:#7d5cff}.lk-visitor-inside{color:#333}.lk-visitor-inside .lk-visitor-target:before{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-right:5px}.lk-visitor-inside.lk-visitor-large .lk-visitor-target:before{font-size:1em}.lk-visitor-inside:hover .lk-visitor-target:before{color:#333;border-bottom-style:solid}.lk-visitor-inside:visited .lk-visitor-target:before{color:#7d5cff}.lk-visitor-before{color:#333}.lk-visitor-before:before{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-right:5px}.lk-visitor-before.lk-visitor-large:before{font-size:1em}.lk-visitor-before:hover:before{color:#333;border-bottom-style:solid}.lk-visitor-before:visited:before{color:#7d5cff}.lk-visitor-before-no-underline:before{border-bottom-width:0}.lk-link-to-green{color:#cbccbc}.lk-link-to-green:visited,.lk-link-to-green:visited:before{color:#1bc211;background-color:#1bc211}.lk-link-to-green:active{outline-color:#1bc211}.lk-link-to-green:hover,.lk-link-to-green:hover:before{color:#8be186;border-bottom-color:#1bc211}.lk-green .lk-link,a.lk-green{color:#1bc211}.lk-green .lk-link:visited,a.lk-green:visited{background-color:rgba(27,194,17,.04)}.lk-green .lk-link:visited .md-code-inline:before,a.lk-green:visited .md-code-inline:before{background-color:#1bc211}.lk-green .lk-link:active,a.lk-green:active{outline-color:#1bc211}.lk-green .lk-link:hover,a.lk-green:hover{border-bottom-color:#1bc211}.lk-green.lk-icon:hover{color:#1bc211}.lk-pink-light .lk-link,a.lk-pink-light{color:#ea6c93}.lk-pink-light .lk-link:visited,a.lk-pink-light:visited{background-color:rgba(234,108,147,.04)}.lk-pink-light .lk-link:visited .md-code-inline:before,a.lk-pink-light:visited .md-code-inline:before{background-color:#ea6c93}.lk-pink-light .lk-link:active,a.lk-pink-light:active{outline-color:#ea6c93}.lk-pink-light .lk-link:hover,a.lk-pink-light:hover{border-bottom-color:#ea6c93}.lk-pink-light.lk-icon:hover{color:#ea6c93}.lk-black .lk-link,a.lk-black{color:#333}.lk-black .lk-link:visited,a.lk-black:visited{background-color:rgba(51,51,51,.04)}.lk-black .lk-link:visited .md-code-inline:before,a.lk-black:visited .md-code-inline:before{background-color:#333}.lk-black .lk-link:active,a.lk-black:active{outline-color:#333}.lk-black .lk-link:hover,a.lk-black:hover{border-bottom-color:#333}.lk-black.lk-icon:hover{color:#333}.lk-gray .lk-link,a.lk-gray{color:#999}.lk-gray .lk-link:visited,a.lk-gray:visited{background-color:rgba(153,153,153,.04)}.lk-gray .lk-link:visited .md-code-inline:before,a.lk-gray:visited .md-code-inline:before{background-color:#999}.lk-gray .lk-link:active,a.lk-gray:active{outline-color:#999}.lk-gray .lk-link:hover,a.lk-gray:hover{border-bottom-color:#999}.lk-gray.lk-icon:hover{color:#999}.lk-white .lk-link,a.lk-white{color:#fcfcfc}.lk-white .lk-link:visited,a.lk-white:visited{background-color:rgba(252,252,252,.04)}.lk-white .lk-link:visited .md-code-inline:before,a.lk-white:visited .md-code-inline:before{background-color:#fcfcfc}.lk-white .lk-link:active,a.lk-white:active{outline-color:#fcfcfc}.lk-white .lk-link:hover,a.lk-white:hover{border-bottom-color:#fcfcfc}.lk-white.lk-icon:hover{color:#fcfcfc}.lk-orange .lk-link,a.lk-orange{color:#f3720d}.lk-orange .lk-link:visited,a.lk-orange:visited{background-color:rgba(243,114,13,.04)}.lk-orange .lk-link:visited .md-code-inline:before,a.lk-orange:visited .md-code-inline:before{background-color:#f3720d}.lk-orange .lk-link:active,a.lk-orange:active{outline-color:#f3720d}.lk-orange .lk-link:hover,a.lk-orange:hover{border-bottom-color:#f3720d}.lk-orange.lk-icon:hover{color:#f3720d}.lk-lilly .lk-link,a.lk-lilly{color:#7d5cff}.lk-lilly .lk-link:visited,a.lk-lilly:visited{background-color:rgba(125,92,255,.04)}.lk-lilly .lk-link:visited .md-code-inline:before,a.lk-lilly:visited .md-code-inline:before{background-color:#7d5cff}.lk-lilly .lk-link:active,a.lk-lilly:active{outline-color:#7d5cff}.lk-lilly .lk-link:hover,a.lk-lilly:hover{border-bottom-color:#7d5cff}.lk-lilly.lk-icon:hover{color:#7d5cff}.lk-blue .lk-link,a.lk-blue{color:#1a4d7f}.lk-blue .lk-link:visited,a.lk-blue:visited{background-color:rgba(26,77,127,.04)}.lk-blue .lk-link:visited .md-code-inline:before,a.lk-blue:visited .md-code-inline:before{background-color:#1a4d7f}.lk-blue .lk-link:active,a.lk-blue:active{outline-color:#1a4d7f}.lk-blue .lk-link:hover,a.lk-blue:hover{border-bottom-color:#1a4d7f}.lk-blue.lk-icon:hover{color:#1a4d7f}.lk-inherited .lk-link,a.lk-inherited{color:inherit}.lk-inherited .lk-link:active,a.lk-inherited:active{outline-color:inherit}.lk-inherited .lk-link:hover,a.lk-inherited:hover{border-bottom-color:inherit}.lk-inherited.lk-icon:hover{color:inherit}.lk-twitter .lk-link,a.lk-twitter{color:#55acee}.lk-twitter .lk-link:visited,a.lk-twitter:visited{background-color:rgba(85,172,238,.04)}.lk-twitter .lk-link:visited .md-code-inline:before,a.lk-twitter:visited .md-code-inline:before{background-color:#55acee}.lk-twitter .lk-link:active,a.lk-twitter:active{outline-color:#55acee}.lk-twitter .lk-link:hover,a.lk-twitter:hover{border-bottom-color:#55acee}.lk-twitter.lk-icon:hover{color:#55acee}.lk-facebook .lk-link,a.lk-facebook{color:#3b5998}.lk-facebook .lk-link:visited,a.lk-facebook:visited{background-color:rgba(59,89,152,.04)}.lk-facebook .lk-link:visited .md-code-inline:before,a.lk-facebook:visited .md-code-inline:before{background-color:#3b5998}.lk-facebook .lk-link:active,a.lk-facebook:active{outline-color:#3b5998}.lk-facebook .lk-link:hover,a.lk-facebook:hover{border-bottom-color:#3b5998}.lk-facebook.lk-icon:hover{color:#3b5998}.lk-clean{background-color:transparent}.lk-chrome:hover{color:#4989f4}.lk-teal .lk-link,a.lk-teal{color:#00a19c}.lk-teal .lk-link:visited,a.lk-teal:visited{background-color:rgba(0,161,156,.04)}.lk-teal .lk-link:visited .md-code-inline:before,a.lk-teal:visited .md-code-inline:before{background-color:#00a19c}.lk-teal .lk-link:active,a.lk-teal:active{outline-color:#00a19c}.lk-teal .lk-link:hover,a.lk-teal:hover{border-bottom-color:#00a19c}.lk-teal.lk-icon:hover{color:#00a19c}table{width:100%;border-spacing:0;border-collapse:separate}td,th{padding:8px}@media only screen and (max-width:950px){.table-responsive{display:block}.table-responsive>thead{display:none}.table-responsive>tbody,.table-responsive>tfoot{display:block}.table-responsive>tbody>tr,.table-responsive>tfoot>tr{display:block;background-color:rgba(203,204,188,.1);margin-bottom:30px}.table-responsive>tbody>tr:nth-child(even),.table-responsive>tfoot>tr:nth-child(even){background-color:rgba(203,204,188,.15)}.table-responsive>tbody>tr:last-child,.table-responsive>tfoot>tr:last-child{margin-bottom:0}.table-responsive>tbody>tr>td,.table-responsive>tfoot>tr>td{display:block;text-align:left}.table-responsive>tbody>tr>td:before,.table-responsive>tfoot>tr>td:before{display:block;content:attr(data-label);color:#555;font-size:13px;margin:0 0 5px}.table-responsive .table-responsive-hide{display:none}}.c-oreilly-teal{color:#00a19c}.c-yellow-highlight{color:#ffe270}.c-dark-orange{color:#f3720d}.c-pink{color:#e92c6c}.c-purple{color:#900070}.c-blue{color:#1a4d7f}.c-dark-turquoise{color:#1686a2}.c-dark-green{color:#1bc211}.c-white{color:#fcfcfc}.c-gray{color:#b7b7b7}.c-lilly{color:#7d5cff}.c-teal{color:#3aca96}.c-bg-oreilly-teal{background-color:#00a19c}.c-bg-yellow-highlight{background-color:#ffe270}.c-bg-dark-orange{background-color:#f3720d}.c-bg-pink{background-color:#e92c6c}.c-bg-purple{background-color:#900070}.c-bg-blue{background-color:#1a4d7f}.c-bg-dark-turquoise{background-color:#1686a2}.c-bg-dark-green{background-color:#1bc211}.c-bg-white{background-color:#fcfcfc}.c-bg-gray{background-color:#b7b7b7}.c-bg-lilly{background-color:#7d5cff}.c-bg-teal{background-color:#3aca96}.tj-emoji{width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em}.dc-header{margin-bottom:60px}.dc-heading{text-align:center;font-size:4em;padding:0 10px;margin-top:0;margin-bottom:10px}.dc-role{line-height:26px;padding:0 20px;margin-top:10px;text-align:center;font-style:italic;color:#cbccbc}.dc-colored{background:#f6f6f6;border-top:9px solid rgba(125,92,255,.5)}.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:800px}.md-markdown blockquote:not(.twitter-tweet){margin:0;padding:20px 0;border:none;border-top:5px solid rgba(0,0,0,.05);border-bottom:5px solid rgba(0,0,0,.05)}.md-markdown blockquote:not(.twitter-tweet) h1,.md-markdown blockquote:not(.twitter-tweet) h2,.md-markdown blockquote:not(.twitter-tweet) h3,.md-markdown blockquote:not(.twitter-tweet) h4,.md-markdown blockquote:not(.twitter-tweet) h5,.md-markdown blockquote:not(.twitter-tweet) h6{margin:-20px 0;padding:20px 0}.md-markdown blockquote:not(.twitter-tweet) .md-code-block{margin:0}.md-markdown blockquote:not(.twitter-tweet) .md-code-block:last-child{margin-bottom:-20px}.md-markdown img:first-child{margin-top:0}.md-markdown img:last-child{margin-bottom:0}.md-markdown p:first-child{margin-top:0}.md-markdown p:last-child{margin-bottom:0}.md-markdown .md-code-block+ol,.md-markdown .md-code-block+ul,.md-markdown ol+.md-code-block,.md-markdown ul+.md-code-block{margin-top:35px}.md-markdown a:not(.md-heading){color:#e92c6c;border-bottom:1px solid transparent;background-color:rgba(255,255,255,.04)}.md-markdown a:not(.md-heading) .md-code-inline{position:relative}.md-markdown a:not(.md-heading) .md-code-inline:only-child{display:inline-block;line-height:17px}.md-markdown a:not(.md-heading) .md-code-inline:before{content:'';position:absolute;background-color:#f1e05a;top:0;left:0;right:0;bottom:0;opacity:.04}.md-markdown a:not(.md-heading):visited{background-color:rgba(233,44,108,.04)}.md-markdown a:not(.md-heading):visited .md-code-inline:before{background-color:#e92c6c}.md-markdown a:not(.md-heading):hover{border-bottom:1px solid #e92c6c}.md-markdown thead{background-color:#e0e0e0}.md-markdown tbody{background-color:#f6f6f6}.md-markdown tbody tr:nth-child(even){background-color:#f9f9f9}.md-markdown h1,.md-markdown h2,.md-markdown h3,.md-markdown h4,.md-markdown h5,.md-markdown h6{padding:10px 0}.md-markdown h1:first-child,.md-markdown h2:first-child,.md-markdown h3:first-child,.md-markdown h4:first-child,.md-markdown h5:first-child,.md-markdown h6:first-child{margin-top:0}.md-markdown h1:last-child,.md-markdown h2:last-child,.md-markdown h3:last-child,.md-markdown h4:last-child,.md-markdown h5:last-child,.md-markdown h6:last-child{margin-bottom:0}.md-markdown iframe{display:block;margin:35px auto}.md-markdown iframe:first-child{margin-top:0}.md-markdown iframe:last-child{margin-bottom:0}.md-markdown li>p:only-child{display:inline}.md-markdown ul{list-style-type:none}.md-markdown ul>li:before{content:'◯';margin-right:5px}.md-heading{color:inherit}.md-markdown-inline{display:inline}.md-markdown-inline p{display:inline;line-height:initial}.md-code-block,.ocha-highlighted{margin:0 -20px}.ocha-code-block{padding:18px 50px}.md-markdown:not(.mm-content-html) .md-code-block+blockquote{max-width:inherit!important;margin:0 -20px;padding-left:20px;padding-right:20px}.md-code-block .md-code{display:block}.md-markdown-summary p{margin:10px 0}@media only screen and (min-width:768px){.md-markdown h1,.md-markdown h2,.md-markdown h3,.md-markdown h4,.md-markdown h5,.md-markdown h6{margin-left:-40px;margin-right:-40px;padding:10px 40px}.md-code-block,.ocha-highlighted{margin:0 -40px}.md-markdown:not(.mm-content-html) .md-code-block+blockquote{margin:0 -40px;padding-left:40px;padding-right:40px}}@media only screen and (min-width:1300px){.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:900px}}@media only screen and (min-width:1400px){.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:1000px}.md-code-block,.md-markdown:not(.mm-content-html) .md-code-block+blockquote,.ocha-highlighted{margin:0 -400px 0 -40px}}.md-markdown-large blockquote,.md-markdown-large code,.md-markdown-large ol,.md-markdown-large p,.md-markdown-large table,.md-markdown-large ul{max-width:inherit}.md-footnotes{margin-top:80px;padding:20px 0;border-top:1px dashed #cbccbc}.md-footnote{margin:0;padding:8px 0;font-size:14px;display:-webkit-box;display:-moz-box;display:-webkit-flex;display:-ms-flexbox;display:box;display:flex;-webkit-box-align:center;-moz-box-align:center;-o-box-align:center;-ms-flex-align:center;-webkit-align-items:center;align-items:center}.md-footnote p{line-height:16px}.md-footnote-anchor{padding:2px 6px;margin-right:10px;text-align:center;font-weight:700;color:#e92c6c}.ly-custom-subheading .md-footnote-anchor,.ly-lean .md-footnote-anchor{font-family:Merriweather,Georgia,serif}.md-markdown a.md-footnote-anchor{border:1px solid #e92c6c}.md-markdown a.md-footnote-anchor:hover{background-color:#e92c6c;color:#fcfcfc}.md-footnote-ref{margin-left:1px;margin-right:3px}.md-markdown a.md-footnote-ref{border-bottom:1px dotted}.md-code-block,.md-code-inline{-webkit-text-size-adjust:none;-ms-text-size-adjust:none;text-size-adjust:none;background:#fcfcf5;color:#4d4d4c}.md-code-block{line-height:24px}.md-code{padding:8px 10px}.md-code-inline{padding:0 6px}a .md-code{color:inherit}.md-code-comment{color:#8e908c}.md-code-attribute,.md-code-built_in,.md-code-constant,.md-code-literal,.md-code-number,.md-code-params,.md-code-pragma,.md-code-preprocessor,.md-code-regexp,.md-code-tag,.md-code-variable,.md-lang-css .md-code-class,.md-lang-css .md-code-id,.md-lang-css .md-code-pseudo,.md-lang-html .md-code-doctype,.md-lang-ruby .md-code-constant,.md-lang-xml .md-code-doctype,.md-lang-xml .md-code-pi,.md-lang-xml .md-code-tag .md-code-title,color #c82829{color:#f5871f}.md-lang-css .md-code-rule .md-code-attribute,.md-lang-ruby .md-code-class .md-code-title{color:#eab700}.md-code-header,.md-code-inheritance,.md-code-name,.md-code-string,.md-code-value,.md-lang-ruby .md-code-symbol,.md-lang-xml .md-code-cdata{color:#718c00}.md-code-title,.md-lang-css .md-code-hexcolor{color:#3e999f}.md-code-function,.md-lang-coffeescript .md-code-title,.md-lang-javascript .md-code-title,.md-lang-perl .md-code-sub,.md-lang-python .md-code-decorator,.md-lang-python .md-code-title,.md-lang-ruby .md-code-function .md-code-title,.md-lang-ruby .md-code-title .md-code-keyword{color:#4271ae}.md-code-keyword,.md-lang-javascript .md-code-function{color:#8959a8}.md-lang-coffeescript .md-lang-javascript,.md-lang-javascript .md-lang-xml,.md-lang-tex .md-code-formula,.md-lang-xml .md-code-cdata,.md-lang-xml .md-lang-css,.md-lang-xml .md-lang-javascript,.md-lang-xml .vbscript{opacity:.5}.md-code-deletion{background-color:rgba(244,0,30,.05);color:#f4001e}.md-code-addition{background-color:rgba(27,194,17,.05);color:#1bc211}.md-mark{background-color:rgba(255,226,112,.5);color:inherit}.md-mark span{color:inherit}.md-heading-hover{cursor:pointer;background-color:rgba(22,134,162,.1)}.mde-text-left{text-align:left}.mde-text-center{text-align:center}.mde-text-right{text-align:right}.mde-size-small{font-size:12px}.mde-size-small,.mde-size-small p{line-height:12px}.mde-size-large{font-size:36px}.mde-size-large,.mde-size-large p{line-height:36px}.mde-size-giant{font-size:72px}.mde-size-giant,.mde-size-giant p{line-height:72px}.mde-clearfix:after{content:' ';display:block;visibility:hidden;clear:both;font-size:0;height:0}.mde-quote{margin:0;padding:20px 0;border:none;border-top:5px solid rgba(0,0,0,.05);border-bottom:5px solid rgba(0,0,0,.05)}.mde-core{font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}.mde-mono{font-family:Consolas,Menlo,Monaco,'Lucida Console','Liberation Mono','DejaVu Sans Mono','Bitstream Vera Sans Mono','Courier New',monospace,serif}.ly-custom-heading .mde-heading,.ly-lean .mde-heading{font-family:Neuton,'Hoefler Text',Palatino,Baskerville,Georgia,'Times New Roman',serif}.ly-custom-subheading .mde-subheading,.ly-lean .mde-subheading{font-family:Merriweather,Georgia,serif}.mde-pad-0{padding:0}.mde-pad-5{padding:5px}.mde-pad-10{padding:10px}.mde-pad-15{padding:15px}.mde-pad-20{padding:20px}.mde-pad-25{padding:25px}.mde-pad-30{padding:30px}.mde-pad-50{padding:50px}.mde-mar-0{margin:0}.mde-mar-5{margin:5px}.mde-mar-10{margin:10px}.mde-mar-15{margin:15px}.mde-mar-20{margin:20px}.mde-mar-25{margin:25px}.mde-mar-30{margin:30px}.mde-mar-50{margin:50px}@media only screen and (min-width:900px){.mde-left{float:left}.mde-right{float:right}.mde-inline{display:inline-block;vertical-align:top}.mde-20{max-width:20%}.mde-25{max-width:25%}.mde-33{max-width:33.3333333333%}.mde-50{max-width:50%}.mde-66{max-width:66.6666666666%}.mde-75{max-width:75%}}.twitter-tweet-figure{background:0 0;padding:0}.twitter-tweet-figure:before{content:none}.twitter-tweet-figure .twitter-tweet{margin:0 auto}blockquote.twitter-tweet{overflow:hidden;color:#1c2022;background-color:#fff;border:1px solid #e1e8ed;border-radius:4px;width:500px;max-width:100%;min-width:220px;padding:1.25rem 1.25rem .725rem}blockquote.twitter-tweet:before{content:none}blockquote.twitter-tweet p{white-space:pre-wrap;font:16px/1.4 Helvetica,Roboto,'Segoe UI',Calibri,'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}blockquote.twitter-tweet a,blockquote.twitter-tweet a:visited{color:#2b7bb9}.wy-container{margin:0 auto;padding:20px 0;max-width:800px}.wy-container .md-markdown p{line-height:22px;margin:10px 0}.wy-container .md-markdown p:first-child{margin-top:0}.wy-container .md-markdown p:last-child{margin-bottom:0}.wy-container .md-markdown blockquote:not(.twitter-tweet){padding:10px 0}.wy-container .md-code-block{margin:0;padding:10px;white-space:pre-wrap}.wy-table{width:100%;padding:0}.wy-td{padding:0}.wy-section-link,.wy-section-markdown,.wy-section-poll,.wy-section-summary{padding-top:25px}.wy-section-thanks{margin-top:25px;padding:10px;font-size:15px;background-color:#f2fcf2}.wy-header-text,.wy-issue{display:inline-block;margin:10px 0;line-height:24px}.wy-issue{float:right;font-size:12px}.wy-issue-content{display:block;padding:0 5px;background-color:#fcfcfc}.wy-section-header{padding-top:40px}.wy-section-header h1,.wy-section-header h2,.wy-section-header h3,.wy-section-header h4,.wy-section-header h5,.wy-section-header h6{margin:0}.wy-section-header p{line-height:inherit}.wy-header-td{padding:0}.wy-header-content{margin:0 10px}.wy-header-text{color:#fcfcfc;text-shadow:1px 1px 0 #1a4d7f;font-weight:700;font-size:24px}.wy-content{padding-bottom:25px}.wy-link-addendum,.wy-link-tag,.wy-link-title{display:inline-block;vertical-align:bottom;margin-bottom:10px}.wy-link-title{border-bottom:1px solid;font-size:20px;margin-right:10px}.wy-link-tag{background-color:#1a4d7f;color:#fcfcfc;text-transform:uppercase;font-size:13px;margin-right:5px;padding:2px 4px}.wy-link-tag:last-child{margin-right:0}.wy-link-addendum{color:#999;margin-left:5px}.wy-link-addendum:hover{border-bottom-color:transparent}.wy-link-title-section{position:relative}.wy-link-stats{position:absolute;right:0;background-color:#3aca96;color:#fcfcfc;border-bottom:1px solid #299a71}.wy-link-stats-logo{background-color:rgba(0,0,0,.1);color:#299a71}.wy-link-stat{margin:3px}.wy-link-description{font-size:14px;color:#666}.wy-link-source-section{margin-top:10px}.wy-link-source{margin-right:10px;margin-bottom:10px;display:inline-block;vertical-align:middle;color:#55acee}.wy-link-source-plain{color:#333}.wy-link-source.wy-link-source-plain a{color:#55acee}.wy-link-source.wy-link-source-plain a:visited{background-color:rgba(85,172,238,.04)}.wy-link-source.wy-link-source-plain a:visited .md-code-inline:before{background-color:#55acee}.wy-link-source.wy-link-source-plain a:active{outline-color:#55acee}.wy-link-source.wy-link-source-plain a:hover{border-bottom-color:#55acee}.wy-link-sponsor{background-color:transparent;color:#999;outline:#999 solid 1px}.wy-link-cell-before-image{vertical-align:middle;width:70%}.wy-link-cell-image{padding-left:10px}.wy-link-image-anchor{display:block;overflow:hidden;max-height:300px}.wy-link-image{display:block;margin:0 auto}.wy-footer-table{margin:20px 0}.wy-footer-cell{text-align:center}.wy-read-online{font-size:13px}.wy-section-link-job .wy-link-source,.wy-section-link-job .wy-link-title{font-size:14px}.wy-section-link-job .wy-link-description{font-size:12px}.wy-link-pixel{float:right}@media only screen and (max-width:500px){.wy-issue-publication,.wy-issue-separator{display:none}}.md-code-block{margin:0!important;padding:10px}</style>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="Improving Cookie Consent">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Improving Cookie Consent</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">27 11 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Cliqz' new feature to make consent fairer
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/159-i-am-inevitable.png" alt="I Am Inevitable">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">I Am Inevitable</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">26 11 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/159-i-am-inevitable.png" alt="I Am Inevitable" title="The Far Future—Coming Soon" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">12 Common Mistakes and Missed Optimization Opportunities in SQL</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">20 11 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>SQL is used by analysts, data scientists, product managers, designers and many others. These professionals have access to databases, but they don't always have the intuition and understanding to write efficient queries. In an effort to make my team write better SQL, I went over reports written by non-developers and code reviews, and gathered common mistakes and missed optimization opportunities in SQL.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Algebraic Data Types: Things I wish someone had explained about functional programming</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">19 11 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Algebraic data types and algebraic data structures sound similar. It’s like they ought to be the same thing. But they’re not. They both have ‘algebraic’ in the name, so it’s confusing. I got them mixed up at times. Others have too. But, they’re different concepts. Understanding the difference will help if you’re trying to learn functional programming.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Algebraic Data Types: Things I wish someone had explained about functional programming</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">19 11 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Algebraic data types and algebraic data structures sound similar. It’s like they ought to be the same thing. But they’re not. They both have ‘algebraic’ in the name, so it’s confusing. I got them mixed up at times. Others have too. But, they’re different concepts. Understanding the difference will help if you’re trying to learn functional programming.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/158-new-world.png" alt="New World">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">New World</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">19 11 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/158-new-world.png" alt="New World" title="Are you enjoying your simulation?" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-Gx2vYWgmTR0/XdGccTbjpZI/AAAAAAAAm30/OY2SvoIPgMYEwp63vcu4C09_GNRFPCcgQCLcBGAsYHQ/s640/mobile-apps-pile-ss-1920.jpg" alt="Ideas para crear aplicaciones en 2020">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Ideas para crear aplicaciones en 2020</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">18 11 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-Gx2vYWgmTR0/XdGccTbjpZI/AAAAAAAAm30/OY2SvoIPgMYEwp63vcu4C09_GNRFPCcgQCLcBGAsYHQ/s1600/mobile-apps-pile-ss-1920.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Ideas para crear aplicaciones en 2020" border="0" data-original-height="900" data-original-width="1600" height="360" src="https://1.bp.blogspot.com/-Gx2vYWgmTR0/XdGccTbjpZI/AAAAAAAAm30/OY2SvoIPgMYEwp63vcu4C09_GNRFPCcgQCLcBGAsYHQ/s640/mobile-apps-pile-ss-1920.jpg" title="Ideas para crear aplicaciones en 2020" width="640" /></a></div><br />Se acerca el fin del año 2019 y con ello la oportunidad de planear la próxima aplicación móvil para tu empresa, para tu negocio propio, o como parte de iniciativas para seguir aprendiendo. En este post les comparto algunas ideas de apps móviles que de acuerdo a las últimas tendencias en torno a desarrollo deberías aprender y/o implementar en 2020.<br /><h2 id="apps-m-viles-enfocas-a-vr">Apps móviles enfocas a VR</h2>Las aplicaciones con virtual reality o realidad virtual son aquellas en donde con el uso de gafas o dispositivos inmersivos puedes ofrecer una experiencia 360 grados. Hoy en día para dispositivos Android hay muchas gafas de realidad virtual que no son necesariamente caras y que puedes usarlas para probar tus aplicaciones. Principalmente esta tecnología se ha usado para construir juegos que permitan tener esa nueva experiencia interactiva donde recreas un entorno virtual completo.<br /><h2 id="apps-con-bots">Apps con bots</h2>Los bots se volvieron un boom el año pasado y su uso se empezó a expandir desde entonces. Los bots como una herramienta de comunicación pueden ayudar mucho si por ejemplo, eres un negocio que desea tener para sus usuarios un apoyo constante de comunicación, sin necesariamente tener a una persona escribiendo los mensajes.<br />Lo que me gusta de los bots es que puedes hacerlo tan inteligente como tu lo necesites, desde que solo tengas que seguir un flujo de comunicación seleccionando opciones, hasta que puedas entablar diálogos más complejos en voz o texto.<br /><h2 id="apps-para-el-cuidado-de-la-salud">Apps para el cuidado de la salud</h2>Las aplicaciones para medir el pulso, los pasos y distancia son hoy en día muy fáciles de construir. La mayoría de los smartphones modernos ya tienen incluidos algunos sensores que pueden ayudarte a monitorear diferentes aspectos del cuerpo, y si lo añades con las funcionalidades de un smartwatch el resultado puede ser mucho más interesante.<br />Todas las apps enfocadas a salud tienen como objetivo que puedas activarte físicamente con recordatorios, juegos o metas para incentivarte de una forma divertida, por lo que para tener un diferenciador es necesario hacerlo lo más amigable y llamativo posible.<br /><h2 id="apps-con-blockchain">Apps con blockchain</h2>Esta tecnología si bien empezó como una forma inteligente y segura para poder usar cripto monedas, hoy en día muchos proveedores hacen uso de esta tecnología para que tu puedas crear servicios y aplicaciones en donde la integridad de la información se mantenga a pesar de los cambios futuros que tenga. Si necesitas que los datos no se modifiquen o que no haya duplicidad en los mismos, la tecnología de blockchain puede ayudar perfecto a cumplir con esa premisa, y hoy ya es relativamente más fácil construir desarrollos sobre ella.<br /><h2 id="apps-realidad-aumentada">Apps Realidad aumentada</h2>Una simple aplicación de realidad aumentada que puedes ir haciendo es la del metro como instrumento de medida. Este ejemplo hace referencia a cómo integras elementos a un entorno físico para realizar alguna actividad. Muchos utilizan la realidad aumentada para juegos, pero así como el ejemplo del metro, podrías constuir apps enfocadas a brindar una herramienta que te ayude a combinar objetos físicos con virtuales.<br /><h2 id="conclusi-n">Conclusión</h2>Estas son 5 tendencias que esperamos ver en 2020 enfocadas al desarrollo de aplicaciones móviles. Cada una representa sus retos y oportunidades, pero lo cierto es que hace un año que algunas de ellas apenas estaban siendo presentadas, era muy difícil poder construir aplicaciones reales, ya que teníamos falta de hardware o software en forma de SDKs que nos permitieran explotar estas tecnologías. En estos momentos que estamos por concluir el 2019 podemos confirmar que ya mucha de la tecnología para hacer estas apps no solo existe en tu teléfono, sino que ya hay muchísimas formas de aplicarlas para tener una app diferente con una interacción y tecnología moderna.<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=CGHFTKhD5c0:Wa8pehsTuJY:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=CGHFTKhD5c0:Wa8pehsTuJY:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=CGHFTKhD5c0:Wa8pehsTuJY:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=CGHFTKhD5c0:Wa8pehsTuJY:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=CGHFTKhD5c0:Wa8pehsTuJY:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=CGHFTKhD5c0:Wa8pehsTuJY:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=CGHFTKhD5c0:Wa8pehsTuJY:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=CGHFTKhD5c0:Wa8pehsTuJY:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=CGHFTKhD5c0:Wa8pehsTuJY:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=CGHFTKhD5c0:Wa8pehsTuJY:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=CGHFTKhD5c0:Wa8pehsTuJY:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=CGHFTKhD5c0:Wa8pehsTuJY:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=CGHFTKhD5c0:Wa8pehsTuJY:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=CGHFTKhD5c0:Wa8pehsTuJY:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/CGHFTKhD5c0" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="¿Es necesario donar productos insanos a los bancos de alimentos?">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">¿Es necesario donar productos insanos a los bancos de alimentos?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">12 11 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Dietistas-nutricionistas recomiendan no incluir productos como azúcar o cacao soluble
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Type Classes: Things I wish someone had explained about functional programming</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">12 11 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Type classes are not the same thing as algebraic structures. But you'll find many people use the terms interchangably. And that can be confusing. It confused me for a long time. In this article we look at what type classes actually are. And we’ll also look at why programmers from other languages are so enthusiastic about them.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Type Classes: Things I wish someone had explained about functional programming</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">12 11 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Type classes are not the same thing as algebraic structures. But you'll find many people use the terms interchangably. And that can be confusing. It confused me for a long time. In this article we look at what type classes actually are. And we’ll also look at why programmers from other languages are so enthusiastic about them.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/157-ai-training-datasets.png" alt="AI Training Datasets">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AI Training Datasets</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">12 11 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/157-ai-training-datasets.png" alt="AI Training Datasets" title="Gerbage in, garbage out" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/media/2019/koko-analytics-dashboard.png" alt="Introducing Koko Analytics">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Introducing Koko Analytics</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Danny van Kooten</a> <span class="article__date">06 11 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>After <a href="/stepping-down-fathom-maintainer/">stepping down from Fathom</a> earlier this year, I was happy working on <a href="https://www.mc4wp.com/">Mailchimp for WordPress</a> for a good few months 
before realising that I was still thinking about how to make web analytics more private.</p>

<p>It dawned on me that part of why I was building Fathom in Go was because I wanted a break from WordPress and because I deemed it necessary to achieve good enough performance.</p>

<p>That last part might still hold true, but when choosing not to keep track of bounce rates and the time a visitor spends on a page, things become much simpler.</p>

<p>Add to that the following facts and an idea was born:</p>

<ul>
  <li>Adding a third-party service to your site to keep track of your visitors will never be as private as a self-hosted service.</li>
  <li>The majority of WordPress users will never self-host their analytics if it’s not as easy as installing and activating a plugin.</li>
  <li><a href="https://w3techs.com/technologies/details/cm-wordpress/all/all">WordPress powers 34.9% of the internet</a>. That’s 34.9% of the internet owning their data, despite usually not being a developer themselves.</li>
</ul>

<p>That’s why I set out to built <a href="https://www.kokoanalytics.com/">Koko Analytics</a>, a privacy-friendly analytics plugin for WordPress that does not use any external services.</p>

<p><a href="https://www.kokoanalytics.com/"><img src="/media/2019/koko-analytics-dashboard.png" alt="Koko Analytics dashboard" /></a></p>

<h3 id="metrics">Metrics</h3>

<p>Koko Analytics currently keeps track of the following metrics:</p>

<ul>
  <li>Total site visitors</li>
  <li>Total site pageviews</li>
  <li>(Unique) pageviews for posts, pages, products, etc.</li>
  <li>Referrers (including a built-in blacklist to filter referrer spam)</li>
</ul>

<p>The nice thing about running inside of WordPress is that it gives the software first-hand knowledge about what’s being tracked and allows it to offer seamless integrations, like built-in event tracking for leaving comments or any of the popular form plugins.</p>

<h3 id="performance">Performance</h3>

<p>Most likely, you won’t even notice that Koko Analytics is there. Even when your site is getting hammered by a sudden burst of traffic.</p>

<p>To achieve this, the plugin uses an append-only buffer file in which pageviews are temporarily stored until they are aggregated using a background process that runs every 60 seconds.</p>

<p>In my tests it was able to handle well over 15.000 requests per second, meaning you don’t have to worry about being on the first page of Hacker News. <a href="/from-go-back-to-php-again/">PHP has really come a long way</a> in the last few years.</p>

<h3 id="downloading-the-plugin">Downloading the plugin</h3>

<p>To make sure as many people as possible have access to Koko Analytics and any improvements made by me or others, the plugin is GPLv3 licensed and available for free download.</p>

<p>As of yesterday, you can <a href="https://wordpress.org/plugins/koko-analytics">download Koko Analytics from WordPress.org</a> or <a href="https://github.com/ibericode/koko-analytics">contribute to it on GitHub</a>.</p>

<p>If you’re running Koko Analytics on your WordPress site then please don’t hesitate to <a href="/contact/">let me know</a> and share your thoughts on how we can make it better.</p>

<p>And definitely consider <a href="https://wordpress.org/support/plugin/koko-analytics/reviews/#new-post">leaving a plugin review on WordPress.org</a>, because as you can see we desperately need some.</p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Python VS Common Lisp Workflow and Ecosystem</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">06 11 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>please see <a href="/pythonvslisp/">Python VS Common Lisp</a> (it&rsquo;s a static page you can find in the menu).</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How Much of a Genius-Level Move Was Using Binary Space Partitioning in Doom?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Two-Bit History</a> <span class="article__date">06 11 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        In 1993, id Software released the first-person shooter Doom, which quickly became a phenomenon. The game is now considered one of the most influential games of all time. A decade after Doom’s release, in 2003, journalist David Kushner published a book about id Software called Masters of Doom, which has since become the canonical account of Doom’s creation. I read Masters of Doom a few years ago and don’t remember much of it now, but there was one story in the book about lead programmer John Carmack that has stuck with me. This is a loose gloss of the story (see below for the full details), but essentially, early in the development of Doom, Carmack realized that the 3D renderer he had written for the game slowed to a crawl when trying to render certain levels. This was unacceptable, because Doom was supposed to be action-packed and frenetic. So Carmack, realizing the problem with his renderer was fundamental enough that he would need to find a better rendering algorithm, started reading research papers. He eventually implemented a technique called “binary space partitioning,” never before used in a video game, that dramatically sped up the Doom engine.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q4 2019 Funding Announcement</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">05 11 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together is happy to announce that for Q4 of 2019 (November-January) we are funding four projects: Expound with Ben Brinckerhoff, Deep Diamond (Neanderthal) with Dragan Djuric, Libpython-clj with David Levy, Oz with Christopher Small.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/156-burnout.png" alt="Burnout">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Burnout</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">05 11 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/156-burnout.png" alt="Burnout" title="Checking the tasks list the 6th time might be a sign." /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Snippet: Manipulating Rows and Columns With ClAWK</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">04 11 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I just discovered <a href="https://github.com/sharplispers/clawk">clawk</a>, that
seems to originate from
<a href="https://github.com/lispbuilder/lispbuilder">lispbuilder-clawk</a>. Its
last commit dates from 2011, typical from Lisp and that&rsquo;s OK,
libraries have the right to be done, it has no useful README nor
documentation, but we can see its use in <a href="https://github.com/sharplispers/clawk/blob/master/clawktest.lisp">the
tests</a>,
and the library is easily discoverable.</p>

<p>This library seems perfect to manipulate data in rows and columns.</p>

<p>Let&rsquo;s have a quick look with this dummy txt file:</p>

<pre><code>1 Alice 40 40
2 Bob 39 50
</code></pre>

<p>I had a conflict when <code>use</code>-ing clawk, which I resolved by not
accepting the change in the debugger.</p>

<p>We parse all lines, give a name to the space-delimited fields, and print them back:</p>

<pre><code class="language-lisp">(for-file-lines (&quot;test.txt&quot;)
    (with-fields ((a b c d))
        ($print a b c d)))

1 Alice 40 40
2 Bob 39 50
NIL
</code></pre>

<p>Let&rsquo;s multiply the two last fields. If we use the regular <code>*</code> operator, we get a
type error because fields are extracted as strings by default. We then
use <code>$*</code>:</p>

<pre><code class="language-lisp">(for-file-lines (&quot;test.txt&quot;)
    (with-fields ((id name payrate hrsworked))
        (declare (ignore id))
        ($print name ($* payrate hrsworked))))
Alice 1600
Bob 1950
NIL
</code></pre>

<p>We can change the field separator with a string or a regexp, with the
no surprising <code>clawk:*fs*</code> variable (<code>FS</code> in awk):</p>

<pre><code class="language-lisp">(for-file-lines (&quot;test.txt&quot;)
    (let ((clawk:*fs* &quot;-&quot;))
        (with-fields ((a b c))
        ($print a))))
</code></pre>

<p>And… that&rsquo;s all folks. Another tool to keep in our toolbelt.</p>

<ul>
<li>more about awk: <a href="https://www.gnu.org/software/gawk/manual/html_node/">https://www.gnu.org/software/gawk/manual/html_node/</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Algebraic Structures: Things I wish someone had explained about functional programming</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">03 11 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Algebraic Structures are something I wish I’d understood better, sooner. I had a hazy idea of what they were, but didn’t know the correct terminology. That was a massive barrier to finding out more. This article is my attempt to stop that happening to others. We'll look at: What are algebraic structures? How do we use them in JavaScript? Why would we bother? What's the big deal?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Algebraic Structures: Things I wish someone had explained about functional programming</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">03 11 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Algebraic Structures are something I wish I’d understood better, sooner. I had a hazy idea of what they were, but didn’t know the correct terminology. That was a massive barrier to finding out more. This article is my attempt to stop that happening to others. We'll look at: What are algebraic structures? How do we use them in JavaScript? Why would we bother? What's the big deal?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/images/debugging-python-VS-lisp.png" alt="Python VS Common Lisp, workflow and ecosystem">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Python VS Common Lisp, workflow and ecosystem</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">30 10 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<!-- started = "2017-02-05T07:51:49+01:00" -->

<!-- finished = "2019-10-30" -->

<p>I learned Java and C at school, I learned Python by myself and it was
a relief. After 8 years working and doing side projects in Python and
JavaScript (mostly web dev, Django/Flask/AngularJS/Vuejs), I am not
satisfied anymore by the overall experience so I&rsquo;m making Common Lisp my
language of choice.</p>

<p>I am not here to compare languages themselves, but their inherent
workflow and their ecosystem. This is the article I wish I had read
earlier, when I was interested in Lisp but was a bit puzzled, because
the Lisp way always seemed different, and I couldn&rsquo;t find many
voices to explain it. The Python way may not be the
most practical or effective, Common Lisp might not be a dead language. I find many &ldquo;workflow
fixes&rdquo;, overall improvements and hackerish possibilities on the CL side, even if sometimes the
Python tooling is superior.</p>

<p>Let&rsquo;s dive in.</p>

<p>and thanks to the proofreaders.</p>

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->

<p><strong>Table of Contents</strong></p>

<ul>
<li><a href="#development-process">Development process</a>

<ul>
<li><a href="#interactivity">Interactivity</a></li>
<li><a href="#editing-code">Editing code</a></li>
<li><a href="#running-testing-programs">Running, testing programs</a></li>
<li><a href="#typing">Typing</a></li>
<li><a href="#refactoring">Refactoring</a></li>
</ul></li>
<li><a href="#libraries">Libraries</a>

<ul>
<li><a href="#library-management">Library management</a></li>
<li><a href="#state-of-the-libraries">State of the libraries</a></li>
</ul></li>
<li><a href="#templates">Templates</a></li>
<li><a href="#deployment-shipping">Deployment, Shipping</a></li>
<li><a href="#performance">Performance</a></li>
<li><a href="#conclusion">Conclusion</a></li>
<li><a href="#appendix-faq">Appendix: FAQ</a>

<ul>
<li><a href="#are-there-no-iterators">Are there no iterators ?</a></li>
<li><a href="#can-i-define-my-own-operator-like-in-an-oo-language">Can I define my own <code>+</code> operator like in an OO language ?</a></li>
<li><a href="#to-which-extent-can-lisp-be-compiled-with-all-its-dynamic-nature-garbage-collection-macros-and-what-else">To which extent can Lisp be compiled, with all its dynamic nature, garbage collection, macros and what else ?</a></li>
<li><a href="#but-what-is-common-lisp-good-for-really">But what is Common Lisp good for, really ?</a></li>
<li><a href="#so-why-is-cl-not-more-popular">So why is CL not more popular ?</a></li>
</ul></li>
</ul>

<!-- markdown-toc end -->

<h1 id="development-process">Development process</h1>

<h2 id="interactivity">Interactivity</h2>

<p>In <em>Python</em>, we typically restart everything at each code change, we use
 breakpoints: this takes some time, I find it too repetitive and boring, it requires to
 re-manipulate data to re-reach the state we were at to analyze and
 debug our program. We might figure out a non-standard,
 more interactive way, but still: a web server needs to restart,
 object instances don&rsquo;t get updated after a class definition. We can get a prompt on an error (<code>-m pdb</code>), some tools include it (Werkzeug): a sign that it is a good thing to have. Unfortunately, it is not built-in, as in CL.</p>

<p>In <em>Common Lisp</em>, everything is much more interactive in the REPL. Even
developing web apps. On an error, we get an interactive debugger with
the stacktrace in our editor, we press <code>v</code> and voilà, we are at the
problematic line. We can of course catch errors to avoid the debugger, or disable it with global settings. We can resume the program execution from any stackframe. No process needs to restart. The variables
that we define on the REPL stay here. If we change a class definition
(say, we remove a field), existing instances get (lazily) updated.</p>

<p>The Lisp REPL is part of the development process, it is not only used
for exploration and debugging. It&rsquo;s fun, it&rsquo;s a productive boost, and
it allows to catch errors earlier, both because we try functions
earlier, and because we get type warnings when we compile the file or
the current function (yes, we can compile a single function).</p>

<p>Now, the cost is that one must learn to play with this live data. We
might come to a state that doesn&rsquo;t reflect the code anymore, so we&rsquo;ll
write our own &ldquo;reset&rdquo; functions or just restart the lisp image.</p>

<p>Here&rsquo;s <a href="https://www.youtube.com/embed/CNFr7zIfyeM">a video</a> where the developer defines a dummy interface, makes it
fail, develops it, and tests it, all quickly by interacting with the REPL.</p>

<iframe width="560" height="315" src="https://www.youtube.com/embed/CNFr7zIfyeM" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<p><img src="/images/debugging-python-VS-lisp.png" alt="Debugging a complex stacktrace in Python VS Common Lisp (author unknown)" /></p>

<h2 id="editing-code">Editing code</h2>

<p><em>Python</em>: we edit code line by line, paragraph by paragraph. We can
try out half-backed editor plugins to edit code by semantic units. Sometimes we
must even pay attention to add a couple whitespace there, remove one
there. We are far from the immediate interactive feedback of the hacker&rsquo;s
vision &ldquo;Inventing on Principles&rdquo;.</p>

<p><em>Common Lisp</em>: we edit code by semantic units. I love emacs&rsquo; <a href="http://oremacs.com/lispy/">lispy
mode</a>, which is weird at first of course,
but so convenient. We can navigate to expressions back and forth, we
can delete a whole &ldquo;if&rdquo; expression with a keypress, indentation is
automatic, etc. There are <a href="http://wikemacs.org/wiki/Lisp_editing">other emacs plugins</a>. <a href="https://shaunlebron.github.io/parinfer/">Parinfer</a> is appreciated in other editors too.</p>

<p>Actually, we edit code by parenthesis units, which doesn&rsquo;t carry as
much meaning as an Abstract Syntax Tree. For a real AST, we&rsquo;d need a
code walker (like <a href="https://github.com/s-expressionists/Concrete-Syntax-Tree">Concrete-Syntax-Tree</a>). But since Lisp&rsquo;s syntax is based on parenthesis, in
practice the experience is similar.</p>

<!-- Some libraries are being built on the code walker: https://github.com/FiV0/cl-navigate-sc -->

<p>I had a try on writing a little plugin to help editing Python code by manipulating
the AST (<a href="https://github.com/vindarel/redbaron4emacs">red4e</a>).  We
first need an AST parser. There was a couple for Python 2, another one
for Python 3 without type annotations, eventually one emerged a couple
years later: these are signs of an unstable language and ecosystem, and it is more work
required by the developer. I went the simple way by calling each
function into a new Python process, which is of course too
slow. <a href="https://github.com/abingham/traad">traad</a> is a better project,
it can do much more but still, it&rsquo;s difficult to answer questions like
cross-referencing: &ldquo;who calls this function&rdquo; or &ldquo;who does this
function call&rdquo;, which are built-in in
SLIME. <a href="https://en.wikipedia.org/wiki/SLIME">SLIME</a> is like the Language
Server Protocol for Common Lisp in Emacs, its backend Swank being
editor-agnostic.</p>

<p>Maybe other editors and proprietary ones come with a better
experience, at the cost of freedom, money, configuration time and
memory and CPU resources. If I have the choice, I prefer to not go
this route, and choose a better platform from the start.</p>

<p>Traad is built around a client-http server approach, this is the idea
behind LSP…  this reminds me of the architecture of SLIME!
It has a backend, Swank, and a client (SLIME for Emacs, SLIMA for Atom,…).
It thus has a modern architecture since its
inception :) It is moreover based on a stable language whose syntax
can not rot and has decades of development behind it, so we can be
confident about the tool. Saying this because it&rsquo;s hard to grasp what
SLIME is at the beginning.</p>

<p>SLIME itself is tied to Emacs, and thus a newcomer can find the UI
unpractical. Swank though can be used outside of Emacs, and it is for
example for Atom&rsquo;s <a href="https://github.com/neil-lindquist/SLIMA/">SLIMA</a>,
which now has all the most important SLIME features: REPL, integrated
debugger, jump to definition, autocompletion, interactive object
inspection, and more.</p>

<ul>
<li>more: <a href="https://lispcookbook.github.io/cl-cookbook/editor-support.html">https://lispcookbook.github.io/cl-cookbook/editor-support.html</a> (Eclipse, Lem, Jupyter Notebook,…)</li>
</ul>

<p><a href="https://github.com/tarsius/paren-face/"><img src="https://raw.githubusercontent.com/tarsius/paren-face/master/parentheses.png" alt="" /></a></p>

<h2 id="running-testing-programs">Running, testing programs</h2>

<p><em>Python</em>: the default workflow is to run commands in the
terminal. Scroll, read the output, copy-paste manually (or use the
non-UX-optimal termux or a terminal inside emacs), go back to your
editor. Type commands without completion, type the whole path to a
single unit test (<code>pytest path/to/test.py::foo</code>), or configure your
editor and find a good plugin that is compatible with your test runner (I
can&rsquo;t use the excellent nose-mode :( ).</p>

<p><em>Common Lisp</em>: the default workflow is to do everything interactively
into the REPL, but some people still use a
write-compile-run approach. Consequently there is built-in completion for
everything. We don&rsquo;t have to use the shell (except from once in a
while to run global tests or build the system) and that&rsquo;s a good
thing. There is an interactive debugger. We can interactively fix and re-run code and
tests.</p>

<p>Here&rsquo;s <a href="https://www.youtube.com/embed/KsHxgP3SRTs">a quick demo</a> on how to interactively fix failing tests:</p>

<iframe width="560" height="315" src="https://www.youtube.com/embed/KsHxgP3SRTs" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<p>Running and debugging on a remote server: in Python, we usually rsync
sources and run tests manually, or start vim/emacs under tmux on the
server. We have to kill the app to reload it. In Common Lisp, we can
connect to the running, remote instance, write changes from the
comfort of our editor locally, hit <code>C-c C-c</code> on a function to compile it
and see changes on the remote image. CL has more hackerish capacities
here, no doubt, and I find it attractive :)</p>

<ul>
<li>more information on (remote) debugging: <a href="https://lispcookbook.github.io/cl-cookbook/debugging.html">https://lispcookbook.github.io/cl-cookbook/debugging.html</a></li>
<li>a demo with a web app: <a href="https://lisp-journey.gitlab.io/blog/i-realized-that-to-live-reload-my-web-app-is-easy-and-convenient/">https://lisp-journey.gitlab.io/blog/i-realized-that-to-live-reload-my-web-app-is-easy-and-convenient/</a></li>
<li>watch Baggers working with OpenGL: <a href="https://www.youtube.com/watch?v=a2tTpjGOhjw&amp;index=20&amp;list=RDxzTH_ZqaFKI">https://www.youtube.com/watch?v=a2tTpjGOhjw&amp;index=20&amp;list=RDxzTH_ZqaFKI</a></li>
<li>a Minecraft game engine that you can change while playing: <a href="https://github.com/gmasching/sucle">https://github.com/gmasching/sucle</a></li>
</ul>

<h2 id="typing">Typing</h2>

<p><em>Python</em>: we catch a lot of type errors in production, and/or we have
to write a lot more unit tests. Hope we agree on this.</p>

<p>Now we can improve the situation somehow with type annotations,
however it has the cons of being an after-thought: it is not stable
(differences between Python versions), not well integrated
(we have to run another command, choose between mypy, the new typing
module, pyre), it is not interactive, we need to configure our IDE, it
adds a start-up penalty (which might or might not be important).</p>

<p>In <em>Common Lisp</em>, particularly with SBCL, we get a lot of type errors
or warnings at compile time. We can compile <em>a single function</em>, and
thus have an immediate feedback.  We&rsquo;re closer (not there, just
closer) to the &ldquo;if it compiles, it works&rdquo; situation (we know it runs,
since we constantly compile and try the functions). We can also create
our compound types and add type declarations to variables and
functions. It&rsquo;s great, though it doesn&rsquo;t do as much static checks as a
real typed language.</p>

<p>Adding type declarations in well chosen places such as inner loops
also allows to gradually speed up the program where needed.</p>

<ul>
<li><a href="https://lispcookbook.github.io/cl-cookbook/type.html">https://lispcookbook.github.io/cl-cookbook/type.html</a></li>
<li><a href="https://medium.com/@MartinCracauer/static-type-checking-in-the-programmable-programming-language-lisp-79bb79eb068a">Compile-time type checking in the programmable programming language Lisp</a></li>
<li>will <a href="https://github.com/tarballs-are-good/coalton">ML embedded into CL</a>
help even more ?</li>
</ul>

<h2 id="refactoring">Refactoring</h2>

<p><em>Python</em>: we can&rsquo;t refactor code as we want. Decorators, context
managers: they have an interface and they are limited to what they
offer. You can&rsquo;t do things a bit differently, you must comply to the
interface. That might be a feature, but I prefer not being
restricted. In my experience, this leads to code repetition whereas
in CL, we can refactor how we want, and we get a cleaner code.</p>

<p><em>Common Lisp</em>: there are similar patterns than in Python, but we can
escape them. We can use macros, be concise and do what we want. We can
have the decorator syntax with the cl-annot library, and any other by
writing our reader macros (they can bring triply-quoted docstrings,
string interpolation, infix notation, C syntax…). It&rsquo;s not only macros
though. The polymorphism of the object system (or generic dispatch)
helps, and Lisp&rsquo;s &ldquo;moldability&rdquo; in a whole allows us to refactor code
exactly how we want, to build a &ldquo;Domain Specific Language&rdquo; to express
what we want. Other language features than macros help here, like
closures or <a href="https://lispcookbook.github.io/cl-cookbook/functions.html#multiple-return-values-values-multiple-value-bind-and-nth-value">multiple
values</a>
(which are different, and safer for refactoring, than returning a tuple).</p>

<p>Now, speaking about refactoring tools, they are better Python side. I
don&rsquo;t know of a Lisp tool that allows to change all the code-base
according to the AST, maybe in a proprietary editor. There are
utilities to make local transformations, like &ldquo;extract this expression
into a <code>let</code> variable at the top of the function&rdquo;, &ldquo;transform a
function to a lambda equivalent&rdquo; or the contrary, etc.</p>

<p>(edit January, 2020: the language-agnostic tool <a href="https://github.com/comby-tools/comby">Comby</a> will be useful here. I used it for syntactic manipulation, for example to replace a <code>(if (…) (progn …))</code> by a <code>(when (…) …)</code>). See <a href="https://github.com/vindarel/colisper">Colisper</a> (a POC).</p>

<h1 id="libraries">Libraries</h1>

<h2 id="library-management">Library management</h2>

<p><em>pip</em>: use virtual environments (virtualenv, virtualenvwrapper, tox,
anaconda,…  or install per-user), pin dependencies (pip-tools, pipenv, poetry,
pyupdate,…). Debug problems due to
a third party library that didn&rsquo;t pin its dependencies strictly
enough (happens at the wrong moment).</p>

<p><em>quicklisp</em>: think of it like Debian&rsquo;s apt, shipping releases that
work together (that load together), and that we upgrade together, when we
want. If needed, we can still clone projects into
<code>~/quicklisp/local-projects/</code> for a system-wide installation, or have
project-local dependencies with
<a href="https://github.com/fukamachi/qlot">Qlot</a>.
Quicklisp is very slick. Libraries are installed at runtime, during
 our REPL session. We don&rsquo;t have to reload the Lisp process.</p>

<p>We are not even limited to Quicklisp any more (it can be limiting
because of its one month release cycle). The
<a href="http://ultralisp.org/">Ultralisp</a> distribution builds every 5
minutes. <a href="https://gitlab.common-lisp.net/clpm/clpm">clpm</a> is a package
manager with a traditional approach. One can publish his own Quicklisp
distribution, to provide a set of packages that are known to work
together.</p>

<h2 id="state-of-the-libraries">State of the libraries</h2>

<p>CL might have more libraries than you think, see the <a href="https://github.com/CodyReichert/awesome-cl">Awesome CL
list</a>,
<a href="http://quickdocs.org/">http://quickdocs.org/</a> or do a quick search on the net. I know I am
constantly surprised.</p>

<p>But sure, the Python ecosystem is huge. A few remarks on the differences:</p>

<ul>
<li>Quicklisp has around 1500 packages, PyPI over than 170 000. It&rsquo;s hard to imagine that there are a hundred times more useful libraries :D Even in CL we have duplication of libraries with a dozen of test frameworks.</li>
<li>Quicklisp is a curated distribution, PyPI is not. That means that
libraries that don&rsquo;t compile anymore are rejected (after a notice to
the maintainers), and that orphan projects&rsquo; URL can be updated to
point to a community maintained one.</li>
<li>Anybody can easily publish a library to PyPI on its own. Less so
with Quicklisp, one must open an issue (Ultralisp doesn&rsquo;t have this limitation).</li>
<li><a href="https://github.com/numcl/numcl">numcl</a> is a Numpy clone.</li>
<li>if needed, you can use <a href="https://github.com/CodyReichert/awesome-cl#python">py4cl and more</a> to interface with Python.</li>
</ul>

<p>An important remark, is that Common Lisp is a stable language, and
that the libraries play this game (I saw a deprecation feature staying
for 12 years). We can still run code that was written in the early 90&rsquo;s.</p>

<p>Lisp&rsquo;s simpler, non-rotting syntax plays a good role on
stability. Caution: that doesn&rsquo;t mean the implementations don&rsquo;t
evolve, quite the contrary.</p>

<p>In his appreciated article <a href="http://stevelosh.com/blog/2018/08/a-road-to-common-lisp/">A Road to Common Lisp</a>, the author writes:</p>

<blockquote>
<p>as you learn Common Lisp and look for libraries, try to suppress the voice in the back of your head that says “This project was last updated six years ago? That’s probably abandoned and broken.” The stability of Common Lisp means that sometimes libraries can just be done, not abandoned, so don’t dismiss them out of hand.</p>
</blockquote>

<p><a href="https://news.ycombinator.com/item?id=17852194">hacker news comments</a></p>

<h1 id="templates">Templates</h1>

<p>Ever had headaches with Jinja ? Ever fought against Django
templates ? Ever abandoned to clean up a big mess of html and
templating code ? Used Jinja macros to factorize code ? Maybe you
turned to the good looking Jade (Pug). So you read another documentation,
you install tools to integrate it into your project. And now damn, no
more cross-files macros. You edit blocks of code whitespace by
whitespace. And in the end, your html may still not be valid…</p>

<p>You might use Mako templates, but there&rsquo;s something you can&rsquo;t do.</p>

<p>In CL, we can also use a Django-like templating engine, <a href="https://github.com/mmontone/djula">Djula</a>
templates (despite its modest number
of stars, it is one of the most downloaded projects on Quicklisp).
The Mako equivalent would be <a href="https://github.com/mmontone/ten">Ten</a>.
However, we can alternatively just use plain old Lisp, for example with
<a href="https://github.com/ruricolist/spinneret/">Spinneret</a>. As a
consequence, we can factorize code as we always do (with spinneret functions or
lisp macros). We manipulate code as we always do. It even warns on
malformed html and has some neat features (it is clever about headers
levels, it can embed markdown, etc).</p>

<p>Stuff like this is less possible with Python, because the language is
less flexible. The components libraries I have seen use strings inside
Python code.</p>

<h1 id="deployment-shipping">Deployment, Shipping</h1>

<p>Shipping an app, even more a web app, in <em>Python</em> (and JS) is
tedious. There are no default way to ship a self-contained
executable. Current projects aiming at fixing that can work… and may not.</p>

<p>So the current solution is to turn to containers. They&rsquo;re the Big
Thing, but we still need to spend hours on reading resources, building
the Docker file, the deployment pipeline, fixing bugs, updating the
stack, accepting security holes, etc. Hours we could put on our
app. With Docker though, users still can&rsquo;t download a binary.</p>

<p>In <em>Common Lisp</em>: we (re)discover the joy of a compiled language. We
compile our program to machine code, the binary embeds the run-time, the
debugger, the web server, the static assets, and we ship it. We run it on
the server and we can access it from the outside straight away.</p>

<p>An SBCL image of a non-trivial web project will weight ± 20 to 30MB
(with core compression). For a lighter binary (not that I care
personally), we could try ECL (that compiles to C), or use
tree-shakers of proprietary implementations (LispWorks, Allegro).</p>

<p>We can still benefit from Docker if needed, of course.</p>

<p><em>Deployment process in Python</em>: install Python and pip, install pip
dependencies and their system requirements and be prepared for errors (or try non-standard tools,
like Platter), configure a server for static files (nginx, whitenoise), run a
WSGI web server,…</p>

<p><em>Deployment in CL</em>: build your binary, send it to the server, run
it. Configure nginx eventually. We can compile and include assets into
the image (see <a href="https://github.com/eudoxia0/rock">Rock</a>).</p>

<h1 id="performance">Performance</h1>

<p>Python is notoriously slow, and passed the hobby project you quickly
realize that.</p>

<p>Python has a Global Interpreter Lock.</p>

<p>SBCL compiles to machine code and is garbage collected [1].</p>

<p>We can fine-tune the types in our Lisp programs for the compiler to
make the consequent optimizations. We can run in &ldquo;debugging first&rdquo; or
in &ldquo;speed first&rdquo; modes. We can inline code to gain in the cost of
function calls.</p>

<p>As a consequence, you may not need memcached in your Lisp project yet.</p>

<ul>
<li><a href="https://lispcookbook.github.io/cl-cookbook/performance.html">https://lispcookbook.github.io/cl-cookbook/performance.html</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/1udu69/how_to_make_lisp_go_faster_than_cpdf/">CL can be tuned to be faster than C</a></li>
<li>interesting stuff:
<a href="https://github.com/marcoheisig/Petalisp">Petalisp</a> - an attempt to
generate high performance code for parallel computers by
JIT-compiling array definitions. It works on a more fundamental
level than NumPy, by providing even more powerful N-dimensional
arrays, but just a few building blocks for working on them.</li>
<li><a href="https://tapoueh.org/blog/2014/05/why-is-pgloader-so-much-faster/">pgloader</a> was re-written from Python to Common Lisp for a 30x speed gain.</li>
</ul>

<p>[1]: and rest assured, <a href="https://lisp-journey.gitlab.io/blog/yes-google-develops-common-lisp/">Google improves the GC</a></p>

<h1 id="conclusion">Conclusion</h1>

<p>I hope I killed some FUD and showed you new ways to make stuff. May
that inspire you!</p>

<h1 id="appendix-faq">Appendix: FAQ</h1>

<p>Some info every Python programmer will come across eventually. Saves you some googling.</p>

<h2 id="are-there-no-iterators">Are there no iterators ?</h2>

<p>In practice, we mostly rely on closures, but there are libraries to
create iterators.</p>

<p>See <a href="https://stackoverflow.com/questions/32956033/is-there-a-straightforward-lisp-equivalent-of-pythons-generators">https://stackoverflow.com/questions/32956033/is-there-a-straightforward-lisp-equivalent-of-pythons-generators</a></p>

<h2 id="can-i-define-my-own-operator-like-in-an-oo-language">Can I define my own <code>+</code> operator like in an OO language ?</h2>

<p>By default, no, because the Common Lisp Object System (CLOS) came after the language specification
and thus everything isn&rsquo;t object-based. However there are libraries
like <a href="https://github.com/alex-gutev/generic-cl/">generic-cl</a> and, in
practice, we quickly forget about this. Different operators is also a
means for performance, good type inference and error messages.</p>

<h2 id="to-which-extent-can-lisp-be-compiled-with-all-its-dynamic-nature-garbage-collection-macros-and-what-else">To which extent can Lisp be compiled, with all its dynamic nature, garbage collection, macros and what else ?</h2>

<p>Many Lisp compilers compile to machine code (SBCL, CCL, CMUCL,…).</p>

<p>Full answer: <a href="https://stackoverflow.com/questions/913671/are-there-lisp-native-code-compilers/914383#914383">https://stackoverflow.com/questions/913671/are-there-lisp-native-code-compilers/914383#914383</a></p>

<h2 id="but-what-is-common-lisp-good-for-really">But what is Common Lisp good for, really ?</h2>

<p>We have a ready-to-use citation :)</p>

<blockquote>
<p>Please don&rsquo;t assume Lisp is only useful for Animation and Graphics, AI, Bio-informatics, B2B and Ecommerce, Data Mining, EDA/Semiconductor applications, Expert Systems, Finance, Intelligent Agents, Knowledge Management, Mechanical CAD, Modeling and Simulation, Natural Language, Optimization, Research, Risk Analysis, Scheduling, Telecom, and Web Authoring just because these are the only things they happened to list. &ndash; Kent Pitman</p>
</blockquote>

<p>Kent Pitman</p>

<p><a href="http://www.nhplace.com/kent/quoted.html">http://www.nhplace.com/kent/quoted.html</a></p>

<p>See also <a href="http://random-state.net/features-of-common-lisp.html">http://random-state.net/features-of-common-lisp.html</a></p>

<h2 id="so-why-is-cl-not-more-popular">So why is CL not more popular ?</h2>

<p>First, some reminders:</p>

<ul>
<li>popularity doesn&rsquo;t equal quality, and popularity is hard to
measure.</li>
<li>some success stories: <a href="http://lisp-lang.org/success/">http://lisp-lang.org/success/</a> Aircraft analysis suits, Missile defense, ICAD, music composition, algebra systems, bulk importer for PostgreSQL, grammar checking, 3D editor, knowledge graphs,…</li>
<li>did you know that <a href="https://tapoueh.org/blog/2014/05/why-is-pgloader-so-much-faster/">pgloader</a> was re-written from Python to Common Lisp? (for a x30 speed gain, among other benefits)</li>
<li>CL was <a href="https://www.youtube.com/watch?v=_gZK0tW8EhQ&amp;feature=youtu.be&amp;t=4175">used in a spacecraft</a> (and the REPL was used to debug the system live from the earth)</li>
<li>some companies still use and pick CL: <a href="https://github.com/azzamsa/awesome-lisp-companies">https://github.com/azzamsa/awesome-lisp-companies</a>, companies provide professional support (<a href="https://platform.sh/">Platform.sh</a>).</li>
<li>Google&rsquo;s <a href="https://en.wikipedia.org/wiki/ITA_Software">ITA Software</a> still powers airfare search on Orbitz or Kaya.com,</li>
<li>reddit v1 was written in CL! JavaScript was <del>written</del> sketched in CL! (<a href="https://jorgetavares.com/2010/05/19/original-implementation-of-javascript-in-cl/">see here</a>, with lisp code still visible in the repository: <a href="https://dxr.mozilla.org/mozilla/source/js2/semantics/">here</a>)</li>
<li>CL was number 2 on the Tiobe index for years in the 80s!</li>
</ul>

<p>That being said, my 2 cents since you ask:</p>

<ul>
<li>I think the CL world missed the web bandwagon for some time (<a href="http://common-lisp.net/">common-lisp.net</a> was horrible for some years), but that&rsquo;s been fixed.</li>
<li>an enormous code-base existed before GitHub.</li>
<li>we missed visually nice, practical content on the web, even though
there are many books. It&rsquo;s a bit better now.</li>
<li>CL missed a package manager for some time behind other languages, that&rsquo;s now fixed.</li>
<li>I reckon CL is still quite hard for the web, it doesn&rsquo;t have a killer web framework (though maybe <a href="http://40ants.com/weblocks/quickstart.html">Weblocks</a>, <a href="https://github.com/rabbibotton/clog">CLOG</a> or <a href="https://github.com/interactive-ssr/hunchenissr">ISSR</a> soon©, all isomorphic web frameworks), hence no hype.</li>
<li>CL seems to be used for big, non-trivial projects, hence it gets no easy hype.</li>
<li>CL has no entity doing marketing today. We saw the Common Lisp
foundation pairing with sponsors recently. It <em>did</em> receive a lot of
financial and institutional support from the MIT, the NASA, Xerox, Carnegie
Mellon University (CMUCL), Lisp vendors (Symbolics, Lucid, Franz…),…</li>
<li>CL worked well with Emacs, Vim, CCL&rsquo;s built-in editor on macOs,
LispWorks&rsquo; editor (which has a free version), but this doesn&rsquo;t
satisfy the masses. We now have more options, including Atom (very
good support), VSCode (okay support) and Eclipse (basic support).</li>
<li>other reasons: it may be hard (or harder than the concurrence) to
grasp and getting started with, Lisp isn&rsquo;t for everyone, it gets a lot of
FUD, and has a so-called Lisp curse!</li>
</ul>

<p>but that&rsquo;s all debatable, I wouldn&rsquo;t focus much on this. <a href="https://lisp-journey.gitlab.io/blog/these-years-in-common-lisp-2018/#implementations">Times are
good for
implementations</a>, that&rsquo;s what counts.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Replic v0.12</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">29 10 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>We recently pushed our <a href="https://github.com/vindarel/replic/">replic</a>
library version 0.12, adding a couple of expected features, thanks to
the input of our <del>users</del> user:</p>

<ul>
<li>we can TAB-complete sentences (strings inside quotes)</li>
<li>we can define a different completion method for each arguments of a
command.</li>
<li>we added a declarative way to automatically print a function&rsquo;s
result. The default function can be overriden by users (in order
too, for example, color output).</li>
</ul>

<p>So we can do something like this: we create a function (that will
become a command on the readline command line):</p>

<pre><code class="language-lisp">(defun say (verb name)
  (format t &quot;~a, ~a !~&amp;&quot; verb name))
</code></pre>

<p>We define how to TAB-complete its arguments:</p>

<pre><code class="language-lisp">(replic.completion:add-completion &quot;say&quot;
                                  (list &quot;greetings&quot; &quot;\&quot;nice to see you\&quot;&quot;)
                                  (lambda () *names*))
</code></pre>

<p>Now if you type <code>say TAB</code> you get the two greeting choices. After you
pick one and press TAB again, you get the names that were given to
<code>hello</code>.</p>

<p>What&rsquo;s beginning to be wanted now is fuzzy completion.</p>

<p>Hope you enjoy.</p>

<hr />

<p>What is replic&rsquo;s goal ?</p>

<blockquote>
<p>Building a readline application is cool, but readline gives you the
basics and you must still build a REPL around it: loop and read
commands, catch a =C-c=, a =C-d=, ask confirmation to quit, print
the general help, the help of a command, setup the completion of
commands, the completion of their arguments, load an init file,
colorize output,&hellip;  =replic= does this for you.</p>
</blockquote>

<p>Replic&rsquo;s goal is that when you have a lisp library, with lisp
functions, it should be straightforward to create a terminal
application out of it.</p>

<p>Here&rsquo;s an example in the wild. The <code>lyrics</code> library is cool. It is a lisp library, it must be used on the Lisp REPL. This is the amount of code that was needed to create a terminal application out of it: <a href="https://github.com/mihaiolteanu/lyrics/pull/1/files">https://github.com/mihaiolteanu/lyrics/pull/1/files</a></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Compile Time Type Checking in Common Lisp</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">29 10 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>We often hear that Common Lisp is dynamically typed, which is not
wrong, but that leads to the belief that Lisp is as bad as Python
concerning types, which is plainly wrong. We don&rsquo;t hear enough that CL
is a compiled language, that we can add type annotations, and that
SBCL does thorough type checking. Hence, what we have at hand is
awesome: we can compile a whole program or <em>compile a single function</em>
and get type warnings. Once again, the feedback is immediate. We can
define our own types and get compile-time type warnings.</p>

<p>You use a paramater that must be a list of list of strings of length 3
? Ok, define the type:</p>

<pre><code class="language-lisp">(defun list-of-3tuples-strings-p (list)
  &quot;Return t if LIST is a list composed of 3-tuples, made only of strings.&quot;
  (and (consp list)
       (every (lambda (it)
                (and
                 (= 3 (length it))
                 (every #'stringp it)))
              list)))

(deftype alist-of-3tuples-strings ()
  `(satisfies list-of-3tuples-strings-p))
</code></pre>

<p>and type the variable as explained below.</p>

<p>It&rsquo;s useful for development, it&rsquo;s also great to catch errors in a
user&rsquo;s configuration file. Checks are done when we <code>load</code> a file, and
error messages are explicit. We use this now in the Next browser.</p>

<p>We don&rsquo;t hear a lot about all that, maybe because the information was
hard to find, maybe because SBCL was not there at the time Lisp books
were written. The following was published to the <a href="https://lispcookbook.github.io/cl-cookbook/type.html">Common Lisp
Cookbook /type.html</a>, so
hopefully the issue is solved!</p>

<p>On the topic, don&rsquo;t miss these:</p>

<ul>
<li>the article <a href="https://medium.com/@MartinCracauer/static-type-checking-in-the-programmable-programming-language-lisp-79bb79eb068a">Static type checking in SBCL</a>, by Martin Cracauer</li>
<li>the article <a href="https://alhassy.github.io/TypedLisp/">Typed List, a Primer</a> - let&rsquo;s explore Lisp&rsquo;s fine-grained type hierarchy! with a shallow comparison to Haskell.</li>
<li>the <a href="https://github.com/stylewarning/coalton">Coalton</a> library
(pre-alpha): adding Hindley-Milner type checking to Common Lisp
which allows for gradual adoption, in the same way Typed Racket or
Hack allows for. It is as an embedded DSL in Lisp that resembles
Standard ML or OCaml, but lets you seamlessly interoperate with
non-statically-typed Lisp code (and vice versa).</li>
</ul>

<h2 id="compile-time-type-checking">Compile-time type checking</h2>

<p>You may provide type information for variables, function arguments
etc via the macros <a href="http://www.lispworks.com/documentation/HyperSpec/Body/s_declar.htm"><code>declare</code></a> and <a href="https://www.xach.com/clhs?q=declaim"><code>declaim</code></a>.
However, similar to the <code>:type</code> slot
introduced in <a href="clos.html">CLOS section</a>, the effects of type declarations are
undefined in Lisp standard and are implementation specific. So there is no
guarantee that the Lisp compiler will perform compile-time type checking.</p>

<p>However, it is possible, and SBCL is an implementation that does
thorough type checking.</p>

<p>Let&rsquo;s recall first that Lisp already warns about simple type
warnings. The following function wrongly wants to concatenate a string
and a number. When we compile it, we get a type warning.</p>

<pre><code class="language-lisp">(defconstant +foo+ 3)
(defun bar ()
  (concatenate 'string &quot;+&quot; +foo+))
; caught WARNING:
;   Constant 3 conflicts with its asserted type SEQUENCE.
;   See also:
;     The SBCL Manual, Node &quot;Handling of Types&quot;
</code></pre>

<p>The example is simple, but it already shows a capacity some other
languages don&rsquo;t have, and it is actually useful during development ;)
Now, we&rsquo;ll do better.</p>

<h3 id="declaring-the-type-of-variables">Declaring the type of variables</h3>

<p>Use the macro <a href="https://www.xach.com/clhs?q=declaim"><code>declaim</code></a>.</p>

<p>Let&rsquo;s declare that our global variable <code>*name*</code> is a string (you can
type the following in any order in the REPL):</p>

<pre><code class="language-lisp">(declaim (type (string) *name*))
(defparameter *name* &quot;book&quot;)
</code></pre>

<p>Now if we try to set it with a bad type, we get a <code>simple-type-error</code>:</p>

<pre><code class="language-lisp">(setf *name* :me)
Value of :ME in (THE STRING :ME) is :ME, not a STRING.
   [Condition of type SIMPLE-TYPE-ERROR]
</code></pre>

<p>We can do the same with our custom types. Let&rsquo;s quickly declare the type <code>list-of-strings</code>:</p>

<pre><code class="language-lisp">(defun list-of-strings-p (list)
  &quot;Return t if LIST is non nil and contains only strings.&quot;
  (and (consp list)
       (every #'stringp list)))

(deftype list-of-strings ()
  `(satisfies list-of-strings-p))
</code></pre>

<p>Now let&rsquo;s declare that our <code>*all-names*</code> variables is a list of strings:</p>

<pre><code class="language-lisp">(declaim (type (list-of-strings) *all-names*))
(defparameter *all-names* &quot;&quot;)
</code></pre>

<p>We can compose types:</p>

<pre><code class="language-lisp">(declaim (type (or null list-of-strings) *all-names*))
</code></pre>

<h3 id="declaring-the-input-and-output-types-of-functions">Declaring the input and output types of functions</h3>

<p>We use again the <code>declaim</code> macro, with <code>ftype (function …)</code> instead of just <code>type</code>:</p>

<pre><code class="language-lisp">(declaim (ftype (function (fixnum) fixnum) add))
;;                         ^^input ^^output [optional]
(defun add (n)
	(+ n  1))
</code></pre>

<p>With this we get nice type warnings at compile time.</p>

<p>If we change the function to erroneously return a string instead of a
fixnum, we get a warning:</p>

<pre><code class="language-lisp">(defun add (n)
	(format nil &quot;~a&quot; (+ n  1)))
; caught WARNING:
;   Derived type of ((GET-OUTPUT-STREAM-STRING STREAM)) is
;     (VALUES SIMPLE-STRING &amp;OPTIONAL),
;   conflicting with the declared function return type
;     (VALUES FIXNUM &amp;REST T).
</code></pre>

<p>If we use <code>add</code> inside another function, to a place that expects a
string, we get a warning:</p>

<pre><code class="language-lisp">(defun bad-concat (n)
    (concatenate 'string (add n)))
; caught WARNING:
;   Derived type of (ADD N) is
;     (VALUES FIXNUM &amp;REST T),
;   conflicting with its asserted type
;     SEQUENCE.
</code></pre>

<p>If we use <code>add</code> inside another function, and that function declares
its argument types which appear to be incompatible with those of
<code>add</code>, we get a warning:</p>

<pre><code class="language-lisp">(declaim (ftype (function (string)) bad-arg))
(defun bad-arg (n)
    (add n))
; caught WARNING:
;   Derived type of N is
;     (VALUES STRING &amp;OPTIONAL),
;   conflicting with its asserted type
;     FIXNUM.
</code></pre>

<p>This all happens indeed <em>at compile time</em>, either in the REPL,
either with a simple <code>C-c C-c</code> in Slime, or when we <code>load</code> a file.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/155-cleanup.png" alt="Cleanup">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cleanup</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">29 10 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/155-cleanup.png" alt="Cleanup" title="If it works, don't touch it!" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Things I wish someone had explained about functional programming</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">28 10 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        It's hard learning functional programming on your own. But it ought not to be. You don't need a PhD to understand functional programming. The concepts are abstract, yes. But that doesn't make them incomprehensible. It shouldn't be this difficult. This is the first in a four-part series on things I wish someone had explained to me about functional programming.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Things I wish someone had explained about functional programming</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">28 10 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        It's hard learning functional programming on your own. But it ought not to be. You don't need a PhD to understand functional programming. The concepts are abstract, yes. But that doesn't make them incomprehensible. It shouldn't be this difficult. This is the first in a four-part series on things I wish someone had explained to me about functional programming.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">September 2019 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">28 10 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        September was our second month with this round of projects, check out their monthly update!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Testing an API with emacs and restclient</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">27 10 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        When we&#39;re developing some application we frequently interact with APIs.
 There are applications like postman, httpie, insomnia and so on to accomplish this task but having an external application only to test a few endpoints or even a complex API is a little overkill.
 Using emacs and a great package called restclient.el we can have a very complete tool to handle API requests without leaving our favorite editor.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Testing an API with emacs and restclient</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">27 10 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>
When we&#39;re developing some application we frequently interact with APIs.</p>
<p>
There are applications like postman, httpie, insomnia and so on to accomplish this task but having an external application only to test a few endpoints or even a complex API is a little overkill.</p>
<p>
Using emacs and a great package called <a href="https://github.com/pashky/restclient.el">restclient.el</a> we can have a very complete tool to handle API requests without leaving our favorite editor.</p>
<div id="outline-container-headline-1" class="outline-2">
<h2 id="headline-1">
Installation
</h2>
<div id="outline-text-headline-1" class="outline-text-2">
<p>
Put these lines of code in your emacs configuration and you&#39;ll be ready to go.</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package restclient
  :ensure <span style="color:#66d9ef">t</span>
  :mode ((<span style="color:#e6db74">&#34;\\.http\\&#39;&#34;</span> <span style="color:#f92672">.</span> restclient-mode)))</code></pre></div>
</div>
<p>
Here we&#39;re using <code class="verbatim">use-package</code> to install restclient.el and also we&#39;re configuring restclient to use extension <code class="verbatim">.http</code> to enable its features.</p>
<p>
Now if we open a file with <code class="verbatim">.http</code> extension restclient will be enabled automatically.</p>
</div>
</div>
<div id="outline-container-headline-2" class="outline-2">
<h2 id="headline-2">
Example api
</h2>
<div id="outline-text-headline-2" class="outline-text-2">
<p>
We&#39;ll be using a example API to test the features of restclient so I prepared a little API in flask with a few endpoints to allow us to check the features of restclient.</p>
<p>
This is the code of the application in case you are curious</p>
<div class="src src-python">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#f92672">from</span> uuid <span style="color:#f92672">import</span> uuid4

<span style="color:#f92672">from</span> flask <span style="color:#f92672">import</span> Flask, escape, jsonify, make_response, request

app <span style="color:#f92672">=</span> Flask(__name__)

items <span style="color:#f92672">=</span> [{<span style="color:#e6db74">&#34;uid&#34;</span>: uuid4()<span style="color:#f92672">.</span>hex, <span style="color:#e6db74">&#34;name&#34;</span>: f<span style="color:#e6db74">&#34;item {i + 1}&#34;</span>} <span style="color:#66d9ef">for</span> i <span style="color:#f92672">in</span> range(<span style="color:#ae81ff">3</span>)]


SECRET <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;password&#34;</span>


<span style="color:#a6e22e">@app.route</span>(<span style="color:#e6db74">&#34;/&#34;</span>)
<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">index</span>():
    name <span style="color:#f92672">=</span> request<span style="color:#f92672">.</span>args<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;name&#34;</span>, <span style="color:#e6db74">&#34;World&#34;</span>)
    <span style="color:#66d9ef">return</span> f<span style="color:#e6db74">&#34;Hello, {escape(name)}!&#34;</span>


<span style="color:#a6e22e">@app.route</span>(<span style="color:#e6db74">&#34;/api&#34;</span>)
<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">api</span>():
    <span style="color:#66d9ef">return</span> jsonify({<span style="color:#e6db74">&#34;version&#34;</span>: <span style="color:#ae81ff">1.0</span>})


<span style="color:#a6e22e">@app.route</span>(<span style="color:#e6db74">&#34;/api/items&#34;</span>)
<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">list_items</span>():
    <span style="color:#66d9ef">return</span> jsonify({<span style="color:#e6db74">&#34;data&#34;</span>: items})


<span style="color:#a6e22e">@app.route</span>(<span style="color:#e6db74">&#34;/api/items&#34;</span>, methods<span style="color:#f92672">=</span>[<span style="color:#e6db74">&#34;post&#34;</span>])
<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">create_item</span>():
    <span style="color:#66d9ef">if</span> authenticated(request):
        new_item <span style="color:#f92672">=</span> {<span style="color:#e6db74">&#34;uid&#34;</span>: uuid4()<span style="color:#f92672">.</span>hex, <span style="color:#e6db74">&#34;name&#34;</span>: request<span style="color:#f92672">.</span>json<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;name&#34;</span>)}
        items<span style="color:#f92672">.</span>append(new_item)
        <span style="color:#66d9ef">return</span> make_response(jsonify({<span style="color:#e6db74">&#34;data&#34;</span>: new_item}), <span style="color:#ae81ff">201</span>)
    <span style="color:#66d9ef">else</span>:
        <span style="color:#66d9ef">return</span> make_response(jsonify({<span style="color:#e6db74">&#34;error&#34;</span>: <span style="color:#e6db74">&#34;please provide credentiales&#34;</span>}), <span style="color:#ae81ff">401</span>)


<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">authenticated</span>(req):
    token <span style="color:#f92672">=</span> req<span style="color:#f92672">.</span>headers<span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#34;authorization&#34;</span>)
    <span style="color:#66d9ef">return</span> token <span style="color:#f92672">is</span> <span style="color:#f92672">not</span> None <span style="color:#f92672">and</span> token <span style="color:#f92672">==</span> SECRET</code></pre></div>
</div>
<p>
If you don&#39;t want to install any other software to test this API you can use a docker image that contains this application.</p>
<p>
Just run the following command and you&#39;ll have an API running on port <code class="verbatim">5000</code>.</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">docker run -p 5000:5000 erickgnavar/restclient-api-example:0.1</code></pre></div>
</div>
<p>
Now we&#39;re ready to test out API using restclient.</p>
</div>
</div>
<div id="outline-container-headline-3" class="outline-2">
<h2 id="headline-3">
Usage
</h2>
<div id="outline-text-headline-3" class="outline-text-2">
<p>
Let&#39;s see some examples of how can we use restclient from within emacs but first lets create a file called <code class="verbatim">api.http</code> and open it from emacs.</p>
<div id="outline-container-headline-4" class="outline-3">
<h3 id="headline-4">
Make a <code class="verbatim">GET</code> request
</h3>
<div id="outline-text-headline-4" class="outline-text-3">
<p>
We can execute this code using <code class="verbatim">C-c C-c</code> to show the results in the current buffer or use <code class="verbatim">C-c C-v</code> to show them in a new buffer.</p>
<div class="src src-restclient">
<pre><code class="language-restclient" data-lang="restclient">GET http://localhost:5000/?name=guest
Content-Type: application/json</code></pre>
</div>
<p>
Result:</p>
<div class="src src-html">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-html" data-lang="html">Hello, guest!
<span style="color:#75715e">&lt;!-- GET http://localhost:5000/?name=guest --&gt;</span>
<span style="color:#75715e">&lt;!-- HTTP/1.0 200 OK --&gt;</span>
<span style="color:#75715e">&lt;!-- Content-Type: text/html; charset=utf-8 --&gt;</span>
<span style="color:#75715e">&lt;!-- Content-Length: 13 --&gt;</span>
<span style="color:#75715e">&lt;!-- Server: Werkzeug/0.16.0 Python/3.6.9 --&gt;</span>
<span style="color:#75715e">&lt;!-- Date: Tue, 29 Oct 2019 05:34:44 GMT --&gt;</span>
<span style="color:#75715e">&lt;!-- Request duration: 0.023261s --&gt;</span></code></pre></div>
</div>
<p>
As we can see we can define a http request in plain text. We just need to define the method and the URL of our API. In this case we&#39;re querying the root of the API. Also the response is presented in plain text including some useful data like http headers and the request duration. We can define the http request headers as well.</p>
<p>
In this case the response use an html format as we can see in the <code class="verbatim">Content-Type</code> response header.</p>
<blockquote>
<p>Note: when you create a file with many requests in it make sure you split them using a comment <code class="verbatim">#</code>, for example:</p>
<div class="src src-restclient">
<pre><code class="language-restclient" data-lang="restclient">
GET http://localhost:5000/?name=foo
# a split
GET http://localhost:5000/?name=bar
# a split
GET http://localhost:5000/?name=baz</code></pre>
</div>
<p>
If you don&#39;t add a separator an error will be raised when you try to execute the request.</p>
</blockquote>
</div>
</div>
<div id="outline-container-headline-5" class="outline-3">
<h3 id="headline-5">
JSON responses
</h3>
<div id="outline-text-headline-5" class="outline-text-3">
<p>
Now lets try to fetch a json type endpoint. Restclient identifies the content-type of the response and use an emacs mode that fits with the content-type. In this case the response is a json object so restclient enable js-mode to present the response.</p>
<div class="src src-restclient">
<pre><code class="language-restclient" data-lang="restclient">GET http://localhost:5000/api
Content-Type: application/json</code></pre>
</div>
<p>
Result:</p>
<div class="src src-js">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-js" data-lang="js">{
  <span style="color:#e6db74">&#34;version&#34;</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">1.0</span>
}
<span style="color:#75715e">// GET http://localhost:5000/api
</span><span style="color:#75715e">// HTTP/1.0 200 OK
</span><span style="color:#75715e">// Content-Type: application/json
</span><span style="color:#75715e">// Content-Length: 16
</span><span style="color:#75715e">// Server: Werkzeug/0.16.0 Python/3.6.9
</span><span style="color:#75715e">// Date: Tue, 29 Oct 2019 05:42:01 GMT
</span><span style="color:#75715e">// Request duration: 0.025286s
</span></code></pre></div>
</div>
<p>
Let&#39;s try with another endpoint that has more interesting information.</p>
<div class="src src-restclient">
<pre><code class="language-restclient" data-lang="restclient">GET http://localhost:5000/api/items
Content-Type: application/json</code></pre>
</div>
<p>
Result:</p>
<div class="src src-js">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-js" data-lang="js">{
  <span style="color:#e6db74">&#34;data&#34;</span><span style="color:#f92672">:</span> [
    {
      <span style="color:#e6db74">&#34;name&#34;</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;item 1&#34;</span>,
      <span style="color:#e6db74">&#34;uid&#34;</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;931d90b493e944d9816061f46b57ce92&#34;</span>
    },
    {
      <span style="color:#e6db74">&#34;name&#34;</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;item 2&#34;</span>,
      <span style="color:#e6db74">&#34;uid&#34;</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;edf9c8dda1ed4e8da205c53d9978ede2&#34;</span>
    },
    {
      <span style="color:#e6db74">&#34;name&#34;</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;item 3&#34;</span>,
      <span style="color:#e6db74">&#34;uid&#34;</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;57a5146e3c98479785374f38e9e4c056&#34;</span>
    }
  ]
}
<span style="color:#75715e">// GET http://localhost:5000/api/items
</span><span style="color:#75715e">// HTTP/1.0 200 OK
</span><span style="color:#75715e">// Content-Type: application/json
</span><span style="color:#75715e">// Content-Length: 188
</span><span style="color:#75715e">// Server: Werkzeug/0.16.0 Python/3.6.9
</span><span style="color:#75715e">// Date: Tue, 29 Oct 2019 05:42:33 GMT
</span><span style="color:#75715e">// Request duration: 0.026217s
</span></code></pre></div>
</div>
</div>
</div>
<div id="outline-container-headline-6" class="outline-3">
<h3 id="headline-6">
Variables and dynamic content
</h3>
<div id="outline-text-headline-6" class="outline-text-3">
<p>
What happen if we need to pass some extra information to make an http request? In restclient we can have variables and we use them in the definition of the request. In this case we&#39;ll define a <code class="verbatim">password</code> variable which contains the required <code class="verbatim">Authorization</code> value to be able access to this endpoint. Also we can define the payload of the request, in this case a json object.</p>
<p>
First let&#39;s try a wrong password to see what happen.</p>
<div class="src src-restclient">
<pre><code class="language-restclient" data-lang="restclient">:password = wrong-password

POST http://localhost:5000/api/items
Content-Type: application/json
Authorization: :password
{
    &#34;name&#34;: &#34;new item&#34;
}</code></pre>
</div>
<p>
Result:</p>
<div class="src src-js">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-js" data-lang="js">{
  <span style="color:#e6db74">&#34;error&#34;</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;please provide credentiales&#34;</span>
}
<span style="color:#75715e">// POST http://localhost:5000/api/items
</span><span style="color:#75715e">// HTTP/1.0 401 UNAUTHORIZED
</span><span style="color:#75715e">// Content-Type: application/json
</span><span style="color:#75715e">// Content-Length: 40
</span><span style="color:#75715e">// Server: Werkzeug/0.16.0 Python/3.6.9
</span><span style="color:#75715e">// Date: Tue, 29 Oct 2019 05:47:24 GMT
</span><span style="color:#75715e">// Request duration: 0.036553s
</span></code></pre></div>
</div>
<p>
We received a 401 response because the credentiales we used are not correct. Now let&#39;s try it again but now with the correct credentials.</p>
<div class="src src-restclient">
<pre><code class="language-restclient" data-lang="restclient">:password = password

POST http://localhost:5000/api/items
Content-Type: application/json
Authorization: :password
{
    &#34;name&#34;: &#34;new item&#34;
}</code></pre>
</div>
<p>
Result:</p>
<div class="src src-js">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-js" data-lang="js">{
  <span style="color:#e6db74">&#34;data&#34;</span><span style="color:#f92672">:</span> {
    <span style="color:#e6db74">&#34;name&#34;</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;new item&#34;</span>,
    <span style="color:#e6db74">&#34;uid&#34;</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;f1ede16e39754b3eb735627e78d26146&#34;</span>
  }
}
<span style="color:#75715e">// POST http://localhost:5000/api/items
</span><span style="color:#75715e">// HTTP/1.0 201 CREATED
</span><span style="color:#75715e">// Content-Type: application/json
</span><span style="color:#75715e">// Content-Length: 70
</span><span style="color:#75715e">// Server: Werkzeug/0.16.0 Python/3.6.9
</span><span style="color:#75715e">// Date: Tue, 29 Oct 2019 05:48:15 GMT
</span><span style="color:#75715e">// Request duration: 0.034962s
</span></code></pre></div>
</div>
<p>
As we can see the request was made successfully. Variables in restclient are evaluated at the time the request is made so we can define a variable and use it in as many requests as we want. This is useful when we&#39;re working with APIs that need some authentication to allow us to access to their endpoints. We can request a token then save it and use it for the rest of the request we&#39;ve defined in our file.</p>
</div>
</div>
</div>
</div>
<div id="outline-container-headline-7" class="outline-2">
<h2 id="headline-7">
Other useful features
</h2>
<div id="outline-text-headline-7" class="outline-text-2">
<div id="outline-container-headline-8" class="outline-3">
<h3 id="headline-8">
Convert request to curl format
</h3>
<div id="outline-text-headline-8" class="outline-text-3">
<p>
If we need to pass a request with its data to some friend who doesn&#39;t use emacs we can pass the request definition(it&#39;s just plain text after all) but we can also generate a <code class="verbatim">curl</code> command so it&#39;s going to be easy for anyone to test the request.</p>
<p>
We can use <code class="verbatim">C-c C-u</code> from within out request to generate a <code class="verbatim">curl</code> command. After we execute this keybinding the <code class="verbatim">curl</code> command will be copied to the clipboard.</p>
<p>
If we use this in our previous example we&#39;ll get the following <code class="verbatim">curl</code> command:</p>
<div class="src src-shell">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">  curl -i -H Authorization<span style="color:#ae81ff">\:\ </span>password -H Content-Type<span style="color:#ae81ff">\:\ </span>application/json -XPOST http<span style="color:#ae81ff">\:</span>//localhost<span style="color:#ae81ff">\:</span>5000/api/items -d <span style="color:#ae81ff">\{</span><span style="color:#e6db74">&#39;
</span><span style="color:#e6db74">  &#39;</span><span style="color:#ae81ff">\ \ \ \ \&#34;</span>name<span style="color:#ae81ff">\&#34;\:\ \&#34;</span>new<span style="color:#ae81ff">\ </span>item<span style="color:#ae81ff">\&#34;</span><span style="color:#e6db74">&#39;
</span><span style="color:#e6db74">  &#39;</span><span style="color:#ae81ff">\}</span></code></pre></div>
</div>
<p>
Now we can paste this in a terminal and the request will be made.</p>
</div>
</div>
<div id="outline-container-headline-9" class="outline-3">
<h3 id="headline-9">
Navigate through the available requests
</h3>
<div id="outline-text-headline-9" class="outline-text-3">
<p>
From the same author we have <code class="verbatim">restclient-helm</code> this package allow us to jump easily to a specific request using the combination <code class="verbatim">C-c C-g</code>. This is useful if we are working with an extensive API and we want to find some request quickly.</p>
<p>
This package use <code class="verbatim">helm</code> to present the available options and when we chose one the cursor will jump to the selection.</p>
</div>
</div>
<div id="outline-container-headline-10" class="outline-3">
<h3 id="headline-10">
Formatting payload
</h3>
<div id="outline-text-headline-10" class="outline-text-3">
<p>
If we are using json as the request body we&#39;ll need to have it formatted in some way. We can use <code class="verbatim">json-mode</code> for accomplish this.</p>
<p>
Now our installation code will be:</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package json-mode
  :ensure <span style="color:#66d9ef">t</span>)

(use-package restclient
  :ensure <span style="color:#66d9ef">t</span>
  :defer <span style="color:#66d9ef">t</span>
  :mode ((<span style="color:#e6db74">&#34;\\.http\\&#39;&#34;</span> <span style="color:#f92672">.</span> restclient-mode))
  :bind (:map restclient-mode-map
	      (<span style="color:#e6db74">&#34;C-c C-f&#34;</span> <span style="color:#f92672">.</span> json-mode-beautify)))</code></pre></div>
</div>
<p>
We&#39;re adding a new keybinding to <code class="verbatim">restclient-mode-map</code> so we can use <code class="verbatim">C-c C-f</code> to format the request body.</p>
</div>
</div>
</div>
</div>
<div id="outline-container-headline-11" class="outline-2">
<h2 id="headline-11">
Conclusion
</h2>
<div id="outline-text-headline-11" class="outline-text-2">
<p>
Having our requests defined in plain text allow us to use it even as documentation and we don&#39;t depend of some external app that use a custom format to store these requests. We can freely pass this <code class="verbatim">.http</code> file to anyone and they will be able to read it and understanding it without the need to install an application.</p>
</div>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q4 2019 Survey Results and Call for Proposals</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">22 10 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        We surveyed our members to see what they wanted us to focus on. Our next funding round for new projects will close on Saturday, July 26th, 2019 at 11:59pm PST. We&rsquo;ll be funding four projects $9,000 each over three months ($3,000/mo).
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/154-everyday-excuses.png" alt="Everyday Excuses">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Everyday Excuses</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">22 10 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/154-everyday-excuses.png" alt="Everyday Excuses" title="Finding a good reason for not doing a good job can be a full time job" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Minimal Setup for Elixir development in Emacs</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">19 10 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I&#39;ve been working professionally with Elixir for 7 months, obviously using emacs as my daily editor. In this post we&#39;ll see some packages that could be useful for Elixir development.
 I&#39;m not using LSP (yet), so the goal here is just to have a minimal setup for Elixir development.
 We&#39;re going to use use-package to install all the needed packages.
Syntax highlighting   We&#39;ll use Elixir-mode.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Minimal Setup for Elixir development in Emacs</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">19 10 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>
I&#39;ve been working professionally with Elixir for 7 months, obviously using emacs as my daily editor. In this post we&#39;ll see some packages that could be useful for Elixir development.</p>
<p>
I&#39;m not using LSP (yet), so the goal here is just to have a minimal setup for Elixir development.</p>
<p>
We&#39;re going to use <code class="verbatim">use-package</code> to install all the needed packages.</p>
<div id="outline-container-headline-1" class="outline-2">
<h2 id="headline-1">
Syntax highlighting
</h2>
<div id="outline-text-headline-1" class="outline-text-2">
<p>
We&#39;ll use <a href="https://github.com/Elixir-editors/emacs-Elixir/">Elixir-mode</a>. This package give us syntax highlighting support and some useful features like <code class="verbatim">mix-format</code> which let us format our code using <code class="verbatim">mix format</code> task, which is available since Elixir 1.6</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package elixir-mode
  :ensure <span style="color:#66d9ef">t</span>
  :bind (:map elixir-mode-map
	      (<span style="color:#e6db74">&#34;C-c C-f&#34;</span> <span style="color:#f92672">.</span> elixir-format)))</code></pre></div>
</div>
</div>
</div>
<div id="outline-container-headline-2" class="outline-2">
<h2 id="headline-2">
Go to definition
</h2>
<div id="outline-text-headline-2" class="outline-text-2">
<p>
A LSP backed package like <code class="verbatim">elixir-lsp</code> could be way more accurate for this functionality but now we&#39;re going to use <a href="https://github.com/jacktasia/dumb-jump">dumb-jump</a>.</p>
<p>
This package give us &#34;go to definition&#34; functionality just using regex. It has support for Elixir out the box and it works pretty well.</p>
<p>
We&#39;ll use <code class="verbatim">helm</code> to show the different options when dumb-jump finds more than one definition for the same term.</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package dumb-jump
  :ensure <span style="color:#66d9ef">t</span>
  :init
  (setq dumb-jump-selector <span style="color:#e6db74">&#39;helm</span>))</code></pre></div>
</div>
</div>
</div>
<div id="outline-container-headline-3" class="outline-2">
<h2 id="headline-3">
Snippets
</h2>
<div id="outline-text-headline-3" class="outline-text-2">
<p>
Using snippets can improve the speed of writing code. I&#39;m using <a href="https://github.com/joaotavora/yasnippet">yasnippet</a>, a snippets template system, and also a set of snippets(for many languages including Elixir) called <a href="https://github.com/AndreaCrotti/yasnippet-snippets">yasnippet-snippets</a>.</p>
<p>
We can install these packages with the following code. Notice that we&#39;re enabling yasnippet only for a few modes. If you want to you can enable it globally using <code class="verbatim">(yas-global-mode 1)</code>.</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package yasnippet
  :ensure <span style="color:#66d9ef">t</span>
  :hook ((prog-mode <span style="color:#f92672">.</span> yas-minor-mode)
	 (conf-mode <span style="color:#f92672">.</span> yas-minor-mode)
	 (text-mode <span style="color:#f92672">.</span> yas-minor-mode)
	 (snippet-mode <span style="color:#f92672">.</span> yas-minor-mode)))

(use-package yasnippet-snippets
  :ensure <span style="color:#66d9ef">t</span>
  :after (yasnippet))</code></pre></div>
</div>
</div>
</div>
<div id="outline-container-headline-4" class="outline-2">
<h2 id="headline-4">
Running tests
</h2>
<div id="outline-text-headline-4" class="outline-text-2">
<p>
Running tests without leaving our editor is a nice feature to have in any editor/IDE. Unfortunately I haven&#39;t found any package that does this, so I wrote some elisp code to accomplish it.</p>
<p>
To make this happen we&#39;re going to use feature called <code class="verbatim">compile</code>. Compile allows us to execute a shell command and print the resulting output in a &#34;compilation&#34; buffer so we can see the results.</p>
<p>
We can run tests using <code class="verbatim">mix test</code> in different ways</p>
<ul>
<li>
<p><code class="verbatim">mix test</code>: run all the tests within our project.</p>
</li>
<li>
<p><code class="verbatim">mix test path_to_test_file.exs</code>: run the given test file.</p>
</li>
<li>
<p><code class="verbatim">mix test path_to_test_file.exs:line_number</code>: run the test defined around the given line number.</p>
</li>
</ul>
<p>There are some other ways but these are the ones we&#39;re going to use.</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun my/mix-run-test (<span style="color:#66d9ef">&amp;optional</span> at-point)
  <span style="color:#e6db74">&#34;If AT-POINT is true it will pass the line number to mix test.&#34;</span>
  (interactive)
  (let* ((current-file (<span style="color:#a6e22e">buffer-file-name</span>))
	 (current-line (line-number-at-pos))
	 (mix-file (<span style="color:#a6e22e">concat</span> (projectile-project-root) <span style="color:#e6db74">&#34;mix.exs&#34;</span>))
	 (default-directory (<span style="color:#a6e22e">file-name-directory</span> mix-file))
	 (mix-env (<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">&#34;MIX_ENV=test &#34;</span>)))

    (if at-point
	(compile (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;%s mix test %s:%s&#34;</span> mix-env current-file current-line))
      (compile (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;%s mix test %s&#34;</span> mix-env current-file)))))

(defun my/mix-run-test-file ()
  <span style="color:#e6db74">&#34;Run mix test over the current file.&#34;</span>
  (interactive)
  (my/mix-run-test <span style="color:#66d9ef">nil</span>))

(defun my/mix-run-test-at-point ()
  <span style="color:#e6db74">&#34;Run mix test at point.&#34;</span>
  (interactive)
  (my/mix-run-test <span style="color:#66d9ef">t</span>))</code></pre></div>
</div>
<p>
We have three functions, a &#34;private&#34; function called <code class="verbatim">my/mix-run-test</code> which will do all the &#34;magic&#34;, this function will get some data about the context where it was called.
We got the <code class="verbatim">current-file</code> and <code class="verbatim">current-line</code> from where the function was called, and now we&#39;ll use this to build our shell command and then use this shell command to call <code class="verbatim">compile</code>.</p>
<p>
Now we can create two more functions to expose two different behaviors, running an entire test file or just the test our cursor is placed on.
We&#39;re going to use the latest to have a keybinding a run the test quickest.</p>
<p>
Now we can add this to our previous code:</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(use-package elixir-mode
  :ensure <span style="color:#66d9ef">t</span>
  :bind (:map elixir-mode-map
	      (<span style="color:#e6db74">&#34;C-c C-f&#34;</span> <span style="color:#f92672">.</span> elixir-format)
	      (<span style="color:#e6db74">&#34;C-c C-t&#34;</span> <span style="color:#f92672">.</span> my/mix-run-test-at-point)))</code></pre></div>
</div>
<p>
Now if we press <code class="verbatim">C-c C-t</code> in a file(<code class="verbatim">my_test.exs</code>) where our cursor is on line 10, emacs will build the command <code class="verbatim">mix test my_test.exs:10</code> and run it in a compilation buffer.</p>
</div>
</div>
<div id="outline-container-headline-5" class="outline-2">
<h2 id="headline-5">
Others useful packages
</h2>
<div id="outline-text-headline-5" class="outline-text-2">
<ul>
<li>
<p>Projectile: It&#39;s a package to handle many projects. It allows us to switch between projects easily.</p>
</li>
<li>
<p>Magit: The best interface so far for use git. If you haven&#39;t use it you definitively should give it a try.</p>
</li>
<li>
<p>direnv-mode: It&#39;s a package to load environment variables using a <code class="verbatim">.envrc</code> file. It&#39;s useful to load all the environment variables you need for a project.</p>
</li>
</ul>
</div>
</div>
<div id="outline-container-headline-6" class="outline-2">
<h2 id="headline-6">
Conclusion
</h2>
<div id="outline-text-headline-6" class="outline-text-2">
<p>
I use this setup with a few tweaks in my daily work and it works pretty well for my needs.</p>
</div>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://thereader.mitpress.mit.edu/wp-content/uploads/2019/09/final-desk.png" alt="Expert Software Designers, V8, Web Page Test, Lovestruck with React, for..in, git, and roughViz! 🧠  — Pony Foo Weekly">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Expert Software Designers, V8, Web Page Test, Lovestruck with React, for..in, git, and roughViz! 🧠  — Pony Foo Weekly</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Pony Foo Weekly</a> <span class="article__date">17 10 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="f-core"><div class="md-markdown"><p>We&#x2019;re glad you could make it this week! </p> <p>With your help, we can make Pony Foo Weekly <em>even more</em> awesome: <a href="https://ponyfoo.com/weekly/submissions?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-188" target="_blank" rel="noopener noreferrer">send tips about cool resources</a>.</p> </div><div class="wy-section-header"><h3 class="md-markdown" style="color:#fcfcfc;background-color:#7d5cff;padding:10px"><div>Expert Advice </div> </h3></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://thereader.mitpress.mit.edu/habits-of-expert-software-designers/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-188" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Habits of Expert Software Designers</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/best-practices" style="color:#900070;background-color:#ffe270" class="wy-link-tag">Best Practices</a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>The best software designers employ specific habits, learned practices, and observed principles when they work. Here are a few of them.</p> </div></div></td><td class="wy-td wy-link-cell-image"><a href="https://thereader.mitpress.mit.edu/habits-of-expert-software-designers/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-188" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://thereader.mitpress.mit.edu/wp-content/uploads/2019/09/final-desk.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://medium.com/better-programming/why-coding-your-own-makes-you-a-better-developer-5c53439c5e4a?source=friends_link&#38;sk=86f893a87f23d1e87ac699e68e87b896&#38;utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-188" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Why Coding Your Own Makes You a Better Developer</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/point-of-view" style="color:#f3720d;background-color:#ffeada" class="wy-link-tag">Point of View</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>As a developer you should not reinvent the wheel, but sometimes that&#x2019;s exactly what you should do to become a better programmer.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/dannymoerkerke?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-188" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Danny Moerkerke</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://alligator.io/js/v8-engine/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-188" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>V8 Engine and JavaScript Optimization Tips</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/performance" class="wy-link-tag">performance</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>A 5,000 feet overview of how the V8 JavaScript engine works and how to write JavaScript code that&#x2019;s optimized for fast parsing speed.</p> </div></div><div class="wy-link-source-section"><span class="wy-link-source wy-link-source-plain md-markdown md-markdown-inline"><p>Paul Ryan</p> </span></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://nooshu.github.io/blog/2019/10/02/how-to-read-a-wpt-waterfall-chart/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-188" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>How to read a Web Page Test waterfall chart</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/performance" class="wy-link-tag">performance</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>WebPageTest waterfall charts are a very powerful web performance tool, but can sometimes be a little confusing.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/TheRealNooshu?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-188" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Matt Hobbs</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-header"><h3 class="md-markdown" style="color:#fcfcfc;background-color:#f3720d;padding:10px"><div>A Mixed Bag </div> </h3></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://upmostly.com/web-development/how-react-reignited-my-love-for-web-development?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-188" style="color:#f3720d;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>How React Reignited My Love for Web Development</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/article" style="color:#e4f9e3;background-color:#1bc211" class="wy-link-tag">Article</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>James shares the reasons why he came back to web development after five years of iOS development, and why he attributes the comeback to React.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/upmostlyhq?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-188" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>James King</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="http://thecodebarbarian.com/mongoose-schema-design-pattern-store-what-you-query-for.html?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-188" style="color:#f3720d;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Mongoose: Store What You Query For</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/article" style="color:#e4f9e3;background-color:#1bc211" class="wy-link-tag">Article</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"></div></div><div class="wy-link-source-section"><a href="https://twitter.com/code_barbarian?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-188" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Valeri Karpov</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-header"><h3 class="md-markdown" style="color:#fcfcfc;background-color:#3aca96;padding:10px"><div>Code Things </div> </h3></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://github.com/tc39/proposal-for-in-order?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-188" style="color:#3aca96;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p><code>for..in</code> Enumeration Order Proposal at TC39</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/news" style="color:#1bc211;background-color:#e4f9e3" class="wy-link-tag">News</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Partially specifying object enumeration order in JavaScript.</p> </div></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://silvenon.com/blog/better-git-history/introduction?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-188" style="color:#3aca96;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Towards a Better Git History</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/deep-dive" style="color:#f7f0f5;background-color:#900070" class="wy-link-tag">Deep Dive</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"></div></div><div class="wy-link-source-section"><a href="https://twitter.com/silvenon?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-188" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Matija Marohni&#x107;</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://github.com/jwilber/roughViz?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-188" style="color:#3aca96;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p><code>jwilber/roughViz</code></p> </a><a href="https://ponyfoo.com/weekly/links/tagged/code" style="color:#1a4d7f;background-color:#ffe270" class="wy-link-tag">Code</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Reusable JavaScript library for creating hand-drawn styled charts in the browser. Great when you want to hand-wavily make your point.</p> <figure><img src="https://raw.githubusercontent.com/jwilber/random_data/master/roughViz.gif" alt></figure> </div></div></td></tr></table></td></tr></table></div></div><style>html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;position:relative;vertical-align:baseline}sup{top:-.5em}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto;resize:vertical;min-height:280px;max-height:900px}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item;margin:-10px -20px;padding:10px;background-color:#f6f6f6;cursor:pointer;border-bottom:2px solid #ddd}[hidden],template{display:none}body,body:after,body:before,html,html:after,html:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*,:after,:before{-webkit-box-sizing:inherit;-moz-box-sizing:inherit;box-sizing:inherit}@-moz-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-webkit-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-o-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-moz-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@-webkit-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@-o-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}.f-core{font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}.f-mono{font-family:Consolas,Menlo,Monaco,'Lucida Console','Liberation Mono','DejaVu Sans Mono','Bitstream Vera Sans Mono','Courier New',monospace,serif}.ly-custom-heading .f-heading,.ly-custom-heading h1,.ly-custom-heading h2,.ly-custom-heading h3,.ly-custom-heading h4,.ly-custom-heading h5,.ly-custom-heading h6,.ly-lean .f-heading,.ly-lean h1,.ly-lean h2,.ly-lean h3,.ly-lean h4,.ly-lean h5,.ly-lean h6{font-family:Neuton,'Hoefler Text',Palatino,Baskerville,Georgia,'Times New Roman',serif}.ly-custom-subheading .f-subheading,.ly-lean .f-subheading{font-family:Merriweather,Georgia,serif}body{margin:0;font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif;background:#fcfcfc;color:#333}img{max-width:100%;border:none}.md-markdown figure:not(.twitter-tweet-figure){background-color:#f6f6f6}.md-markdown figure:not(.twitter-tweet-figure)>a{display:block}.md-markdown figure:not(.twitter-tweet-figure)>a>img,.md-markdown figure:not(.twitter-tweet-figure)>img{display:block;margin-left:auto;margin-right:auto}.md-markdown figcaption{padding:10px;font-style:italic;font-size:14px;background:-webkit-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-moz-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-o-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-ms-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:linear-gradient(to right,#fff9e2 33%,#fcf9ee 100%);color:#555}.md-markdown .figure-has-loaded{background:-webkit-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-moz-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-o-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-ms-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:linear-gradient(to bottom,rgba(255,255,255,0) 0,#fcf9ee 100%)}b,em,font-style italic,font-weight bold,i,ins,strong{text-decoration:none}del{text-decoration:line-through}sub,sup{bottom:0;line-height:18px}button,input{overflow:visible;border-radius:0}button{border:none;padding:6px 8px;font-size:1.2em;background:0 0}button[disabled]{color:#cbccbc!important}input,select,textarea{display:block;width:100%;padding:10px 8px;line-height:18px;border:none;font:inherit}select{height:38px}ol,ul{padding:0;margin:0;list-style-position:inside}li>ol,li>ul{margin-left:20px}hr{border:none;border-top:5px solid rgba(0,0,0,.05);margin:20px 0}kbd{display:inline-block;border:1px solid #ccc;margin:0 .1em;padding:.1em .6em;line-height:1.4;font-size:11px;background-color:#f7f7f7;-webkit-box-shadow:0 1px 0 #bbb,0 0 0 2px #fff inset;box-shadow:0 1px 0 #bbb,0 0 0 2px #fff inset;border-radius:3px;color:#333;text-shadow:0 1px 0 #fff;white-space:nowrap}iframe{display:inline-block;border:none;max-width:100%}summary:hover{opacity:.8}details{padding:10px 20px 20px;border-bottom:2px dashed #ddd}details[open] summary{margin-bottom:20px}blockquote{border:none;margin:0!important}ol,p,ul{line-height:35px}p{margin:35px 0}@media only screen and (min-width:768px){ol,p,ul{line-height:30px}}a,button,input[type=submit]{cursor:pointer;text-decoration:none}.lk-link{color:#e92c6c;border-bottom:1px solid transparent;background-color:rgba(255,255,255,.04)}.lk-link .md-code-inline{position:relative}.lk-link .md-code-inline:only-child{display:inline-block;line-height:17px}.lk-link .md-code-inline:before{content:'';position:absolute;background-color:#f1e05a;top:0;left:0;right:0;bottom:0;opacity:.04}.lk-link:visited{background-color:rgba(233,44,108,.04)}.lk-link:visited .md-code-inline:before{background-color:#e92c6c}.lk-link:hover{border-bottom:1px solid #e92c6c}.lk-rainbows{position:relative;color:#333;margin-bottom:5px}.lk-rainbows:hover:before{position:absolute;content:'';left:0;right:0;bottom:-8px;height:3px;opacity:.8;-webkit-transition:.1s ease-in-out;-moz-transition:.1s ease-in-out;-o-transition:.1s ease-in-out;-ms-transition:all .1s ease-in-out;transition:.1s ease-in-out;-webkit-animation:.5s infinite bg-rainbow;-moz-animation:.5s infinite bg-rainbow;-o-animation:.5s infinite bg-rainbow;-ms-animation:bg-rainbow .5s infinite;animation:.5s infinite bg-rainbow}.lk-icon{color:#333}.lk-icon:hover{color:#e92c6c}.lk-visitor{color:#333}.lk-visitor:after{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-left:5px}.lk-visitor.lk-visitor-large:after{font-size:1em}.lk-visitor:hover:after{color:#333;border-bottom-style:solid}.lk-visitor:visited:after{color:#7d5cff}.lk-visitor-inside{color:#333}.lk-visitor-inside .lk-visitor-target:before{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-right:5px}.lk-visitor-inside.lk-visitor-large .lk-visitor-target:before{font-size:1em}.lk-visitor-inside:hover .lk-visitor-target:before{color:#333;border-bottom-style:solid}.lk-visitor-inside:visited .lk-visitor-target:before{color:#7d5cff}.lk-visitor-before{color:#333}.lk-visitor-before:before{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-right:5px}.lk-visitor-before.lk-visitor-large:before{font-size:1em}.lk-visitor-before:hover:before{color:#333;border-bottom-style:solid}.lk-visitor-before:visited:before{color:#7d5cff}.lk-visitor-before-no-underline:before{border-bottom-width:0}.lk-link-to-green{color:#cbccbc}.lk-link-to-green:visited,.lk-link-to-green:visited:before{color:#1bc211;background-color:#1bc211}.lk-link-to-green:active{outline-color:#1bc211}.lk-link-to-green:hover,.lk-link-to-green:hover:before{color:#8be186;border-bottom-color:#1bc211}.lk-green .lk-link,a.lk-green{color:#1bc211}.lk-green .lk-link:visited,a.lk-green:visited{background-color:rgba(27,194,17,.04)}.lk-green .lk-link:visited .md-code-inline:before,a.lk-green:visited .md-code-inline:before{background-color:#1bc211}.lk-green .lk-link:active,a.lk-green:active{outline-color:#1bc211}.lk-green .lk-link:hover,a.lk-green:hover{border-bottom-color:#1bc211}.lk-green.lk-icon:hover{color:#1bc211}.lk-pink-light .lk-link,a.lk-pink-light{color:#ea6c93}.lk-pink-light .lk-link:visited,a.lk-pink-light:visited{background-color:rgba(234,108,147,.04)}.lk-pink-light .lk-link:visited .md-code-inline:before,a.lk-pink-light:visited .md-code-inline:before{background-color:#ea6c93}.lk-pink-light .lk-link:active,a.lk-pink-light:active{outline-color:#ea6c93}.lk-pink-light .lk-link:hover,a.lk-pink-light:hover{border-bottom-color:#ea6c93}.lk-pink-light.lk-icon:hover{color:#ea6c93}.lk-black .lk-link,a.lk-black{color:#333}.lk-black .lk-link:visited,a.lk-black:visited{background-color:rgba(51,51,51,.04)}.lk-black .lk-link:visited .md-code-inline:before,a.lk-black:visited .md-code-inline:before{background-color:#333}.lk-black .lk-link:active,a.lk-black:active{outline-color:#333}.lk-black .lk-link:hover,a.lk-black:hover{border-bottom-color:#333}.lk-black.lk-icon:hover{color:#333}.lk-gray .lk-link,a.lk-gray{color:#999}.lk-gray .lk-link:visited,a.lk-gray:visited{background-color:rgba(153,153,153,.04)}.lk-gray .lk-link:visited .md-code-inline:before,a.lk-gray:visited .md-code-inline:before{background-color:#999}.lk-gray .lk-link:active,a.lk-gray:active{outline-color:#999}.lk-gray .lk-link:hover,a.lk-gray:hover{border-bottom-color:#999}.lk-gray.lk-icon:hover{color:#999}.lk-white .lk-link,a.lk-white{color:#fcfcfc}.lk-white .lk-link:visited,a.lk-white:visited{background-color:rgba(252,252,252,.04)}.lk-white .lk-link:visited .md-code-inline:before,a.lk-white:visited .md-code-inline:before{background-color:#fcfcfc}.lk-white .lk-link:active,a.lk-white:active{outline-color:#fcfcfc}.lk-white .lk-link:hover,a.lk-white:hover{border-bottom-color:#fcfcfc}.lk-white.lk-icon:hover{color:#fcfcfc}.lk-orange .lk-link,a.lk-orange{color:#f3720d}.lk-orange .lk-link:visited,a.lk-orange:visited{background-color:rgba(243,114,13,.04)}.lk-orange .lk-link:visited .md-code-inline:before,a.lk-orange:visited .md-code-inline:before{background-color:#f3720d}.lk-orange .lk-link:active,a.lk-orange:active{outline-color:#f3720d}.lk-orange .lk-link:hover,a.lk-orange:hover{border-bottom-color:#f3720d}.lk-orange.lk-icon:hover{color:#f3720d}.lk-lilly .lk-link,a.lk-lilly{color:#7d5cff}.lk-lilly .lk-link:visited,a.lk-lilly:visited{background-color:rgba(125,92,255,.04)}.lk-lilly .lk-link:visited .md-code-inline:before,a.lk-lilly:visited .md-code-inline:before{background-color:#7d5cff}.lk-lilly .lk-link:active,a.lk-lilly:active{outline-color:#7d5cff}.lk-lilly .lk-link:hover,a.lk-lilly:hover{border-bottom-color:#7d5cff}.lk-lilly.lk-icon:hover{color:#7d5cff}.lk-blue .lk-link,a.lk-blue{color:#1a4d7f}.lk-blue .lk-link:visited,a.lk-blue:visited{background-color:rgba(26,77,127,.04)}.lk-blue .lk-link:visited .md-code-inline:before,a.lk-blue:visited .md-code-inline:before{background-color:#1a4d7f}.lk-blue .lk-link:active,a.lk-blue:active{outline-color:#1a4d7f}.lk-blue .lk-link:hover,a.lk-blue:hover{border-bottom-color:#1a4d7f}.lk-blue.lk-icon:hover{color:#1a4d7f}.lk-inherited .lk-link,a.lk-inherited{color:inherit}.lk-inherited .lk-link:active,a.lk-inherited:active{outline-color:inherit}.lk-inherited .lk-link:hover,a.lk-inherited:hover{border-bottom-color:inherit}.lk-inherited.lk-icon:hover{color:inherit}.lk-twitter .lk-link,a.lk-twitter{color:#55acee}.lk-twitter .lk-link:visited,a.lk-twitter:visited{background-color:rgba(85,172,238,.04)}.lk-twitter .lk-link:visited .md-code-inline:before,a.lk-twitter:visited .md-code-inline:before{background-color:#55acee}.lk-twitter .lk-link:active,a.lk-twitter:active{outline-color:#55acee}.lk-twitter .lk-link:hover,a.lk-twitter:hover{border-bottom-color:#55acee}.lk-twitter.lk-icon:hover{color:#55acee}.lk-facebook .lk-link,a.lk-facebook{color:#3b5998}.lk-facebook .lk-link:visited,a.lk-facebook:visited{background-color:rgba(59,89,152,.04)}.lk-facebook .lk-link:visited .md-code-inline:before,a.lk-facebook:visited .md-code-inline:before{background-color:#3b5998}.lk-facebook .lk-link:active,a.lk-facebook:active{outline-color:#3b5998}.lk-facebook .lk-link:hover,a.lk-facebook:hover{border-bottom-color:#3b5998}.lk-facebook.lk-icon:hover{color:#3b5998}.lk-clean{background-color:transparent}.lk-chrome:hover{color:#4989f4}.lk-teal .lk-link,a.lk-teal{color:#00a19c}.lk-teal .lk-link:visited,a.lk-teal:visited{background-color:rgba(0,161,156,.04)}.lk-teal .lk-link:visited .md-code-inline:before,a.lk-teal:visited .md-code-inline:before{background-color:#00a19c}.lk-teal .lk-link:active,a.lk-teal:active{outline-color:#00a19c}.lk-teal .lk-link:hover,a.lk-teal:hover{border-bottom-color:#00a19c}.lk-teal.lk-icon:hover{color:#00a19c}table{width:100%;border-spacing:0;border-collapse:separate}td,th{padding:8px}@media only screen and (max-width:950px){.table-responsive{display:block}.table-responsive>thead{display:none}.table-responsive>tbody,.table-responsive>tfoot{display:block}.table-responsive>tbody>tr,.table-responsive>tfoot>tr{display:block;background-color:rgba(203,204,188,.1);margin-bottom:30px}.table-responsive>tbody>tr:nth-child(even),.table-responsive>tfoot>tr:nth-child(even){background-color:rgba(203,204,188,.15)}.table-responsive>tbody>tr:last-child,.table-responsive>tfoot>tr:last-child{margin-bottom:0}.table-responsive>tbody>tr>td,.table-responsive>tfoot>tr>td{display:block;text-align:left}.table-responsive>tbody>tr>td:before,.table-responsive>tfoot>tr>td:before{display:block;content:attr(data-label);color:#555;font-size:13px;margin:0 0 5px}.table-responsive .table-responsive-hide{display:none}}.c-oreilly-teal{color:#00a19c}.c-yellow-highlight{color:#ffe270}.c-dark-orange{color:#f3720d}.c-pink{color:#e92c6c}.c-purple{color:#900070}.c-blue{color:#1a4d7f}.c-dark-turquoise{color:#1686a2}.c-dark-green{color:#1bc211}.c-white{color:#fcfcfc}.c-gray{color:#b7b7b7}.c-lilly{color:#7d5cff}.c-teal{color:#3aca96}.c-bg-oreilly-teal{background-color:#00a19c}.c-bg-yellow-highlight{background-color:#ffe270}.c-bg-dark-orange{background-color:#f3720d}.c-bg-pink{background-color:#e92c6c}.c-bg-purple{background-color:#900070}.c-bg-blue{background-color:#1a4d7f}.c-bg-dark-turquoise{background-color:#1686a2}.c-bg-dark-green{background-color:#1bc211}.c-bg-white{background-color:#fcfcfc}.c-bg-gray{background-color:#b7b7b7}.c-bg-lilly{background-color:#7d5cff}.c-bg-teal{background-color:#3aca96}.tj-emoji{width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em}.dc-header{margin-bottom:60px}.dc-heading{text-align:center;font-size:4em;padding:0 10px;margin-top:0;margin-bottom:10px}.dc-role{line-height:26px;padding:0 20px;margin-top:10px;text-align:center;font-style:italic;color:#cbccbc}.dc-colored{background:#f6f6f6;border-top:9px solid rgba(125,92,255,.5)}.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:800px}.md-markdown blockquote:not(.twitter-tweet){margin:0;padding:20px 0;border:none;border-top:5px solid rgba(0,0,0,.05);border-bottom:5px solid rgba(0,0,0,.05)}.md-markdown blockquote:not(.twitter-tweet) h1,.md-markdown blockquote:not(.twitter-tweet) h2,.md-markdown blockquote:not(.twitter-tweet) h3,.md-markdown blockquote:not(.twitter-tweet) h4,.md-markdown blockquote:not(.twitter-tweet) h5,.md-markdown blockquote:not(.twitter-tweet) h6{margin:-20px 0;padding:20px 0}.md-markdown blockquote:not(.twitter-tweet) .md-code-block{margin:0}.md-markdown blockquote:not(.twitter-tweet) .md-code-block:last-child{margin-bottom:-20px}.md-markdown img:first-child{margin-top:0}.md-markdown img:last-child{margin-bottom:0}.md-markdown p:first-child{margin-top:0}.md-markdown p:last-child{margin-bottom:0}.md-markdown .md-code-block+ol,.md-markdown .md-code-block+ul,.md-markdown ol+.md-code-block,.md-markdown ul+.md-code-block{margin-top:35px}.md-markdown a:not(.md-heading){color:#e92c6c;border-bottom:1px solid transparent;background-color:rgba(255,255,255,.04)}.md-markdown a:not(.md-heading) .md-code-inline{position:relative}.md-markdown a:not(.md-heading) .md-code-inline:only-child{display:inline-block;line-height:17px}.md-markdown a:not(.md-heading) .md-code-inline:before{content:'';position:absolute;background-color:#f1e05a;top:0;left:0;right:0;bottom:0;opacity:.04}.md-markdown a:not(.md-heading):visited{background-color:rgba(233,44,108,.04)}.md-markdown a:not(.md-heading):visited .md-code-inline:before{background-color:#e92c6c}.md-markdown a:not(.md-heading):hover{border-bottom:1px solid #e92c6c}.md-markdown thead{background-color:#e0e0e0}.md-markdown tbody{background-color:#f6f6f6}.md-markdown tbody tr:nth-child(even){background-color:#f9f9f9}.md-markdown h1,.md-markdown h2,.md-markdown h3,.md-markdown h4,.md-markdown h5,.md-markdown h6{padding:10px 0}.md-markdown h1:first-child,.md-markdown h2:first-child,.md-markdown h3:first-child,.md-markdown h4:first-child,.md-markdown h5:first-child,.md-markdown h6:first-child{margin-top:0}.md-markdown h1:last-child,.md-markdown h2:last-child,.md-markdown h3:last-child,.md-markdown h4:last-child,.md-markdown h5:last-child,.md-markdown h6:last-child{margin-bottom:0}.md-markdown iframe{display:block;margin:35px auto}.md-markdown iframe:first-child{margin-top:0}.md-markdown iframe:last-child{margin-bottom:0}.md-markdown li>p:only-child{display:inline}.md-markdown ul{list-style-type:none}.md-markdown ul>li:before{content:'◯';margin-right:5px}.md-heading{color:inherit}.md-markdown-inline{display:inline}.md-markdown-inline p{display:inline;line-height:initial}.md-code-block,.ocha-highlighted{margin:0 -20px}.ocha-code-block{padding:18px 50px}.md-markdown:not(.mm-content-html) .md-code-block+blockquote{max-width:inherit!important;margin:0 -20px;padding-left:20px;padding-right:20px}.md-code-block .md-code{display:block}.md-markdown-summary p{margin:10px 0}@media only screen and (min-width:768px){.md-markdown h1,.md-markdown h2,.md-markdown h3,.md-markdown h4,.md-markdown h5,.md-markdown h6{margin-left:-40px;margin-right:-40px;padding:10px 40px}.md-code-block,.ocha-highlighted{margin:0 -40px}.md-markdown:not(.mm-content-html) .md-code-block+blockquote{margin:0 -40px;padding-left:40px;padding-right:40px}}@media only screen and (min-width:1300px){.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:900px}}@media only screen and (min-width:1400px){.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:1000px}.md-code-block,.md-markdown:not(.mm-content-html) .md-code-block+blockquote,.ocha-highlighted{margin:0 -400px 0 -40px}}.md-markdown-large blockquote,.md-markdown-large code,.md-markdown-large ol,.md-markdown-large p,.md-markdown-large table,.md-markdown-large ul{max-width:inherit}.md-footnotes{margin-top:80px;padding:20px 0;border-top:1px dashed #cbccbc}.md-footnote{margin:0;padding:8px 0;font-size:14px;display:-webkit-box;display:-moz-box;display:-webkit-flex;display:-ms-flexbox;display:box;display:flex;-webkit-box-align:center;-moz-box-align:center;-o-box-align:center;-ms-flex-align:center;-webkit-align-items:center;align-items:center}.md-footnote p{line-height:16px}.md-footnote-anchor{padding:2px 6px;margin-right:10px;text-align:center;font-weight:700;color:#e92c6c}.ly-custom-subheading .md-footnote-anchor,.ly-lean .md-footnote-anchor{font-family:Merriweather,Georgia,serif}.md-markdown a.md-footnote-anchor{border:1px solid #e92c6c}.md-markdown a.md-footnote-anchor:hover{background-color:#e92c6c;color:#fcfcfc}.md-footnote-ref{margin-left:1px;margin-right:3px}.md-markdown a.md-footnote-ref{border-bottom:1px dotted}.md-code-block,.md-code-inline{-webkit-text-size-adjust:none;-ms-text-size-adjust:none;text-size-adjust:none;background:#fcfcf5;color:#4d4d4c}.md-code-block{line-height:24px}.md-code{padding:8px 10px}.md-code-inline{padding:0 6px}a .md-code{color:inherit}.md-code-comment{color:#8e908c}.md-code-attribute,.md-code-built_in,.md-code-constant,.md-code-literal,.md-code-number,.md-code-params,.md-code-pragma,.md-code-preprocessor,.md-code-regexp,.md-code-tag,.md-code-variable,.md-lang-css .md-code-class,.md-lang-css .md-code-id,.md-lang-css .md-code-pseudo,.md-lang-html .md-code-doctype,.md-lang-ruby .md-code-constant,.md-lang-xml .md-code-doctype,.md-lang-xml .md-code-pi,.md-lang-xml .md-code-tag .md-code-title,color #c82829{color:#f5871f}.md-lang-css .md-code-rule .md-code-attribute,.md-lang-ruby .md-code-class .md-code-title{color:#eab700}.md-code-header,.md-code-inheritance,.md-code-name,.md-code-string,.md-code-value,.md-lang-ruby .md-code-symbol,.md-lang-xml .md-code-cdata{color:#718c00}.md-code-title,.md-lang-css .md-code-hexcolor{color:#3e999f}.md-code-function,.md-lang-coffeescript .md-code-title,.md-lang-javascript .md-code-title,.md-lang-perl .md-code-sub,.md-lang-python .md-code-decorator,.md-lang-python .md-code-title,.md-lang-ruby .md-code-function .md-code-title,.md-lang-ruby .md-code-title .md-code-keyword{color:#4271ae}.md-code-keyword,.md-lang-javascript .md-code-function{color:#8959a8}.md-lang-coffeescript .md-lang-javascript,.md-lang-javascript .md-lang-xml,.md-lang-tex .md-code-formula,.md-lang-xml .md-code-cdata,.md-lang-xml .md-lang-css,.md-lang-xml .md-lang-javascript,.md-lang-xml .vbscript{opacity:.5}.md-code-deletion{background-color:rgba(244,0,30,.05);color:#f4001e}.md-code-addition{background-color:rgba(27,194,17,.05);color:#1bc211}.md-mark{background-color:rgba(255,226,112,.5);color:inherit}.md-mark span{color:inherit}.md-heading-hover{cursor:pointer;background-color:rgba(22,134,162,.1)}.mde-text-left{text-align:left}.mde-text-center{text-align:center}.mde-text-right{text-align:right}.mde-size-small{font-size:12px}.mde-size-small,.mde-size-small p{line-height:12px}.mde-size-large{font-size:36px}.mde-size-large,.mde-size-large p{line-height:36px}.mde-size-giant{font-size:72px}.mde-size-giant,.mde-size-giant p{line-height:72px}.mde-clearfix:after{content:' ';display:block;visibility:hidden;clear:both;font-size:0;height:0}.mde-quote{margin:0;padding:20px 0;border:none;border-top:5px solid rgba(0,0,0,.05);border-bottom:5px solid rgba(0,0,0,.05)}.mde-core{font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}.mde-mono{font-family:Consolas,Menlo,Monaco,'Lucida Console','Liberation Mono','DejaVu Sans Mono','Bitstream Vera Sans Mono','Courier New',monospace,serif}.ly-custom-heading .mde-heading,.ly-lean .mde-heading{font-family:Neuton,'Hoefler Text',Palatino,Baskerville,Georgia,'Times New Roman',serif}.ly-custom-subheading .mde-subheading,.ly-lean .mde-subheading{font-family:Merriweather,Georgia,serif}.mde-pad-0{padding:0}.mde-pad-5{padding:5px}.mde-pad-10{padding:10px}.mde-pad-15{padding:15px}.mde-pad-20{padding:20px}.mde-pad-25{padding:25px}.mde-pad-30{padding:30px}.mde-pad-50{padding:50px}.mde-mar-0{margin:0}.mde-mar-5{margin:5px}.mde-mar-10{margin:10px}.mde-mar-15{margin:15px}.mde-mar-20{margin:20px}.mde-mar-25{margin:25px}.mde-mar-30{margin:30px}.mde-mar-50{margin:50px}@media only screen and (min-width:900px){.mde-left{float:left}.mde-right{float:right}.mde-inline{display:inline-block;vertical-align:top}.mde-20{max-width:20%}.mde-25{max-width:25%}.mde-33{max-width:33.3333333333%}.mde-50{max-width:50%}.mde-66{max-width:66.6666666666%}.mde-75{max-width:75%}}.twitter-tweet-figure{background:0 0;padding:0}.twitter-tweet-figure:before{content:none}.twitter-tweet-figure .twitter-tweet{margin:0 auto}blockquote.twitter-tweet{overflow:hidden;color:#1c2022;background-color:#fff;border:1px solid #e1e8ed;border-radius:4px;width:500px;max-width:100%;min-width:220px;padding:1.25rem 1.25rem .725rem}blockquote.twitter-tweet:before{content:none}blockquote.twitter-tweet p{white-space:pre-wrap;font:16px/1.4 Helvetica,Roboto,'Segoe UI',Calibri,'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}blockquote.twitter-tweet a,blockquote.twitter-tweet a:visited{color:#2b7bb9}.wy-container{margin:0 auto;padding:20px 0;max-width:800px}.wy-container .md-markdown p{line-height:22px;margin:10px 0}.wy-container .md-markdown p:first-child{margin-top:0}.wy-container .md-markdown p:last-child{margin-bottom:0}.wy-container .md-markdown blockquote:not(.twitter-tweet){padding:10px 0}.wy-container .md-code-block{margin:0;padding:10px;white-space:pre-wrap}.wy-table{width:100%;padding:0}.wy-td{padding:0}.wy-section-link,.wy-section-markdown,.wy-section-poll,.wy-section-summary{padding-top:25px}.wy-section-thanks{margin-top:25px;padding:10px;font-size:15px;background-color:#f2fcf2}.wy-header-text,.wy-issue{display:inline-block;margin:10px 0;line-height:24px}.wy-issue{float:right;font-size:12px}.wy-issue-content{display:block;padding:0 5px;background-color:#fcfcfc}.wy-section-header{padding-top:40px}.wy-section-header h1,.wy-section-header h2,.wy-section-header h3,.wy-section-header h4,.wy-section-header h5,.wy-section-header h6{margin:0}.wy-section-header p{line-height:inherit}.wy-header-td{padding:0}.wy-header-content{margin:0 10px}.wy-header-text{color:#fcfcfc;text-shadow:1px 1px 0 #1a4d7f;font-weight:700;font-size:24px}.wy-content{padding-bottom:25px}.wy-link-addendum,.wy-link-tag,.wy-link-title{display:inline-block;vertical-align:bottom;margin-bottom:10px}.wy-link-title{border-bottom:1px solid;font-size:20px;margin-right:10px}.wy-link-tag{background-color:#1a4d7f;color:#fcfcfc;text-transform:uppercase;font-size:13px;margin-right:5px;padding:2px 4px}.wy-link-tag:last-child{margin-right:0}.wy-link-addendum{color:#999;margin-left:5px}.wy-link-addendum:hover{border-bottom-color:transparent}.wy-link-title-section{position:relative}.wy-link-stats{position:absolute;right:0;background-color:#3aca96;color:#fcfcfc;border-bottom:1px solid #299a71}.wy-link-stats-logo{background-color:rgba(0,0,0,.1);color:#299a71}.wy-link-stat{margin:3px}.wy-link-description{font-size:14px;color:#666}.wy-link-source-section{margin-top:10px}.wy-link-source{margin-right:10px;margin-bottom:10px;display:inline-block;vertical-align:middle;color:#55acee}.wy-link-source-plain{color:#333}.wy-link-source.wy-link-source-plain a{color:#55acee}.wy-link-source.wy-link-source-plain a:visited{background-color:rgba(85,172,238,.04)}.wy-link-source.wy-link-source-plain a:visited .md-code-inline:before{background-color:#55acee}.wy-link-source.wy-link-source-plain a:active{outline-color:#55acee}.wy-link-source.wy-link-source-plain a:hover{border-bottom-color:#55acee}.wy-link-sponsor{background-color:transparent;color:#999;outline:#999 solid 1px}.wy-link-cell-before-image{vertical-align:middle;width:70%}.wy-link-cell-image{padding-left:10px}.wy-link-image-anchor{display:block;overflow:hidden;max-height:300px}.wy-link-image{display:block;margin:0 auto}.wy-footer-table{margin:20px 0}.wy-footer-cell{text-align:center}.wy-read-online{font-size:13px}.wy-section-link-job .wy-link-source,.wy-section-link-job .wy-link-title{font-size:14px}.wy-section-link-job .wy-link-description{font-size:12px}.wy-link-pixel{float:right}@media only screen and (max-width:500px){.wy-issue-publication,.wy-issue-separator{display:none}}.md-code-block{margin:0!important;padding:10px}</style>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/153-edge-cases.png" alt="Edge Cases">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Edge Cases</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">15 10 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/153-edge-cases.png" alt="Edge Cases" title="There is a time consuming difference between running a feature and having a runnable feature" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://images.ponyfoo.com/uploads/carbon_small_logo-d991652d0fc54c579a0a3223b9ec95b4.png" alt="VR, Intercepting HTTP, QUIC &amp; HTTP/3, Performance, Intersection Observer, Async Functions, Recursion in React! 🍨  — Pony Foo Weekly">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">VR, Intercepting HTTP, QUIC &amp; HTTP/3, Performance, Intersection Observer, Async Functions, Recursion in React! 🍨  — Pony Foo Weekly</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Pony Foo Weekly</a> <span class="article__date">10 10 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="f-core"><div class="md-markdown"><p>We&#x2019;re glad you could make it this week! </p> <p>With your help, we can make Pony Foo Weekly <em>even more</em> awesome: <a href="https://ponyfoo.com/weekly/submissions?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" target="_blank" rel="noopener noreferrer">send tips about cool resources</a>.</p> </div><div class="wy-section-header"><h3 class="md-markdown" style="color:#fcfcfc;background-color:#3aca96;padding:10px"><div>Bleeding Edge </div> </h3></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://www.youtube.com/watch?v=RCB_mfGmh9w&#38;t=1h47m12s&#38;utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" style="color:#3aca96;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Facebook Horizon and the future of VR</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/inspiration" class="wy-link-tag">inspiration</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Facebook Horizon might not seem like such a great idea, but the vision Facebook leaders have for VR and AR in mixed reality is nothing short of inspiring. Watch the end of the keynote and skip right ahead to see what I mean.</p> </div></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-primary"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://www.educative.io/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" style="color:#3aca96;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Educative: Learn anything from CSS to System Design</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/code" style="color:#1a4d7f;background-color:#ffe270" class="wy-link-tag">Code</a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Rich, text-based courses with embedded coding environments make learning a breeze. Pick up Vue, learn React, conquer Redux, or just prep for an interview. Try a free preview today!</p> </div></div><div class="wy-link-source-section"><a href="https://ponyfoo.com/weekly/links/tagged/sponsored" class="wy-link-tag wy-link-sponsor">Sponsored</a></div></td><td class="wy-td wy-link-cell-image"><a href="https://www.educative.io/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://images.ponyfoo.com/uploads/carbon_small_logo-d991652d0fc54c579a0a3223b9ec95b4.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://httptoolkit.tech/mock/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" style="color:#3aca96;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Intercept, debug and build HTTP</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/tools" class="wy-link-tag">tools</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Intercept &#38; view all your HTTP traffic. Mock endpoints or entire servers. Rewrite, redirect, or inject errors.</p> </div></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://blog.cloudflare.com/http3-the-past-present-and-future/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" style="color:#3aca96;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>HTTP/3: the past, the present, and the future</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/news" style="color:#1bc211;background-color:#e4f9e3" class="wy-link-tag">News</a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Cloudflare dives into HTTP/3, QUIC, and how we got here.</p> </div></div></td><td class="wy-td wy-link-cell-image"><a href="https://blog.cloudflare.com/http3-the-past-present-and-future/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://blog-cloudflare-com-assets.storage.googleapis.com/2019/09/http3-option-tunnel@2x-1-1.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://www.swyx.io/writing/js-tooling?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" style="color:#3aca96;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Why JavaScript Tooling Sucks</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/point-of-view" style="color:#f3720d;background-color:#ffeada" class="wy-link-tag">Point of View</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>A reasonably balanced explainer on why JavaScript tooling sucks.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/swyx?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Shawn Wang</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-header"><h3 class="md-markdown" style="color:#fcfcfc;background-color:#900070;padding:10px"><div>Web of Bits </div> </h3></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://engineering.shopify.com/blogs/engineering/improve-ui-performance-understanding-your-user?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" style="color:#900070;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Improve Performance by Understanding Your User</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/performance" class="wy-link-tag">performance</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Darren&#x2019;s team did a deep dive into the performance of a section in the Shopify admin app. This included a mix of improvements that affected load time, perceived load time, as well as any interactions that happen after the merchant has landed in the page.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/darrenhebner?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Darren Hebner</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://css-tricks.com/an-explanation-of-how-the-intersection-observer-watches/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" style="color:#900070;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>How the Intersection Observer Watches</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/deep-dive" style="color:#f7f0f5;background-color:#900070" class="wy-link-tag">Deep Dive</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"></div></div><div class="wy-link-source-section"><span class="wy-link-source wy-link-source-plain md-markdown md-markdown-inline"><p>Travis Almand</p> </span></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://medium.com/@zhirzh/an-async-function-will-never-throw-5f75c19d78e8?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" style="color:#900070;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>An async function will never throw</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/introductory" style="color:#900070;background-color:#f7f0f5" class="wy-link-tag">Introductory</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>As it&#x2019;s promise based, it might reject, but it would never throw.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/zhirzh?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Shirsh Zibbu</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://phoboslab.org/log/2019/09/voidcall-making-of?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" style="color:#900070;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Making of a 13kB JavaScript Game</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/deep-dive" style="color:#f7f0f5;background-color:#900070" class="wy-link-tag">Deep Dive</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Dominic explains how he built a tightly packed RTS game using only 13kb of JavaScript and WebGL.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/phoboslab?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Dominic Szablewski</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-header"><h3 class="md-markdown" style="color:#fcfcfc;background-color:#7d5cff;padding:10px"><div>Just React Things </div> </h3></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://blog.sapegin.me/all/react-testing-3-jest-and-react-testing-library/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Modern React testing</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/deep-dive" style="color:#f7f0f5;background-color:#900070" class="wy-link-tag">Deep Dive</a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><blockquote> <p><em>&#x201C;In-depth snapshot of the current state of testing React components and frontend in general, explaining many whys, not just hows. We&#x2019;ll discuss why to write automated tests, what tests to write and how to write them. In practical articles we&#x2019;ll learn how to use Jest, Enzyme and React Testing Library to test React components.&#x201D;</em></p> </blockquote> <p>In this part: how to test React components with Jest and React Testing Library, as well as best practices!</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/iamsapegin?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Artem Sapegin</p> </a></div></td><td class="wy-td wy-link-cell-image"><a href="https://blog.sapegin.me/all/react-testing-3-jest-and-react-testing-library/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://d33wubrfki0l68.cloudfront.net/d7ab3695abb54f0ccf221a75cddce4296e64c5a1/41e9e/images/jest-react-testing-library.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://kentcdodds.com/blog/state-colocation-will-make-your-react-app-faster?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>State Colocation will make your React app faster</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/performance" class="wy-link-tag">performance</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>How state colocation makes your app not only more maintainable but also faster.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/kentcdodds?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Kent C. Dodds</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://coderrocketfuel.com/article/recursion-in-react-render-comments-with-nested-children?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Recursion in React: An Example</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/article" style="color:#e4f9e3;background-color:#1bc211" class="wy-link-tag">Article</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>What is recursion and why should you use when building software? And how could it be used to render recursive and nested comments component in React?</p> </div></div><div class="wy-link-source-section"><span class="wy-link-source wy-link-source-plain md-markdown md-markdown-inline"><p>Nick Major</p> </span></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://kentcdodds.com/blog/dont-sync-state-derive-it?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" style="color:#7d5cff;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Derive State instead of Syncing it</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/best-practices" style="color:#900070;background-color:#ffe270" class="wy-link-tag">Best Practices</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>How to avoid state synchronization bugs and complexity by using derived state instead.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/kentcdodds?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-187" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Kent C. Dodds</p> </a></div></td></tr></table></td></tr></table></div></div><style>html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;position:relative;vertical-align:baseline}sup{top:-.5em}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto;resize:vertical;min-height:280px;max-height:900px}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item;margin:-10px -20px;padding:10px;background-color:#f6f6f6;cursor:pointer;border-bottom:2px solid #ddd}[hidden],template{display:none}body,body:after,body:before,html,html:after,html:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*,:after,:before{-webkit-box-sizing:inherit;-moz-box-sizing:inherit;box-sizing:inherit}@-moz-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-webkit-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-o-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-moz-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@-webkit-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@-o-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}.f-core{font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}.f-mono{font-family:Consolas,Menlo,Monaco,'Lucida Console','Liberation Mono','DejaVu Sans Mono','Bitstream Vera Sans Mono','Courier New',monospace,serif}.ly-custom-heading .f-heading,.ly-custom-heading h1,.ly-custom-heading h2,.ly-custom-heading h3,.ly-custom-heading h4,.ly-custom-heading h5,.ly-custom-heading h6,.ly-lean .f-heading,.ly-lean h1,.ly-lean h2,.ly-lean h3,.ly-lean h4,.ly-lean h5,.ly-lean h6{font-family:Neuton,'Hoefler Text',Palatino,Baskerville,Georgia,'Times New Roman',serif}.ly-custom-subheading .f-subheading,.ly-lean .f-subheading{font-family:Merriweather,Georgia,serif}body{margin:0;font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif;background:#fcfcfc;color:#333}img{max-width:100%;border:none}.md-markdown figure:not(.twitter-tweet-figure){background-color:#f6f6f6}.md-markdown figure:not(.twitter-tweet-figure)>a{display:block}.md-markdown figure:not(.twitter-tweet-figure)>a>img,.md-markdown figure:not(.twitter-tweet-figure)>img{display:block;margin-left:auto;margin-right:auto}.md-markdown figcaption{padding:10px;font-style:italic;font-size:14px;background:-webkit-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-moz-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-o-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-ms-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:linear-gradient(to right,#fff9e2 33%,#fcf9ee 100%);color:#555}.md-markdown .figure-has-loaded{background:-webkit-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-moz-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-o-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-ms-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:linear-gradient(to bottom,rgba(255,255,255,0) 0,#fcf9ee 100%)}b,em,font-style italic,font-weight bold,i,ins,strong{text-decoration:none}del{text-decoration:line-through}sub,sup{bottom:0;line-height:18px}button,input{overflow:visible;border-radius:0}button{border:none;padding:6px 8px;font-size:1.2em;background:0 0}button[disabled]{color:#cbccbc!important}input,select,textarea{display:block;width:100%;padding:10px 8px;line-height:18px;border:none;font:inherit}select{height:38px}ol,ul{padding:0;margin:0;list-style-position:inside}li>ol,li>ul{margin-left:20px}hr{border:none;border-top:5px solid rgba(0,0,0,.05);margin:20px 0}kbd{display:inline-block;border:1px solid #ccc;margin:0 .1em;padding:.1em .6em;line-height:1.4;font-size:11px;background-color:#f7f7f7;-webkit-box-shadow:0 1px 0 #bbb,0 0 0 2px #fff inset;box-shadow:0 1px 0 #bbb,0 0 0 2px #fff inset;border-radius:3px;color:#333;text-shadow:0 1px 0 #fff;white-space:nowrap}iframe{display:inline-block;border:none;max-width:100%}summary:hover{opacity:.8}details{padding:10px 20px 20px;border-bottom:2px dashed #ddd}details[open] summary{margin-bottom:20px}blockquote{border:none;margin:0!important}ol,p,ul{line-height:35px}p{margin:35px 0}@media only screen and (min-width:768px){ol,p,ul{line-height:30px}}a,button,input[type=submit]{cursor:pointer;text-decoration:none}.lk-link{color:#e92c6c;border-bottom:1px solid transparent;background-color:rgba(255,255,255,.04)}.lk-link .md-code-inline{position:relative}.lk-link .md-code-inline:only-child{display:inline-block;line-height:17px}.lk-link .md-code-inline:before{content:'';position:absolute;background-color:#f1e05a;top:0;left:0;right:0;bottom:0;opacity:.04}.lk-link:visited{background-color:rgba(233,44,108,.04)}.lk-link:visited .md-code-inline:before{background-color:#e92c6c}.lk-link:hover{border-bottom:1px solid #e92c6c}.lk-rainbows{position:relative;color:#333;margin-bottom:5px}.lk-rainbows:hover:before{position:absolute;content:'';left:0;right:0;bottom:-8px;height:3px;opacity:.8;-webkit-transition:.1s ease-in-out;-moz-transition:.1s ease-in-out;-o-transition:.1s ease-in-out;-ms-transition:all .1s ease-in-out;transition:.1s ease-in-out;-webkit-animation:.5s infinite bg-rainbow;-moz-animation:.5s infinite bg-rainbow;-o-animation:.5s infinite bg-rainbow;-ms-animation:bg-rainbow .5s infinite;animation:.5s infinite bg-rainbow}.lk-icon{color:#333}.lk-icon:hover{color:#e92c6c}.lk-visitor{color:#333}.lk-visitor:after{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-left:5px}.lk-visitor.lk-visitor-large:after{font-size:1em}.lk-visitor:hover:after{color:#333;border-bottom-style:solid}.lk-visitor:visited:after{color:#7d5cff}.lk-visitor-inside{color:#333}.lk-visitor-inside .lk-visitor-target:before{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-right:5px}.lk-visitor-inside.lk-visitor-large .lk-visitor-target:before{font-size:1em}.lk-visitor-inside:hover .lk-visitor-target:before{color:#333;border-bottom-style:solid}.lk-visitor-inside:visited .lk-visitor-target:before{color:#7d5cff}.lk-visitor-before{color:#333}.lk-visitor-before:before{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-right:5px}.lk-visitor-before.lk-visitor-large:before{font-size:1em}.lk-visitor-before:hover:before{color:#333;border-bottom-style:solid}.lk-visitor-before:visited:before{color:#7d5cff}.lk-visitor-before-no-underline:before{border-bottom-width:0}.lk-link-to-green{color:#cbccbc}.lk-link-to-green:visited,.lk-link-to-green:visited:before{color:#1bc211;background-color:#1bc211}.lk-link-to-green:active{outline-color:#1bc211}.lk-link-to-green:hover,.lk-link-to-green:hover:before{color:#8be186;border-bottom-color:#1bc211}.lk-green .lk-link,a.lk-green{color:#1bc211}.lk-green .lk-link:visited,a.lk-green:visited{background-color:rgba(27,194,17,.04)}.lk-green .lk-link:visited .md-code-inline:before,a.lk-green:visited .md-code-inline:before{background-color:#1bc211}.lk-green .lk-link:active,a.lk-green:active{outline-color:#1bc211}.lk-green .lk-link:hover,a.lk-green:hover{border-bottom-color:#1bc211}.lk-green.lk-icon:hover{color:#1bc211}.lk-pink-light .lk-link,a.lk-pink-light{color:#ea6c93}.lk-pink-light .lk-link:visited,a.lk-pink-light:visited{background-color:rgba(234,108,147,.04)}.lk-pink-light .lk-link:visited .md-code-inline:before,a.lk-pink-light:visited .md-code-inline:before{background-color:#ea6c93}.lk-pink-light .lk-link:active,a.lk-pink-light:active{outline-color:#ea6c93}.lk-pink-light .lk-link:hover,a.lk-pink-light:hover{border-bottom-color:#ea6c93}.lk-pink-light.lk-icon:hover{color:#ea6c93}.lk-black .lk-link,a.lk-black{color:#333}.lk-black .lk-link:visited,a.lk-black:visited{background-color:rgba(51,51,51,.04)}.lk-black .lk-link:visited .md-code-inline:before,a.lk-black:visited .md-code-inline:before{background-color:#333}.lk-black .lk-link:active,a.lk-black:active{outline-color:#333}.lk-black .lk-link:hover,a.lk-black:hover{border-bottom-color:#333}.lk-black.lk-icon:hover{color:#333}.lk-gray .lk-link,a.lk-gray{color:#999}.lk-gray .lk-link:visited,a.lk-gray:visited{background-color:rgba(153,153,153,.04)}.lk-gray .lk-link:visited .md-code-inline:before,a.lk-gray:visited .md-code-inline:before{background-color:#999}.lk-gray .lk-link:active,a.lk-gray:active{outline-color:#999}.lk-gray .lk-link:hover,a.lk-gray:hover{border-bottom-color:#999}.lk-gray.lk-icon:hover{color:#999}.lk-white .lk-link,a.lk-white{color:#fcfcfc}.lk-white .lk-link:visited,a.lk-white:visited{background-color:rgba(252,252,252,.04)}.lk-white .lk-link:visited .md-code-inline:before,a.lk-white:visited .md-code-inline:before{background-color:#fcfcfc}.lk-white .lk-link:active,a.lk-white:active{outline-color:#fcfcfc}.lk-white .lk-link:hover,a.lk-white:hover{border-bottom-color:#fcfcfc}.lk-white.lk-icon:hover{color:#fcfcfc}.lk-orange .lk-link,a.lk-orange{color:#f3720d}.lk-orange .lk-link:visited,a.lk-orange:visited{background-color:rgba(243,114,13,.04)}.lk-orange .lk-link:visited .md-code-inline:before,a.lk-orange:visited .md-code-inline:before{background-color:#f3720d}.lk-orange .lk-link:active,a.lk-orange:active{outline-color:#f3720d}.lk-orange .lk-link:hover,a.lk-orange:hover{border-bottom-color:#f3720d}.lk-orange.lk-icon:hover{color:#f3720d}.lk-lilly .lk-link,a.lk-lilly{color:#7d5cff}.lk-lilly .lk-link:visited,a.lk-lilly:visited{background-color:rgba(125,92,255,.04)}.lk-lilly .lk-link:visited .md-code-inline:before,a.lk-lilly:visited .md-code-inline:before{background-color:#7d5cff}.lk-lilly .lk-link:active,a.lk-lilly:active{outline-color:#7d5cff}.lk-lilly .lk-link:hover,a.lk-lilly:hover{border-bottom-color:#7d5cff}.lk-lilly.lk-icon:hover{color:#7d5cff}.lk-blue .lk-link,a.lk-blue{color:#1a4d7f}.lk-blue .lk-link:visited,a.lk-blue:visited{background-color:rgba(26,77,127,.04)}.lk-blue .lk-link:visited .md-code-inline:before,a.lk-blue:visited .md-code-inline:before{background-color:#1a4d7f}.lk-blue .lk-link:active,a.lk-blue:active{outline-color:#1a4d7f}.lk-blue .lk-link:hover,a.lk-blue:hover{border-bottom-color:#1a4d7f}.lk-blue.lk-icon:hover{color:#1a4d7f}.lk-inherited .lk-link,a.lk-inherited{color:inherit}.lk-inherited .lk-link:active,a.lk-inherited:active{outline-color:inherit}.lk-inherited .lk-link:hover,a.lk-inherited:hover{border-bottom-color:inherit}.lk-inherited.lk-icon:hover{color:inherit}.lk-twitter .lk-link,a.lk-twitter{color:#55acee}.lk-twitter .lk-link:visited,a.lk-twitter:visited{background-color:rgba(85,172,238,.04)}.lk-twitter .lk-link:visited .md-code-inline:before,a.lk-twitter:visited .md-code-inline:before{background-color:#55acee}.lk-twitter .lk-link:active,a.lk-twitter:active{outline-color:#55acee}.lk-twitter .lk-link:hover,a.lk-twitter:hover{border-bottom-color:#55acee}.lk-twitter.lk-icon:hover{color:#55acee}.lk-facebook .lk-link,a.lk-facebook{color:#3b5998}.lk-facebook .lk-link:visited,a.lk-facebook:visited{background-color:rgba(59,89,152,.04)}.lk-facebook .lk-link:visited .md-code-inline:before,a.lk-facebook:visited .md-code-inline:before{background-color:#3b5998}.lk-facebook .lk-link:active,a.lk-facebook:active{outline-color:#3b5998}.lk-facebook .lk-link:hover,a.lk-facebook:hover{border-bottom-color:#3b5998}.lk-facebook.lk-icon:hover{color:#3b5998}.lk-clean{background-color:transparent}.lk-chrome:hover{color:#4989f4}.lk-teal .lk-link,a.lk-teal{color:#00a19c}.lk-teal .lk-link:visited,a.lk-teal:visited{background-color:rgba(0,161,156,.04)}.lk-teal .lk-link:visited .md-code-inline:before,a.lk-teal:visited .md-code-inline:before{background-color:#00a19c}.lk-teal .lk-link:active,a.lk-teal:active{outline-color:#00a19c}.lk-teal .lk-link:hover,a.lk-teal:hover{border-bottom-color:#00a19c}.lk-teal.lk-icon:hover{color:#00a19c}table{width:100%;border-spacing:0;border-collapse:separate}td,th{padding:8px}@media only screen and (max-width:950px){.table-responsive{display:block}.table-responsive>thead{display:none}.table-responsive>tbody,.table-responsive>tfoot{display:block}.table-responsive>tbody>tr,.table-responsive>tfoot>tr{display:block;background-color:rgba(203,204,188,.1);margin-bottom:30px}.table-responsive>tbody>tr:nth-child(even),.table-responsive>tfoot>tr:nth-child(even){background-color:rgba(203,204,188,.15)}.table-responsive>tbody>tr:last-child,.table-responsive>tfoot>tr:last-child{margin-bottom:0}.table-responsive>tbody>tr>td,.table-responsive>tfoot>tr>td{display:block;text-align:left}.table-responsive>tbody>tr>td:before,.table-responsive>tfoot>tr>td:before{display:block;content:attr(data-label);color:#555;font-size:13px;margin:0 0 5px}.table-responsive .table-responsive-hide{display:none}}.c-oreilly-teal{color:#00a19c}.c-yellow-highlight{color:#ffe270}.c-dark-orange{color:#f3720d}.c-pink{color:#e92c6c}.c-purple{color:#900070}.c-blue{color:#1a4d7f}.c-dark-turquoise{color:#1686a2}.c-dark-green{color:#1bc211}.c-white{color:#fcfcfc}.c-gray{color:#b7b7b7}.c-lilly{color:#7d5cff}.c-teal{color:#3aca96}.c-bg-oreilly-teal{background-color:#00a19c}.c-bg-yellow-highlight{background-color:#ffe270}.c-bg-dark-orange{background-color:#f3720d}.c-bg-pink{background-color:#e92c6c}.c-bg-purple{background-color:#900070}.c-bg-blue{background-color:#1a4d7f}.c-bg-dark-turquoise{background-color:#1686a2}.c-bg-dark-green{background-color:#1bc211}.c-bg-white{background-color:#fcfcfc}.c-bg-gray{background-color:#b7b7b7}.c-bg-lilly{background-color:#7d5cff}.c-bg-teal{background-color:#3aca96}.tj-emoji{width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em}.dc-header{margin-bottom:60px}.dc-heading{text-align:center;font-size:4em;padding:0 10px;margin-top:0;margin-bottom:10px}.dc-role{line-height:26px;padding:0 20px;margin-top:10px;text-align:center;font-style:italic;color:#cbccbc}.dc-colored{background:#f6f6f6;border-top:9px solid rgba(125,92,255,.5)}.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:800px}.md-markdown blockquote:not(.twitter-tweet){margin:0;padding:20px 0;border:none;border-top:5px solid rgba(0,0,0,.05);border-bottom:5px solid rgba(0,0,0,.05)}.md-markdown blockquote:not(.twitter-tweet) h1,.md-markdown blockquote:not(.twitter-tweet) h2,.md-markdown blockquote:not(.twitter-tweet) h3,.md-markdown blockquote:not(.twitter-tweet) h4,.md-markdown blockquote:not(.twitter-tweet) h5,.md-markdown blockquote:not(.twitter-tweet) h6{margin:-20px 0;padding:20px 0}.md-markdown blockquote:not(.twitter-tweet) .md-code-block{margin:0}.md-markdown blockquote:not(.twitter-tweet) .md-code-block:last-child{margin-bottom:-20px}.md-markdown img:first-child{margin-top:0}.md-markdown img:last-child{margin-bottom:0}.md-markdown p:first-child{margin-top:0}.md-markdown p:last-child{margin-bottom:0}.md-markdown .md-code-block+ol,.md-markdown .md-code-block+ul,.md-markdown ol+.md-code-block,.md-markdown ul+.md-code-block{margin-top:35px}.md-markdown a:not(.md-heading){color:#e92c6c;border-bottom:1px solid transparent;background-color:rgba(255,255,255,.04)}.md-markdown a:not(.md-heading) .md-code-inline{position:relative}.md-markdown a:not(.md-heading) .md-code-inline:only-child{display:inline-block;line-height:17px}.md-markdown a:not(.md-heading) .md-code-inline:before{content:'';position:absolute;background-color:#f1e05a;top:0;left:0;right:0;bottom:0;opacity:.04}.md-markdown a:not(.md-heading):visited{background-color:rgba(233,44,108,.04)}.md-markdown a:not(.md-heading):visited .md-code-inline:before{background-color:#e92c6c}.md-markdown a:not(.md-heading):hover{border-bottom:1px solid #e92c6c}.md-markdown thead{background-color:#e0e0e0}.md-markdown tbody{background-color:#f6f6f6}.md-markdown tbody tr:nth-child(even){background-color:#f9f9f9}.md-markdown h1,.md-markdown h2,.md-markdown h3,.md-markdown h4,.md-markdown h5,.md-markdown h6{padding:10px 0}.md-markdown h1:first-child,.md-markdown h2:first-child,.md-markdown h3:first-child,.md-markdown h4:first-child,.md-markdown h5:first-child,.md-markdown h6:first-child{margin-top:0}.md-markdown h1:last-child,.md-markdown h2:last-child,.md-markdown h3:last-child,.md-markdown h4:last-child,.md-markdown h5:last-child,.md-markdown h6:last-child{margin-bottom:0}.md-markdown iframe{display:block;margin:35px auto}.md-markdown iframe:first-child{margin-top:0}.md-markdown iframe:last-child{margin-bottom:0}.md-markdown li>p:only-child{display:inline}.md-markdown ul{list-style-type:none}.md-markdown ul>li:before{content:'◯';margin-right:5px}.md-heading{color:inherit}.md-markdown-inline{display:inline}.md-markdown-inline p{display:inline;line-height:initial}.md-code-block,.ocha-highlighted{margin:0 -20px}.ocha-code-block{padding:18px 50px}.md-markdown:not(.mm-content-html) .md-code-block+blockquote{max-width:inherit!important;margin:0 -20px;padding-left:20px;padding-right:20px}.md-code-block .md-code{display:block}.md-markdown-summary p{margin:10px 0}@media only screen and (min-width:768px){.md-markdown h1,.md-markdown h2,.md-markdown h3,.md-markdown h4,.md-markdown h5,.md-markdown h6{margin-left:-40px;margin-right:-40px;padding:10px 40px}.md-code-block,.ocha-highlighted{margin:0 -40px}.md-markdown:not(.mm-content-html) .md-code-block+blockquote{margin:0 -40px;padding-left:40px;padding-right:40px}}@media only screen and (min-width:1300px){.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:900px}}@media only screen and (min-width:1400px){.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:1000px}.md-code-block,.md-markdown:not(.mm-content-html) .md-code-block+blockquote,.ocha-highlighted{margin:0 -400px 0 -40px}}.md-markdown-large blockquote,.md-markdown-large code,.md-markdown-large ol,.md-markdown-large p,.md-markdown-large table,.md-markdown-large ul{max-width:inherit}.md-footnotes{margin-top:80px;padding:20px 0;border-top:1px dashed #cbccbc}.md-footnote{margin:0;padding:8px 0;font-size:14px;display:-webkit-box;display:-moz-box;display:-webkit-flex;display:-ms-flexbox;display:box;display:flex;-webkit-box-align:center;-moz-box-align:center;-o-box-align:center;-ms-flex-align:center;-webkit-align-items:center;align-items:center}.md-footnote p{line-height:16px}.md-footnote-anchor{padding:2px 6px;margin-right:10px;text-align:center;font-weight:700;color:#e92c6c}.ly-custom-subheading .md-footnote-anchor,.ly-lean .md-footnote-anchor{font-family:Merriweather,Georgia,serif}.md-markdown a.md-footnote-anchor{border:1px solid #e92c6c}.md-markdown a.md-footnote-anchor:hover{background-color:#e92c6c;color:#fcfcfc}.md-footnote-ref{margin-left:1px;margin-right:3px}.md-markdown a.md-footnote-ref{border-bottom:1px dotted}.md-code-block,.md-code-inline{-webkit-text-size-adjust:none;-ms-text-size-adjust:none;text-size-adjust:none;background:#fcfcf5;color:#4d4d4c}.md-code-block{line-height:24px}.md-code{padding:8px 10px}.md-code-inline{padding:0 6px}a .md-code{color:inherit}.md-code-comment{color:#8e908c}.md-code-attribute,.md-code-built_in,.md-code-constant,.md-code-literal,.md-code-number,.md-code-params,.md-code-pragma,.md-code-preprocessor,.md-code-regexp,.md-code-tag,.md-code-variable,.md-lang-css .md-code-class,.md-lang-css .md-code-id,.md-lang-css .md-code-pseudo,.md-lang-html .md-code-doctype,.md-lang-ruby .md-code-constant,.md-lang-xml .md-code-doctype,.md-lang-xml .md-code-pi,.md-lang-xml .md-code-tag .md-code-title,color #c82829{color:#f5871f}.md-lang-css .md-code-rule .md-code-attribute,.md-lang-ruby .md-code-class .md-code-title{color:#eab700}.md-code-header,.md-code-inheritance,.md-code-name,.md-code-string,.md-code-value,.md-lang-ruby .md-code-symbol,.md-lang-xml .md-code-cdata{color:#718c00}.md-code-title,.md-lang-css .md-code-hexcolor{color:#3e999f}.md-code-function,.md-lang-coffeescript .md-code-title,.md-lang-javascript .md-code-title,.md-lang-perl .md-code-sub,.md-lang-python .md-code-decorator,.md-lang-python .md-code-title,.md-lang-ruby .md-code-function .md-code-title,.md-lang-ruby .md-code-title .md-code-keyword{color:#4271ae}.md-code-keyword,.md-lang-javascript .md-code-function{color:#8959a8}.md-lang-coffeescript .md-lang-javascript,.md-lang-javascript .md-lang-xml,.md-lang-tex .md-code-formula,.md-lang-xml .md-code-cdata,.md-lang-xml .md-lang-css,.md-lang-xml .md-lang-javascript,.md-lang-xml .vbscript{opacity:.5}.md-code-deletion{background-color:rgba(244,0,30,.05);color:#f4001e}.md-code-addition{background-color:rgba(27,194,17,.05);color:#1bc211}.md-mark{background-color:rgba(255,226,112,.5);color:inherit}.md-mark span{color:inherit}.md-heading-hover{cursor:pointer;background-color:rgba(22,134,162,.1)}.mde-text-left{text-align:left}.mde-text-center{text-align:center}.mde-text-right{text-align:right}.mde-size-small{font-size:12px}.mde-size-small,.mde-size-small p{line-height:12px}.mde-size-large{font-size:36px}.mde-size-large,.mde-size-large p{line-height:36px}.mde-size-giant{font-size:72px}.mde-size-giant,.mde-size-giant p{line-height:72px}.mde-clearfix:after{content:' ';display:block;visibility:hidden;clear:both;font-size:0;height:0}.mde-quote{margin:0;padding:20px 0;border:none;border-top:5px solid rgba(0,0,0,.05);border-bottom:5px solid rgba(0,0,0,.05)}.mde-core{font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}.mde-mono{font-family:Consolas,Menlo,Monaco,'Lucida Console','Liberation Mono','DejaVu Sans Mono','Bitstream Vera Sans Mono','Courier New',monospace,serif}.ly-custom-heading .mde-heading,.ly-lean .mde-heading{font-family:Neuton,'Hoefler Text',Palatino,Baskerville,Georgia,'Times New Roman',serif}.ly-custom-subheading .mde-subheading,.ly-lean .mde-subheading{font-family:Merriweather,Georgia,serif}.mde-pad-0{padding:0}.mde-pad-5{padding:5px}.mde-pad-10{padding:10px}.mde-pad-15{padding:15px}.mde-pad-20{padding:20px}.mde-pad-25{padding:25px}.mde-pad-30{padding:30px}.mde-pad-50{padding:50px}.mde-mar-0{margin:0}.mde-mar-5{margin:5px}.mde-mar-10{margin:10px}.mde-mar-15{margin:15px}.mde-mar-20{margin:20px}.mde-mar-25{margin:25px}.mde-mar-30{margin:30px}.mde-mar-50{margin:50px}@media only screen and (min-width:900px){.mde-left{float:left}.mde-right{float:right}.mde-inline{display:inline-block;vertical-align:top}.mde-20{max-width:20%}.mde-25{max-width:25%}.mde-33{max-width:33.3333333333%}.mde-50{max-width:50%}.mde-66{max-width:66.6666666666%}.mde-75{max-width:75%}}.twitter-tweet-figure{background:0 0;padding:0}.twitter-tweet-figure:before{content:none}.twitter-tweet-figure .twitter-tweet{margin:0 auto}blockquote.twitter-tweet{overflow:hidden;color:#1c2022;background-color:#fff;border:1px solid #e1e8ed;border-radius:4px;width:500px;max-width:100%;min-width:220px;padding:1.25rem 1.25rem .725rem}blockquote.twitter-tweet:before{content:none}blockquote.twitter-tweet p{white-space:pre-wrap;font:16px/1.4 Helvetica,Roboto,'Segoe UI',Calibri,'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}blockquote.twitter-tweet a,blockquote.twitter-tweet a:visited{color:#2b7bb9}.wy-container{margin:0 auto;padding:20px 0;max-width:800px}.wy-container .md-markdown p{line-height:22px;margin:10px 0}.wy-container .md-markdown p:first-child{margin-top:0}.wy-container .md-markdown p:last-child{margin-bottom:0}.wy-container .md-markdown blockquote:not(.twitter-tweet){padding:10px 0}.wy-container .md-code-block{margin:0;padding:10px;white-space:pre-wrap}.wy-table{width:100%;padding:0}.wy-td{padding:0}.wy-section-link,.wy-section-markdown,.wy-section-poll,.wy-section-summary{padding-top:25px}.wy-section-thanks{margin-top:25px;padding:10px;font-size:15px;background-color:#f2fcf2}.wy-header-text,.wy-issue{display:inline-block;margin:10px 0;line-height:24px}.wy-issue{float:right;font-size:12px}.wy-issue-content{display:block;padding:0 5px;background-color:#fcfcfc}.wy-section-header{padding-top:40px}.wy-section-header h1,.wy-section-header h2,.wy-section-header h3,.wy-section-header h4,.wy-section-header h5,.wy-section-header h6{margin:0}.wy-section-header p{line-height:inherit}.wy-header-td{padding:0}.wy-header-content{margin:0 10px}.wy-header-text{color:#fcfcfc;text-shadow:1px 1px 0 #1a4d7f;font-weight:700;font-size:24px}.wy-content{padding-bottom:25px}.wy-link-addendum,.wy-link-tag,.wy-link-title{display:inline-block;vertical-align:bottom;margin-bottom:10px}.wy-link-title{border-bottom:1px solid;font-size:20px;margin-right:10px}.wy-link-tag{background-color:#1a4d7f;color:#fcfcfc;text-transform:uppercase;font-size:13px;margin-right:5px;padding:2px 4px}.wy-link-tag:last-child{margin-right:0}.wy-link-addendum{color:#999;margin-left:5px}.wy-link-addendum:hover{border-bottom-color:transparent}.wy-link-title-section{position:relative}.wy-link-stats{position:absolute;right:0;background-color:#3aca96;color:#fcfcfc;border-bottom:1px solid #299a71}.wy-link-stats-logo{background-color:rgba(0,0,0,.1);color:#299a71}.wy-link-stat{margin:3px}.wy-link-description{font-size:14px;color:#666}.wy-link-source-section{margin-top:10px}.wy-link-source{margin-right:10px;margin-bottom:10px;display:inline-block;vertical-align:middle;color:#55acee}.wy-link-source-plain{color:#333}.wy-link-source.wy-link-source-plain a{color:#55acee}.wy-link-source.wy-link-source-plain a:visited{background-color:rgba(85,172,238,.04)}.wy-link-source.wy-link-source-plain a:visited .md-code-inline:before{background-color:#55acee}.wy-link-source.wy-link-source-plain a:active{outline-color:#55acee}.wy-link-source.wy-link-source-plain a:hover{border-bottom-color:#55acee}.wy-link-sponsor{background-color:transparent;color:#999;outline:#999 solid 1px}.wy-link-cell-before-image{vertical-align:middle;width:70%}.wy-link-cell-image{padding-left:10px}.wy-link-image-anchor{display:block;overflow:hidden;max-height:300px}.wy-link-image{display:block;margin:0 auto}.wy-footer-table{margin:20px 0}.wy-footer-cell{text-align:center}.wy-read-online{font-size:13px}.wy-section-link-job .wy-link-source,.wy-section-link-job .wy-link-title{font-size:14px}.wy-section-link-job .wy-link-description{font-size:12px}.wy-link-pixel{float:right}@media only screen and (max-width:500px){.wy-issue-publication,.wy-issue-separator{display:none}}.md-code-block{margin:0!important;padding:10px}</style>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">¿Compostamos? Compostaje y el quinto contenedor</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">09 10 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-0eY4B7y8yzE/XZvrzWLKDtI/AAAAAAAAmas/L48x_EFJ9XEuhxdoOr5PtTwqfKS1XS0nACLcBGAsYHQ/s320/principios-diseno.png" alt="10 principios básicos de diseño ">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">10 principios básicos de diseño </h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">08 10 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"><a href="https://1.bp.blogspot.com/-0eY4B7y8yzE/XZvrzWLKDtI/AAAAAAAAmas/L48x_EFJ9XEuhxdoOr5PtTwqfKS1XS0nACLcBGAsYHQ/s1600/principios-diseno.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="10 principios básicos de diseño " border="0" data-original-height="500" data-original-width="370" height="320" src="https://1.bp.blogspot.com/-0eY4B7y8yzE/XZvrzWLKDtI/AAAAAAAAmas/L48x_EFJ9XEuhxdoOr5PtTwqfKS1XS0nACLcBGAsYHQ/s320/principios-diseno.png" title="10 principios básicos de diseño " width="236" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;"><br /></td></tr></tbody></table><br />Hace tiempo que no hablamos de diseño. En este post les voy a platicar sobre 10 principios básicos que todo diseño debe tener, independientemente de donde lo veamos, creemos o imprimamos, estos <b>10 principios deben estar siempre visibles</b> y saber representarse en una obra como dibujo, interfaz web, diseño web, etc. Así que comencemos 👍🏼<br /><h2 id="1-balance">1. Balance</h2>El balance se entiende como la armonía de elementos, tanto gráficos como de fuentes, colores, ilustraciones, etc. Incluso un diseño super saturado puede tener balance. Incluso el diseño más minimalista y sobrio puede tener balance, y eso depende de qué tan bien acomodamos los elementos, para que exista armonía y estructura.<br />No significa que todos los elementos deban estar alineados o milimétricamente separados por la misma distancia, sino que a simple vista no piensen que a un diseño le faltó color, o algún elemento para rellenar, o que hay un espacio de más que no encaja.<br /><h2 id="2-proximidad">2. Proximidad</h2>La proximidad ayuda a crear relación entre elementos de un diseño. No se vería bien tener un campo de búsqueda en un extremo de la pantalla y el botón para buscar al otro lado, porque no tendrían proximidad. <br />Ese ejemplo básico sirve para ejemplificar que los elementos en un diseño deben estar juntos y separados dependiendo del significado y la intención que queremos dar. Ni todo super junto, ni todo separado si no existe un significado que explique por qué tiene que ser así.<br /><h2 id="3-alineaci-n">3. Alineación</h2>Muchos diseñadores que empiezan creen que por alineación tiene que ser todo al centro o distribuido, como si pusieras tus elementos en una caja donde no pueden salir, y no hay nada más erróneo que eso. Alineación significa orden y se combina con proximidad. Hay elementos que en conjunto dan un significado y necesitan una alineación, y hay otros que no. <br />Un ejemplo de esto es cuando en una aplicación tenemos un menú lateral. Los elementos que están relacionados estarán alineados y agrupados; aquellos que no tendrán otra alineación, posición y distribución, y no necesariamente tienen que estar desalineados.<br /><h2 id="4-jerarqu-a-visual">4. Jerarquía visual</h2>Este es uno de los elementos más importantes, ya que permite a los usuarios dirigir la mirada en lo más importante primero, y en lo secundario al final. La jerarquía implica que usen fuentes más grandes en los textos que quieres resaltar, imágenes más llamativas en donde la imagen es la principal, y todos los demás elementos como secundarios, pequeños, no tan llamativos y que aún así complemente tu diseño.<br /><h2 id="5-repetici-n">5. Repetición</h2>¿Alguna vez han visto que empiezan a definir estilos CSS para ciertos campos y al final terminando aplicando otros? este es un problema de repetición, ya que sin un estilo de colores a lo largo de un proyecto se pierde el sentido de marca.<br />Usar la misma paleta de colores en todo el diseño, o en un sitio web es primordial para mantener consistencia, de tal forma que ese botón azul con borde redondeado lo identifiques en todas las páginas de tu sitio, y no te confundas con otro que tiene otra forma y color.<br /><h2 id="6-contraste">6. Contraste</h2>Hemos hablado mucho del contraste en el blog. Sin contraste no sabríamos diferenciar elementos del fondo, texto como cabecera de texto de párrafo, o de ilustraciones entre sí. Siempre recuerda tener contraste, no solo a nivel de blanco-negro, sino de diferentes colores, formas y fuentes que permita que no exista un resalte, una duda o una interpretación que implique gastar la vista.<br /><h2 id="7-color">7. Color</h2>En colores hay toda una ciencia de cómo escoger una gama de colores. No es tema de este post pero los puntos importantes son:<br /><ul><li>no uses más de dos o tres colores para un diseño</li><li>usa tonos de grises</li><li>usa una paleta de colores usando alguna aplicación de combinación de colores</li><li>trata de ver combinaciones nuevas, no uses siempre las mismas</li></ul><h2 id="8-espacio-negativo">8. Espacio negativo</h2>El espacio negativo se usa cuando jugamos con las siluetas de otros elementos para crear más elementos. No es un recurso que deberíamos explotar demasiado pero sí lo suficiente para que el usuario se sorprenda al identificar por sí mismo la figura escondida<br /><h2 id="9-tipograf-a">9. Tipografía</h2>La tipografía es super importante para cada diseño, y por lo tanto necesita una tipografía específica para ello. Evitemos usar las que vienen por defecto en nuestra computadora. Las fuentes que puedes encontrar en internet de forma gratuita son ideales para crear textos llamativos pero no muy originales, y las que tienes que pagar son las que son perfectas para crear toda una colección e identidad para el diseño.<br /><h2 id="10-estilo-propio">10. Estilo propio</h2>Ya que conoces todos estos principios, entonces ya puedes buscar tu propio estilo, combinando, creando y ajustando todos los principios anteriores a algo que siga manteniendo un diseño bueno. El estilo propio es lo que eventualmente muchos lanzan como lenguaje de diseño, estilos, temas, y todo lo que puedas relacionar a nivel de diseño para un sitio, aplicación, campaña de publicidad, y muchas cosas más.<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=T5Fh3Nvuvyk:mUPeUCD8xvM:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=T5Fh3Nvuvyk:mUPeUCD8xvM:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=T5Fh3Nvuvyk:mUPeUCD8xvM:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=T5Fh3Nvuvyk:mUPeUCD8xvM:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=T5Fh3Nvuvyk:mUPeUCD8xvM:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=T5Fh3Nvuvyk:mUPeUCD8xvM:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=T5Fh3Nvuvyk:mUPeUCD8xvM:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=T5Fh3Nvuvyk:mUPeUCD8xvM:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=T5Fh3Nvuvyk:mUPeUCD8xvM:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=T5Fh3Nvuvyk:mUPeUCD8xvM:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=T5Fh3Nvuvyk:mUPeUCD8xvM:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=T5Fh3Nvuvyk:mUPeUCD8xvM:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=T5Fh3Nvuvyk:mUPeUCD8xvM:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=T5Fh3Nvuvyk:mUPeUCD8xvM:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/T5Fh3Nvuvyk" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/152-s3cur1ty.png" alt="S3cur1ty">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">S3cur1ty</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">08 10 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/152-s3cur1ty.png" alt="S3cur1ty" title="At least the account passwords are sent using the national postal office" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://staticinstapaper.s3-us-west-2.amazonaws.com/blog/macos-safari.png" alt="Instapaper Save now available for Safari on Mac">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Instapaper Save now available for Safari on Mac</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Instapaper</a> <span class="article__date">02 10 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Today we’re launching Instapaper Save for Safari on Mac. You can <a href="https://apps.apple.com/us/app/instapaper-save/id1481302432?mt=12">download it now from the Mac App Store</a>.</p><figure class="tmblr-full" data-orig-height="750" data-orig-width="1200" data-orig-src="https://staticinstapaper.s3-us-west-2.amazonaws.com/blog/macos-safari.png"><img src="https://64.media.tumblr.com/693106d3940a0aae7c2bf239311ca9f1/0a5305b59c50139c-a7/s540x810/148c367edbf8e614a207e3968e6c6a3a45e96446.png" width="600" data-orig-height="750" data-orig-width="1200" data-orig-src="https://staticinstapaper.s3-us-west-2.amazonaws.com/blog/macos-safari.png" alt="image"/></figure><b></b><p>Once you’ve downloaded the app, you can set up the Safari extension as follows:</p><ol><li>Open the app</li><li>Login with your account</li><li>After you’re logged in, click “Open Safari Preferences”</li><li>Enable “Instapaper 1.0” in the Extensions tab of Safari Preferences</li></ol><p><b></b></p><p>In order to make the updated Safari extension available as soon as possible, this version of the extension only supports saving by clicking the Instapaper toolbar icon in Safari. In future versions we plan to add:</p><p><b></b></p><ul><li>Inline Twitter link saving.</li><li>Right-click to save links or pages.</li><li>Keyboard shortcut to save.</li><li>An extension to save links from other macOS apps.</li></ul><p><b></b></p><p>If you have any questions, feature requests, or issues you’d like us to sort out, please let us know at support@instapaper.com or <a href="https://twitter.com/@InstapaperHelp">@InstapaperHelp</a> on Twitter. Thanks for using Instapaper!</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/151-product-description.png" alt="Product Description">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Product Description</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">01 10 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/151-product-description.png" alt="Product Description" title="Are you going to buy it now? Please!" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Preventing SQL Injection Attacks With Python</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">30 09 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>SQL injection attacks are constantly ranked among the most common attacks against systems. While binding <em>values</em> is very common, I often find my self needing to being table and column names as well. This article will walk you through everything you need to know about SQL injections in Python.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://blog.ch3m4.org/pictures/pathlib-inheritance.png" alt="Hyperreals *R: Manejo de rutas con&amp;#160;pathlib">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hyperreals *R: Manejo de rutas con&amp;#160;pathlib</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">28 09 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Es dif&#237;cil escribir un script de python que no interaccione con el sistema de ficheros de un modo u otro, por lo que python dispone de varios m&#243;dulos para tal fin: <code>os</code>, <code>os.path</code> (<em>subm&#243;dulo de os</em>), <code>shutil</code>, <code>stats</code>, <code>glob</code>,&#8230;En la intenci&#243;n estaba ser multiplataforma, lo que ha sido fuente de muchos mayores quebraderos de cabeza con las distintas codificaciones de caracteres y distintas formas de expresar rutas de ficheros que&nbsp;existen.</p>
<p>El objeto <code>Path</code> viene a poner orden entre tantos m&#243;dulos y funciones para manejo de ficheros. La librer&#237;a est&#225;ndar se ha reescrito para aceptar estos objetos <code>Path</code>. Se puede decir sin duda que usar <code>Path</code> se ha convertido en la forma m&#225;s <em>pyth&#243;nica</em> de manipular ficheros y&nbsp;directorios.</p>
<p>Empecemos por un ejemplo tra&#237;do de la <a href="https://docs.python.org/3.7/library/pathlib.html" title="Documentaci&#243;n del m&#243;dulo pathlib">documentaci&#243;n oficial</a>:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">p</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="s1">'/etc'</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">q</span> <span class="o">=</span> <span class="n">p</span> <span class="o">/</span> <span class="s1">'init.d'</span> <span class="o">/</span> <span class="s1">'reboot'</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">q</span>
<span class="n">PosixPath</span><span class="p">(</span><span class="s1">'/etc/init.d/reboot'</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">q</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span>
<span class="n">PosixPath</span><span class="p">(</span><span class="s1">'/etc/rc.d/init.d/halt'</span><span class="p">)</span>
</code></pre></div>

<p>Paso por paso: importa el constructor <code>Path</code> del m&#243;dulo <code>pathlib</code>. Con &#233;l construye un objeto con la ruta <code>/etc</code> y, usando el operador <code>/</code>, genera otro objeto que representa la ruta <code>/etc/init.d/reboot</code>. Autom&#225;ticamente, estos objetos se construyen como instancias de <code>PosixPath</code>, que es una subclase especializada de <code>Path</code> para manejos de ficheros en sistemas Posix. La ruta <code>/etc/init.d/reboot</code> apunta a un <em>enlace simb&#243;lico</em>, por lo que se usa el m&#233;todo <code>resolve</code> para obtener la ruta absoluta del fichero al que&nbsp;apunta.</p>
<div class="admonition nota">
<p class="admonition-title">Nota</p>
<p>Observa que las operaciones con objetos <em>Path</em> generan objetos <em>Path</em> con lo que podemos encadenar operaciones para navegar a trav&#233;s de una jerarqu&#237;a de&nbsp;directorios.</p>
</div>
<h2>M&#243;dulos a los que sustituye o no&nbsp;sustituye</h2>
<p>Obviamtente, el m&#243;dulo cl&#225;sico <code>os.path</code>, utilizado para manipulaci&#243;n de rutas, es reemplazado totalmente por <code>pathlib</code>.</p>
<p>Del m&#243;dulo <code>os</code> reemplaza muchas de sus funciones para manipular ficheros y directorios. A&#250;n as&#237;, el m&#243;dulo <code>os</code> contiene otras muchas funciones para el manejo de entornos o lanzamiento de procesos que no cambian. As&#237; mismo, hay algunas operaciones especializadas con ficheros y directorios (eg: <code>os.walk</code>) que no han sido reempladas. De hecho son m&#225;s eficientes que si se hicieran con objetos <code>Path</code>.</p>
<p>Otro m&#243;dulo que ya no es necesario es <code>glob</code>, utilizado para buscar ficheros mediante patrones de&nbsp;b&#250;squeda.</p>
<h2>Rutas puras y&nbsp;concretas</h2>
<p>Seg&#250;n si tienen acceso al sistema de ficheros, podemos distingure&nbsp;entre:</p>
<ul>
<li>Ruta pura: rutas que no requieren acceso al sistema de ficheros (<code>PurePath</code>, <code>PurePosixPath</code>, <code>PureWindowsPath</code>)</li>
<li>Ruta concreta: rutas con acceso al sistema de ficheros (<code>Path</code>, <code>PosixPath</code>, <code>WindowsPath</code>)</li>
</ul>
<p>Las <em>rutas puras</em> son superclases de las <em>rutas concretas</em>. Mejor verlo gr&#225;ficamente como jerarqu&#237;a de&nbsp;clases:</p>
<p><img alt="Jerarqu&#237;a de clases Path" src="https://blog.ch3m4.org/pictures/pathlib-inheritance.png" /></p>
<h2>Ejemplos</h2>
<p>Voy a poner algunos ejemplos de uso de <code>pathlib</code> para que compares con el modo como lo estabas haciendo hasta ahora. Recomiendo revisar la documentaci&#243;n del m&#243;dulo <a href="https://docs.python.org/3.7/library/pathlib.html" title="Documentaci&#243;n del m&#243;dulo pathlib">pathlib</a> ante cualquier&nbsp;duda.</p>
<p>Para escribir en un fichero, usamos el m&#233;todo <code>open</code> de modo similar a como se hac&#237;a con la funci&#243;n <code>open</code> del mismo&nbsp;nombre:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>

<span class="n">path</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="s1">'.config'</span><span class="p">)</span>
<span class="k">with</span> <span class="n">path</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">mode</span><span class="o">=</span><span class="s1">'w'</span><span class="p">)</span> <span class="k">as</span> <span class="n">config</span><span class="p">:</span>
    <span class="n">config</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s1">'# config goes here'</span><span class="p">)</span>
</code></pre></div>

<p>Si s&#243;lo vamos a escribir una l&#237;nea, tambi&#233;n se podr&#237;a hacer de un modo m&#225;s&nbsp;directo:</p>
<div class="highlight"><pre><span></span><code><span class="n">Path</span><span class="p">(</span><span class="s1">'.config'</span><span class="p">)</span><span class="o">.</span><span class="n">write_text</span><span class="p">(</span><span class="s1">'# config goes here'</span><span class="p">)</span>
</code></pre></div>

<p>Pongamos un ejemplo m&#225;s complejo: queremos localizar los scripts de python dentro de la carpeta <code>proyectos</code> que tengan una frase. Lo habitual para recorrer un directorio era usar alguna funci&#243;n como <code>os.walk</code> o <code>os.scandir</code> para ir navegando a trav&#233;s de la jerarqu&#237;a de directorios e ir leyendo los ficheros python hasta localizar los que&nbsp;buscamos.</p>
<p>Veamos c&#243;mo se hace con <code>Path</code>:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>

<span class="n">proyectos</span> <span class="o">=</span> <span class="n">Path</span><span class="o">.</span><span class="n">home</span><span class="p">()</span> <span class="o">/</span> <span class="s1">'proyectos'</span>  <span class="c1"># carpeta en el directorio HOME</span>
<span class="n">palabra</span> <span class="o">=</span> <span class="s2">&quot;pathlib&quot;</span>

<span class="n">ficheros</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">proyectos</span><span class="o">.</span><span class="n">rglob</span><span class="p">(</span><span class="s2">&quot;*.py&quot;</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">palabra</span> <span class="ow">in</span> <span class="n">p</span><span class="o">.</span><span class="n">read_text</span><span class="p">()]</span>
</code></pre></div>

<p>Partimos del <code>Path.home()</code>, el directorio de usuario, y creamos la ruta del directorio <code>proyectos</code>. Invocando el m&#233;todo <code>.rglob()</code> obtenemos, recursivamente, todos los ficheros que cumplan con el patr&#243;n dado. Bastante&nbsp;simple.</p>
<p>La lista resultante es una lista de objetos <em>Path</em>, lo que nos facilita cualquier manipulaci&#243;n posterior que deseemos hacer sobre estos ficheros. Por ejemplo, vamos a calcular el tama&#241;o total que&nbsp;ocupan:</p>
<div class="highlight"><pre><span></span><code><span class="n">size</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">stat</span><span class="p">()</span><span class="o">.</span><span class="n">st_size</span> <span class="k">for</span> <span class="n">p</span> <span class="n">ficheros</span><span class="p">)</span>
</code></pre></div>

<p>Si se prefiere, se puede seguir usando el viejo <code>os.path.getsize</code>. Ahora tambi&#233;n acepta objetos <code>Path</code>:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">os.path</span>

<span class="n">size</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">getsize</span><span class="p">(</span><span class="n">p</span><span class="p">)</span> <span class="k">for</span> <span class="n">p</span> <span class="n">ficheros</span><span class="p">)</span>
</code></pre></div>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://staticinstapaper.s3-us-west-2.amazonaws.com/blog/darkmode.png" alt="Instapaper iOS 7.8: Dark Mode, Improved Scroll Performance, and “Share Image”">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Instapaper iOS 7.8: Dark Mode, Improved Scroll Performance, and “Share Image”</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Instapaper</a> <span class="article__date">26 09 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><figure class="tmblr-full" data-orig-height="425" data-orig-width="600" data-orig-src="https://staticinstapaper.s3-us-west-2.amazonaws.com/blog/darkmode.png"><img src="https://64.media.tumblr.com/e6c00ff8ed2e8743769ed1110e38422f/6044be3414825632-28/s540x810/0f8d90253c3ed4b988c09e939a5a19d3b84d3bbd.png" width="600" alt="image" data-orig-height="425" data-orig-width="600" data-orig-src="https://staticinstapaper.s3-us-west-2.amazonaws.com/blog/darkmode.png"/></figure></p><p>Today we launched Instapaper 7.8 for iOS 13. In the new version, dark mode will automatically turn on when you enable dark mode at the system level through iOS Settings &gt; Display &amp; Brightness &gt; Dark mode. Disabling dark mode will return Instapaper to your non-dark mode theme. If you set your device to automatically go into dark mode, Instapaper will mirror the transition.</p>
<p>Additionally, we rewrote the article list to improve scroll performance, especially during large volume syncs. You should now see smoother scrolling in general, and especially while content is downloading.</p>
<p>Lastly, we&rsquo;ve expanded the &ldquo;Tweet Shot&rdquo; feature to be compatible with apps beyond Twitter. With the new &ldquo;Share Image&rdquo; option, you can now share an image of your highlight or text selection to any app (including Twitter, of course).</p>
<figure class="tmblr-full" data-orig-height="429" data-orig-width="600" data-orig-src="https://staticinstapaper.s3-us-west-2.amazonaws.com/blog/shareimage.png"><img src="https://64.media.tumblr.com/c0c8615040b9acbd9b04f62a62c2f36b/6044be3414825632-58/s540x810/5dcf136d3734d66eb25a259bb47fbc87ad4ede09.png" width="600" alt="image" data-orig-height="429" data-orig-width="600" data-orig-src="https://staticinstapaper.s3-us-west-2.amazonaws.com/blog/shareimage.png"/></figure><p>If you have any questions, feature requests, or issues you’d like us to sort out, please let us know at support@instapaper.com or <a href="https://twitter.com/@InstapaperHelp">@InstapaperHelp</a> on Twitter. We love hearing from you and we thank you for using Instapaper!</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://phab.wmfusercontent.org/file/data/t64rdovzxdi7lzxxxkh3/PHID-FILE-lwaqoruegcizfxzsza5m/wmchart.png" alt="Performance budgets, Preloading, Profiling Performance and Animations, Visual Regression Testing &amp; Tensorflow! 🎪  — Pony Foo Weekly">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Performance budgets, Preloading, Profiling Performance and Animations, Visual Regression Testing &amp; Tensorflow! 🎪  — Pony Foo Weekly</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Pony Foo Weekly</a> <span class="article__date">26 09 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="f-core"><div class="md-markdown"><p>We&#x2019;re glad you could make it this week! </p> <p>With your help, we can make Pony Foo Weekly <em>even more</em> awesome: <a href="https://ponyfoo.com/weekly/submissions?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" target="_blank" rel="noopener noreferrer">send tips about cool resources</a>.</p> </div><div class="wy-section-header"><h3 class="md-markdown" style="color:#fcfcfc;background-color:#ff895c;padding:10px"><div>Raw Performance </div> </h3></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://phabricator.wikimedia.org/phame/live/7/post/175/wikipedia_s_javascript_initialisation_on_a_budget/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" style="color:#ff895c;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Wikipedia&#x2019;s JavaScript initialization on a budget</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/performance" class="wy-link-tag">performance</a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Wikipedia shrunk its budget to 28 KB for the initial JavaScript pipeline, to fit in two network packets.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/timotijhof?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Timo Tijhof</p> </a></div></td><td class="wy-td wy-link-cell-image"><a href="https://phabricator.wikimedia.org/phame/live/7/post/175/wikipedia_s_javascript_initialisation_on_a_budget/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://phab.wmfusercontent.org/file/data/t64rdovzxdi7lzxxxkh3/PHID-FILE-lwaqoruegcizfxzsza5m/wmchart.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-primary"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://www.educative.io/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" style="color:#ff895c;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Educative: Learn anything from CSS to System Design</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/code" style="color:#1a4d7f;background-color:#ffe270" class="wy-link-tag">Code</a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Rich, text-based courses with embedded coding environments make learning a breeze. Pick up Vue, learn React, conquer Redux, or just prep for an interview. Try a free preview today!</p> </div></div><div class="wy-link-source-section"><a href="https://ponyfoo.com/weekly/links/tagged/sponsored" class="wy-link-tag wy-link-sponsor">Sponsored</a></div></td><td class="wy-td wy-link-cell-image"><a href="https://www.educative.io/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://images.ponyfoo.com/uploads/carbon_small_logo-d991652d0fc54c579a0a3223b9ec95b4.png" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://www.alexrp.co.uk/blog/preloading-fonts.html?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" style="color:#ff895c;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>&#x201C;Preloading a font even when I shouldn&#x2019;t have to&#x201D;</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/performance" class="wy-link-tag">performance</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Preloading fonts is a great way to get text to display faster on a web page. Alex talks about the benefits of preloading fonts even when they&#x2019;re referenced in inline CSS.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/alexrp?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Alex Painter</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-header"><h3 class="md-markdown" style="color:#fcfcfc;background-color:#1686a2;padding:10px"><div>Perf Profiling </div> </h3></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://blog.superhuman.com/performance-metrics-for-blazingly-fast-web-apps-ec12efa26bcb?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" style="color:#1686a2;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Performance metrics for blazingly fast web apps</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/performance" class="wy-link-tag">performance</a></div><table><tr><td class="wy-td wy-link-cell-before-image"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>On the one hand, it is hard to design metrics that accurately represent the user experience. On the other hand, it is difficult to make metrics that are usefully precise. As a result, many teams cannot trust their performance data.</p> <p>Conrad shares an approach to create metrics that are accurate and precise, make graphs that quickly show regressions, design visualizations that quickly show the impact of optimizations, and build fast software faster!</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/conradirwin?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Conrad Irwin</p> </a></div></td><td class="wy-td wy-link-cell-image"><a href="https://blog.superhuman.com/performance-metrics-for-blazingly-fast-web-apps-ec12efa26bcb?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" target="_blank" rel="noopener noreferrer" class="wy-link-image-anchor"><img src="https://miro.medium.com/max/1200/1*1RziAA40uBncN3UBwn9i7w.jpeg" alt class="wy-link-image"></a></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://kentcdodds.com/blog/profile-a-react-app-for-performance?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" style="color:#1686a2;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Profile a React App for Performance</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/performance" class="wy-link-tag">performance</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>How to use the React DevTools and React&#x2019;s profiling build to properly profile a production app.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/kentcdodds?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Kent C. Dodds</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-secondary"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="http://go.thoughtleaders.io/1353920190926?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" style="color:#1686a2;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Use Clubhouse: It&#x2019;s Free and Awesome</p> </a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>&#x201C;Clubhouse is like a fast and delightful version of Jira, a more purposeful version of Trello,&#x201D; says a current user. See if you agree.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/clubhouse?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Clubhouse</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/sponsored" class="wy-link-tag wy-link-sponsor">Sponsored</a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://calibreapp.com/blog/investigate-animation-performance-with-devtools/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" style="color:#1686a2;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Investigate animation performance with DevTools</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/performance" class="wy-link-tag">performance</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Users want snappy and delightful experiences, which means 60 FPS. To achieve this, you&#x2019;ll have to know how browsers transform code to pixels on the screen and how styles can affect that process.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/bibydigital?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Milica Mihajlija</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://seesparkbox.com/foundry/design_system_visual_regression_testing?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" style="color:#1686a2;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Visual Regression Testing in Design Systems</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/best-practices" style="color:#900070;background-color:#ffe270" class="wy-link-tag">Best Practices</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Visual regression testing in a design system helps detect unintended changes, and it can be done with various tools such as Percy, Chromatic, and Appitools.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/patrickfulton?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Patrick Fulton</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-header"><h3 class="md-markdown" style="color:#fcfcfc;background-color:#555;padding:10px"><div>Even more stuff </div> </h3></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://www.smashingmagazine.com/2019/09/machine-learning-front-end-developers-tensorflowjs/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" style="color:#555;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Machine Learning with Tensorflow</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/introductory" style="color:#900070;background-color:#f7f0f5" class="wy-link-tag">Introductory</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Using JavaScript and frameworks like Tensorflow.js is a great way to get started and learn more about machine learning. Charlie covers the three main features currently available using Tensorflow.js and sheds light onto the limits of using machine learning in the frontend.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/devdevcharlie?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Charlie Gerard</p> </a></div></td></tr></table></td></tr></table></div><div class="wy-section-link wy-section-link-suggestion"><table class="wy-table"><tr><td class="wy-td"><div class="wy-link-title-section"><a href="https://alligator.io/css/understanding-specificity-in-css/?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" style="color:#555;background-color:transparent" target="_blank" rel="noopener noreferrer" class="wy-link-title md-markdown md-markdown-inline"><p>Specificity in CSS</p> </a><a href="https://ponyfoo.com/weekly/links/tagged/best-practices" style="color:#900070;background-color:#ffe270" class="wy-link-tag">Best Practices</a></div><table><tr><td class="wy-td"><div class="wy-link-description-section"><div class="wy-link-description md-markdown"><p>Learn the basics of specificity in CSS and why you never need <code class="md-code md-code-inline">!important</code>.</p> </div></div><div class="wy-link-source-section"><a href="https://twitter.com/gemontracks?utm_source=ponyfoo+weekly&#38;utm_medium=email&#38;utm_campaign=issue-186" target="_blank" rel="noopener noreferrer" class="wy-link-source md-markdown md-markdown-inline"><p>Jess Mitchell</p> </a></div></td></tr></table></td></tr></table></div></div><style>html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;position:relative;vertical-align:baseline}sup{top:-.5em}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto;resize:vertical;min-height:280px;max-height:900px}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item;margin:-10px -20px;padding:10px;background-color:#f6f6f6;cursor:pointer;border-bottom:2px solid #ddd}[hidden],template{display:none}body,body:after,body:before,html,html:after,html:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*,:after,:before{-webkit-box-sizing:inherit;-moz-box-sizing:inherit;box-sizing:inherit}@-moz-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-webkit-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-o-keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@keyframes bg-rainbow{0%{background-color:#e92c6c}50%{background-color:#f1e05a}90%{opacity:.6;background-color:#37ed2c}}@-moz-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@-webkit-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@-o-keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}@keyframes sb-pulse{0%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,.5);box-shadow:0 0 0 0 rgba(233,44,108,.5)}70%{-webkit-box-shadow:0 0 0 15px rgba(233,44,108,0);box-shadow:0 0 0 15px rgba(233,44,108,0)}100%{-webkit-box-shadow:0 0 0 0 rgba(233,44,108,0);box-shadow:0 0 0 0 rgba(233,44,108,0)}}.f-core{font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}.f-mono{font-family:Consolas,Menlo,Monaco,'Lucida Console','Liberation Mono','DejaVu Sans Mono','Bitstream Vera Sans Mono','Courier New',monospace,serif}.ly-custom-heading .f-heading,.ly-custom-heading h1,.ly-custom-heading h2,.ly-custom-heading h3,.ly-custom-heading h4,.ly-custom-heading h5,.ly-custom-heading h6,.ly-lean .f-heading,.ly-lean h1,.ly-lean h2,.ly-lean h3,.ly-lean h4,.ly-lean h5,.ly-lean h6{font-family:Neuton,'Hoefler Text',Palatino,Baskerville,Georgia,'Times New Roman',serif}.ly-custom-subheading .f-subheading,.ly-lean .f-subheading{font-family:Merriweather,Georgia,serif}body{margin:0;font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif;background:#fcfcfc;color:#333}img{max-width:100%;border:none}.md-markdown figure:not(.twitter-tweet-figure){background-color:#f6f6f6}.md-markdown figure:not(.twitter-tweet-figure)>a{display:block}.md-markdown figure:not(.twitter-tweet-figure)>a>img,.md-markdown figure:not(.twitter-tweet-figure)>img{display:block;margin-left:auto;margin-right:auto}.md-markdown figcaption{padding:10px;font-style:italic;font-size:14px;background:-webkit-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-moz-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-o-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:-ms-linear-gradient(left,#fff9e2 33%,#fcf9ee 100%);background:linear-gradient(to right,#fff9e2 33%,#fcf9ee 100%);color:#555}.md-markdown .figure-has-loaded{background:-webkit-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-moz-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-o-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:-ms-linear-gradient(top,rgba(255,255,255,0) 0,#fcf9ee 100%);background:linear-gradient(to bottom,rgba(255,255,255,0) 0,#fcf9ee 100%)}b,em,font-style italic,font-weight bold,i,ins,strong{text-decoration:none}del{text-decoration:line-through}sub,sup{bottom:0;line-height:18px}button,input{overflow:visible;border-radius:0}button{border:none;padding:6px 8px;font-size:1.2em;background:0 0}button[disabled]{color:#cbccbc!important}input,select,textarea{display:block;width:100%;padding:10px 8px;line-height:18px;border:none;font:inherit}select{height:38px}ol,ul{padding:0;margin:0;list-style-position:inside}li>ol,li>ul{margin-left:20px}hr{border:none;border-top:5px solid rgba(0,0,0,.05);margin:20px 0}kbd{display:inline-block;border:1px solid #ccc;margin:0 .1em;padding:.1em .6em;line-height:1.4;font-size:11px;background-color:#f7f7f7;-webkit-box-shadow:0 1px 0 #bbb,0 0 0 2px #fff inset;box-shadow:0 1px 0 #bbb,0 0 0 2px #fff inset;border-radius:3px;color:#333;text-shadow:0 1px 0 #fff;white-space:nowrap}iframe{display:inline-block;border:none;max-width:100%}summary:hover{opacity:.8}details{padding:10px 20px 20px;border-bottom:2px dashed #ddd}details[open] summary{margin-bottom:20px}blockquote{border:none;margin:0!important}ol,p,ul{line-height:35px}p{margin:35px 0}@media only screen and (min-width:768px){ol,p,ul{line-height:30px}}a,button,input[type=submit]{cursor:pointer;text-decoration:none}.lk-link{color:#e92c6c;border-bottom:1px solid transparent;background-color:rgba(255,255,255,.04)}.lk-link .md-code-inline{position:relative}.lk-link .md-code-inline:only-child{display:inline-block;line-height:17px}.lk-link .md-code-inline:before{content:'';position:absolute;background-color:#f1e05a;top:0;left:0;right:0;bottom:0;opacity:.04}.lk-link:visited{background-color:rgba(233,44,108,.04)}.lk-link:visited .md-code-inline:before{background-color:#e92c6c}.lk-link:hover{border-bottom:1px solid #e92c6c}.lk-rainbows{position:relative;color:#333;margin-bottom:5px}.lk-rainbows:hover:before{position:absolute;content:'';left:0;right:0;bottom:-8px;height:3px;opacity:.8;-webkit-transition:.1s ease-in-out;-moz-transition:.1s ease-in-out;-o-transition:.1s ease-in-out;-ms-transition:all .1s ease-in-out;transition:.1s ease-in-out;-webkit-animation:.5s infinite bg-rainbow;-moz-animation:.5s infinite bg-rainbow;-o-animation:.5s infinite bg-rainbow;-ms-animation:bg-rainbow .5s infinite;animation:.5s infinite bg-rainbow}.lk-icon{color:#333}.lk-icon:hover{color:#e92c6c}.lk-visitor{color:#333}.lk-visitor:after{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-left:5px}.lk-visitor.lk-visitor-large:after{font-size:1em}.lk-visitor:hover:after{color:#333;border-bottom-style:solid}.lk-visitor:visited:after{color:#7d5cff}.lk-visitor-inside{color:#333}.lk-visitor-inside .lk-visitor-target:before{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-right:5px}.lk-visitor-inside.lk-visitor-large .lk-visitor-target:before{font-size:1em}.lk-visitor-inside:hover .lk-visitor-target:before{color:#333;border-bottom-style:solid}.lk-visitor-inside:visited .lk-visitor-target:before{color:#7d5cff}.lk-visitor-before{color:#333}.lk-visitor-before:before{display:inline-block;font:.7em/1 FontAwesome;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:'\f00c';border-bottom:1px dotted #cbccbc;color:#cbccbc;margin-right:5px}.lk-visitor-before.lk-visitor-large:before{font-size:1em}.lk-visitor-before:hover:before{color:#333;border-bottom-style:solid}.lk-visitor-before:visited:before{color:#7d5cff}.lk-visitor-before-no-underline:before{border-bottom-width:0}.lk-link-to-green{color:#cbccbc}.lk-link-to-green:visited,.lk-link-to-green:visited:before{color:#1bc211;background-color:#1bc211}.lk-link-to-green:active{outline-color:#1bc211}.lk-link-to-green:hover,.lk-link-to-green:hover:before{color:#8be186;border-bottom-color:#1bc211}.lk-green .lk-link,a.lk-green{color:#1bc211}.lk-green .lk-link:visited,a.lk-green:visited{background-color:rgba(27,194,17,.04)}.lk-green .lk-link:visited .md-code-inline:before,a.lk-green:visited .md-code-inline:before{background-color:#1bc211}.lk-green .lk-link:active,a.lk-green:active{outline-color:#1bc211}.lk-green .lk-link:hover,a.lk-green:hover{border-bottom-color:#1bc211}.lk-green.lk-icon:hover{color:#1bc211}.lk-pink-light .lk-link,a.lk-pink-light{color:#ea6c93}.lk-pink-light .lk-link:visited,a.lk-pink-light:visited{background-color:rgba(234,108,147,.04)}.lk-pink-light .lk-link:visited .md-code-inline:before,a.lk-pink-light:visited .md-code-inline:before{background-color:#ea6c93}.lk-pink-light .lk-link:active,a.lk-pink-light:active{outline-color:#ea6c93}.lk-pink-light .lk-link:hover,a.lk-pink-light:hover{border-bottom-color:#ea6c93}.lk-pink-light.lk-icon:hover{color:#ea6c93}.lk-black .lk-link,a.lk-black{color:#333}.lk-black .lk-link:visited,a.lk-black:visited{background-color:rgba(51,51,51,.04)}.lk-black .lk-link:visited .md-code-inline:before,a.lk-black:visited .md-code-inline:before{background-color:#333}.lk-black .lk-link:active,a.lk-black:active{outline-color:#333}.lk-black .lk-link:hover,a.lk-black:hover{border-bottom-color:#333}.lk-black.lk-icon:hover{color:#333}.lk-gray .lk-link,a.lk-gray{color:#999}.lk-gray .lk-link:visited,a.lk-gray:visited{background-color:rgba(153,153,153,.04)}.lk-gray .lk-link:visited .md-code-inline:before,a.lk-gray:visited .md-code-inline:before{background-color:#999}.lk-gray .lk-link:active,a.lk-gray:active{outline-color:#999}.lk-gray .lk-link:hover,a.lk-gray:hover{border-bottom-color:#999}.lk-gray.lk-icon:hover{color:#999}.lk-white .lk-link,a.lk-white{color:#fcfcfc}.lk-white .lk-link:visited,a.lk-white:visited{background-color:rgba(252,252,252,.04)}.lk-white .lk-link:visited .md-code-inline:before,a.lk-white:visited .md-code-inline:before{background-color:#fcfcfc}.lk-white .lk-link:active,a.lk-white:active{outline-color:#fcfcfc}.lk-white .lk-link:hover,a.lk-white:hover{border-bottom-color:#fcfcfc}.lk-white.lk-icon:hover{color:#fcfcfc}.lk-orange .lk-link,a.lk-orange{color:#f3720d}.lk-orange .lk-link:visited,a.lk-orange:visited{background-color:rgba(243,114,13,.04)}.lk-orange .lk-link:visited .md-code-inline:before,a.lk-orange:visited .md-code-inline:before{background-color:#f3720d}.lk-orange .lk-link:active,a.lk-orange:active{outline-color:#f3720d}.lk-orange .lk-link:hover,a.lk-orange:hover{border-bottom-color:#f3720d}.lk-orange.lk-icon:hover{color:#f3720d}.lk-lilly .lk-link,a.lk-lilly{color:#7d5cff}.lk-lilly .lk-link:visited,a.lk-lilly:visited{background-color:rgba(125,92,255,.04)}.lk-lilly .lk-link:visited .md-code-inline:before,a.lk-lilly:visited .md-code-inline:before{background-color:#7d5cff}.lk-lilly .lk-link:active,a.lk-lilly:active{outline-color:#7d5cff}.lk-lilly .lk-link:hover,a.lk-lilly:hover{border-bottom-color:#7d5cff}.lk-lilly.lk-icon:hover{color:#7d5cff}.lk-blue .lk-link,a.lk-blue{color:#1a4d7f}.lk-blue .lk-link:visited,a.lk-blue:visited{background-color:rgba(26,77,127,.04)}.lk-blue .lk-link:visited .md-code-inline:before,a.lk-blue:visited .md-code-inline:before{background-color:#1a4d7f}.lk-blue .lk-link:active,a.lk-blue:active{outline-color:#1a4d7f}.lk-blue .lk-link:hover,a.lk-blue:hover{border-bottom-color:#1a4d7f}.lk-blue.lk-icon:hover{color:#1a4d7f}.lk-inherited .lk-link,a.lk-inherited{color:inherit}.lk-inherited .lk-link:active,a.lk-inherited:active{outline-color:inherit}.lk-inherited .lk-link:hover,a.lk-inherited:hover{border-bottom-color:inherit}.lk-inherited.lk-icon:hover{color:inherit}.lk-twitter .lk-link,a.lk-twitter{color:#55acee}.lk-twitter .lk-link:visited,a.lk-twitter:visited{background-color:rgba(85,172,238,.04)}.lk-twitter .lk-link:visited .md-code-inline:before,a.lk-twitter:visited .md-code-inline:before{background-color:#55acee}.lk-twitter .lk-link:active,a.lk-twitter:active{outline-color:#55acee}.lk-twitter .lk-link:hover,a.lk-twitter:hover{border-bottom-color:#55acee}.lk-twitter.lk-icon:hover{color:#55acee}.lk-facebook .lk-link,a.lk-facebook{color:#3b5998}.lk-facebook .lk-link:visited,a.lk-facebook:visited{background-color:rgba(59,89,152,.04)}.lk-facebook .lk-link:visited .md-code-inline:before,a.lk-facebook:visited .md-code-inline:before{background-color:#3b5998}.lk-facebook .lk-link:active,a.lk-facebook:active{outline-color:#3b5998}.lk-facebook .lk-link:hover,a.lk-facebook:hover{border-bottom-color:#3b5998}.lk-facebook.lk-icon:hover{color:#3b5998}.lk-clean{background-color:transparent}.lk-chrome:hover{color:#4989f4}.lk-teal .lk-link,a.lk-teal{color:#00a19c}.lk-teal .lk-link:visited,a.lk-teal:visited{background-color:rgba(0,161,156,.04)}.lk-teal .lk-link:visited .md-code-inline:before,a.lk-teal:visited .md-code-inline:before{background-color:#00a19c}.lk-teal .lk-link:active,a.lk-teal:active{outline-color:#00a19c}.lk-teal .lk-link:hover,a.lk-teal:hover{border-bottom-color:#00a19c}.lk-teal.lk-icon:hover{color:#00a19c}table{width:100%;border-spacing:0;border-collapse:separate}td,th{padding:8px}@media only screen and (max-width:950px){.table-responsive{display:block}.table-responsive>thead{display:none}.table-responsive>tbody,.table-responsive>tfoot{display:block}.table-responsive>tbody>tr,.table-responsive>tfoot>tr{display:block;background-color:rgba(203,204,188,.1);margin-bottom:30px}.table-responsive>tbody>tr:nth-child(even),.table-responsive>tfoot>tr:nth-child(even){background-color:rgba(203,204,188,.15)}.table-responsive>tbody>tr:last-child,.table-responsive>tfoot>tr:last-child{margin-bottom:0}.table-responsive>tbody>tr>td,.table-responsive>tfoot>tr>td{display:block;text-align:left}.table-responsive>tbody>tr>td:before,.table-responsive>tfoot>tr>td:before{display:block;content:attr(data-label);color:#555;font-size:13px;margin:0 0 5px}.table-responsive .table-responsive-hide{display:none}}.c-oreilly-teal{color:#00a19c}.c-yellow-highlight{color:#ffe270}.c-dark-orange{color:#f3720d}.c-pink{color:#e92c6c}.c-purple{color:#900070}.c-blue{color:#1a4d7f}.c-dark-turquoise{color:#1686a2}.c-dark-green{color:#1bc211}.c-white{color:#fcfcfc}.c-gray{color:#b7b7b7}.c-lilly{color:#7d5cff}.c-teal{color:#3aca96}.c-bg-oreilly-teal{background-color:#00a19c}.c-bg-yellow-highlight{background-color:#ffe270}.c-bg-dark-orange{background-color:#f3720d}.c-bg-pink{background-color:#e92c6c}.c-bg-purple{background-color:#900070}.c-bg-blue{background-color:#1a4d7f}.c-bg-dark-turquoise{background-color:#1686a2}.c-bg-dark-green{background-color:#1bc211}.c-bg-white{background-color:#fcfcfc}.c-bg-gray{background-color:#b7b7b7}.c-bg-lilly{background-color:#7d5cff}.c-bg-teal{background-color:#3aca96}.tj-emoji{width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em}.dc-header{margin-bottom:60px}.dc-heading{text-align:center;font-size:4em;padding:0 10px;margin-top:0;margin-bottom:10px}.dc-role{line-height:26px;padding:0 20px;margin-top:10px;text-align:center;font-style:italic;color:#cbccbc}.dc-colored{background:#f6f6f6;border-top:9px solid rgba(125,92,255,.5)}.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:800px}.md-markdown blockquote:not(.twitter-tweet){margin:0;padding:20px 0;border:none;border-top:5px solid rgba(0,0,0,.05);border-bottom:5px solid rgba(0,0,0,.05)}.md-markdown blockquote:not(.twitter-tweet) h1,.md-markdown blockquote:not(.twitter-tweet) h2,.md-markdown blockquote:not(.twitter-tweet) h3,.md-markdown blockquote:not(.twitter-tweet) h4,.md-markdown blockquote:not(.twitter-tweet) h5,.md-markdown blockquote:not(.twitter-tweet) h6{margin:-20px 0;padding:20px 0}.md-markdown blockquote:not(.twitter-tweet) .md-code-block{margin:0}.md-markdown blockquote:not(.twitter-tweet) .md-code-block:last-child{margin-bottom:-20px}.md-markdown img:first-child{margin-top:0}.md-markdown img:last-child{margin-bottom:0}.md-markdown p:first-child{margin-top:0}.md-markdown p:last-child{margin-bottom:0}.md-markdown .md-code-block+ol,.md-markdown .md-code-block+ul,.md-markdown ol+.md-code-block,.md-markdown ul+.md-code-block{margin-top:35px}.md-markdown a:not(.md-heading){color:#e92c6c;border-bottom:1px solid transparent;background-color:rgba(255,255,255,.04)}.md-markdown a:not(.md-heading) .md-code-inline{position:relative}.md-markdown a:not(.md-heading) .md-code-inline:only-child{display:inline-block;line-height:17px}.md-markdown a:not(.md-heading) .md-code-inline:before{content:'';position:absolute;background-color:#f1e05a;top:0;left:0;right:0;bottom:0;opacity:.04}.md-markdown a:not(.md-heading):visited{background-color:rgba(233,44,108,.04)}.md-markdown a:not(.md-heading):visited .md-code-inline:before{background-color:#e92c6c}.md-markdown a:not(.md-heading):hover{border-bottom:1px solid #e92c6c}.md-markdown thead{background-color:#e0e0e0}.md-markdown tbody{background-color:#f6f6f6}.md-markdown tbody tr:nth-child(even){background-color:#f9f9f9}.md-markdown h1,.md-markdown h2,.md-markdown h3,.md-markdown h4,.md-markdown h5,.md-markdown h6{padding:10px 0}.md-markdown h1:first-child,.md-markdown h2:first-child,.md-markdown h3:first-child,.md-markdown h4:first-child,.md-markdown h5:first-child,.md-markdown h6:first-child{margin-top:0}.md-markdown h1:last-child,.md-markdown h2:last-child,.md-markdown h3:last-child,.md-markdown h4:last-child,.md-markdown h5:last-child,.md-markdown h6:last-child{margin-bottom:0}.md-markdown iframe{display:block;margin:35px auto}.md-markdown iframe:first-child{margin-top:0}.md-markdown iframe:last-child{margin-bottom:0}.md-markdown li>p:only-child{display:inline}.md-markdown ul{list-style-type:none}.md-markdown ul>li:before{content:'◯';margin-right:5px}.md-heading{color:inherit}.md-markdown-inline{display:inline}.md-markdown-inline p{display:inline;line-height:initial}.md-code-block,.ocha-highlighted{margin:0 -20px}.ocha-code-block{padding:18px 50px}.md-markdown:not(.mm-content-html) .md-code-block+blockquote{max-width:inherit!important;margin:0 -20px;padding-left:20px;padding-right:20px}.md-code-block .md-code{display:block}.md-markdown-summary p{margin:10px 0}@media only screen and (min-width:768px){.md-markdown h1,.md-markdown h2,.md-markdown h3,.md-markdown h4,.md-markdown h5,.md-markdown h6{margin-left:-40px;margin-right:-40px;padding:10px 40px}.md-code-block,.ocha-highlighted{margin:0 -40px}.md-markdown:not(.mm-content-html) .md-code-block+blockquote{margin:0 -40px;padding-left:40px;padding-right:40px}}@media only screen and (min-width:1300px){.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:900px}}@media only screen and (min-width:1400px){.md-markdown blockquote,.md-markdown code,.md-markdown ol,.md-markdown p,.md-markdown table,.md-markdown ul{max-width:1000px}.md-code-block,.md-markdown:not(.mm-content-html) .md-code-block+blockquote,.ocha-highlighted{margin:0 -400px 0 -40px}}.md-markdown-large blockquote,.md-markdown-large code,.md-markdown-large ol,.md-markdown-large p,.md-markdown-large table,.md-markdown-large ul{max-width:inherit}.md-footnotes{margin-top:80px;padding:20px 0;border-top:1px dashed #cbccbc}.md-footnote{margin:0;padding:8px 0;font-size:14px;display:-webkit-box;display:-moz-box;display:-webkit-flex;display:-ms-flexbox;display:box;display:flex;-webkit-box-align:center;-moz-box-align:center;-o-box-align:center;-ms-flex-align:center;-webkit-align-items:center;align-items:center}.md-footnote p{line-height:16px}.md-footnote-anchor{padding:2px 6px;margin-right:10px;text-align:center;font-weight:700;color:#e92c6c}.ly-custom-subheading .md-footnote-anchor,.ly-lean .md-footnote-anchor{font-family:Merriweather,Georgia,serif}.md-markdown a.md-footnote-anchor{border:1px solid #e92c6c}.md-markdown a.md-footnote-anchor:hover{background-color:#e92c6c;color:#fcfcfc}.md-footnote-ref{margin-left:1px;margin-right:3px}.md-markdown a.md-footnote-ref{border-bottom:1px dotted}.md-code-block,.md-code-inline{-webkit-text-size-adjust:none;-ms-text-size-adjust:none;text-size-adjust:none;background:#fcfcf5;color:#4d4d4c}.md-code-block{line-height:24px}.md-code{padding:8px 10px}.md-code-inline{padding:0 6px}a .md-code{color:inherit}.md-code-comment{color:#8e908c}.md-code-attribute,.md-code-built_in,.md-code-constant,.md-code-literal,.md-code-number,.md-code-params,.md-code-pragma,.md-code-preprocessor,.md-code-regexp,.md-code-tag,.md-code-variable,.md-lang-css .md-code-class,.md-lang-css .md-code-id,.md-lang-css .md-code-pseudo,.md-lang-html .md-code-doctype,.md-lang-ruby .md-code-constant,.md-lang-xml .md-code-doctype,.md-lang-xml .md-code-pi,.md-lang-xml .md-code-tag .md-code-title,color #c82829{color:#f5871f}.md-lang-css .md-code-rule .md-code-attribute,.md-lang-ruby .md-code-class .md-code-title{color:#eab700}.md-code-header,.md-code-inheritance,.md-code-name,.md-code-string,.md-code-value,.md-lang-ruby .md-code-symbol,.md-lang-xml .md-code-cdata{color:#718c00}.md-code-title,.md-lang-css .md-code-hexcolor{color:#3e999f}.md-code-function,.md-lang-coffeescript .md-code-title,.md-lang-javascript .md-code-title,.md-lang-perl .md-code-sub,.md-lang-python .md-code-decorator,.md-lang-python .md-code-title,.md-lang-ruby .md-code-function .md-code-title,.md-lang-ruby .md-code-title .md-code-keyword{color:#4271ae}.md-code-keyword,.md-lang-javascript .md-code-function{color:#8959a8}.md-lang-coffeescript .md-lang-javascript,.md-lang-javascript .md-lang-xml,.md-lang-tex .md-code-formula,.md-lang-xml .md-code-cdata,.md-lang-xml .md-lang-css,.md-lang-xml .md-lang-javascript,.md-lang-xml .vbscript{opacity:.5}.md-code-deletion{background-color:rgba(244,0,30,.05);color:#f4001e}.md-code-addition{background-color:rgba(27,194,17,.05);color:#1bc211}.md-mark{background-color:rgba(255,226,112,.5);color:inherit}.md-mark span{color:inherit}.md-heading-hover{cursor:pointer;background-color:rgba(22,134,162,.1)}.mde-text-left{text-align:left}.mde-text-center{text-align:center}.mde-text-right{text-align:right}.mde-size-small{font-size:12px}.mde-size-small,.mde-size-small p{line-height:12px}.mde-size-large{font-size:36px}.mde-size-large,.mde-size-large p{line-height:36px}.mde-size-giant{font-size:72px}.mde-size-giant,.mde-size-giant p{line-height:72px}.mde-clearfix:after{content:' ';display:block;visibility:hidden;clear:both;font-size:0;height:0}.mde-quote{margin:0;padding:20px 0;border:none;border-top:5px solid rgba(0,0,0,.05);border-bottom:5px solid rgba(0,0,0,.05)}.mde-core{font-family:'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}.mde-mono{font-family:Consolas,Menlo,Monaco,'Lucida Console','Liberation Mono','DejaVu Sans Mono','Bitstream Vera Sans Mono','Courier New',monospace,serif}.ly-custom-heading .mde-heading,.ly-lean .mde-heading{font-family:Neuton,'Hoefler Text',Palatino,Baskerville,Georgia,'Times New Roman',serif}.ly-custom-subheading .mde-subheading,.ly-lean .mde-subheading{font-family:Merriweather,Georgia,serif}.mde-pad-0{padding:0}.mde-pad-5{padding:5px}.mde-pad-10{padding:10px}.mde-pad-15{padding:15px}.mde-pad-20{padding:20px}.mde-pad-25{padding:25px}.mde-pad-30{padding:30px}.mde-pad-50{padding:50px}.mde-mar-0{margin:0}.mde-mar-5{margin:5px}.mde-mar-10{margin:10px}.mde-mar-15{margin:15px}.mde-mar-20{margin:20px}.mde-mar-25{margin:25px}.mde-mar-30{margin:30px}.mde-mar-50{margin:50px}@media only screen and (min-width:900px){.mde-left{float:left}.mde-right{float:right}.mde-inline{display:inline-block;vertical-align:top}.mde-20{max-width:20%}.mde-25{max-width:25%}.mde-33{max-width:33.3333333333%}.mde-50{max-width:50%}.mde-66{max-width:66.6666666666%}.mde-75{max-width:75%}}.twitter-tweet-figure{background:0 0;padding:0}.twitter-tweet-figure:before{content:none}.twitter-tweet-figure .twitter-tweet{margin:0 auto}blockquote.twitter-tweet{overflow:hidden;color:#1c2022;background-color:#fff;border:1px solid #e1e8ed;border-radius:4px;width:500px;max-width:100%;min-width:220px;padding:1.25rem 1.25rem .725rem}blockquote.twitter-tweet:before{content:none}blockquote.twitter-tweet p{white-space:pre-wrap;font:16px/1.4 Helvetica,Roboto,'Segoe UI',Calibri,'Helvetica Neue',HelveticaNeue,TeXGyreHeros,FreeSans,'Nimbus Sans L','Liberation Sans',Helvetica,Arial,sans-serif}blockquote.twitter-tweet a,blockquote.twitter-tweet a:visited{color:#2b7bb9}.wy-container{margin:0 auto;padding:20px 0;max-width:800px}.wy-container .md-markdown p{line-height:22px;margin:10px 0}.wy-container .md-markdown p:first-child{margin-top:0}.wy-container .md-markdown p:last-child{margin-bottom:0}.wy-container .md-markdown blockquote:not(.twitter-tweet){padding:10px 0}.wy-container .md-code-block{margin:0;padding:10px;white-space:pre-wrap}.wy-table{width:100%;padding:0}.wy-td{padding:0}.wy-section-link,.wy-section-markdown,.wy-section-poll,.wy-section-summary{padding-top:25px}.wy-section-thanks{margin-top:25px;padding:10px;font-size:15px;background-color:#f2fcf2}.wy-header-text,.wy-issue{display:inline-block;margin:10px 0;line-height:24px}.wy-issue{float:right;font-size:12px}.wy-issue-content{display:block;padding:0 5px;background-color:#fcfcfc}.wy-section-header{padding-top:40px}.wy-section-header h1,.wy-section-header h2,.wy-section-header h3,.wy-section-header h4,.wy-section-header h5,.wy-section-header h6{margin:0}.wy-section-header p{line-height:inherit}.wy-header-td{padding:0}.wy-header-content{margin:0 10px}.wy-header-text{color:#fcfcfc;text-shadow:1px 1px 0 #1a4d7f;font-weight:700;font-size:24px}.wy-content{padding-bottom:25px}.wy-link-addendum,.wy-link-tag,.wy-link-title{display:inline-block;vertical-align:bottom;margin-bottom:10px}.wy-link-title{border-bottom:1px solid;font-size:20px;margin-right:10px}.wy-link-tag{background-color:#1a4d7f;color:#fcfcfc;text-transform:uppercase;font-size:13px;margin-right:5px;padding:2px 4px}.wy-link-tag:last-child{margin-right:0}.wy-link-addendum{color:#999;margin-left:5px}.wy-link-addendum:hover{border-bottom-color:transparent}.wy-link-title-section{position:relative}.wy-link-stats{position:absolute;right:0;background-color:#3aca96;color:#fcfcfc;border-bottom:1px solid #299a71}.wy-link-stats-logo{background-color:rgba(0,0,0,.1);color:#299a71}.wy-link-stat{margin:3px}.wy-link-description{font-size:14px;color:#666}.wy-link-source-section{margin-top:10px}.wy-link-source{margin-right:10px;margin-bottom:10px;display:inline-block;vertical-align:middle;color:#55acee}.wy-link-source-plain{color:#333}.wy-link-source.wy-link-source-plain a{color:#55acee}.wy-link-source.wy-link-source-plain a:visited{background-color:rgba(85,172,238,.04)}.wy-link-source.wy-link-source-plain a:visited .md-code-inline:before{background-color:#55acee}.wy-link-source.wy-link-source-plain a:active{outline-color:#55acee}.wy-link-source.wy-link-source-plain a:hover{border-bottom-color:#55acee}.wy-link-sponsor{background-color:transparent;color:#999;outline:#999 solid 1px}.wy-link-cell-before-image{vertical-align:middle;width:70%}.wy-link-cell-image{padding-left:10px}.wy-link-image-anchor{display:block;overflow:hidden;max-height:300px}.wy-link-image{display:block;margin:0 auto}.wy-footer-table{margin:20px 0}.wy-footer-cell{text-align:center}.wy-read-online{font-size:13px}.wy-section-link-job .wy-link-source,.wy-section-link-job .wy-link-title{font-size:14px}.wy-section-link-job .wy-link-description{font-size:12px}.wy-link-pixel{float:right}@media only screen and (max-width:500px){.wy-issue-publication,.wy-issue-separator{display:none}}.md-code-block{margin:0!important;padding:10px}</style>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/150-v-201.png" alt="v2.0.1">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">v2.0.1</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">24 09 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/150-v-201.png" alt="v2.0.1" title="release notes: fixed some bugs" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Reddit: ABCL Common Lisp vs Clojure</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">22 09 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Not that I&rsquo;m interested in using the Java platform :D but relevant
comparisons between ABCL (Common Lisp on Java) and Clojure are
rare. We just had a nice feedback on reddit, so here it is. The
question was:</p>

<blockquote>
<p>After looking at the quite old benchmarks, ABCL seems to perform alright. Can anyone share their experience with ABCL in terms of performance, stability and memory usage?</p>
</blockquote>

<hr />

<p>I wish I could give you more concrete numbers with an application you could test and see for yourself. Since I can&rsquo;t do that, I will tell you about my recent work with ABCL. I ported a small Clojure server-side utility to ABCL and can qualitatively tell you that the performance was close to Clojure. After profiling the ABCL version, I believe I can attribute the differences to ABCL&rsquo;s use of Java reflection for its Java FFI.</p>

<p>I&rsquo;ve already been successfully deploying Clojure-based applications professionally, and as I&rsquo;ve gotten more into Common Lisp, I&rsquo;d like to start deploying Common Lisp based applications as well. I recently posted a patch to the ABCL mailing list and got a very quick response from the maintainer. I really like the quality of the ABCL code base. The compiler itself was very approachable and easy to understand.</p>

<p>I think ABCL really is a worthwhile target in the Common Lisp world because:</p>

<ul>
<li>Painless Java FFI. You avoid all the instability and signaling issues that crop up when using the JVM combined with SBCL or CCL. If you make a lot of calls, native Java is always going to be faster anyhow than calls over JNI (which is more comparable to reflection).</li>
<li>Use large heaps without worry. Part of the benefit of the JVM is its proven ability to have huge heaps (I&rsquo;ve been part of projects that had 64GB+ heaps (though honestly I&rsquo;d rather stay small)).</li>
<li>JVM platform is well supported and tested on a number of OS and hardware platforms</li>
</ul>

<p>SBCL uses conservative garbage collection and I&rsquo;m curious how well it would handle really large heaps. CCL uses precise garbage collection but again, I&rsquo;d like to know how it handles really large heaps. In general, I want all my applications to run with heaps that are naturally in CCL&rsquo;s or SBCL&rsquo;s sweet spot, but I&rsquo;d love to know I could use ABCL if I really ever needed huge heaps. I&rsquo;m really getting into Common Lisp because I really like the implementation choices. Having a solid Java FFI unfortunately is usually a requirement in my workplace.</p>

<p>To me, ABCL will be /better/ than using Clojure if ABCL&rsquo;s Java FFI moves away from reflection (when possible). This will close any performance gap with Clojure for most applications. I think this can be done relatively easily in the current ABCL implementation, and I have an idea of how to do it but unfortunately have had no time lately to devote to it. The reason I say &ldquo;better than Clojure&rdquo; is that I can write applications that target both ABCL and SBCL/CCL &ndash; I can abstract away my Java APIs if I really have to have them (or use LispWorks with a solid Java FFI if I don&rsquo;t need a ton of Java interoperability). Then when I need fast startup time or low memory footprint, I can use these other CL implementations which are much better suited to it.</p>

<p>The main benefit where I still see Clojure having an edge is if you need a heavy JS-based web interface. I&rsquo;m not a JS developer, but I was able to successfully use Clojurescript and make a nice looking web application that had pretty seamless interoperability with my Clojure-based server.</p>

<p>Anyhow, I hope this helps you. ABCL is great, I have been very impressed with it and I encourage you to try it out.</p>

<hr />

<p>by the user <code>somewhat-functional</code> <a href="https://www.reddit.com/r/lisp/comments/d48gcr/how_well_does_abcl_perform/">on reddit</a>, september 2019</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/149-tribalism.png" alt="Tribalism">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Tribalism</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">17 09 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/149-tribalism.png" alt="Tribalism" title="Rearrange the deck chairs on the Titanic" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How &quot;Export to Excel&quot; Almost Killed Our System</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">16 09 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Inspired by an actual incident we had in one of our systems caused by an "Export to Excel" functionality implemented in Python, we go through the process of identifying the problem, experimenting and benchmarking different solutions.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-KNASNGYpLsQ/XX6dZkcFN3I/AAAAAAAAmOw/9YQoAKDDY2EJHbABvYVtzh_Fb8mrpKUFQCLcBGAsYHQ/s640/como-ser-mejor-desarrollador.jpg" alt="Consejos para ser un mejor desarrollador">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Consejos para ser un mejor desarrollador</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">16 09 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-KNASNGYpLsQ/XX6dZkcFN3I/AAAAAAAAmOw/9YQoAKDDY2EJHbABvYVtzh_Fb8mrpKUFQCLcBGAsYHQ/s1600/como-ser-mejor-desarrollador.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Consejos para ser un mejor desarrollador" border="0" data-original-height="560" data-original-width="900" height="398" src="https://1.bp.blogspot.com/-KNASNGYpLsQ/XX6dZkcFN3I/AAAAAAAAmOw/9YQoAKDDY2EJHbABvYVtzh_Fb8mrpKUFQCLcBGAsYHQ/s640/como-ser-mejor-desarrollador.jpg" title="Consejos para ser un mejor desarrollador" width="640" /></a></div><br />Cuando se trata de programación no hay una forma o estándar a seguir para poder desarrollarse y madurar. Solo la experiencia te da más herramientas dentro de este mundo de programación, pero también hay actividades que puedes realizar para poder ir ganando más experiencia y seguir mejorando como desarrollador, y en este post te los voy a compartir.<br /><br /><h2 id="experimentarenvariosproyectos">Experimentar en varios proyectos</h2><br />Puede sonar lógico que para poder ser un mejor desarrollador lo primero que tienes que ahcer s practicar, desarrollar proyectos,  estar involucrado en varios, de tal forma que en cada uno aprendas algo diferente. Sin embargo aquí hay algunos puntos que deberías estar teniendo en cuenta al momento de tener proyectos para poder ser un mejor desarrollador<br /><br /><ul><li>Tienes que fallar para aprender: el terminar un proyecto sencillo no te da ningún aprendizaje. Aprende con el error y sabiendo tus capacidades técnicas</li><li>Aprender significa tener creatividad: programar de la misma forma y haciendo las mismas aplicaciones no te dejan ninguna experiencia. Juega a hacer las cosas de diferentes formas para saber si lo que actualmente haces es la forma más adecuada o hay alguna mejor.</li><li>Aplica los métodos paso a paso: ¿cuándo fue la última vez que seguiste todo un ciclo de desarrollo para una aplicación? cosas tan sencillas como esas las obviamos y nos vamos directo a programar y ver en el camino qué nos falta. Intenta ir lento, siguiendo la teoría, y verás que de la misma forma que buscas soluciones a tu código, vas a querer soluciones a situiaciones en las etapas.</li></ul><br /><h2 id="planeaantesdeprogramar">Planea antes de programar</h2><br />Como lo mencionaba anteriormente, solemos emepezar a programar sin siqueira estar seguros de lo que queremos lograr. La planeación es una etapa en la que tienes que poner bien los alcances de lo que vas a hacer, y el resultado que quieres obtener. Si solo empiezas a programar no vas a saber cuándo terminar, o al final no vas a recordar por qué empezaste ese prioyecto.<br /><br /><h2 id="sdurocontucdigo">Sé duro con tu código</h2><br />La mejor forma para mejorar como programador o desarrollador es siempre ser auto críticos con nuestro código. Si le presentaras tu código a algún desarrollador experto o con muchos años de experiencia, reconocido entre una comunidad ¿qué crees que diría de él? ¿qué es código de calidad? ¿o que es código de principiantes?<br />Siempre debemos buscar los patrones o mejores prácticas para nuestro código. Hay muchas metodologías y dependiendo del lenguaje irás aprendiendo si la técnica de programación que tienes es buena o mala, y a partir de ahí ver cómo la puedes mejorar.<br /><br /><h2 id="leecdigodedesarrolladoresrespetados">Lee código de desarrolladores respetados</h2><br />Es un punto adicional a  lo que comentaba anteriormente. No hay nada mejor que ponerte al tú por tú contra un desarrollador que sea realmente bueno. Basta incluso con ver las librerías de organizaciones o comunidades Open Source y ver si entendemos el código que muestran, y después, validar si nuestro código es de la misma calidad.<br />En Github puedes encontrar desarrolladores que postean sus proyectos personales o de colaboración con otros, y medirte para ver qué tan bueno eres comparado con ellos.<br /><br /><h2 id="aprendeadebuggearcdigoquenoestuyo">Aprende a 'debuggear' código que no es tuyo</h2><br />Si trabajas para una empresa que desarrolla proyectos a clientes esta es una de las situaciones más comunes que vas a vivir, y es la de heredar proyectos que alguien más hizo. Los más novatos dirán que ahorras tiempo si vuelves a hacer todo desde cero, pero lo cierto es que es al revés. Aprender a leer, debuggear y probar código de alguien más es una de las mejores experiencias (dolorosas, lo sé) que te puede ayudar para ser un mejor desarrollador, porque ahí pones en práctica qué tan bien lo harías tu, o qué tan mal dejaron ese código heredado.<br /><br /><h2 id="siempretrataderompertucdigo">Siempre trata de romper tu código</h2><br />Los que empezamos a programar nos preocupamos más porque nuestro código funcione en el escenario ideal, a probar los escenarios donde no. Un código de calidad no es el que cumple su funcionamiento, sino que también responde ante entradas de datos erróneas, ante desbordamientos, ante escenarios extremos o nulos de datos, etc.<br /><br /><h2 id="conclusiones">Conclusiones</h2><br />Estos son algunos tips que puedes poner en práctica en tu día a día sin tener que invertir tiempo en cosas que no sean tareas comunes de cualquier desarrollador, solo necesitas la actitud y disposición para poder ejercerlas.<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=14g1cQhxFWw:SDobdrfojvE:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=14g1cQhxFWw:SDobdrfojvE:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=14g1cQhxFWw:SDobdrfojvE:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=14g1cQhxFWw:SDobdrfojvE:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=14g1cQhxFWw:SDobdrfojvE:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=14g1cQhxFWw:SDobdrfojvE:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=14g1cQhxFWw:SDobdrfojvE:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=14g1cQhxFWw:SDobdrfojvE:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=14g1cQhxFWw:SDobdrfojvE:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=14g1cQhxFWw:SDobdrfojvE:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=14g1cQhxFWw:SDobdrfojvE:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=14g1cQhxFWw:SDobdrfojvE:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=14g1cQhxFWw:SDobdrfojvE:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=14g1cQhxFWw:SDobdrfojvE:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/14g1cQhxFWw" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-0HzOrBCuMj0/XXhW-a3DcTI/AAAAAAAAmNA/QheMEvmpZXUm6d5vNIv1KniKwYtJhHF6QCLcBGAsYHQ/s640/docker-mongo-express.jpg" alt="Tutorial conexión de MongoDB en Docker con Express y NodeJS">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Tutorial conexión de MongoDB en Docker con Express y NodeJS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">11 09 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-0HzOrBCuMj0/XXhW-a3DcTI/AAAAAAAAmNA/QheMEvmpZXUm6d5vNIv1KniKwYtJhHF6QCLcBGAsYHQ/s1600/docker-mongo-express.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Mongo express y docker" border="0" data-original-height="900" data-original-width="1600" height="360" src="https://1.bp.blogspot.com/-0HzOrBCuMj0/XXhW-a3DcTI/AAAAAAAAmNA/QheMEvmpZXUm6d5vNIv1KniKwYtJhHF6QCLcBGAsYHQ/s640/docker-mongo-express.jpg" title="Mongo express y docker" width="640" /></a></div><br />He estado jugando con Docker para crear algunos servicios, y sobre todo, evitar tener que descargar e instalar plataformas que solo quiero usar de prueba. En mi último demo estuve jugando con MongoDB y se me ocurrió hacer un tutorial para enseñarles a configurar MondoDB en Docker para crear una conexión con NodeJS y ExpressJS.<br /><h2 id="prerequisitos">Prerequisitos</h2>Para poder seguir este tutorial se necesitan tener bases de cómo funciona NodeJS y ExpressJS, así como algo muy introductorio a Docker y Dockerfile, pero ya lo iré explicando.<br /><h2 id="1-creaci-n-de-dockerfile">1. Creación de Dockerfile</h2>Una de las maravillas que ofrece Docker es la posibilidad de preparar todos los componentes que necesitas para tu desarrollo en un editor de texto y de ahí ejecutarlo. Yo para poder montar MongoDB voy a necesitar dos servicios:<br /><ol><li>El motor de bases de datos de MongoDB</li><li>Una interfaz web para administrar visualmente mis bases de datos. En este caso uso Mongo Express</li></ol>Para empezar hay que crear nuestro documento (docker-compose.yaml). Yo tengo uno similar a este:<br /><pre><code><span class="hljs-attribute">version</span>: <span class="hljs-string">'3.1'</span><br /><span class="hljs-attribute">services</span>:<br />  <span class="hljs-attribute">mongo</span>:<br />    <span class="hljs-attribute">image</span>: mongo<br />    <span class="hljs-attribute">container_name</span>: mongodb<br />    <span class="hljs-attribute">restart</span>: always<br />    <span class="hljs-attribute">environment</span>:<br />      <span class="hljs-attribute">MONGO_INITDB_ROOT_USERNAME</span>: root<br />      <span class="hljs-attribute">MONGO_INITDB_ROOT_PASSWORD</span>: example<br />      <span class="hljs-attribute">MONGO_INITDB_DATABASE</span>: ejemplodb<br />    <span class="hljs-attribute">ports</span>:<br />      - <span class="hljs-number">27017</span>:<span class="hljs-number">27017</span><br /><br />  <span class="hljs-attribute">mongo-express</span>: <br />    <span class="hljs-attribute">image</span>: mongo-express<br />    <span class="hljs-attribute">restart</span>: always<br />    <span class="hljs-attribute">container_name</span>: mongodb-ui<br />    <span class="hljs-attribute">ports</span>:<br />      - <span class="hljs-number">8081</span>:<span class="hljs-number">8081</span><br />    <span class="hljs-attribute">environment</span>:<br />      <span class="hljs-attribute">ME_CONFIG_MONGODB_ADMINUSERNAME</span>: root<br />      <span class="hljs-attribute">ME_CONFIG_MONGODB_ADMINPASSWORD</span>: example<br /></code></pre>En este Dockerfile estoy configurando las imagenes de MongoDB y Mongo Express, el nombre de los contenedores para identificarlos al momento de detenerlos o eliminarlos, y las configuraciones como el username y password del usuario root. Los puertos están siendo los de default: 27017 para la base de datos y 8081 para la interfaz web.<br />Una vez hecho eso procedemos a correr el comando<br /><pre><code><span class="hljs-attribute">docker-compose up</span><br /></code></pre>En este momento se aprovisionan nuestros servicios, y una vez que hayan terminado de inicializarse y construido el contenedor podemos acceder a la interfaz web de Mongo Express<br /><h2 id="2-configurar-aplicaci-n-de-nodejs-y-expressjs">2. Configurar aplicación de NodeJS y ExpressJS</h2>Ahora vamos a crear nuestra conexión desde nuestra aplicación de NodeJS usando Express. Lo primero es installar Express<br /><pre><code>npm <span class="hljs-keyword">install</span> express<br /></code></pre>adicional instalamos Mongoose, que es un módulo que nos permite de forma más amigable hacer la conexión y operaciones a nuestras bases de datos de Mongo<br /><pre><code>npm <span class="hljs-keyword">install</span> mongoose<br /></code></pre>Ahora sí, a crear nuestra aplicación. (app.js)<br /><pre><code><span class="hljs-keyword">const</span> express       = <span class="hljs-keyword">require</span>(<span class="hljs-string">'express'</span>);<br /><span class="hljs-keyword">const</span> bodyParser    = <span class="hljs-keyword">require</span>(<span class="hljs-string">'body-parser'</span>);<br /><span class="hljs-keyword">const</span> cors          = <span class="hljs-keyword">require</span>(<span class="hljs-string">'cors'</span>); <br /><span class="hljs-keyword">const</span> mongoose      = <span class="hljs-keyword">require</span>(<span class="hljs-string">'mongoose'</span>);<br /><br /><span class="hljs-keyword">const</span> PORT = <span class="hljs-number">3000</span>;<br /><span class="hljs-keyword">const</span> app = express();<br />app.<span class="hljs-keyword">use</span>(cors());<br />app.<span class="hljs-keyword">use</span>(bodyParser.json());<br /><br />app.get(<span class="hljs-string">'/'</span>, (req, res) =&gt;{<br />    res.send(<span class="hljs-string">'Index'</span>);<br />});<br /><br />app.listen(PORT, () =&gt;{<br />    console.log(<span class="hljs-string">'Servidor backend listo...'</span>);<br />});<br /></code></pre>Lo que tenemos en esta app es simplemente:<br /><ol><li>Incluir los módulos que vamos a ocupar</li><li>Inicializar nuestro middleware, el cual puedes o no ocupar para tu aplicación</li><li>inicializar un ruteo para cargar nuestro index</li><li>configurar el puerto para escuchar peticiones</li></ol>Teniendo eso ya podemos configurar la conexión a MongoDB en nuestro contenedor en Docker.<br /><h2 id="3-conexi-n-a-mongodb">3. Conexión a MongoDB</h2>Vamos a empezar con la conexión a nuestra base de datos:<br /><pre><code>mongoose.connect(<span class="hljs-string">'mongodb://localhost/basededatos'</span>, {<span class="hljs-string">useNewUrlParser:</span> <span class="hljs-literal">true</span>, <span class="hljs-string">useUnifiedTopology:</span> <span class="hljs-literal">true</span>});<br /></code></pre>Aquí está lo importante para poder conectarnos a nuestra base de datos. Lo primero es que siempre usemos el usuario:password para conectarnos a nuestra base de datos, y lo segundo es que mencionemos a qué base de datos queremos conectarnos.<br /><pre><code>const connection = mongoose.connection;<br /><br />connection.once(<span class="hljs-string">'open'</span>, <span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span>{<br />    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Conectado a la BD'</span>);<br />});<br /></code></pre>Lo siguiente es la conexión con el evento de 'open', y una vez que conecte vamos a poder ver en nuestra consola el mensaje de que tuvimos éxito.<br /><h2 id="algunos-errores-comunes">Algunos errores comunes</h2>Al menos a mi en un principio traté de usar la conexión de este forma<br /><pre><code>mongoose.connect(<span class="hljs-string">'mongodb://user:pass@localhost/db'</span>, {<span class="hljs-string">useNewUrlParser:</span> <span class="hljs-literal">true</span>, <span class="hljs-string">useUnifiedTopology:</span> <span class="hljs-literal">true</span>});<br /></code></pre>poniendo las credenciales de root no me dejaba autenticarme, me salía el siguiente error:<br /><pre><code><span class="hljs-string">UnhandledPromiseRejectionWarning:</span> <span class="hljs-string">MongoError:</span> Authentication failed<br /></code></pre>Lo que podemos es crear un nuevo usuario para poder autenticarnos sin tener que ser root.<br />Para ello nos conectamos a nuestra consola de mongo en Docker<br /><pre><code>docker exec -<span class="hljs-keyword">it</span> mongodb mongo -u root<br /></code></pre>Usamos el comando exec para poder ejecutar un servicio dentro de nuestro contenedor, el cual es mongo. Hay que notar que pongo la bandera de usuario para poder loguearnos como root y me pidan la contraseña. Añadir un nuevo usuario con permisos require que seas administrador para hacerlo, si solo te logueas no va a ser posible.<br />Ya dentro de nuestra consola de Mongo, vamos a ir a ejecutar la siguiente función para crear un nuevo usuario<br /><pre><code><span class="hljs-selector-tag">use</span> <span class="hljs-selector-tag">tu-base-de-datos</span><br /><span class="hljs-selector-tag">db</span><span class="hljs-selector-class">.createUser</span>({<br />    <span class="hljs-attribute">user</span>: <span class="hljs-string">'user'</span>,<br />    <span class="hljs-attribute">pwd</span>: <span class="hljs-string">'pass'</span>,<br />    <span class="hljs-attribute">roles</span>: [<br />        { <span class="hljs-attribute">role</span>: <span class="hljs-string">'readWrite'</span>, <span class="hljs-attribute">db</span>: <span class="hljs-string">'tu-base-de-datos'</span> }<br />    ]<br />})<br /></code></pre>con eso ya puedes autenticarte con esta forma<br /><pre><code>mongoose.connect(<span class="hljs-string">'mongodb://user:pass@localhost/db'</span>, {<span class="hljs-string">useNewUrlParser:</span> <span class="hljs-literal">true</span>, <span class="hljs-string">useUnifiedTopology:</span> <span class="hljs-literal">true</span>});<br /></code></pre><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=2nYx76qcKR0:qlkuV7hM6No:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=2nYx76qcKR0:qlkuV7hM6No:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=2nYx76qcKR0:qlkuV7hM6No:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=2nYx76qcKR0:qlkuV7hM6No:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=2nYx76qcKR0:qlkuV7hM6No:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=2nYx76qcKR0:qlkuV7hM6No:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=2nYx76qcKR0:qlkuV7hM6No:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=2nYx76qcKR0:qlkuV7hM6No:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=2nYx76qcKR0:qlkuV7hM6No:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=2nYx76qcKR0:qlkuV7hM6No:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=2nYx76qcKR0:qlkuV7hM6No:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=2nYx76qcKR0:qlkuV7hM6No:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=2nYx76qcKR0:qlkuV7hM6No:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=2nYx76qcKR0:qlkuV7hM6No:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/2nYx76qcKR0" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/148-determinism.png" alt="Determinism">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Determinism</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">10 09 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/148-determinism.png" alt="Determinism" title="Assumptions are the mother of all fuck ups!" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">August 2019 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">09 09 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        August was our first month with this new round of projects, check out their monthly update!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-G-l0BvgslG0/XW18lVGLvOI/AAAAAAAAmIY/TOdkDjuKwMMaCoOlqKzaNyExm2q4ZS8_QCLcBGAs/s640/promesas.jpg" alt="Introducción a promesas en Javascript">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Introducción a promesas en Javascript</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">02 09 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-G-l0BvgslG0/XW18lVGLvOI/AAAAAAAAmIY/TOdkDjuKwMMaCoOlqKzaNyExm2q4ZS8_QCLcBGAs/s1600/promesas.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="720" data-original-width="1280" height="360" src="https://1.bp.blogspot.com/-G-l0BvgslG0/XW18lVGLvOI/AAAAAAAAmIY/TOdkDjuKwMMaCoOlqKzaNyExm2q4ZS8_QCLcBGAs/s640/promesas.jpg" width="640" /></a></div><span class="fullpost"><br /></span><span class="fullpost"> Hoy en día manejar promesas es una de las actividades que necesitas hacer para poder programar aplicaciones mucho más robustas y limpias visualmente. En este tutorial vamos a ver una introducción a las promesas, para qué sirven y cómo nos ayudan en nuestro día a día como programadores.</span><br /><div class="separator" style="clear: both; text-align: center;"><iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/VPHAIUFgc3k/0.jpg" src="https://www.youtube.com/embed/VPHAIUFgc3k?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div><span class="fullpost"><br /></span><br /><span class="fullpost"><br /></span> <br /><h2>¿Qué son las promesas?</h2>Las promesas son una forma de poder implementar código, el cual se ejecute después de evaluar si una condición esperada es verdadera o salió algo mal. Muchas de las operaciones donde vamos a implementar promesas es en operaciones asíncronas, donde no sabemos cuando va a terminar una actividad, y por eso las promesas nos ayudan a evaluar si dicha operación asíncrona fue exitosa o falló.<br /><br /><br /><h2>¿Cómo se implementan?</h2>En Javascript vamos a usar la siguiente notación para crear una nueva promesa:<br /><script src="https://gist.github.com/marcosrivasr/10933635635efdaa45b8e50876e05952.js"></script><br />Al definir una promesa debemos tomar en cuenta los dos parámetros que aparecen ahí, ya que son los que vamos a usar posteriormente en la implementación para mandar a llamarlos. Esos dos parámetros actúan como placeholders que van a invocarse cuando nosotros programemos que nuestra promesa tuvo éxito al ejecutar su actividad, o cuando hubo algún error.<br /><br />Para un ejemplo muy sencillo podemos evaluar el valor de una variable. Si la variable cumple nuestra condición vamos a invocar a resolve() como función. Dentro de ella podemos colocar valores que queramos pasar para cuando se invoque nuestra promesa.<br /><br /><script src="https://gist.github.com/marcosrivasr/e9207e2e23e80aba8c7257c4faa92ecc.js"></script><br /><br />Por último, para mandar a llamar a nuestra promesa basta con ejecutar el método .then(), una vez hecho esto dentro podemos hacer referencia al valor que pasamos en la función de resolve() y con ello implementar una función. Si llegase a fallar nuestra promesa podemos usar el método .catch() para poder implementar una función de error<br /><br /><script src="https://gist.github.com/marcosrivasr/0a25ba1b8fe07a53e6e2272d541b49e3.js"></script><br /><br />Al final, nuestro código completo se vería así:<br /><br /><script src="https://gist.github.com/marcosrivasr/131bfdca247e6f40645b2680851316cc.js"></script><br /><br /><h3>Conclusiones</h3>Las promesas en su mínima expresión son una forma muy poderosa de sustitución a los callbacks, además de que nos permiten definir la promesa y luego implementarla de forma muy ordenada sintácticamente. Más adelante vamos a ver otros usos más completos y avanzados ya poniendo en práctica otros temas de Javascript<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=rjHBtkTwORM:qt2JY9H2KnM:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=rjHBtkTwORM:qt2JY9H2KnM:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=rjHBtkTwORM:qt2JY9H2KnM:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=rjHBtkTwORM:qt2JY9H2KnM:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=rjHBtkTwORM:qt2JY9H2KnM:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=rjHBtkTwORM:qt2JY9H2KnM:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=rjHBtkTwORM:qt2JY9H2KnM:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=rjHBtkTwORM:qt2JY9H2KnM:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=rjHBtkTwORM:qt2JY9H2KnM:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=rjHBtkTwORM:qt2JY9H2KnM:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=rjHBtkTwORM:qt2JY9H2KnM:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=rjHBtkTwORM:qt2JY9H2KnM:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=rjHBtkTwORM:qt2JY9H2KnM:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=rjHBtkTwORM:qt2JY9H2KnM:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/rjHBtkTwORM" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/147-gut-feeling.png" alt="Gut Feeling">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Gut Feeling</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">02 09 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/147-gut-feeling.png" alt="Gut Feeling" title="Creative minds don't follow rules, they follow will." /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/146-applied-scrum.png" alt="Applied Scrum">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Applied Scrum</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">27 08 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/146-applied-scrum.png" alt="Applied Scrum" title="Points, badges, belts and leaderboards" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Slime Tips</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">26 08 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>Recently on reddit there was a reminder about
<a href="https://lisptips.com/">lisptips.com</a> and
<a href="https://slime-tips.tumblr.com/">slime-tips</a>. I already knew the two,
but this time I fully enjoyed the Slime tips. I copy my favourites.</p>

<p>As usual, I enhanced the <a href="https://lispcookbook.github.io/cl-cookbook/emacs-ide.html">Cookbook/emacs-ide.html</a> at the same time.</p>

<p>The Slime documentation is here: <a href="https://common-lisp.net/project/slime/doc/html/">https://common-lisp.net/project/slime/doc/html/</a></p>

<h2 id="documentation-lookup">Documentation lookup</h2>

<ul>
<li><strong>C-c C-d h</strong>  looks up documentation in CLHS. But it works only on symbols, so there are two more bindings:</li>
<li><strong>C-c C-d #</strong> for reader macros</li>
<li><strong>C-c C-d ~</strong>  for format directives</li>
</ul>

<p>Other bindings which may be useful:</p>

<ul>
<li><strong>C-c C-d d</strong>  describes a symbol using <code>describe</code></li>
<li><strong>C-c C-d f</strong>  describes a function using <code>describe</code></li>
</ul>

<h2 id="synchronizing-packages">Synchronizing packages</h2>

<p><strong>C-c ~</strong> (<em>slime-sync-package-and-default-directory</em>): When run in a
buffer with a lisp file it will change the current package of the REPL
to the package of that file and also set the current directory of the REPL
to the parent directory of the file.</p>

<h2 id="calling-code">Calling code</h2>

<p><strong>C-c C-y</strong> (<em>slime-call-defun</em>): When the point is inside a defun and
C-c C-y is pressed,</p>

<p>(I’ll use [] as an indication where the cursor is)</p>

<pre><code class="language-lisp">(defun foo ()
 nil[])
</code></pre>

<p>then <code>(foo [])</code> will be inserted into the REPL, so that you can write
additional arguments and run it.</p>

<p>If <code>foo</code> was in a different package than the package of the REPL,
<code>(package:foo )</code> or <code>(package::foo )</code> will be inserted.</p>

<p>This feature is very useful for testing a function you just wrote.</p>

<p>That works not only for defun, but also for defgeneric, defmethod,
defmacro, and define-compiler-macro in the same fashion as for defun.</p>

<p>For defvar, defparameter, defconstant: <code>[] *foo*</code> will be inserted
(the cursor is positioned before the symbol so that you can easily
wrap it into a function call).</p>

<p>For defclass: <code>(make-instance ‘class-name )</code>.</p>

<p><strong>Inserting calls to frames in the debugger</strong></p>

<p><strong>C-y</strong> in SLDB on a frame will insert a call to that frame into the REPL, e.g.,</p>

<pre><code>(/ 0) =&gt;
…
1: (CCL::INTEGER-/-INTEGER 1 0)
…
</code></pre>

<p><strong>C-y</strong> will insert <code>(CCL::INTEGER-/-INTEGER 1 0)</code>.</p>

<p>(thanks to <a href="https://slime-tips.tumblr.com/page/2">Slime tips</a>)</p>

<h2 id="exporting-symbols">Exporting symbols</h2>

<p><strong>C-c x</strong> (<em>slime-export-symbol-at-point</em>) from the <code>slime-package-fu</code>
contrib: takes the symbol at point and modifies the <code>:export</code> clause of
the corresponding defpackage form. It also exports the symbol.  When
called with a negative argument (C-u C-c x) it will remove the symbol
from <code>:export</code> and unexport it.</p>

<p><strong>M-x slime-export-class</strong> does the same but with symbols defined
by a structure or a class, like accesors, constructors, and so on.
It works on structures only on SBCL and Clozure CL so far.
Classes should work everywhere with MOP.</p>

<p>Customization</p>

<p>There are different styles of how symbols are presented in
<code>defpackage</code>, the default is to use uninterned symbols (<code>#:foo</code>).
This can be changed:</p>

<p>to use keywords:</p>

<pre><code class="language-lisp">(setq slime-export-symbol-representation-function
      (lambda (n) (format &quot;:%s&quot; n)))
</code></pre>

<p>or strings:</p>

<pre><code class="language-lisp">(setq slime-export-symbol-representation-function
 (lambda (n) (format &quot;\&quot;%s\&quot;&quot; (upcase n))))
</code></pre>

<h3 id="crossreferencing-find-who-s-calling-referencing-setting-a-symbol">Crossreferencing: find who&rsquo;s calling, referencing, setting a symbol</h3>

<p>Slime has a nice cross referencing facility, for example, you can see
what calls a particular function or expands a macro.  It presents a
list of places which reference a particular entity, from there you can
recompile the thing which references by pressing <strong>C-c C-c</strong> on that
line. <strong>C-c C-k</strong> will recompile all the references. This is useful when
modifying macros, inline functions, or constants.</p>

<p>The following bindings are also shown in Slime&rsquo;s menu:</p>

<ul>
<li><strong>C-c C-w c</strong> <em>slime-who-calls</em> callers of a function</li>
<li><strong>C-c C-w m</strong> <em>slime-who-macroexpands</em> places where a macro is expanded</li>
<li><strong>C-c C-w r</strong> <em>slime-who-references</em> global variable references</li>
<li><strong>C-c C-w b</strong> <em>slime-who-bind</em> global variable bindings</li>
<li><strong>C-c C-w s</strong> <em>slime-who-sets</em> global variable setters</li>
<li><strong>C-c C-w a</strong> <em>slime-who-specializes</em> methods specialized on a symbol</li>
</ul>

<p>And when the <code>slime-asdf</code> contrib is enabled,
<strong>C-c C-w d</strong> <em>slime-who-depends-on</em> lists dependent ASDF systems</p>

<p>And a general binding: <strong>M-? or M-_</strong> *slime-edit-uses** combines all
of the above, it lists every kind of references.</p>

<h2 id="monitoring-and-controlling-threads-with-slime">Monitoring and controlling threads with Slime</h2>

<p><strong>M-x slime-list-threads</strong> (you can also access it through the
<em>slime-selector</em>, shortcut <strong>t</strong>) will list running threads by their
names, and their statuses.</p>

<p>The thread on the current line can be killed with <strong>k</strong>, or if there’s a
lot of threads to kill, several lines can be selected and <strong>k</strong> will kill
all the threads in the selected region.</p>

<p><strong>g</strong> will update the thread list, but when you have a lot of threads
starting and stopping it may be too cumbersome to always press <strong>g</strong>, so
there’s a variable <code>slime-threads-update-interval</code>, when set to a number
X the thread list will be automatically updated each X seconds, a
reasonable value would be 0.5.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://javierarcheni.com/wp-content/uploads/2021/04/cropped-favicon-javierarcheni-32x32.png" alt="Lanzando Tipicolis, mi proyecto personal dirigido a apoyar a productores gastronómicos locales">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Lanzando Tipicolis, mi proyecto personal dirigido a apoyar a productores gastronómicos locales</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Javier Archeni</a> <span class="article__date">23 08 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Hace tiempo que llevaba dándole vueltas a una idea que tuviera relación con los productos gastronómicos locales. Me siento muy atraído por esos productores locales que pelean por tener alimentos genuinos y auténticos. En un mercado tan competitivo como el de la distribución, se me antojan como una suerte de resistencia a los grandes grupos &#8230; <a href="https://javierarcheni.com/blog/lanzando-tipicolis/">Ver más</a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Things You Didn’t Know About GNU Readline</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Two-Bit History</a> <span class="article__date">22 08 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I sometimes think of my computer as a very large house. I visit this house every day and know most of the rooms on the ground floor, but there are bedrooms I’ve never been in, closets I haven’t opened, nooks and crannies that I’ve never explored. I feel compelled to learn more about my computer the same way anyone would feel compelled to see a room they had never visited in their own home. GNU Readline is an unassuming little software library that I relied on for years without realizing that it was there. Tens of thousands of people probably use it every day without thinking about it. If you use the Bash shell, every time you auto-complete a filename, or move the cursor around within a single line of input text, or search through the history of your previous commands, you are using GNU Readline. When you do those same things while using the command-line interface to Postgres (psql), say, or the Ruby REPL (irb), you are again using GNU Readline. Lots of software depends on the GNU Readline library to implement functionality that users expect, but the functionality is so auxiliary and unobtrusive that I imagine few people stop to wonder where it comes from.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/145-platypuscorn.png" alt="Platypuscorn">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Platypuscorn</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">20 08 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/145-platypuscorn.png" alt="Platypuscorn" title="It's available now pre alpha" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/144-brittle.png" alt="Brittle">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Brittle</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">13 08 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/144-brittle.png" alt="Brittle" title="All we need now is to automate the script updating." /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to Get the First or Last Value in a Group Using Group By in SQL</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">12 08 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Getting the last value of a group in an aggregated query in PostgreSQL is a challenging task. In this article we present a simple way to get the first or last value of a group using group by.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-E2Dc0w8ZsBM/XU8DjPcnFiI/AAAAAAAAmEE/JL2YTe4mcJ0O5aike_Bh7rdti5VniBXMQCLcBGAs/s640/tabla-01.jpg" alt="7 consejos para diseño de tablas comparativas">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">7 consejos para diseño de tablas comparativas</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">12 08 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-E2Dc0w8ZsBM/XU8DjPcnFiI/AAAAAAAAmEE/JL2YTe4mcJ0O5aike_Bh7rdti5VniBXMQCLcBGAs/s1600/tabla-01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="7 consejos para diseño de tablas comparativas" border="0" data-original-height="369" data-original-width="600" height="392" src="https://1.bp.blogspot.com/-E2Dc0w8ZsBM/XU8DjPcnFiI/AAAAAAAAmEE/JL2YTe4mcJ0O5aike_Bh7rdti5VniBXMQCLcBGAs/s640/tabla-01.jpg" title="7 consejos para diseño de tablas comparativas" width="640" /></a></div>Las tablas comparativas las vamos a ver muy frecuentemente en sitios como Amazon, donde podemos ver la comparación de características de un conjunto de productos para saber las diferencias de cada una de ellas. Otro uso muy común es cuando vamos a adquirir algún producto o suscripción, y hay varios niveles, desde el básico hasta el customizado. En este tipo de escenarios lo importante de poner una tabla comparativa es que el usuario pueda ver de forma visual las diferencias entre ese producto o servicio, para que de una u otra forma también se pueda inducir la elección a un tipo específico. En este video vamos a ver algunos consejos para el diseño de tablas comparativas.<div><br /></div><div><b>1. Resalta atributos importantes</b></div><div>Este es el primer consejo. Cuando construimos sitios interactivos es fundamental saber qué atributos debemos resaltar como por ejemplo el precio de la opción que más recomendamos a los usuarios, o características que no tienen las demás opciones. Esto es para que el usuario tenga presente esas cualidades y que al momento de tomar su decisión siempre recuerde las características resaltadas.</div><div><a href="https://1.bp.blogspot.com/-E2Dc0w8ZsBM/XU8DjPcnFiI/AAAAAAAAmEE/JL2YTe4mcJ0O5aike_Bh7rdti5VniBXMQCLcBGAs/s1600/tabla-01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="369" data-original-width="600" height="392" src="https://1.bp.blogspot.com/-E2Dc0w8ZsBM/XU8DjPcnFiI/AAAAAAAAmEE/JL2YTe4mcJ0O5aike_Bh7rdti5VniBXMQCLcBGAs/s640/tabla-01.jpg" width="640" /></a></div><div><br /></div><div><b>2. El problema del contenido</b></div><div>Las tablas comparativas no deberían tener mucho contenido por celda, pero tampoco debería haber celdas sin contenido, ya que esto hace ver a la tabla vacía. Lo importante es siempre acotar el contenido con características puntuales, y si es posible poner un link a otra sección para explicar mejor. Las opciones donde no haya contenido que poner, ya sea porque esa opción o columna no tiene características de los demás niveles, siempre es preferible poner que no existe, no aplica, o alguna marca que indique que ese campo es vacío. Este tema afecta mucho al usuario ya que si no ve nada en la celda pensará que faltó ponerle contenido o lo dejará con la duda de si aplica o no.</div><div><br /></div><div><b>3. Agrupa atributos</b></div><div>Una forma visual de poder navegar en una tabla comparativa es con el uso de grupos, o cabeceras, para que si tu tabla va a tener muchas filas de contenido, mejor las agrupes y el usuario pueda consultar aquellos atributos que le son más interesantes en ese momento.</div><div><a href="https://1.bp.blogspot.com/-aj6DPWMAs8g/XU8DjE4UEUI/AAAAAAAAmEM/EtjbRbUFAQMo3dmjZBEOl-m1xbFxa52pACLcBGAs/s1600/tabla-02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="409" data-original-width="600" height="436" src="https://1.bp.blogspot.com/-aj6DPWMAs8g/XU8DjE4UEUI/AAAAAAAAmEM/EtjbRbUFAQMo3dmjZBEOl-m1xbFxa52pACLcBGAs/s640/tabla-02.jpg" width="640" /></a></div><div><br /></div><div><b>4. Resalta de acuerdo a la necesidad</b></div><div>Una forma más dinámica para una tabla comparativa puede ser resaltar atributos que busque el cliente, por ejemplo, el producto más barato, o el que tiene más beneficios, o el más popular. No hagamos solo estático el resaltado de atributos, sino que también démosle al usuario la oportunidad de tener varios resaltados.</div><div><br /></div><div><b>5. Mantén un balance en el diseño</b></div><div>Lo más simple siempre va a ser mejor. Las tablas comparativas no deberían tener simbologías complejas, detalles o links adicionales, solo los atributos importantes, las imágenes y resaltados fundamentales para que haya un balance entre la tabla y el contenido. Recuerda que al final el usuario solo quiere comparar de un vistazo dos productos o servicios, no hace falta complicar mucho el diseño.</div><div><a href="https://1.bp.blogspot.com/-yZe8qW3o8MI/XU8DjFd2UEI/AAAAAAAAmEI/v-Ww2-RV_QUbl8Wb9hXbi_iMnEOQeJRxQCLcBGAs/s1600/tabla-03.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="455" data-original-width="600" height="484" src="https://1.bp.blogspot.com/-yZe8qW3o8MI/XU8DjFd2UEI/AAAAAAAAmEI/v-Ww2-RV_QUbl8Wb9hXbi_iMnEOQeJRxQCLcBGAs/s640/tabla-03.jpg" width="640" /></a></div><div><br /></div><div><b>6. Haz tu tabla fácil de compartir</b></div><div>Sobre todo en productos donde el precio es considerable siempre ten en mente que alguien va a sacar un screenshot en su computadora o pantalla, por lo que trata de mantener una tabla libre de scrolls, de paneles colapsables o de tablas muy grandes que no permitan tener en una pantalla mediana o pequeña la comparación. Si es posible trata de tener esa misma tabla en formato de imagen para que peuda ser compartida en las redes sociales.</div><div><br /></div><div><b>7. No uses muchos colores para resaltar</b></div><div>Basta con tener un solo color para resaltar los puntos importantes de una tabla comparativa. El uso exagerado de colores para resaltar, o un esquema complejo para identificar similitudes y diferencias solo hará que el usuario busque comparar en otro sitio o simplemente la decisión de comparar tus productos y servicios se extinga.</div><div><a href="https://1.bp.blogspot.com/-eFgk_N2TwYk/XU8DjrMUg4I/AAAAAAAAmEQ/9ze6PpUEy5owbGHb0vxDcffCBLo19MgFwCLcBGAs/s1600/tabla-04.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="350" data-original-width="600" height="371" src="https://1.bp.blogspot.com/-eFgk_N2TwYk/XU8DjrMUg4I/AAAAAAAAmEQ/9ze6PpUEy5owbGHb0vxDcffCBLo19MgFwCLcBGAs/s640/tabla-04.jpg" width="640" /></a></div><div><br /></div><div>Vía&nbsp;<a href="https://line25.com/ui-ux-design/comparison-table" target="_blank">line25</a></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=IJJbBD3gVzc:SPF6Zkbsa4Q:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=IJJbBD3gVzc:SPF6Zkbsa4Q:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=IJJbBD3gVzc:SPF6Zkbsa4Q:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=IJJbBD3gVzc:SPF6Zkbsa4Q:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=IJJbBD3gVzc:SPF6Zkbsa4Q:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=IJJbBD3gVzc:SPF6Zkbsa4Q:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=IJJbBD3gVzc:SPF6Zkbsa4Q:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=IJJbBD3gVzc:SPF6Zkbsa4Q:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=IJJbBD3gVzc:SPF6Zkbsa4Q:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=IJJbBD3gVzc:SPF6Zkbsa4Q:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=IJJbBD3gVzc:SPF6Zkbsa4Q:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=IJJbBD3gVzc:SPF6Zkbsa4Q:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=IJJbBD3gVzc:SPF6Zkbsa4Q:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=IJJbBD3gVzc:SPF6Zkbsa4Q:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/IJJbBD3gVzc" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://javierarcheni.com/wp-content/uploads/2021/04/cropped-favicon-javierarcheni-32x32.png" alt="Crear una cuenta de correo electrónico gratuita con tu propio dominio gracias a Migadu">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Crear una cuenta de correo electrónico gratuita con tu propio dominio gracias a Migadu</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Javier Archeni</a> <span class="article__date">11 08 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Actualización Noviembre 2020: Migadu ha realizado recientemente un cambio en su política de precios y ha retirado el plan gratuito. Ahora ofrecen un plan de bajo coste anual como primera opción. Mantengo el artículo como pista para otras opciones de configuración y porque Migadu me sigue pareciendo un gran servicio. Otra opción interesante a bajo &#8230; <a href="https://javierarcheni.com/blog/cuenta-correo-electronico-gratuita-con-propio-dominio-migadu/">Ver más</a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/143.png" alt="_">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">_</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">06 08 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/143.png" alt="_" title="Programs are meant to be read by humans and only incidentally for computers to execute. - Donald Knuth" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q3 2019 Funding Announcement</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">05 08 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together is happy to announce that for Q3 of 2019 (August-October) we are funding four projects: Shadow CLJS with Thomas Heller, Meander with Joel Holdbrooks, Calva with Peter Strömberg, and CIDER with Bozhidar Batsov.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">July 2019 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">05 08 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Daniel has just come back from Belgium to speak at Heart of Clojure about building stable foundations. The talk was recorded and will be coming out sometime in the future. We met lots of Clojurists Together supporters at the conference and had a stand there to talk about the work we are able to fund thanks to our members.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">What You Need to Know to Manage Users in Django Admin</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">04 08 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Have you ever stopped to think what staff user can do in your Django admin site? Did you know staff users with misconfigured permissions on the user model can make themselves superusers? Permissive permissions to staff users can cause disastrous human errors at best, and lead to major data leaks and at worst.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/142-the-superficial-high.png" alt="The Superficial High">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Superficial High</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">30 07 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/142-the-superficial-high.png" alt="The Superficial High" title="effectiveness - the degree to which something is successful in producing a desired result" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-Rj-XifAOIyk/XT-CjEBcM3I/AAAAAAAAmB8/VInFgilHB3UGTdFaAOoeZHjdySOzzw_WACLcBGAs/s640/hacker-programmer-working-with-data-code-in-a-dark-room-hackers-desk_r5btgt1bl_thumbnail-full01.png" alt="30 cosas que me gustaría haber sabido cuando empecé a programar">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">30 cosas que me gustaría haber sabido cuando empecé a programar</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">29 07 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-Rj-XifAOIyk/XT-CjEBcM3I/AAAAAAAAmB8/VInFgilHB3UGTdFaAOoeZHjdySOzzw_WACLcBGAs/s1600/hacker-programmer-working-with-data-code-in-a-dark-room-hackers-desk_r5btgt1bl_thumbnail-full01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="30 cosas que me gustaría haber sabido cuando empecé a programar" border="0" data-original-height="900" data-original-width="1600" height="360" src="https://1.bp.blogspot.com/-Rj-XifAOIyk/XT-CjEBcM3I/AAAAAAAAmB8/VInFgilHB3UGTdFaAOoeZHjdySOzzw_WACLcBGAs/s640/hacker-programmer-working-with-data-code-in-a-dark-room-hackers-desk_r5btgt1bl_thumbnail-full01.png" title="30 cosas que me gustaría haber sabido cuando empecé a programar" width="640" /></a></div><span class="fullpost"><br /></span><span class="fullpost">Entrar al mundo de la programación puede ser sencillo o muy difícil dependiendo del contexto de la persona. De hecho, creo que aunque hoy hay muchísma más información que hace cinco años, la dificultad todavía es un poco elevada para alguien que nunca ha estado en contacto con el mundo de la programación, especialmente si se adentra directo en ella. En este post les voy a compartir algunas ideas de lo que me hubiera gustado conocer cuando empecé con la programación, que tal vez a ti si te sirvan y con eso puedas tener una curva de aprendizaje mucho más rápida en menos tiempo.</span><br /><span class="fullpost"><br /></span><br /><ol><li><span class="fullpost">No necesitas un grado universitario para ser desarrollador, pero sí necesitas tener conocimientos de ingeniería</span></li><li>La programación no solo es resolver problemas, sino también usar la creatividad para poder encontrar diferentes formas de resolver problemas</li><li>No puedes aprender todo sobre programación, es imposible, pero sí puedes aprender cosas básicas que te pueden servir en cualquier momento, todas las áreas de la programación comparten cosas similares, y cada una ofrece algo más específico.</li><li>Date un descanso en la programación, no es cierto que tengas que estar horas en la computadora para ser mejor, requiere esfuerzo pero no dejar tu vida personal</li><li>Programar es acerca de entender conceptos y aplicarlos, no de memorizar código, nadie que intente memorizar código puede ser considerado un programador</li><li>Siempre habrá alguien que sepa más que tu, y es normal, pasa con todas las áreas de estudio, lo importante es que tu sepas lo que necesitas aprender y lo aprendas.</li><li>No seas adicto a la programación, sal, juega, ten una relación; que ser programador no sea lo primero, sino lo que te complementa después de tener una vida propia</li><li>Aprenderás a programar si te pones retos contigo mismo, es decir, si te pones objetivos de programas, funciones, o ciertas cosas que necesitas hacer en un determinado tiempo (y que sea técnicamente realista)</li><li>Al contrario de lo que dicen, no es 100% cierto que necesites saber matemáticas para ser buen programador, como lo dije antes, hay diferentes áreas de aplicación, y no todas requieren que seas bueno, pero sí que conozcas las operaciones básicas de suma, resta, multiplicación y división.</li><li>No necesitas ponerte un estereotipo de novato en programación, hay mucha gente que puede saber otros lenguajes y no uno específico, y no por eso se considera novato, simplemente estás aprendiendo.</li><li>Trata de terminar tus proyectos, porque de esa forma podrás llegar a un objetivo inicial, que es terminar algo.</li><li>Te traumarás eventualmente por encontrar el error que evita que funcione tu programa correctamente, y es algo normal</li><li>Es normal que busques en internet cómo se hace determinada cosa para tu programa, como dije, no es buen programador el que memoriza, sino el que usa lo sabe para programar mejor, y buscar es una buena habilidad</li><li>Necesitas no solo programar sino también guiarte en prácticas recomendadas, inicia tu vida de programador también aprendiendo los consejos de patrones de diseño de programación</li><li>Una obsesión más será el poner nombres correctos a tus variables y funciones, es totalmente normal y siempre pensarás que pueden llamarse de otra forma</li><li>Un trauma común es programar con nombres en inglés o español, o si es deEstaForma o de_esta_otra_forma, cualquiera de las opciones es válida, lo importante es que tu código sea entendible</li><li>Es bueno darse por vencido, porque en algún proyecto puede que veas que necesitas otros conocimientos para terminar esa parte que te faltaba. De aquí en adelante si lo que deseas es seguir aprendiendo, hazlo y vuelve a interntarlo</li><li>Si ves que un programa ya se hizo muy elaborado o complicado vuelve a empezar desde cero, eso te dará la oportunidad de volverlo a hacer de otra forma, y no tratar de arreglar algo que quizá ya no tiene solución</li><li>Cuando estés programando te empezarás a preguntar si lo que haces es la mejor forma de hacerlo, no pierdas esa curiosidad</li><li>Programar por gusto no es lo mismo que trabajar en programar. Lo primero te va a encantar, y lo segundo no, pero es algo que tienes que identificar para no odiar la programación</li><li>Es completamente normal no pasar una entrevista técnica de programación, mas si nunca has practicado problemas de lógica realmente difíciles</li><li>Siempre creete que eres bueno, pero no lo suficiente para perder el piso y creer que nadie puede contra ti</li><li>Habrá quien te diga que lo que haces está mal, pero si no te ayuda a mejorar puedes hacer caso omiso de esos comentarios</li><li>Trata de buscar programadores que admires, porque de esa forma querrás tener una visión de ti mismo en un futuro</li><li>Siempre es difícil trabajar en equipo para un proyecto, porque no es la misma técnica para todos, pero trata siempre de demostrar por qué deberían hacer las cosas de cierta forma</li><li>Si revisas después de un año el código de algún proyecto, te vas a dar cuenta que pudo haber sido mejor, toma ese feedback y aplícalo en el siguiente proyecto que hagas</li><li>Siempre tenemos un momentum, ese instante donde a pesar de que ya quieres terminar algo no te deja descansar. Si te pasa eso es que realmente te gusta la programación, pero evita que pase seguido</li><li>Odiarás y amarás los hackatones porque te permite ponerte a prueba contra el tiempo, pero te dolerá si lo tuyo no es la presión&nbsp;</li><li>No todo va a ser copiar código de páginas como Stack overflow, también necesitas entender el por qué de una solución que buscas</li><li>La programación con música es mucho mejor, inténtalo</li></ol><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=8Tyd9Q2dk10:aYTCVVrpeyo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8Tyd9Q2dk10:aYTCVVrpeyo:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8Tyd9Q2dk10:aYTCVVrpeyo:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=8Tyd9Q2dk10:aYTCVVrpeyo:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8Tyd9Q2dk10:aYTCVVrpeyo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=8Tyd9Q2dk10:aYTCVVrpeyo:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8Tyd9Q2dk10:aYTCVVrpeyo:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8Tyd9Q2dk10:aYTCVVrpeyo:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8Tyd9Q2dk10:aYTCVVrpeyo:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=8Tyd9Q2dk10:aYTCVVrpeyo:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8Tyd9Q2dk10:aYTCVVrpeyo:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8Tyd9Q2dk10:aYTCVVrpeyo:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=8Tyd9Q2dk10:aYTCVVrpeyo:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8Tyd9Q2dk10:aYTCVVrpeyo:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/8Tyd9Q2dk10" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://javierarcheni.com/wp-content/uploads/2021/04/cropped-favicon-javierarcheni-32x32.png" alt="Tailwind CSS, disciplina y diversión a partes iguales para diseñar tus proyectos web">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Tailwind CSS, disciplina y diversión a partes iguales para diseñar tus proyectos web</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Javier Archeni</a> <span class="article__date">29 07 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        El CSS entra en la categoría de esas materias que son fáciles de aprender, pero difíciles de dominar. Creo que uno de los motivos está en la bendita libertad que ofrece el CSS, ya que más allá de conocer la sintaxis y cumplir unos mínimos, no impone unas reglas muy estrictas. Uno va construyendo sus &#8230; <a href="https://javierarcheni.com/blog/tailwind-css-disciplina-y-diversion-a-partes-iguales-para-disenar-tus-proyectos-web/">Ver más</a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure Forum</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">25 07 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div class="paragraph">
<p>We are pleased to announce today a new forum for Clojure and ClojureScript users: <a href="https://ask.clojure.org">https://ask.clojure.org</a>. You can ask questions, discuss possible problems, request enhancements, and vote on questions and answers.</p>
</div>
<div class="paragraph">
<p>The new forum was seeded with all of the open JIRA issues, one question per issue with JIRA comments turned into answers. Over time, we expect this site to serve as a persistent store of common questions, answers, etc - it is open for web indexing and has both search and "similar question" functionality to help you find previous related discussions. This addresses one of the biggest issues with current places to ask questions about Clojure - the ability to search and find similar prior discussions.</p>
</div>
<div class="paragraph">
<p>For problems and enhancements, we have been using JIRA for years (and will continue to do so). However, there are naturally two audiences for issues, users and developers, who have different needs. The new forum will serve as the primary place for users to ask questions about potential problems or request possible enhancments. Authentication occurs via GitHub (other auth providers may be added in the future). No contributor agreement is needed.</p>
</div>
<div class="paragraph">
<p>Developers on Clojure, ClojureScript, etc will monitor these forums and create JIRAs when necessary. Any user may vote on questions in the forum and the dev teams can use this information when prioritizing fixes and enhancements. This capability has been available in JIRA for many years, but it was too much of a barrier to receive feedback from casual users. The new forum greatly reduces this friction. JIRA will still be used by developers submitting and working on patches, but not for initial problem reporting.</p>
</div>
<div class="paragraph">
<p>For more information see the <a href="xref/../../../../../community/ask">forum usage details</a>.</p>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/141-ptsd.png" alt="PTSD">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">PTSD</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">23 07 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/141-ptsd.png" alt="PTSD" title="Go ahead, make my day" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://ep00.epimg.net/iconos/v1.x/v1.0/logos/cabecera_portada.png" alt="50 años de la llegada a la Luna">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">50 años de la llegada a la Luna</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Sección Materia | Ciencia en EL PAÍS</a> <span class="article__date">22 07 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Serie de artículos sobre la conquista del satélite
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://javierarcheni.com/wp-content/uploads/2021/04/cropped-favicon-javierarcheni-32x32.png" alt="Motivos para desconfiar de las buenas prácticas en tu marketing digital">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Motivos para desconfiar de las buenas prácticas en tu marketing digital</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Javier Archeni</a> <span class="article__date">17 07 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        En esto de lo digital y los negocios, es bastante común andar a la caza de buenas prácticas y casos de éxito. Copiar es saludable y además suele salir barato. Lo cuento porque de vez en cuando, por petición de algún cliente, tengo que leer o revisar ofertas de profesionales. Y yo que disfruto cuando &#8230; <a href="https://javierarcheni.com/blog/motivos-desconfiar-buenas-practicas-marketing-digital/">Ver más</a>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q3 2019 Survey Results and Call for Proposals</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">12 07 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        We surveyed our members again and asked them what they wanted us to focus on. Our next funding round closes on Wednesday, July 17th, 2019 at 11:59pm PST.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to Check Slots Types at make-instance</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">10 07 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>In CLOS, a slot can have a <code>:type</code> option, but it doesn&rsquo;t inforce type
checking. It is good practice to use it, for documentation and for
compiler optimizations and warnings sometimes (with CCL and SBCL when
safety is high), but one shouldn&rsquo;t rely on it. To comply this need, we
can simply create our own constructor functions.</p>

<p>However, the
<a href="https://github.com/fisxoj/sanity-clause">sanity-clause</a> library can
do it since a couple of days. The validation error messages are
pretty good.  Demonstration.</p>

<blockquote>
<p>Sanity clause is a data validation/contract library. You might use it for configuration data, validating an api response, or documents from a datastore. In a dynamically typed langauge, it helps you define clearly defined areas of doubt and uncertainty. We should love our users, but we should never blindly trust their inputs.</p>

<p>To make use of it, you define schemas, which can be property lists with symbols for keys and instances of :class:sanity-clause.field:field</p>
</blockquote>

<p>We define a class <code>person</code> with slot options from sanity-clause:
<code>:field-type</code>, <code>type</code> <code>:members</code>, <code>:required</code>:</p>

<pre><code class="language-lisp">(defclass person ()
  ((favorite-dog :type symbol
                 :field-type :member
                 :members (:wedge :walter)
                 :initarg :favorite-dog
                 :required t)
   (age :type (integer 0)
        :initarg :age
        :required t)
   (potato :type string
           :initarg :potato
           :required t))
  (:metaclass sanity-clause.metaclass:validated-metaclass))
</code></pre>

<p>Now we try to create a <code>person</code> with <code>make-instance</code>, but we give a bad dog name:</p>

<pre><code class="language-lisp">(make-instance 'person :favorite-dog :nope)
; Evaluation aborted on Error converting value for field #&lt;MEMBER-FIELD {1004BFA973}&gt;:
Value &quot;NOPE&quot; couldn't be found in set (WEDGE WALTER)
</code></pre>

<p>Now with a bad age:</p>

<pre><code class="language-lisp">(make-instance 'person :age -1 :favorite-dog :walter)
; Evaluation aborted on Error validating value -1 in field #&lt;INTEGER-FIELD {1004BFF103}&gt;:
* Value -1 didn't satisfy condition &quot;must be larger than 0&quot;
</code></pre>

<p>When a required field is missing:</p>

<pre><code class="language-lisp">(make-instance 'person :age 7 :favorite-dog :walter)
; Evaluation aborted on A value for field POTATO is required but none was provided..
</code></pre>

<p>And well, it works when all is OK :]</p>

<pre><code class="language-lisp">(make-instance 'person :age 1 :favorite-dog :walter :potato &quot;patate&quot;)
#&lt;PERSON {10060371E3}&gt;
</code></pre>

<p>The usual warnings apply: it&rsquo;s a new library, we must try it and use
it with caution. It however opens up more possibilities. It would be
awesome to couple it with an ORM like Mito. This is an <a href="https://github.com/fisxoj/sanity-clause/issues/8">open
issue</a>.</p>

<p>Resources:</p>

<ul>
<li><a href="https://stackoverflow.com/questions/51723992/how-to-force-slots-type-to-be-checked-during-make-instance/56920918">https://stackoverflow.com/questions/51723992/how-to-force-slots-type-to-be-checked-during-make-instance/56920918</a></li>
<li><a href="https://lispcookbook.github.io/cl-cookbook/clos.html#slot-type">https://lispcookbook.github.io/cl-cookbook/clos.html#slot-type</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/140-bug-fixing-ways.png" alt="Bug Fixing Ways">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Bug Fixing Ways</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">09 07 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/140-bug-fixing-ways.png" alt="Bug Fixing Ways" title="You cannot escape the responsibility of tomorrow by evading it today." /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Fastest Way to Load Data Into PostgreSQL Using Python</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">08 07 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Explore the best way to import messy data from remote source into PostgreSQL using Python and Psycopg2. The data is big, fetched from a remote source, and needs to be cleaned and transformed.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Little Known Vim Command – Join</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Jovica Ilic</a> <span class="article__date">08 07 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>As the author of Mastering Vim Quickly I sometimes get various Vim related questions from my readers. Much more often I get emails from my subscribers at masteringvim.com where I share free Vim tips. Although this command is very simple, my experience showed that a lot of people are not aware of it. So it&#8217;s... <a class="more-link" href="https://jovicailic.org/2019/07/vim-command-join/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a rel="nofollow" href="https://jovicailic.org/2019/07/vim-command-join/">Little Known Vim Command &#8211; Join</a> appeared first on <a rel="nofollow" href="https://jovicailic.org">Jovica Ilic</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://camo.githubusercontent.com/17dd6e0a7a916c8118f0134a94404f6757bee9dc/68747470733a2f2f7261772e6769746875622e636f6d2f6575646f786961302f636c61636b2d6572726f72732f6d61737465722f73637265656e73686f742d6465762e706e67" alt="Web Development in Common Lisp: frameworks overview, templating, deployment">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Web Development in Common Lisp: frameworks overview, templating, deployment</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">07 07 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>We just published a long overdue page on the Cookbook: <a href="https://lispcookbook.github.io/cl-cookbook/web.html">web
development in Common
Lisp</a>. We have an
ambivalent feeling about it since it isn&rsquo;t really a recipe as in the
other pages. Yet it is valuable content that required a certain amount
of digging and tryouts. Indeed, it took us about two years to discover
and advertise many projects, to learn, try and put a tutorial
together. We also wrote a commercial application. During that time, we
were taking notes on our <a href="/web-dev/">web-dev/</a> page.</p>

<p>We present Hunchentoot, Clack (briefly), we have an overview of other
web frameworks, of templating libraries, we introduce Weblocks, we give
recipes for common tasks (such as checking if a user is logged in,
encrypting passwords), and we speak about deployment.</p>

<p>Some topics still need to be adressed, so check for updates on the Cookbook !</p>

<hr />

<p><em>Prior notice:</em></p>

<p>Some people sell ten pages long ebooks or publish their tutorial on
Gitbook to have a purchase option. I prefer to enhance the
collaborative Cookbook (I am by far <a href="https://github.com/LispCookbook/cl-cookbook/graphs/contributors">the main
contributor</a>). You
can tip me on liberapay if you like:
<a href="https://liberapay.com/vindarel/">https://liberapay.com/vindarel/</a>. Thanks !</p>

<hr />

<p>For web development as for any other task, one can leverage Common
Lisp&rsquo;s advantages: the unmatched REPL and exception handling system,
performance, the ability to build a self-contained executable,
stability, good threads story, strong typing, etc. We can, say, define
a new route and try it right away, there is no need to restart any
running server. We can change and compile <em>one function at a time</em>
(the usual <code>C-c C-c</code> in Slime) and try it. The feedback is
immediate. We can choose the degree of interactivity: the web server
can catch exceptions and fire the interactive debugger, or print lisp
backtraces on the browser, or display a 404 error page and print logs
on standard output. The ability to build self-contained executables eases
deployment tremendously (compared to, for example, npm-based apps), in
that we just copy the executable to a server and run it.</p>

<p>We&rsquo;ll present here some established web frameworks and other common
libraries to help you getting started in developing a web
application. We do <em>not</em> aim to be exhaustive nor to replace the
upstream documentation. Your feedback and contributions are
appreciated.</p>

<!-- form creation, form validation -->

<!-- Javascript -->

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->

<p><strong>Table of Contents</strong></p>

<ul>
<li><a href="#overview">Overview</a></li>
<li><a href="#installation">Installation</a></li>
<li><a href="#simple-webserver">Simple webserver</a>

<ul>
<li><a href="#serve-local-files">Serve local files</a>

<ul>
<li><a href="#hunchentoot">Hunchentoot</a></li>
</ul></li>
</ul></li>
<li><a href="#access-your-server-from-the-internet">Access your server from the internet</a>

<ul>
<li><a href="#hunchentoot-1">Hunchentoot</a></li>
</ul></li>
<li><a href="#routing">Routing</a>

<ul>
<li><a href="#simple-routes">Simple routes</a>

<ul>
<li><a href="#hunchentoot-2">Hunchentoot</a></li>
<li><a href="#caveman">Caveman</a></li>
</ul></li>
<li><a href="#accessing-get-and-post-parameters">Accessing GET and POST parameters</a>

<ul>
<li><a href="#hunchentoot-3">Hunchentoot</a></li>
</ul></li>
</ul></li>
<li><a href="#error-handling">Error handling</a>

<ul>
<li><a href="#hunchentoot-4">Hunchentoot</a></li>
<li><a href="#clack">Clack</a></li>
</ul></li>
<li><a href="#weblocks---solving-the-javascript-problem">Weblocks - solving the &ldquo;JavaScript problem&rdquo;©</a></li>
<li><a href="#templates">Templates</a>

<ul>
<li><a href="#djula---html-markup">Djula - HTML markup</a></li>
<li><a href="#spinneret---lispy-templates">Spinneret - lispy templates</a></li>
</ul></li>
<li><a href="#connecting-to-a-database">Connecting to a database</a>

<ul>
<li><a href="#checking-a-user-is-logged-in">Checking a user is logged-in</a></li>
<li><a href="#encrypting-passwords">Encrypting passwords</a></li>
</ul></li>
<li><a href="#building">Building</a>

<ul>
<li><a href="#building-a-self-contained-executable">Building a self-contained executable</a></li>
<li><a href="#continuous-delivery-with-travis-ci-or-gitlab-ci">Continuous delivery with Travis CI or Gitlab CI</a></li>
<li><a href="#multiplatform-delivery-with-electron">Multiplatform delivery with Electron</a></li>
</ul></li>
<li><a href="#deployment">Deployment</a>

<ul>
<li><a href="#deploying-manually">Deploying manually</a></li>
<li><a href="#daemonizing-restarting-in-case-of-crashes-handling-logs-with-systemd">Daemonizing, restarting in case of crashes, handling logs with Systemd</a></li>
<li><a href="#with-docker">With Docker</a></li>
<li><a href="#with-guix">With Guix</a></li>
<li><a href="#deploying-on-heroku-and-other-services">Deploying on Heroku and other services</a></li>
<li><a href="#monitoring">Monitoring</a></li>
<li><a href="#connecting-to-a-remote-lisp-image">Connecting to a remote Lisp image</a></li>
<li><a href="#hot-reload">Hot reload</a></li>
</ul></li>
<li><a href="#credits">Credits</a></li>
</ul>

<!-- markdown-toc end -->

<h1 id="overview">Overview</h1>

<p><a href="https://edicl.github.io/hunchentoot">Hunchentoot</a> and <a href="https://github.com/fukamachi/clack">Clack</a> are two projects that
you&rsquo;ll often hear about.</p>

<p>Hunchentoot is</p>

<blockquote>
<p>a web server and at the same time a toolkit for building dynamic websites. As a stand-alone web server, Hunchentoot is capable of HTTP/1.1 chunking (both directions), persistent connections (keep-alive), and SSL. It provides facilities like automatic session handling (with and without cookies), logging, customizable error handling, and easy access to GET and POST parameters sent by the client.</p>
</blockquote>

<p>It is a software written by Edi Weitz (&ldquo;Common Lisp Recipes&rdquo;,
<code>cl-ppcre</code> and <a href="https://edicl.github.io/">much more</a>), it&rsquo;s used and
proven solid. One can achieve a lot with it, but sometimes with more
friction than with a traditional web framework. For example,
dispatching a route by the HTTP method is a bit convoluted, one must
write a function for the <code>:uri</code> parameter that does the check, when it
is a built-in keyword in other frameworks like Caveman.</p>

<p>Clack is</p>

<blockquote>
<p>a web application environment for Common Lisp inspired by Python&rsquo;s WSGI and Ruby&rsquo;s Rack.</p>
</blockquote>

<p>Also written by a prolific lisper
(<a href="https://github.com/fukamachi/">E. Fukamachi</a>), it actually uses
Hunchentoot by default as the server, but thanks to its pluggable
architecture one can use another web server, like the asynchronous
<a href="https://github.com/fukamachi/woo">Woo</a>, built on the
<a href="http://software.schmorp.de/pkg/libev.html">libev</a> event loop, maybe
&ldquo;the fastest web server written in any programming language&rdquo;.</p>

<p>We&rsquo;ll cite also <a href="https://github.com/orthecreedence/wookie">Wookie</a>, an asynchronous HTTP server, and its
companion library
<a href="https://github.com/orthecreedence/cl-async">cl-async</a>, for general
purpose, non-blocking programming in Common Lisp, built on libuv, the
backend library in Node.js.</p>

<p>Clack being more recent and less documented, and Hunchentoot a
de-facto standard, we&rsquo;ll concentrate on the latter for this
recipe. Your contributions are of course welcome.</p>

<p>Web frameworks build upon web servers and can provide facilities for
common activities in web development, like a templating system, access
to a database, session management, or facilities to build a REST api.</p>

<p>Some web frameworks include:</p>

<ul>
<li><a href="https://github.com/fukamachi/caveman">Caveman</a>, by E. Fukamachi. It provides, out of the box,
database management, a templating engine (Djula), a project skeleton
generator, a routing system à la Flask or Sinatra, deployment options
(mod_lisp or FastCGI), support for Roswell on the command line, etc.</li>
<li><a href="https://github.com/Shirakumo/radiance">Radiance</a>, by <a href="https://github.com/Shinmera">Shinmera</a>
(Qtools, Portacle, lquery, …), is a web application environment,
more general than usual web frameworks. It lets us write and tie
websites and applications together, easing their deployment as a
whole. It has thorough <a href="https://shirakumo.github.io/radiance/">documentation</a>, a <a href="https://github.com/Shirakumo/radiance-tutorial">tutorial</a>, <a href="https://github.com/Shirakumo/radiance-contribs">modules</a>, <a href="https://github.com/Shirakumo?utf8=%E2%9C%93&amp;q=radiance&amp;type=&amp;language=">pre-written applications</a> such as <a href="https://github.com/Shirakumo/purplish">an image board</a> or a <a href="https://github.com/Shirakumo/reader">blogging platform</a>, and more.
For example websites, see
<a href="https://shinmera.com/">https://shinmera.com/</a>,
<a href="https://reader.tymoon.eu/">reader.tymoon.eu</a> and <a href="https://events.tymoon.eu/">events.tymoon.eu</a>.</li>
<li><a href="https://github.com/joaotavora/snooze">Snooze</a>, by João Távora (Sly, Emacs&rsquo; Yasnippet, Eglot, …),
is &ldquo;an URL router designed around REST web services&rdquo;. It is
different because in Snooze, routes are just functions and HTTP
conditions are just Lisp conditions.</li>
<li><a href="https://github.com/mmontone/cl-rest-server">cl-rest-server</a> is a library for writing REST web
APIs. It features validation with schemas, annotations for logging,
caching, permissions or authentication, documentation via OpenAPI (Swagger),
etc.</li>
<li>last but not least, <a href="https://github.com/40ants/weblocks">Weblocks</a> is a venerable Common Lisp
web framework that permits to write ajax-based dynamic web
applications without writing any JavaScript, nor writing some lisp
that would transpile to JavaScript. It is seeing an extensive
rewrite and update since 2017. We present it in more details below.</li>
</ul>

<p>For a full list of libraries for the web, please see the <a href="https://github.com/CodyReichert/awesome-cl#network-and-internet">awesome-cl
list
#network-and-internet</a>
and <a href="https://www.cliki.net/Web">Cliki</a>. If you are looking for a
featureful static site generator, see
<a href="https://github.com/coleslaw-org/coleslaw">Coleslaw</a>.</p>

<h1 id="installation">Installation</h1>

<p>Let&rsquo;s install the libraries we&rsquo;ll use:</p>

<pre><code class="language-lisp">(ql:quickload '(&quot;hunchentoot&quot; &quot;caveman&quot; &quot;spinneret&quot; &quot;djula&quot;))
</code></pre>

<p>To try Weblocks, please see its documentation. The Weblocks in
Quicklisp is not yet, as of writing, the one we are interested in.</p>

<p>We&rsquo;ll start by serving local files and we&rsquo;ll run more than one local
server in the running image.</p>

<h1 id="simple-webserver">Simple webserver</h1>

<h2 id="serve-local-files">Serve local files</h2>

<h3 id="hunchentoot">Hunchentoot</h3>

<p>Create and start a webserver like this:</p>

<pre><code class="language-lisp">(defvar *acceptor* (make-instance 'hunchentoot:easy-acceptor :port 4242))
(hunchentoot:start *acceptor*)
</code></pre>

<p>We create an instance of <code>easy-acceptor</code> on port 4242 and we start
it. We can now access <a href="http://127.0.0.1:4242/">http://127.0.0.1:4242/</a>. You should get a welcome
screen with a link to the documentation and logs to the console.</p>

<p>By default, Hunchentoot serves the files from the <code>www/</code> directory in
its source tree. Thus, if you go to the source of
<code>easy-acceptor</code> (<code>M-.</code> in Slime), which is probably
<code>~/quicklisp/dists/quicklisp/software/hunchentoot-v1.2.38/</code>, you&rsquo;ll
find the <code>root/</code> directory. It contains:</p>

<ul>
<li>an <code>errors/</code> directory, with the error templates <code>404.html</code> and <code>500.html</code>,</li>
<li>an <code>img/</code> directory,</li>
<li>an <code>index.html</code> file.</li>
</ul>

<p>To serve another directory, we give the option <code>document-root</code> to
<code>easy-acceptor</code>. We can also set the slot with its accessor:</p>

<pre><code class="language-lisp">(setf (hunchentoot:acceptor-document-root *acceptor*) #p&quot;path/to/www&quot;)
</code></pre>

<p>Let&rsquo;s create our <code>index.html</code> first. Put this in a new
<code>www/index.html</code> at the current directory (of the lisp repl):</p>

<pre><code class="language-html">&lt;html&gt;
  &lt;head&gt;
    &lt;title&gt;Hello!&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;Hello local server!&lt;/h1&gt;
    &lt;p&gt;
    We just served our own files.
    &lt;/p&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre>

<p>Let&rsquo;s start a new acceptor on a new port:</p>

<pre><code class="language-lisp">(defvar *my-acceptor* (make-instance 'hunchentoot:easy-acceptor :port 4444
                                   :document-root #p&quot;www/&quot;))
(hunchentoot:start *my-acceptor*)
</code></pre>

<p>go to <a href="http://127.0.0.1:4444/">p://127.0.0.1:4444/</a> and see the difference.</p>

<p>Note that we just created another <em>acceptor</em> on a different port on
the same lisp image. This is already pretty cool.</p>

<h1 id="access-your-server-from-the-internet">Access your server from the internet</h1>

<h2 id="hunchentoot-1">Hunchentoot</h2>

<p>With Hunchentoot we have nothing to do, we can see the server from the
internet right away.</p>

<p>If you evaluate this on your VPS:</p>

<pre><code>(hunchentoot:start (make-instance 'hunchentoot:easy-acceptor :port 4242))
</code></pre>

<p>You can see it right away on your server&rsquo;s IP.</p>

<p>Stop it with <code>(hunchentoot:stop *)</code>.</p>

<h1 id="routing">Routing</h1>

<h2 id="simple-routes">Simple routes</h2>

<h3 id="hunchentoot-2">Hunchentoot</h3>

<p>To bind an existing function to a route, we create a &ldquo;prefix dispatch&rdquo;
that we push onto the <code>*dispatch-table*</code> list:</p>

<pre><code class="language-lisp">(defun hello ()
   (format nil &quot;Hello, it works!&quot;))

(push
  (hunchentoot:create-prefix-dispatcher &quot;/hello.html&quot; #'hello)
  hunchentoot:*dispatch-table*)
</code></pre>

<p>To create a route with a regexp, we use <code>create-regex-dispatcher</code>, where
the url-as-regexp can be a string, an s-expression or a cl-ppcre scanner.</p>

<p>If you didn&rsquo;t yet, create an acceptor and start the server:</p>

<pre><code class="language-lisp">(defvar *server* (make-instance 'hunchentoot:easy-acceptor :port 4242))
(hunchentoot:start *server*)
</code></pre>

<p>and access it on [<a href="http://localhost:4242/hello.html]http://localhost:4242/hello.html)">http://localhost:4242/hello.html]http://localhost:4242/hello.html)</a>.</p>

<p>We can see logs on the REPL:</p>

<pre><code>127.0.0.1 - [2018-10-27 23:50:09] &quot;get / http/1.1&quot; 200 393 &quot;-&quot; &quot;Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0&quot;
127.0.0.1 - [2018-10-27 23:50:10] &quot;get /img/made-with-lisp-logo.jpg http/1.1&quot; 200 12583 &quot;http://localhost:4242/&quot; &quot;Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0&quot;
127.0.0.1 - [2018-10-27 23:50:10] &quot;get /favicon.ico http/1.1&quot; 200 1406 &quot;-&quot; &quot;Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0&quot;
127.0.0.1 - [2018-10-27 23:50:19] &quot;get /hello.html http/1.1&quot; 200 20 &quot;-&quot; &quot;Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0&quot;
</code></pre>

<hr />

<p><a href="https://edicl.github.io/hunchentoot/#define-easy-handler">define-easy-handler</a> allows to create a function and to bind it to an uri at once.</p>

<p>Its form follows</p>

<pre><code>define-easy-handler (function-name :uri &lt;uri&gt; …) (lambda list parameters)
</code></pre>

<p>where <code>&lt;uri&gt;</code> can be a string or a function.</p>

<p>Example:</p>

<pre><code class="language-lisp">(hunchentoot:define-easy-handler (say-yo :uri &quot;/yo&quot;) (name)
  (setf (hunchentoot:content-type*) &quot;text/plain&quot;)
  (format nil &quot;Hey~@[ ~A~]!&quot; name))
</code></pre>

<p>Visit it at <a href="http://localhost:4242/yo">p://localhost:4242/yo</a> and add parameters on the url:
<a href="http://localhost:4242/yo?name=Alice">http://localhost:4242/yo?name=Alice</a>.</p>

<p>Just a thought… we didn&rsquo;t explicitely ask Hunchentoot to add this
route to our first acceptor of the port 4242. Let&rsquo;s try another acceptor (see
previous section), on port 4444: <a href="http://localhost:4444/yo?name=Bob">http://localhost:4444/yo?name=Bob</a> It
works too ! In fact, <code>define-easy-handler</code> accepts an <code>acceptor-names</code>
parameter:</p>

<blockquote>
<p>acceptor-names (which is evaluated) can be a list of symbols which means that the handler will only be returned by DISPATCH-EASY-HANDLERS in acceptors which have one of these names (see ACCEPTOR-NAME). acceptor-names can also be the symbol T which means that the handler will be returned by DISPATCH-EASY-HANDLERS in every acceptor.</p>
</blockquote>

<p>So, <code>define-easy-handler</code> has the following signature:</p>

<pre><code>define-easy-handler (function-name &amp;key uri acceptor-names default-request-type) (lambda list parameters)
</code></pre>

<p>It also has a <code>default-parameter-type</code> which we&rsquo;ll use in a minute to get url parameters.</p>

<p>There are also keys to know for the lambda list. Please see the documentation.</p>

<h3 id="caveman">Caveman</h3>

<p><a href="caveman">Caveman</a> provides two ways to
define a route: the <code>defroute</code> macro and the <code>@route</code> pythonic
<em>annotation</em>:</p>

<pre><code class="language-lisp">(defroute &quot;/welcome&quot; (&amp;key (|name| &quot;Guest&quot;))
  (format nil &quot;Welcome, ~A&quot; |name|))

@route GET &quot;/welcome&quot;
(lambda (&amp;key (|name| &quot;Guest&quot;))
  (format nil &quot;Welcome, ~A&quot; |name|))
</code></pre>

<p>A route with an url parameter (note <code>:name</code> in the url):</p>

<pre><code class="language-lisp">(defroute &quot;/hello/:name&quot; (&amp;key name)
  (format nil &quot;Hello, ~A&quot; name))
</code></pre>

<p>It is also possible to define &ldquo;wildcards&rdquo; parameters. It works with
the <code>splat</code> key:</p>

<pre><code class="language-lisp">(defroute &quot;/say/*/to/*&quot; (&amp;key splat)
  ; matches /say/hello/to/world
  (format nil &quot;~A&quot; splat))
;=&gt; (hello world)
</code></pre>

<p>We must enable regexps with <code>:regexp t</code>:</p>

<pre><code class="language-lisp">(defroute (&quot;/hello/([\\w]+)&quot; :regexp t) (&amp;key captures)
  (format nil &quot;Hello, ~A!&quot; (first captures)))
</code></pre>

<h2 id="accessing-get-and-post-parameters">Accessing GET and POST parameters</h2>

<h3 id="hunchentoot-3">Hunchentoot</h3>

<p>First of all, note that we can access query parameters anytime with</p>

<pre><code class="language-lisp">(hunchentoot:parameter &quot;my-param&quot;)
</code></pre>

<p>It acts on the default <code>*request*</code> object which is passed to all handlers.</p>

<p>There is also <code>get-paramater</code> and <code>post-parameter</code>.</p>

<p>Earlier we saw some key parameters to <code>define-easy-handler</code>. We now
introduce <code>default-parameter-type</code>.</p>

<p>We defined the following handler:</p>

<pre><code class="language-lisp">(hunchentoot:define-easy-handler (say-yo :uri &quot;/yo&quot;) (name)
  (setf (hunchentoot:content-type*) &quot;text/plain&quot;)
  (format nil &quot;Hey~@[ ~A~]!&quot; name))
</code></pre>

<p>The variable <code>name</code> is a string by default. Let&rsquo;s check it out:</p>

<pre><code class="language-lisp">(hunchentoot:define-easy-handler (say-yo :uri &quot;/yo&quot;) (name)
  (setf (hunchentoot:content-type*) &quot;text/plain&quot;)
  (format nil &quot;Hey~@[ ~A~] you are of type ~a&quot; name (type-of name)))
</code></pre>

<p>Going to <a href="http://localhost:4242/yo?name=Alice">http://localhost:4242/yo?name=Alice</a> returns</p>

<pre><code>Hey Alice you are of type (SIMPLE-ARRAY CHARACTER (5))
</code></pre>

<p>To automatically bind it to another type, we use <code>default-parameter-type</code>. It can be
one of those simple types:</p>

<ul>
<li><code>'string</code> (default),</li>
<li><code>'integer</code>,</li>
<li><code>'character</code> (accepting strings of length 1 only, otherwise it is nil)</li>
<li>or <code>'boolean</code></li>
</ul>

<p>or a compound list:</p>

<ul>
<li><code>'(:list &lt;type&gt;)</code></li>
<li><code>'(:array &lt;type&gt;)</code></li>
<li><code>'(:hash-table &lt;type&gt;)</code></li>
</ul>

<p>where <code>&lt;type&gt;</code> is a simple type.</p>

<!-- ## Sessions -->

<!-- todo ? -->

<!-- ## Cookies -->

<h1 id="error-handling">Error handling</h1>

<p>In all frameworks, we can choose the level of interactivity. The web
framework can return a 404 page and print output on the repl, it can
catch errors and invoke the interactive lisp debugger, or it can show
the lisp backtrace on the html page.</p>

<h2 id="hunchentoot-4">Hunchentoot</h2>

<p>The global variables to set are <code>*catch-errors-p*</code>,
<code>*show-lisp-errors-p*</code> and <code>*show-lisp-backtraces-p*</code>.</p>

<p>Hunchentoot also defines condition classes.</p>

<p>See the documentation: <a href="https://edicl.github.io/hunchentoot/#conditions">https://edicl.github.io/hunchentoot/#conditions</a>.</p>

<h2 id="clack">Clack</h2>

<p>Clack users might make a good use of plugins, like the clack-errors middleware: <a href="https://github.com/CodyReichert/awesome-cl#clack-plugins">https://github.com/CodyReichert/awesome-cl#clack-plugins</a>.</p>

<p><img src="https://camo.githubusercontent.com/17dd6e0a7a916c8118f0134a94404f6757bee9dc/68747470733a2f2f7261772e6769746875622e636f6d2f6575646f786961302f636c61636b2d6572726f72732f6d61737465722f73637265656e73686f742d6465762e706e67" width="800"/></p>

<h1 id="weblocks-solving-the-javascript-problem">Weblocks - solving the &ldquo;JavaScript problem&rdquo;©</h1>

<p><a href="https://github.com/40ants/weblocks">Weblocks</a> is a widgets-based and
server-based framework with a built-in ajax update mechanism. It
allows to write dynamic web applications <em>without the need to write
JavaScript or to write lisp code that would transpile to JavaScript</em>.</p>

<p><img src="http://40ants.com/weblocks/_images/quickstart-check-task.gif" alt="" /></p>

<p>Weblocks is an old framework developed by Slava Akhmechet, Stephen
Compall and Leslie Polzer. After nine calm years, it is seeing a very
active update, refactoring and rewrite effort by Alexander Artemenko.</p>

<p>It was initially based on continuations (they were removed to date)
and thus a lispy cousin of Smalltalk&rsquo;s
<a href="https://en.wikipedia.org/wiki/Seaside_(software)">Seaside</a>. We can
also relate it to Haskell&rsquo;s Haste, OCaml&rsquo;s Eliom,
Elixir&rsquo;s Phoenix LiveView and others.</p>

<p>The <a href="http://ultralisp.org/">Ultralisp</a> website is an example Weblocks
website in production known in the CL community.</p>

<hr />

<p>Weblock&rsquo;s unit of work is the <em>widget</em>. They look like a class definition:</p>

<pre><code class="language-lisp">(defwidget task ()
        ((title
          :initarg :title
          :accessor title)
         (done
          :initarg :done
          :initform nil
          :accessor done)))
</code></pre>

<p>Then all we have to do is to define the <code>render</code> method for this widget:</p>

<pre><code class="language-lisp">(defmethod render ((task task))
        &quot;Render a task.&quot;
        (with-html
              (:span (if (done task)
                         (with-html
                               (:s (title task)))
                       (title task)))))
</code></pre>

<p>It uses the Spinneret template engine by default, but we can bind any
other one of our choice.</p>

<p>To trigger an ajax event, we write lambdas in full Common Lisp:</p>

<pre><code class="language-lisp">...
(with-html
          (:p (:input :type &quot;checkbox&quot;
            :checked (done task)
            :onclick (make-js-action
                      (lambda (&amp;key &amp;allow-other-keys)
                        (toggle task))))
...
</code></pre>

<p>The function <code>make-js-action</code> creates a simple javascript function
that calls the lisp one on the server, and automatically refreshes the
HTML of the widgets that need it. In our example, it re-renders one
task only.</p>

<p>Is it appealing ? Carry on this quickstart guide here: <a href="http://40ants.com/weblocks/quickstart.html">http://40ants.com/weblocks/quickstart.html</a>.</p>

<h1 id="templates">Templates</h1>

<h2 id="djula-html-markup">Djula - HTML markup</h2>

<p><a href="https://github.com/mmontone/djula">Djula</a> is a port of Python&rsquo;s
Django template engine to Common Lisp. It has <a href="https://mmontone.github.io/djula/doc/build/html/index.html">excellent documentation</a>.</p>

<p>Caveman uses it by default, but otherwise it is not difficult to
setup. We must declare where our templates are with something like</p>

<pre><code class="language-lisp">(djula:add-template-directory (asdf:system-relative-pathname &quot;webapp&quot; &quot;templates/&quot;))
</code></pre>

<p>A Djula template looks like this, no surprises (forgive the antislash
in <code>\%</code>, this is a Jekyll limitation):</p>

<pre><code>{\% extends &quot;base.html&quot; \%}
{\% block title %}Memberlist{\% endblock \%}
{\% block content \%}
  &lt;ul&gt;
  {\% for user in users \%}
    &lt;li&gt;&lt;a href=&quot;{{ user.url }}&quot;&gt;{{ user.username }}&lt;/a&gt;&lt;/li&gt;
  {\% endfor \%}
  &lt;/ul&gt;
{\% endblock \%}
</code></pre>

<p>Djula compiles the templates before rendering them.</p>

<p>It is, along with its companion
<a href="https://github.com/AccelerationNet/access/">access</a> library, one of
the most downloaded libraries of Quicklisp.</p>

<h2 id="spinneret-lispy-templates">Spinneret - lispy templates</h2>

<p><a href="https://github.com/ruricolist/spinneret">Spinneret</a> is a &ldquo;lispy&rdquo;
HTML5 generator. It looks like this:</p>

<pre><code class="language-lisp">(with-page (:title &quot;Home page&quot;)
     (:header
      (:h1 &quot;Home page&quot;))
     (:section
      (&quot;~A, here is *your* shopping list: &quot; *user-name*)
      (:ol (dolist (item *shopping-list*)
             (:li (1+ (random 10)) item))))
     (:footer (&quot;Last login: ~A&quot; *last-login*)))
</code></pre>

<p>The author finds it is easier to compose the HTML in separate
functions and macros than with the more famous cl-who. But it
has more features under it sleeves:</p>

<ul>
<li>it warns on invalid tags and attributes</li>
<li>it can automatically number headers, given their depth</li>
<li>it pretty prints html per default, with control over line breaks</li>
<li>it understands embedded markdown</li>
<li>it can tell where in the document a generator function is (see <code>get-html-tag</code>)</li>
</ul>

<h1 id="connecting-to-a-database">Connecting to a database</h1>

<p>Please see the <a href="databases.html">databases section</a>. The Mito ORM
supports SQLite3, PostgreSQL, MySQL, it has migrations and db schema
versioning, etc.</p>

<p>In Caveman, a database connection is alive during the Lisp session and is
reused in each HTTP requests.</p>

<h2 id="checking-a-user-is-logged-in">Checking a user is logged-in</h2>

<p>A framework will provide a way to work with sessions. We&rsquo;ll create a
little macro to wrap our routes to check if the user is logged in.</p>

<p>In Caveman, <code>*session*</code> is a hash table that represents the session&rsquo;s
data. Here are our login and logout functions:</p>

<pre><code class="language-lisp">(defun login (user)
  &quot;Log the user into the session&quot;
  (setf (gethash :user *session*) user))

(defun logout ()
  &quot;Log the user out of the session.&quot;
  (setf (gethash :user *session*) nil))
</code></pre>

<p>We define a simple predicate:</p>

<pre><code class="language-lisp">(defun logged-in-p ()
  (gethash :user cm:*session*))
</code></pre>

<p>and we define our <code>with-logged-in</code> macro:</p>

<pre><code class="language-lisp">(defmacro with-logged-in (&amp;body body)
  `(if (logged-in-p)
       (progn ,@body)
       (render #p&quot;login.html&quot;
               '(:message &quot;Please log-in to access this page.&quot;))))
</code></pre>

<p>If the user isn&rsquo;t logged in, there will nothing in the session store,
and we render the login page. When all is well, we execute the macro&rsquo;s
body. We use it like this:</p>

<pre><code class="language-lisp">(defroute &quot;/account/logout&quot; ()
  &quot;Show the log-out page, only if the user is logged in.&quot;
  (with-logged-in
    (logout)
    (render #p&quot;logout.html&quot;)))

(defroute (&quot;/account/review&quot; :method :get) ()
  (with-logged-in
    (render #p&quot;review.html&quot;
            (list :review (get-review (gethash :user *session*))))))
</code></pre>

<p>and so on.</p>

<h2 id="encrypting-passwords">Encrypting passwords</h2>

<p>In this recipe we use the de-facto standard
<a href="https://github.com/froydnj/ironclad">Ironclad</a> cryptographic toolkit
and the <a href="https://github.com/cl-babel/babel">Babel</a> charset
encoding/decoding library.</p>

<p>This snippet creates the password hash that should be stored in your
database. Note that Ironclad expects a byte-vector, not a string.</p>

<pre><code class="language-lisp">(defun password-hash (password)
  (ironclad:pbkdf2-hash-password-to-combined-string
   (babel:string-to-octets password)))
</code></pre>

<p><code>pbkdf2</code> is defined in <a href="https://tools.ietf.org/html/rfc2898">RFC2898</a>.
It uses a pseudorandom function to derive a secure encryption key
based on the password.</p>

<p>The following function checks if a user is active and verifies the
entered password. It returns the user-id if active and verified and
nil in all other cases even if an error occurs. Adapt it to your
application.</p>

<pre><code class="language-lisp">(defun check-user-password (user password)
  (handler-case
      (let* ((data (my-get-user-data user))
             (hash (my-get-user-hash data))
             (active (my-get-user-active data)))
        (when (and active (ironclad:pbkdf2-check-password (babel:string-to-octets password)
                                                          hash))
          (my-get-user-id data)))
    (condition () nil)))
</code></pre>

<p>And the following is an example on how to set the password on the
database. Note that we use <code>(password-hash password)</code> to save the
password. The rest is specific to the web framework and to the DB
library.</p>

<pre><code class="language-lisp">(defun set-password (user password)
  (with-connection (db)
    (execute
     (make-statement :update :web_user
                     (set= :hash (password-hash password))
                     (make-clause :where
                                  (make-op := (if (integerp user)
                                                  :id_user
                                                  :email)
                                           user))))))
</code></pre>

<p><em>Credit: <code>/u/arvid</code> on <a href="https://www.reddit.com/r/learnlisp/comments/begcf9/can_someone_give_me_an_eli5_on_hiw_to_encrypt_and/">/r/learnlisp</a></em>.</p>

<h1 id="building">Building</h1>

<h2 id="building-a-self-contained-executable">Building a self-contained executable</h2>

<p>As for all Common Lisp applications, we can bundle our web app in one
single executable, including the assets. It makes deployment very
easy: copy it to your server and run it.</p>

<pre><code>$ ./my-web-app
Hunchentoot server is started.
Listening on localhost:9003.
</code></pre>

<p>See this recipe on <a href="scripting.html#for-web-apps">scripting#for-web-apps</a>.</p>

<h2 id="continuous-delivery-with-travis-ci-or-gitlab-ci">Continuous delivery with Travis CI or Gitlab CI</h2>

<p>Please see the section on <a href="testing.html#continuous-integration">testing#continuous-integration</a>.</p>

<h2 id="multiplatform-delivery-with-electron">Multiplatform delivery with Electron</h2>

<p><a href="https://ceramic.github.io/">Ceramic</a> makes all the work for us.</p>

<p>It is as simple as this:</p>

<pre><code class="language-lisp">;; Load Ceramic and our app
(ql:quickload '(:ceramic :our-app))

;; Ensure Ceramic is set up
(ceramic:setup)
(ceramic:interactive)

;; Start our app (here based on the Lucerne framework)
(lucerne:start our-app.views:app :port 8000)

;; Open a browser window to it
(defvar window (ceramic:make-window :url &quot;http://localhost:8000/&quot;))

;; start Ceramic
(ceramic:show-window window)
</code></pre>

<p>and we can ship this on Linux, Mac and Windows.</p>

<p>There is more:</p>

<blockquote>
<p>Ceramic applications are compiled down to native code, ensuring both performance and enabling you to deliver closed-source, commercial applications.</p>
</blockquote>

<p>Thus, no need to minify our JS.</p>

<h1 id="deployment">Deployment</h1>

<h2 id="deploying-manually">Deploying manually</h2>

<p>We can start our executable in a shell and send it to the bakcground (<code>C-z bg</code>), or run it inside a <code>tmux</code> session. These are not the best but hey, it works©.</p>

<h2 id="daemonizing-restarting-in-case-of-crashes-handling-logs-with-systemd">Daemonizing, restarting in case of crashes, handling logs with Systemd</h2>

<p>This is actually a system-specific task. See how to do that on your system.</p>

<p>Most GNU/Linux distros now come with Systemd, so here&rsquo;s a little example.</p>

<p>Deploying an app with Systemd is as simple as writing a configuration file:</p>

<pre><code>$ emacs -nw /etc/systemd/system/my-app.service
[Unit]
Description=stupid simple example

[Service]
WorkingDirectory=/path/to/your/app
ExecStart=/usr/local/bin/sthg sthg
Type=simple
Restart=always
RestartSec=10
</code></pre>

<p>Then we have a command to start it:</p>

<pre><code>sudo systemctl start my-app.service
</code></pre>

<p>a command to check its status:</p>

<pre><code>systemctl status my-app.service
</code></pre>

<p>and Systemd can handle <strong>logging</strong> (we write to stdout or stderr, it writes logs):</p>

<pre><code>journalctl -f -u my-app.service
</code></pre>

<p>and it handles crashes and <strong>restarts the app</strong>:</p>

<pre><code>Restart=always
</code></pre>

<p>and it can <strong>start the app after a reboot</strong>:</p>

<pre><code>[Install]
WantedBy=basic.target
</code></pre>

<p>to enable it:</p>

<pre><code>sudo systemctl enable my-app.service
</code></pre>

<h2 id="with-docker">With Docker</h2>

<p>There are several Docker images for Common
Lisp. For example:</p>

<ul>
<li><a href="https://github.com/40ants/base-lisp-image">40ants/base-lisp-image</a>
is based on Ubuntu LTS and includes SBCL, CCL, Quicklisp, Qlot and
Roswell.</li>
<li><a href="https://github.com/container-lisp/s2i-lisp">container-lisp/s2i-lisp</a>
is CentOs based and contains the source for building a Quicklisp based
Common Lisp application as a reproducible docker image using OpenShift&rsquo;s
source-to-image.</li>
</ul>

<h2 id="with-guix">With Guix</h2>

<p><a href="https://www.gnu.org/software/guix/">GNU Guix</a> is a transactional
package manager, that can be installed on top of an existing OS, and a
whole distro that supports declarative system configuration. It allows
to ship self-contained tarballs, which also contain system
dependencies. For an example, see the <a href="https://github.com/atlas-engineer/next/">Next browser</a>.</p>

<h2 id="deploying-on-heroku-and-other-services">Deploying on Heroku and other services</h2>

<p>See <a href="https://gitlab.com/duncan-bayne/heroku-buildpack-common-lisp">heroku-buildpack-common-lisp</a> and the <a href="https://github.com/CodyReichert/awesome-cl#deployment">Awesome CL#deploy</a> section for interface libraries for Kubernetes, OpenShift, AWS, etc.</p>

<h2 id="monitoring">Monitoring</h2>

<p>See <a href="https://github.com/deadtrickster/prometheus.cl">Prometheus.cl</a>
for a Grafana dashboard for SBCL and Hunchentoot metrics (memory,
threads, requests per second,…).</p>

<h2 id="connecting-to-a-remote-lisp-image">Connecting to a remote Lisp image</h2>

<p>This this section: <a href="debugging.html#remote-debugging">debugging#remote-debugging</a>.</p>

<h2 id="hot-reload">Hot reload</h2>

<p>This is an example from <a href="https://github.com/stylewarning/quickutil/blob/master/quickutil-server/">Quickutil</a>. It is actually an automated version of the precedent section.</p>

<p>It has a Makefile target:</p>

<pre><code class="language-lisp">hot_deploy:
	$(call $(LISP), \
		(ql:quickload :quickutil-server) (ql:quickload :swank-client), \
		(swank-client:with-slime-connection (conn &quot;localhost&quot; $(SWANK_PORT)) \
			(swank-client:slime-eval (quote (handler-bind ((error (function continue))) \
				(ql:quickload :quickutil-utilities) (ql:quickload :quickutil-server) \
				(funcall (symbol-function (intern &quot;STOP&quot; :quickutil-server))) \
				(funcall (symbol-function (intern &quot;START&quot; :quickutil-server)) $(start_args)))) conn)) \
		$($(LISP)-quit))
</code></pre>

<p>It has to be run on the server (a simple fabfile command can call this
through ssh). Beforehand, a <code>fab update</code> has run <code>git pull</code> on the
server, so new code is present but not running. It connects to the
local swank server, loads the new code, stops and starts the app in a
row.</p>

<h1 id="credits">Credits</h1>

<ul>
<li><a href="https://lisp-journey.gitlab.io/web-dev/">https://lisp-journey.gitlab.io/web-dev/</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Relatos cortos y cuentos como herramienta para la educación ambiental</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">07 07 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-tLUd1P8E9Sw/XR7cN3o_9XI/AAAAAAAAl-U/E0tVtOfgvLU9Y2RURwWfrl_j33-6-npvACLcBGAs/s400/video-04.jpg" alt="Realiza videos rápidos y profesionales con Flexclip">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Realiza videos rápidos y profesionales con Flexclip</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">05 07 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-tLUd1P8E9Sw/XR7cN3o_9XI/AAAAAAAAl-U/E0tVtOfgvLU9Y2RURwWfrl_j33-6-npvACLcBGAs/s1600/video-04.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Realiza videos rápidos y profesionales con Flexclip" border="0" data-original-height="506" data-original-width="1600" height="126" src="https://1.bp.blogspot.com/-tLUd1P8E9Sw/XR7cN3o_9XI/AAAAAAAAl-U/E0tVtOfgvLU9Y2RURwWfrl_j33-6-npvACLcBGAs/s400/video-04.jpg" title="Realiza videos rápidos y profesionales con Flexclip" width="400" /></a></div><span class="fullpost"><br /></span><span class="fullpost"><a href="https://www.flexclip.com/" target="_blank">Flexclip</a> es un servicio que encontré y me pareció de lo más interesante para realizar videos rápidos pero bonitos. Uno de los problemas más grandes que a veces tengo es que si quiero hacer un video rápido, sin necesidad de tener mucha edición, opciones como Adobe Premiere no cumplen su cometido, porque añaden muchísima complejidad a una cinemática con imágenes y texto.</span><br /><span class="fullpost">Encontré a Flexclip y creo que de cualquier opción que hayas visto en internet, diría que es la más sencilla de usar con grandes resultados.</span><br /><span class="fullpost"><a href="https://1.bp.blogspot.com/-jee4l_PumB0/XR7dXcKWDdI/AAAAAAAAl-s/fpdpaaNNxnAeux6M8MBt9U3lCpT852pBwCLcBGAs/s1600/video-05.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="Realiza videos rápidos y profesionales con Flexclip" border="0" data-original-height="914" data-original-width="1486" height="392" src="https://1.bp.blogspot.com/-jee4l_PumB0/XR7dXcKWDdI/AAAAAAAAl-s/fpdpaaNNxnAeux6M8MBt9U3lCpT852pBwCLcBGAs/s640/video-05.jpg" title="Realiza videos rápidos y profesionales con Flexclip" width="640" /></a></span><br /><span class="fullpost">Para empezar podemos elegir una temática de un template para no partir desde cero. La ventaja de usar estas opciones es que ya no necesitas nada más que cambiar el texto y las imágenes, por lo que ya te ahorras al menos la mitad del trabajo.</span><br /><span class="fullpost"><a href="https://1.bp.blogspot.com/-aB1Tb-slNuU/XR7cBzNGmkI/AAAAAAAAl-M/y_ENrOdnBRgpNZbs8WMRaFqDlrUKBNXngCLcBGAs/s1600/video-01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="Realiza videos rápidos y profesionales con Flexclip" border="0" data-original-height="777" data-original-width="1600" height="310" src="https://1.bp.blogspot.com/-aB1Tb-slNuU/XR7cBzNGmkI/AAAAAAAAl-M/y_ENrOdnBRgpNZbs8WMRaFqDlrUKBNXngCLcBGAs/s640/video-01.jpg" title="Realiza videos rápidos y profesionales con Flexclip" width="640" /></a></span><br /><span class="fullpost">Cuando llegamos a la interfaz no pude estar más impresionado de lo minimalista y funcional que puede ser tener dos o tres herramientas para trabajar. Como les digo, esto es para cuando necesitamos algo rápido, tenemos videos, imágenes y música, y no queremos perder el tiempo en acomodarlos pixel por pixel a ver si queda bien.</span><br /><span class="fullpost"><a href="https://1.bp.blogspot.com/-K-xprFyu89U/XR7cBY-08eI/AAAAAAAAl-I/Rd5azVp5GNsMSawKHKWq7uqVYd5_5AADACLcBGAs/s1600/video-02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="Realiza videos rápidos y profesionales con Flexclip" border="0" data-original-height="434" data-original-width="676" height="410" src="https://1.bp.blogspot.com/-K-xprFyu89U/XR7cBY-08eI/AAAAAAAAl-I/Rd5azVp5GNsMSawKHKWq7uqVYd5_5AADACLcBGAs/s640/video-02.jpg" title="Realiza videos rápidos y profesionales con Flexclip" width="640" /></a></span><br /><span class="fullpost">Los cuadros de control son muy rápidos de editar, no hace falta gran complejidad para poder meter un texto en un formato ya definido para que puedas ver luego luego el resultado.</span><br /><span class="fullpost"><a href="https://1.bp.blogspot.com/-yi_d7uiyiNg/XR7cBw4TYkI/AAAAAAAAl-Q/QbQtXjN49jwYtum0gGcZ876KFR64QuNNACLcBGAs/s1600/video-03.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="778" data-original-width="1600" height="310" src="https://1.bp.blogspot.com/-yi_d7uiyiNg/XR7cBw4TYkI/AAAAAAAAl-Q/QbQtXjN49jwYtum0gGcZ876KFR64QuNNACLcBGAs/s640/video-03.jpg" width="640" /></a></span><br /><span class="fullpost">Si al contrario, no tenemos ningún contenido para empezar a trabajar, podemos agregar de la galería de Flexclip imágenes y música que sorpresivamente tienen una calidad muy buena.</span><br /><span class="fullpost">Al final tu video se presenta como la composición de varias escenas, donde si quieres acomodarlas solo necesitas moverlas de lugar y ya, a previsualizar el video y si te gustó lo puedes exportar.</span><br /><span class="fullpost"><br /></span><h2><span class="fullpost">Conclusiones</span></h2><span class="fullpost">Este servicio en línea me recordó mucho a cuando usaba Windows Movie Maker para hacer videos cortos o que por la urgencia necesitaba tener en unos cuantos minutos. No ha vuelto a existir un programa igual, pero me sorprende que los servicios web ahora estén tomando esa responsabilidad de seguir ofreciendo hacer videos como lo hace Flexclip, sin la necesidad de ser un experto en edición para crear un contenido de calidad de forma muy rápida.</span><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=Cfn1MCec2AA:FaL_HAeeRJo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Cfn1MCec2AA:FaL_HAeeRJo:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Cfn1MCec2AA:FaL_HAeeRJo:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=Cfn1MCec2AA:FaL_HAeeRJo:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Cfn1MCec2AA:FaL_HAeeRJo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=Cfn1MCec2AA:FaL_HAeeRJo:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Cfn1MCec2AA:FaL_HAeeRJo:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Cfn1MCec2AA:FaL_HAeeRJo:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Cfn1MCec2AA:FaL_HAeeRJo:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=Cfn1MCec2AA:FaL_HAeeRJo:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Cfn1MCec2AA:FaL_HAeeRJo:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Cfn1MCec2AA:FaL_HAeeRJo:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=Cfn1MCec2AA:FaL_HAeeRJo:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Cfn1MCec2AA:FaL_HAeeRJo:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/Cfn1MCec2AA" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/139-mvp.png" alt="MVP">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">MVP</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">02 07 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/139-mvp.png" alt="MVP" title="The king is dead, long live the king!" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Functional JavaScript: What are higher-order functions, and why should anyone care?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">01 07 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        “Higher-order function” is one of those phrases people throw around a lot. But it's rare for anyone to stop to explain what that means. Perhaps you already know what a higher-order function is. But how do we use them in the real world? What are some practical examples of when and how they're useful? Can we use them for manipulating the DOM? Or, are people who use higher-order functions showing off? Are they over-complicating code for no good reason?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Functional JavaScript: What are higher-order functions, and why should anyone care?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">01 07 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        “Higher-order function” is one of those phrases people throw around a lot. But it's rare for anyone to stop to explain what that means. Perhaps you already know what a higher-order function is. But how do we use them in the real world? What are some practical examples of when and how they're useful? Can we use them for manipulating the DOM? Or, are people who use higher-order functions showing off? Are they over-complicating code for no good reason?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">June 2019 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">01 07 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        It&rsquo;s been a successful second month with our selected Q2 project, Fireplace, check out the updates below. The Call for Proposals for Q3 Projects at Clojurists Together is now open!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Recomendaciones para reducir nuestro consumo de plástico</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">29 06 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/138-obvious.png" alt="Obvious">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Obvious</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">25 06 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/138-obvious.png" alt="Obvious" title="Maybe some hallway testing isn't a bad idea after all" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-x3OFqplvSaU/XQ_xzWB1l1I/AAAAAAAAl7I/-qiBF9GCusY5ZDFhpH3xrkw9tvt5ys8nwCLcBGAs/s640/vidamrr-codigo.jpeg" alt="7 hábitos de programadores altamente efectivos">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">7 hábitos de programadores altamente efectivos</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">24 06 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-x3OFqplvSaU/XQ_xzWB1l1I/AAAAAAAAl7I/-qiBF9GCusY5ZDFhpH3xrkw9tvt5ys8nwCLcBGAs/s1600/vidamrr-codigo.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="7 hábitos de programadores altamente efectivos" border="0" data-original-height="501" data-original-width="750" height="426" src="https://1.bp.blogspot.com/-x3OFqplvSaU/XQ_xzWB1l1I/AAAAAAAAl7I/-qiBF9GCusY5ZDFhpH3xrkw9tvt5ys8nwCLcBGAs/s640/vidamrr-codigo.jpeg" title="7 hábitos de programadores altamente efectivos" width="640" /></a></div><div><br /></div>Los programadores de calidad son los que van avanzando, crean mejores proyectos y colaboran en equipo. Hay ciertos hábitos que los developers necesitan estar ejecutando de forma regular para poder ofrecer código de calidad, y en este post les voy a mostrar algunos de ellos.&nbsp;<div><br /></div><h2>1. Aprende a leer el código de los demás</h2><div>Poder leer código escrito de alguien más te dará más visión sobre si el código que haces es bueno o malo. También es bueno de vez en cuando aprender a entender el código de alguien más porque podrías adoptar técnicas y formas de programar que quizá ni sabías que existían, y de la misma forma hacer que los demás aprendan.</div><div><br /></div><h2>2. La sensación de malos proyectos</h2><div>¿Les ha pasado que antes de empezar un proyecto pueden empezar a estructurar el futuro del mismo? eso se aprende con la experiencia, con los retrasos o la dificultad de los proyectos cuando no se planean bien. Este punto de aprender a identificar buenos y malos proyectos ayuda mucho porque al final un desarrollador debería ser capaz de determinar la viabilidad de un proyecto, y más cuando no tiene futuro.</div><h2>3. Evitar las reuniones</h2><div>Todos odiamos las reuniones largas en un proyecto. Dar estatus, explicaciones y en general, invertir tiempo en explicarle a los demás qué es lo que pasa con un proyecto es algo que siempre deberíamos evitar. No es estar en contra de tener reuniones, pero para dar avances no es necesario tener una reunión diario, con una a la semana, con correos, y con herramientas como Github se puede reemplazar el tener que invertir tiempo innecesario.</div><h2>4. Uso de Github</h2><div>Github y Git son de las herramientas indispensables hoy en día para cualquier desarrollador. Ya sea que trabajes de forma local o colaborativa tener un sistema de versionamiento permite tener eficiencia en los cambios que se hacen a un proyecto, especialmente si es grande. El otro plus es que tener un sistema como Github permite que otros vean tu código sin tener que perder tiempo tratando de mostrarles avances a los líderes del proyecto.</div><h2>5. Escribir código que pueda ser mantenido</h2><div>Para ser efectivo como programador, uno de los primeros pasos es programar correctamente. De nada sirve tener los puntos anteriores, si cuando inicia otro proyecto no puedas reusar código que podría servirte de nuevo. Hay que aprender a crear código que pueda ser extendido y mantenido, es decir, que puedas quitar, adaptar y volver a usar en n número de proyectos. Cuando logres hacer lo anterior, habrás ahorrado muchísimo tiempo de programación.</div><h2>6. Aprende a decir no y prioriza</h2><div>No todo vas a poder hacer, por eso tienes que priorizar las actividades que sí puedes hacer excelente. La parte del éxito de los programadores es poder ejecutar lo que está en su alcance, compartir responsabilidad con un equipo cuando así se necesita, y decir que no cuando no agrega valor la actividad al proyecto. Si sigues ese mismo principio de desechar lo que te puede hacer perder tiempo y no agregar valor a un proyecto de programación puedes entonces priorizar de forma correcta.</div><h2>7. Pensamiento de diseño operacional</h2>Siempre que trabajamos en un proyecto de programación creemos que con probar los escenarios más obvios, nuestro proyecto ya va a funcionar correctamente. Desde la modificación del código hasta el lanzamiento hay muchísimas variables que podrían afectar el funcionamiento del producto final, por eso un hábito muy identificado en programadores efectivos es que prueban y prueban de todas las formas posibles el software para poder identificar cualquier error posible durante la programación y la liberación. La simple modificación de una línea de código podría afectar otras partes del sistema que probablemente no estemos notando.<br /><br /><h3>Conclusiones</h3>Estos son algunos consejos de programadores que no solo programan bien, sino que tienen un panorama mucho más amplio de cómo contribuir a un proyecto con calidad y acertividad cuando se colabora con otros.<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=DLwthD7V9pM:edBscvwt5Do:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=DLwthD7V9pM:edBscvwt5Do:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=DLwthD7V9pM:edBscvwt5Do:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=DLwthD7V9pM:edBscvwt5Do:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=DLwthD7V9pM:edBscvwt5Do:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=DLwthD7V9pM:edBscvwt5Do:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=DLwthD7V9pM:edBscvwt5Do:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=DLwthD7V9pM:edBscvwt5Do:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=DLwthD7V9pM:edBscvwt5Do:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=DLwthD7V9pM:edBscvwt5Do:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=DLwthD7V9pM:edBscvwt5Do:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=DLwthD7V9pM:edBscvwt5Do:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=DLwthD7V9pM:edBscvwt5Do:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=DLwthD7V9pM:edBscvwt5Do:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/DLwthD7V9pM" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Microplásticos. Enemigos del mar IV</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">20 06 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/137-a-qa-walks-into-the-office.png" alt="A QA walks into the office">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">A QA walks into the office</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">18 06 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/137-a-qa-walks-into-the-office.png" alt="A QA walks into the office" title="We call it Manual Continuous Integration" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="Chrome&#39;s Manifest V3 - Improving Privacy?">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Chrome&#39;s Manifest V3 - Improving Privacy?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">17 06 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        How Chrome's changes will reduce user privacy
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Functional JavaScript: Traversing Trees with a Recursive Reduce</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">12 06 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Trees come up a lot in web development. As in, more than you would expect. They pop up all over the place. But trees can be tricky. If you're like me, you know that there ought to be a way to process them neatly. You might want to change all the values, or make some calculation on the tree. But the way to do it isn't always obvious. And utility libraries like Ramda or Lodash don't come with tree-traversing functions. So, what do we do?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Functional JavaScript: Traversing Trees with a Recursive Reduce</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">12 06 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Trees come up a lot in web development. As in, more than you would expect. They pop up all over the place. But trees can be tricky. If you're like me, you know that there ought to be a way to process them neatly. You might want to change all the values, or make some calculation on the tree. But the way to do it isn't always obvious. And utility libraries like Ramda or Lodash don't come with tree-traversing functions. So, what do we do?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/136-exit-condition.png" alt="Exit Condition">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Exit Condition</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">11 06 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/136-exit-condition.png" alt="Exit Condition" title="this" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">La libertad de desarrollar...: Validando un API rest as&amp;#237;ncrono con Cerberus</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">09 06 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Validando un API rest as&#237;ncrono con Cerberus<br /><br />El art&#237;culo lo pueden leer en el siguiente <a href="https://www.seraph.to/apirest-aiohttp-cerberus-2019.html#apirest-aiohttp-cerberus-2019" target="_blank">enlace</a><br /><br /><br /><br />Visiten el blog&nbsp;<a href="http://www.seraph.to/" target="_blank">www.seraph.to</a><br /><br /><br />
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">La libertad de desarrollar...: C&amp;#243;mo usar el API de Wikipedia desde Python</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">08 06 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Pueden leer el art&#237;culo en el siguiente enlace<br /><br />&nbsp;<a href="https://www.seraph.to/python-wikipedia-2019.html#python-wikipedia-2019%20#Wikipedia%20#API%20#Python" target="_blank">C&#243;mo usar el API de Wikipedia desde Python </a><br /><br /><br />
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Improve Serialization Performance in Django Rest Framework</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">07 06 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>When a developer chooses Python, Django, or Django Rest Framework, it's usually not because of its blazing fast performance. All of this doesn't mean performance is not important. As this story taught us, major performance boosts can be gained with just a little attention, and a few small changes.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure 1.10.1 release</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">06 06 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Clojure 1.10.1 is a small release focusing on two issues: working around a Java performance regression and improving error reporting from clojure.main.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_java_performance_regression"><a class="anchor" href="#_java_performance_regression"></a>Java performance regression</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Recent builds of Java 8 (u202), 11 (11.0.2), 12, and 13 included some changes that drastically affect optimization performance of calls from static initializers to static fields. Clojure provides support for loading code on startup from a user.clj file and this occurred in the static initializer of the Clojure runtime (RT) class and was thus affected.</p>
</div>
<div class="paragraph">
<p>This issue may eventually be resolved in Java, but in Clojure we have modified runtime initialization to avoid loading user.clj in a static initializer, which mitigates the case where this caused a performance degradation.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_clojure_main_error_reporting"><a class="anchor" href="#_clojure_main_error_reporting"></a>clojure.main error reporting</h2>
<div class="sectionbody">
<div class="paragraph">
<p>clojure.main is frequently used as a Clojure program launcher by external tools. Previously, uncaught exceptions would be automatically printed by the JVM, which would also print the stack trace.</p>
</div>
<div class="paragraph">
<p>This release will now catch exceptions and use the same error triage and printing functionality as the Clojure repl. The full stack trace, ex-info, and other information will be printed to a target specified by the configuration. See <a href="xref/../../../../../reference/repl_and_main#_as_launcher">clojure.main docs</a> for configuration details.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_changelog"><a class="anchor" href="#_changelog"></a>Changelog</h2>
<div class="sectionbody">
<div class="paragraph">
<p>See the <a href="https://github.com/clojure/clojure/blob/master/changes.md#changes-to-clojure-in-version-1101">change log</a> for a complete list of all changes in Clojure 1.10.1.</p>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">May 2019 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">06 06 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        This month we present the first updates from one of our Q2 Projects - Fireplace!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Magical, Mystical JavaScript Transducers</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">05 06 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Transducers are very cool. They give us a lot of power. But they are also a bit abstract. And that makes them hard to explain. But they also embody the dream of functional programming. We write tiny, simple functions. Then we piece them together with flexible tools that work for lots of different data structures. And we end up with powerful, performant programs.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Magical, Mystical JavaScript Transducers</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">05 06 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Transducers are very cool. They give us a lot of power. But they are also a bit abstract. And that makes them hard to explain. But they also embody the dream of functional programming. We write tiny, simple functions. Then we piece them together with flexible tools that work for lots of different data structures. And we end up with powerful, performant programs.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/135-ui-vs-ux.png" alt="UI vs UX">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">UI vs UX</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">04 06 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/135-ui-vs-ux.png" alt="UI vs UX" title="Don't judge a book by its cover" /></p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-xQoZtAsg71s/XPQJl7kAVwI/AAAAAAAAly8/nStVBUCCMsAWLlMQ_6Qwfow0bF_GBDJIACLcBGAs/s640/powerpoint-presentation-tips-templates-1.jpg" alt="23 consejos para dar presentaciones técnicas efectivas">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">23 consejos para dar presentaciones técnicas efectivas</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">03 06 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-xQoZtAsg71s/XPQJl7kAVwI/AAAAAAAAly8/nStVBUCCMsAWLlMQ_6Qwfow0bF_GBDJIACLcBGAs/s1600/powerpoint-presentation-tips-templates-1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="23 consejos para dar presentaciones técnicas efectivas" border="0" data-original-height="398" data-original-width="598" height="424" src="https://1.bp.blogspot.com/-xQoZtAsg71s/XPQJl7kAVwI/AAAAAAAAly8/nStVBUCCMsAWLlMQ_6Qwfow0bF_GBDJIACLcBGAs/s640/powerpoint-presentation-tips-templates-1.jpg" title="23 consejos para dar presentaciones técnicas efectivas" width="640" /></a></div><div class="separator" style="clear: both; text-align: left;">¿Has asistido a presentaciones técnicas en público? muchas de ellas aunque por los temas suenas interesantes, la forma en que son expuestas hacen que en ocasiones aburran, se hagan tediosas o largas, o simplemente no aprendas lo que en un principio te están vendiendo que vas a conocer. Estos son algunos tips si vas a hacer una presentación de este tipo, donde debemos cuidar ciertos puntos específicos para atraer al público y que una plática técnica sea una buena experiencia de aprendizaje.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"></div><ol><li>Explicar antes de empezar de qué va a tratar la presentación&nbsp;</li><li>Asegúrate de entender el lenguaje que maneja tu audiencia</li><li>Explica los acrónimos que uses para poner contexto</li><li>Si necesitas que el público aprenda un concepto específico, repítelo 3 veces de diferentes maneras</li><li>Usa imágenes en tu presentación, evita texto que haga que la gente lo lea primero antes de ponerte atención</li><li>Preséntate y di tu nombre con claridad</li><li>Hila las recomendaciones con historias que argumenten el por qué de la recomendación</li><li>No te limites a un slide</li><li>Si vas a colocar código en una presentación, asegúrate de que tenga el tamaño adecuado para ser leído a la distancia</li><li>Recuerda que tu público es inteligente, pero no es especialista en el tema que tu hablas, procura explicar todos tus puntos claramente</li><li>Pon un resumen al final de tu charla, para volver a recordar los puntos más importantes</li><li>Usa ejemplos y metáforas para explicar conceptos difíciles</li><li>Trata de explicar a tu audiencia por qué a nivel técnico hay mejoras o no, por qué se están haciendo las cosas de otra forma y el beneficio que ellos obtendrán de hacerlo.</li><li>Practica para tener el tiempo suficiente de dar tu plática y tener espacio de preguntas y respuestas</li><li>Haz pausas entre cada explicación de puntos importantes, para que la audiencia pueda entenderlas.</li><li>Haz bromas para llamar la atención de las personas que están distrayéndose, solo si puedes hacerlo.</li><li>Trata de orientar al público no solo en lo que está pasando ahora, sino lo que vendrá en el futuro.</li><li>Usa un tono de voz dinámico, para evitar que la gente se canse o se duerma por un tono de voz bajo y lento.</li><li>Evita dar contexto muy largo del tema que hablas, usa 10 o menos minutos para darle y a continuación entra de lleno en lo más importante que vienes a platicar.</li><li>Crea suspenso y curiosidad desde el inicio de tu plática</li><li>Pon información adicional a videos, posts o lecturas sugeridas para que la gente pueda encontrar más información relacionada.</li><li>Al final de la presentación da las gracias y espera que la gente aplauda. Cuando el presentador no planea espacios para que el público aplauda se crea un momento muy incómodo.</li><li>Practica con alguien que confíes y te pueda dar retroalimentación para que puedas mejorarlo.</li></ol><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=1kzdAOcbwDQ:ICgQulcsgTw:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=1kzdAOcbwDQ:ICgQulcsgTw:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=1kzdAOcbwDQ:ICgQulcsgTw:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=1kzdAOcbwDQ:ICgQulcsgTw:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=1kzdAOcbwDQ:ICgQulcsgTw:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=1kzdAOcbwDQ:ICgQulcsgTw:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=1kzdAOcbwDQ:ICgQulcsgTw:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=1kzdAOcbwDQ:ICgQulcsgTw:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=1kzdAOcbwDQ:ICgQulcsgTw:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=1kzdAOcbwDQ:ICgQulcsgTw:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=1kzdAOcbwDQ:ICgQulcsgTw:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=1kzdAOcbwDQ:ICgQulcsgTw:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=1kzdAOcbwDQ:ICgQulcsgTw:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=1kzdAOcbwDQ:ICgQulcsgTw:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/1kzdAOcbwDQ" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Diferencias entre == y === en Javascript</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Óscar Lijó</a> <span class="article__date">30 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Veamos cuales son las diferencias entre == y === cuando programamos en Javascript. Mientras que al == se le considera igualdad débil o abstracta, al === se le conoce como igualdad estricta, fuerte o también se le llama identidad. La diferencia es que mientras que con el == antes de hacer la comparación se convierten&#8230;</p>
<p>La entrada <a rel="nofollow" href="https://www.oscarlijo.com/blog/diferencias-entre-y-en-javascript/">Diferencias entre == y === en Javascript</a> aparece primero en <a rel="nofollow" href="https://www.oscarlijo.com/blog">Óscar Lijó</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Functional JavaScript: Five ways to calculate an average with array reduce</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">30 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The JavaScript array reduce method seems to give people trouble. Part of the reason is that many tutorials start out using reduce only with numbers. So I wrote a previous article about the many other things you can do with reduce that don’t involve arithmetic. But what if you do need to work with numbers? How do you use reduce for real-world arithmetic problems?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Functional JavaScript: Five ways to calculate an average with array reduce</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">30 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The JavaScript array reduce method seems to give people trouble. Part of the reason is that many tutorials start out using reduce only with numbers. So I wrote a previous article about the many other things you can do with reduce that don’t involve arithmetic. But what if you do need to work with numbers? How do you use reduce for real-world arithmetic problems?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cestas ecológicas - Grupo de consumo</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">29 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/134-hack-slash-revert.png" alt="Hack Slash Revert">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hack Slash Revert</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">28 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/134-hack-slash-revert.png" alt="Hack Slash Revert" title="Anyone got a hot iron?" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Pattern Matching in Common Lisp</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">26 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>New page on the Cookbook:
<a href="https://lispcookbook.github.io/cl-cookbook/pattern_matching.html">https://lispcookbook.github.io/cl-cookbook/pattern_matching.html</a> All
examples come from Trivia&rsquo;s wiki.</p>

<p>The ANSI Common Lisp standard does not include facilities for pattern
matching, but libraries existed for this task and
<a href="https://github.com/guicho271828/trivia">Trivia</a> became a community
standard.</p>

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->

<p><strong>Table of Contents</strong></p>

<ul>
<li><a href="#common-destructuring-patterns">Common destructuring patterns</a>

<ul>
<li><a href="#cons"><code>cons</code></a></li>
<li><a href="#list-list"><code>list</code>, <code>list*</code></a></li>
<li><a href="#vector-vector"><code>vector</code>, <code>vector*</code></a></li>
<li><a href="#class-and-structure-pattern">Class and structure pattern</a></li>
<li><a href="#type-satisfies"><code>type</code>, <code>satisfies</code></a></li>
<li><a href="#assoc-property-alist-plist"><code>assoc</code>, <code>property</code>, <code>alist</code>, <code>plist</code></a></li>
<li><a href="#array-simple-array-row-major-array-patterns">Array, simple-array, row-major-array patterns</a></li>
<li><a href="#logic-based-patterns">Logic based patterns</a>

<ul>
<li><a href="#and-or"><code>and</code>, <code>or</code></a></li>
<li><a href="#not"><code>not</code></a></li>
<li><a href="#guards"><code>guards</code></a></li>
</ul></li>
<li><a href="#nesting-patterns">Nesting patterns</a></li>
<li><a href="#see-more">See more</a></li>
</ul></li>
</ul>

<!-- markdown-toc end -->

<p>For an introduction to the concepts of pattern matching, see <a href="https://github.com/guicho271828/trivia/wiki/What-is-pattern-matching%3F-Benefits%3F">Trivia&rsquo;s wiki</a>.</p>

<p>Trivia matches against <em>a lot</em> of lisp objects and is extensible.</p>

<p>The library is in Quicklisp:</p>

<pre><code class="language-lisp">(ql:quickload &quot;trivia&quot;)
</code></pre>

<p>For the following examples, let&rsquo;s <code>use</code> the library:</p>

<pre><code class="language-lisp">(use-package :trivia)
</code></pre>

<h2 id="common-destructuring-patterns">Common destructuring patterns</h2>

<h3 id="cons"><code>cons</code></h3>

<pre><code class="language-lisp">(match '(1 2 3)
  ((cons x y)
  ; ^^ pattern
   (print x)
   (print y)))
;; |-&gt; 1
;; |-&gt; (2 3)
</code></pre>

<h3 id="list-list"><code>list</code>, <code>list*</code></h3>

<pre><code class="language-lisp">(match '(something #(0 1 2))
  ((list a (vector 0 _ b))
   (values a b)))
SOMETHING
2
</code></pre>

<p><code>list*</code> pattern:</p>

<pre><code class="language-lisp">(match '(1 2 . 3)
  ((list* _ _ x)
   x))
3
</code></pre>

<p>Note that using <code>list</code> would match nothing.</p>

<h3 id="vector-vector"><code>vector</code>, <code>vector*</code></h3>

<p><code>vector</code> checks if the object is a vector, if the lengths are the
same, and if the contents matches against each subpatterns.</p>

<p><code>vector*</code> is similar, but called a soft-match variant that allows if
the length is larger-than-equal to the length of subpatterns.</p>

<pre><code class="language-lisp">(match #(1 2 3)
  ((vector _ x _)
   x))
;; -&gt; 2
</code></pre>

<pre><code class="language-lisp">(match #(1 2 3 4)
  ((vector _ x _)
   x))
;; -&gt; NIL : does not match
</code></pre>

<pre><code class="language-lisp">(match #(1 2 3 4)
  ((vector* _ x _)
   x))
;; -&gt; 2 : soft match.
</code></pre>

<pre><code>&lt;vector-pattern&gt; : vector      | simple-vector
                   bit-vector  | simple-bit-vector
                   string      | simple-string
                   base-string | simple-base-string | sequence
(&lt;vector-pattern&gt; &amp;rest subpatterns)
</code></pre>

<h3 id="class-and-structure-pattern">Class and structure pattern</h3>

<p>There are three styles that are equivalent:</p>

<pre><code class="language-lisp">(defstruct foo bar baz)
(defvar *x* (make-foo :bar 0 :baz 1)

(match *x*
  ;; make-instance style
  ((foo :bar a :baz b)
   (values a b))
  ;; with-slots style
  ((foo (bar a) (baz b))
   (values a b))
  ;; slot name style
  ((foo bar baz)
   (values bar baz)))
</code></pre>

<h3 id="type-satisfies"><code>type</code>, <code>satisfies</code></h3>

<p>The <code>type</code> pattern matches if the object is of type. <code>satisfies</code> matches
if the predicate returns true for the object. A lambda form is
acceptable.</p>

<h3 id="assoc-property-alist-plist"><code>assoc</code>, <code>property</code>, <code>alist</code>, <code>plist</code></h3>

<p>All these patterns first check if the pattern is a list. If that is
satisfied, then they obtain the contents, and the value is matched
against the subpattern.</p>

<h3 id="array-simple-array-row-major-array-patterns">Array, simple-array, row-major-array patterns</h3>

<p>See <a href="https://github.com/guicho271828/trivia/wiki/Type-Based-Destructuring-Patterns#array-simple-array-row-major-array-pattern">https://github.com/guicho271828/trivia/wiki/Type-Based-Destructuring-Patterns#array-simple-array-row-major-array-pattern</a> !</p>

<h2 id="logic-based-patterns">Logic based patterns</h2>

<h3 id="and-or"><code>and</code>, <code>or</code></h3>

<pre><code class="language-lisp">(match x
  ((or (list 1 a)
       (cons a 3))
   a))
</code></pre>

<p>matches against both <code>(1 2)</code> and <code>(4 . 3)</code> and returns 2 and 4, respectively.</p>

<h3 id="not"><code>not</code></h3>

<p>It does not match when subpattern matches. The variables used in the
subpattern are not visible in the body.</p>

<h3 id="guards"><code>guards</code></h3>

<p>The syntax is <code>guard</code> + <code>subpattern</code> + <code>a test form</code>, and the body.</p>

<pre><code class="language-lisp">(match (list 2 5)
  ((guard (list x y)     ; subpattern
          (= 10 (* x y)) ; test-form
          (- x y) (satisfies evenp)) ; generator1, subpattern1
   t))
</code></pre>

<p>If the subpattern is true, the test form is evaluated, and if it is
true it is matched against subpattern1.</p>

<p>The above returns <code>nil</code>, since <code>(- x y) == 3</code> does not satisfies <code>evenp</code>.</p>

<h2 id="nesting-patterns">Nesting patterns</h2>

<p>Patterns can be nested:</p>

<pre><code class="language-lisp">(match '(:a (3 4) 5)
  ((list :a (list _ c) _)
   c))
</code></pre>

<p>returns <code>4</code>.</p>

<h2 id="see-more">See more</h2>

<p>See <a href="https://github.com/guicho271828/trivia/wiki/Special-Patterns">special patterns</a>: <code>place</code>, <code>bind</code> and <code>access</code>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Functions Tutorial: Arguments, Multiple Values, funcall and apply, closures and more</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">26 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>Here&rsquo;s an enhanced page for the Cookbook: <a href="https://lispcookbook.github.io/cl-cookbook/functions.html">https://lispcookbook.github.io/cl-cookbook/functions.html</a></p>

<p>Only the Currying part was untouched (we enhanced it already), the
higher-order functions part existed and was rewritten. The rest is
new, and it should help you start writing Common Lisp quicker than
ever.</p>

<p>Happy lisping !</p>

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->

<p><strong>Table of Contents</strong></p>

<ul>
<li><a href="#named-functions-defun">Named functions: <code>defun</code></a></li>
<li><a href="#arguments">Arguments</a>

<ul>
<li><a href="#base-case-required-arguments">Base case: required arguments</a></li>
<li><a href="#optional-arguments-optional">Optional arguments: <code>&amp;optional</code></a></li>
<li><a href="#named-parameters-key">Named parameters: <code>&amp;key</code></a>

<ul>
<li><a href="#mixing-optional-and-key-parameters">Mixing optional and key parameters</a></li>
<li><a href="#default-values">Default values</a></li>
<li><a href="#variable-number-of-arguments-rest">Variable number of arguments: <code>&amp;rest</code></a></li>
<li><a href="#allow-other-keys"><code>&amp;allow-other-keys</code></a></li>
</ul></li>
<li><a href="#return-values">Return values</a>

<ul>
<li><a href="#multiple-return-values-values-and-multiple-value-bind">Multiple return values: <code>values</code> and <code>multiple-value-bind</code></a></li>
</ul></li>
<li><a href="#anonymous-functions-lambda">Anonymous functions: <code>lambda</code></a></li>
<li><a href="#calling-functions-programatically-funcall-and-apply">Calling functions programatically: <code>funcall</code> and <code>apply</code></a></li>
<li><a href="#higher-order-functions-functions-that-return-functions">Higher order functions: functions that return functions</a></li>
<li><a href="#closures">Closures</a></li>
<li><a href="#setf-functions"><code>setf</code> functions</a></li>
<li><a href="#currying">Currying</a>

<ul>
<li><a href="#concept">Concept</a></li>
<li><a href="#with-the-alexandria-library">With the Alexandria library</a></li>
</ul></li>
<li><a href="#documentation">Documentation</a></li>
</ul></li>
</ul>

<!-- markdown-toc end -->

<h2 id="named-functions-defun">Named functions: <code>defun</code></h2>

<p>Creating named functions is done with the <code>defun</code> keyword. It follows this model:</p>

<pre><code class="language-lisp">(defun &lt;name&gt; (list of arguments)
  &quot;docstring&quot;
  (function body))
</code></pre>

<p>The return value is the value returned by the last expression of the body
(see below for more). There is no &ldquo;return xx&rdquo; statement.</p>

<p>So, for example:</p>

<pre><code class="language-lisp">(defun hello-world ()
  ;;               ^^ no arguments
  (print &quot;hello world!&quot;))
</code></pre>

<p>Call it:</p>

<pre><code class="language-lisp">(hello-world)
;; &quot;hello world!&quot;  &lt;-- output
;; &quot;hello world!&quot;  &lt;-- a string is returned.
</code></pre>

<h2 id="arguments">Arguments</h2>

<h3 id="base-case-required-arguments">Base case: required arguments</h3>

<p>Add in arguments like this:</p>

<pre><code class="language-lisp">(defun hello (name)
  &quot;Say hello to `name'.&quot;
  (format t &quot;hello ~a !~&amp;&quot; name))
;; HELLO
</code></pre>

<p>(where <code>~a</code> is the most used <code>format</code> directive to print a variable
<em>aesthetically</em> and <code>~&amp;</code> prints a newline)</p>

<p>Call the function:</p>

<pre><code class="language-lisp">(hello &quot;me&quot;)
;; hello me !  &lt;-- this is printed by `format`
;; NIL         &lt;-- return value: `format t` prints a string to standard output and returns nil.
</code></pre>

<p>If you don&rsquo;t specify the right amount of arguments, you&rsquo;ll be trapped
into the interactive debugger with an explicit error message:</p>

<p>(hello)</p>

<blockquote>
<p>invalid number of arguments: 0</p>
</blockquote>

<h3 id="optional-arguments-optional">Optional arguments: <code>&amp;optional</code></h3>

<p>Optional arguments are declared after the <code>&amp;optional</code> keyword in the
lambda list. They are ordered, they must appear one after another.</p>

<p>This function:</p>

<pre><code class="language-lisp">(defun hello (name &amp;optional age gender) …)
</code></pre>

<p>must be called like this:</p>

<pre><code class="language-lisp">(hello &quot;me&quot;) ;; a value for the required argument, zero optional arguments
(hello &quot;me&quot; &quot;7&quot;)  ;; a value for age
(hello &quot;me&quot; 7 :h) ;; a value for age and gender
</code></pre>

<h3 id="named-parameters-key">Named parameters: <code>&amp;key</code></h3>

<p>It is not always convenient to remember the order of the arguments. It
is thus possible to supply arguments by name: we declare them using
<code>&amp;key &lt;name&gt;</code>, we set them with <code>:name &lt;value&gt;</code> in the function call,
and we use <code>name</code> as a regular variable in the function body. They are
<code>nil</code> by default.</p>

<pre><code class="language-lisp">(defun hello (name &amp;key happy)
  &quot;If `happy' is `t', print a smiley&quot;
  (format t &quot;hello ~a &quot; name)
  (when happy
    (format t &quot;:)~&amp;&quot;))
</code></pre>

<p>The following calls are possible:</p>

<pre><code>(hello &quot;me&quot;)
(hello &quot;me&quot; :happy t)
(hello &quot;me&quot; :happy nil) ;; useless, equivalent to (hello &quot;me&quot;)
</code></pre>

<p>and this is not valid: <code>(hello &quot;me&quot; :happy)</code>:</p>

<blockquote>
<p>odd number of &amp;KEY arguments</p>
</blockquote>

<p>A similar example of a function declaration, with several key parameters:</p>

<pre><code class="language-lisp">(defun hello (name &amp;key happy lisper cookbook-contributor-p) …)
</code></pre>

<p>it can be called with zero or more key parameters, in any order:</p>

<pre><code class="language-lisp">(hello &quot;me&quot; :lisper t)
(hello &quot;me&quot; :lisper t :happy t)
(hello &quot;me&quot; :cookbook-contributor-p t :happy t)
</code></pre>

<h4 id="mixing-optional-and-key-parameters">Mixing optional and key parameters</h4>

<p>It is generally a style warning, but it is possible.</p>

<pre><code class="language-lisp">(defun hello (&amp;optional name &amp;key happy)
  (format t &quot;hello ~a &quot; name)
  (when happy
    (format t &quot;:)~&amp;&quot;)))
</code></pre>

<p>In SBCL, this yields:</p>

<pre><code class="language-lisp">; in: DEFUN HELLO
;     (SB-INT:NAMED-LAMBDA HELLO
;         (&amp;OPTIONAL NAME &amp;KEY HAPPY)
;       (BLOCK HELLO (FORMAT T &quot;hello ~a &quot; NAME) (WHEN HAPPY (FORMAT T &quot;:)~&amp;&quot;))))
;
; caught STYLE-WARNING:
;   &amp;OPTIONAL and &amp;KEY found in the same lambda list: (&amp;OPTIONAL (NAME &quot;John&quot;) &amp;KEY
;                                                      HAPPY)
;
; compilation unit finished
;   caught 1 STYLE-WARNING condition
</code></pre>

<p>We can call it:</p>

<pre><code class="language-lisp">(hello &quot;me&quot; :happy t)
;; hello me :)
;; NIL
</code></pre>

<h3 id="default-values">Default values</h3>

<p>In the lambda list, use pairs to give a default value to an optional or a key argument, like <code>(happy t)</code> below:</p>

<pre><code class="language-lisp">(defun hello (name &amp;key (happy t))
</code></pre>

<p>Now <code>happy</code> is true by default.</p>

<h3 id="variable-number-of-arguments-rest">Variable number of arguments: <code>&amp;rest</code></h3>

<p>Sometimes you want a function to accept a variable number of
arguments. Use <code>&amp;rest &lt;variable&gt;</code>, where <code>&lt;variable&gt;</code> will be a list.</p>

<pre><code class="language-lisp">(defun mean (x &amp;rest numbers)
    (/ (apply #'+ x numbers)
       (1+ (length numbers))))
</code></pre>

<pre><code class="language-lisp">(mean 1)
(mean 1 2)
(mean 1 2 3 4 5)
</code></pre>

<h3 id="allow-other-keys"><code>&amp;allow-other-keys</code></h3>

<p>Observe:</p>

<pre><code class="language-lisp">(defun hello (name &amp;key happy)
  (format t &quot;hello ~a~&amp;&quot; name))

(hello &quot;me&quot; :lisper t)
;; =&gt; Error: unknown keyword argument
</code></pre>

<p>whereas</p>

<pre><code class="language-lisp">(defun hello (name &amp;key happy &amp;allow-other-keys)
  (format t &quot;hello ~a~&amp;&quot; name))

(hello &quot;me&quot; :lisper t)
;; hello me
</code></pre>

<p>We might need <code>&amp;allow-other-keys</code> when passing around arguments or
with higher level manipulation of functions.</p>

<h2 id="return-values">Return values</h2>

<p>The return value of the function is the value returned by the last
executed form of the body.</p>

<p>There are ways for non-local exits (<code>return-from &lt;function name&gt; &lt;value&gt;</code>), but they are usually not needed.</p>

<p>Common Lisp has also the concept of multiple return values.</p>

<h3 id="multiple-return-values-values-and-multiple-value-bind">Multiple return values: <code>values</code> and <code>multiple-value-bind</code></h3>

<p>Returning multiple values is <em>not</em> like returning a tuple or a list of
results ;) This is a common misconception.</p>

<p>Multiple values are specially useful and powerful because a change in
them needs little to no refactoring.</p>

<pre><code class="language-lisp">(defun foo (a b c)
  a)
</code></pre>

<p>This function returns <code>a</code>.</p>

<pre><code class="language-lisp">(defvar *res* (foo :a :b :c))
;; :A
</code></pre>

<p>We use <code>values</code> to return multiple values:</p>

<pre><code class="language-lisp">(defun foo (a b c)
  (values a b c))
</code></pre>

<pre><code class="language-lisp">(setf *res* (foo :a :b :c))
;; :A
</code></pre>

<p>Observe here that <code>*res*</code> <em>is still <code>:A</code></em>.</p>

<p>All functions that use the return value of <code>foo</code> need no change, they
still work. If we had returned a list or an array, this would be
different.</p>

<p>We destructure multiple values with <code>multiple-value-bind</code> (or
<code>mvb</code>+TAB in Slime for short):</p>

<pre><code class="language-lisp">(multiple-value-bind (res1 res2 res3)
    (foo :a :b :c)
  (format t &quot;res1 is ~a, res2 is ~a, res2 is ~a~&amp;&quot; res1 res2 res3))
;; res1 is A, res2 is B, res2 is C
;; NIL
</code></pre>

<p>Its general form is</p>

<pre><code class="language-lisp">(multiple-value-bind (var-1 .. var-n) expr
  body)
</code></pre>

<p>The variables <code>var-n</code> are not available outside the scope of <code>multiple-value-bind</code>.</p>

<p>Last but not least: note that <code>(values)</code> with no values returns… no values at all.</p>

<p>See also <code>multiple-value-call</code>.</p>

<h2 id="anonymous-functions-lambda">Anonymous functions: <code>lambda</code></h2>

<p>Anonymous functions are created with <code>lambda</code>:</p>

<pre><code class="language-lisp">(lambda (x) (print x))
</code></pre>

<p>We can call a lambda with <code>funcall</code> or <code>apply</code> (see below).</p>

<p>If the first element of an unquoted list is a lambda expression, the
lambda is called:</p>

<pre><code class="language-lisp">((lambda (x) (print x)) &quot;hello&quot;)
;; hello
</code></pre>

<h2 id="calling-functions-programatically-funcall-and-apply">Calling functions programatically: <code>funcall</code> and <code>apply</code></h2>

<p><code>funcall</code> is to be used with a known number of arguments, when <code>apply</code>
can be used on a list, for example from <code>&amp;rest</code>:</p>

<pre><code class="language-lisp">(funcall #'+ 1 2)
(apply #'+ '(1 2))
</code></pre>

<h2 id="higher-order-functions-functions-that-return-functions">Higher order functions: functions that return functions</h2>

<p>Writing functions that return functions is simple enough:</p>

<pre><code class="language-lisp">(defun adder (n)
  (lambda (x) (+ x n)))
;; ADDER
</code></pre>

<p>Here we have defined the function <code>adder</code> which returns an <em>object</em> of <em>type</em> <a href="http://www.lispworks.com/documentation/HyperSpec/Body/t_fn.htm"><code>function</code></a>.</p>

<p>To call the resulting function, we must use <code>funcall</code> or <code>apply</code>:</p>

<pre><code class="language-lisp">(adder 5)
;; #&lt;CLOSURE (LAMBDA (X) :IN ADDER) {100994ACDB}&gt;
(funcall (adder 5) 3)
;; 8
</code></pre>

<p>Trying to call it right away leads to an illegal function call:</p>

<pre><code class="language-lisp">((adder 3) 5)
In: (ADDER 3) 5
    ((ADDER 3) 5)
Error: Illegal function call.
</code></pre>

<p>Indeed, CL has different <em>namespaces</em> for functions and variables, i.e. the same <em>name</em> can refer to different things depending on its position in a form that&rsquo;s evaluated.</p>

<pre><code class="language-lisp">;; The symbol foo is bound to nothing:
CL-USER&gt; (boundp 'foo)
NIL
CL-USER&gt; (fboundp 'foo)
NIL
;; We create a variable:
CL-USER&gt; (defparameter foo 42)
FOO
* foo
42
;; Now foo is &quot;bound&quot;:
CL-USER&gt; (boundp 'foo)
T
;; but still not as a function:
CL-USER&gt; (fboundp 'foo)
NIL
;; So let's define a function:
CL-USER&gt; (defun foo (x) (* x x))
FOO
;; Now the symbol foo is bound as a function too:
CL-USER&gt; (fboundp 'foo)
T
;; Get the function:
CL-USER&gt; (function foo)
#&lt;FUNCTION FOO&gt;
;; and the shorthand notation:
* #'foo
#&lt;FUNCTION FOO&gt;
;; We call it:
(funcall (function adder) 5)
#&lt;CLOSURE (LAMBDA (X) :IN ADDER) {100991761B}&gt;
;; and call the lambda:
(funcall (funcall (function adder) 5) 3)
8
</code></pre>

<p>To simplify a bit, you can think of each symbol in CL having (at least) two &ldquo;cells&rdquo; in which information is stored. One cell - sometimes referred to as its <em>value cell</em> - can hold a value that is <em>bound</em> to this symbol, and you can use <a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_boundp.htm"><code>boundp</code></a> to test whether the symbol is bound to a value (in the global environment). You can access the value cell of a symbol with <a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_symb_5.htm"><code>symbol-value</code></a>.</p>

<p>The other cell - sometimes referred to as its <em>function cell</em> - can hold the definition of the symbol&rsquo;s (global) function binding. In this case, the symbol is said to be <em>fbound</em> to this definition. You can use <a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_fbound.htm"><code>fboundp</code></a> to test whether a symbol is fbound. You can access the function cell of a symbol (in the global environment) with <a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_symb_1.htm"><code>symbol-function</code></a>.</p>

<p>Now, if a <em>symbol</em> is evaluated, it is treated as a <em>variable</em> in that its value cell is returned (just <code>foo</code>). If a <em>compound form</em>, i.e. a <em>cons</em>, is evaluated and its <em>car</em> is a symbol, then the function cell of this symbol is used (as in <code>(foo 3)</code>).</p>

<p>In Common Lisp, as opposed to Scheme, it is <em>not</em> possible that the car of the compound form to be evaluated is an arbitrary form. If it is not a symbol, it <em>must</em> be a <em>lambda expression</em>, which looks like <code>(lambda</code><em>lambda-list</em> <em>form*</em><code>)</code>.</p>

<p>This explains the error message we got above - <code>(adder 3)</code> is neither a symbol nor a lambda expression.</p>

<p>If we want to be able to use the symbol <code>*my-fun*</code> in the car of a compound form, we have to explicitely store something in its <em>function cell</em> (which is normally done for us by the macro <a href="http://www.lispworks.com/documentation/HyperSpec/Body/m_defun.htm"><code>defun</code></a>):</p>

<pre><code class="language-lisp">;;; continued from above
CL-USER&gt; (fboundp '*my-fun*)
NIL
CL-USER&gt; (setf (symbol-function '*my-fun*) (adder 3))
#&lt;CLOSURE (LAMBDA (X) :IN ADDER) {10099A5EFB}&gt;
CL-USER&gt; (fboundp '*my-fun*)
T
CL-USER&gt; (*my-fun* 5)
8
</code></pre>

<p>Read the CLHS section about <a href="http://www.lispworks.com/documentation/HyperSpec/Body/03_aba.htm">form evaluation</a> for more.</p>

<h2 id="closures">Closures</h2>

<p>Closures allow to capture lexical bindings:</p>

<pre><code class="language-lisp">(let ((limit 3)
      (counter -1))
    (defun my-counter ()
      (if (&lt; counter limit)
          (incf counter)
          (setf counter 0))))

(my-counter)
0
(my-counter)
1
(my-counter)
2
(my-counter)
3
(my-counter)
0
</code></pre>

<p>Or similarly:</p>

<pre><code class="language-lisp">(defun repeater (n)
  (let ((counter -1))
     (lambda ()
       (if (&lt; counter n)
         (incf counter)
         (setf counter 0)))))

(defparameter *my-repeater* (repeater 3))
;; *MY-REPEATER*
(funcall *my-repeater*)
0
(funcall *my-repeater*)
1
(funcall *my-repeater*)
2
(funcall *my-repeater*)
3
(funcall *my-repeater*)
0
</code></pre>

<p>See more on <a href="http://www.gigamonkeys.com/book/variables.html">Practical Common Lisp</a>.</p>

<h2 id="setf-functions"><code>setf</code> functions</h2>

<p>A function name can also be a list of two symbols with <code>setf</code> as the
first one, and where the first argument is the new value:</p>

<pre><code class="language-lisp">(defun (setf &lt;name&gt;) (new-value &lt;other arguments&gt;)
  body)
</code></pre>

<p>This mechanism is particularly used for CLOS methods.</p>

<p>A silly example:</p>

<pre><code class="language-lisp">(defparameter *current-name* &quot;&quot;
  &quot;A global name.&quot;)

(defun hello (name)
  (format t &quot;hello ~a~&amp;&quot; name))

(defun (setf hello) (new-value)
  (hello new-value)
  (setf *current-name* new-value)
  (format t &quot;current name is now ~a~&amp;&quot; new-value))

(setf (hello) &quot;Alice&quot;)
;; hello Alice
;; current name is now Alice
;; NIL
</code></pre>

<p><a name="curry"></a></p>

<h2 id="currying">Currying</h2>

<h3 id="concept">Concept</h3>

<p>A related concept is that of <em><a href="https://en.wikipedia.org/wiki/Currying">currying</a></em> which you might be familiar with if you&rsquo;re coming from a functional language. After we&rsquo;ve read the last section that&rsquo;s rather easy to implement:</p>

<pre><code class="language-lisp">CL-USER&gt; (declaim (ftype (function (function &amp;rest t) function) curry) (inline curry))
NIL
CL-USER&gt; (defun curry (function &amp;rest args)
           (lambda (&amp;rest more-args)
	           (apply function (append args more-args))))
CURRY
CL-USER&gt; (funcall (curry #'+ 3) 5)
8
CL-USER&gt; (funcall (curry #'+ 3) 6)
9
CL-USER&gt; (setf (symbol-function 'power-of-ten) (curry #'expt 10))
#&lt;Interpreted Function &quot;LAMBDA (FUNCTION &amp;REST ARGS)&quot; {482DB969}&gt;
CL-USER&gt; (power-of-ten 3)
1000
</code></pre>

<p>Note that the <a href="http://www.lispworks.com/documentation/HyperSpec/Body/m_declai.htm"><code>declaim</code></a> statement above is just a hint for the compiler so it can produce more efficient code if it so wishes. Leaving it out won&rsquo;t change the semantics of the function.</p>

<h3 id="with-the-alexandria-library">With the Alexandria library</h3>

<p>Now that you know how to do it, you may appreciate using the
implementation of the
<a href="https://common-lisp.net/project/alexandria/draft/alexandria.html#Data-and-Control-Flow">Alexandria</a>
library (in Quicklisp).</p>

<pre><code class="language-lisp">(ql:quickload :alexandria)

(defun adder (foo bar)
  &quot;Add the two arguments.&quot;
  (+ foo bar))

(defvar add-one (alexandria:curry #'adder 1) &quot;Add 1 to the argument.&quot;)

(funcall add-one 10)  ;; =&gt; 11

(setf (symbol-function 'add-one) add-one)
(add-one 10)  ;; =&gt; 11
</code></pre>

<h2 id="documentation">Documentation</h2>

<ul>
<li>functions: <a href="http://www.lispworks.com/documentation/HyperSpec/Body/t_fn.htm#function">http://www.lispworks.com/documentation/HyperSpec/Body/t_fn.htm#function</a></li>
<li>ordinary lambda lists: <a href="http://www.lispworks.com/documentation/HyperSpec/Body/03_da.htm">http://www.lispworks.com/documentation/HyperSpec/Body/03_da.htm</a></li>
<li>multiple-value-bind: <a href="http://clhs.lisp.se/Body/m_multip.htm">http://clhs.lisp.se/Body/m_multip.htm</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Functional JavaScript: How to use array reduce for more than just numbers</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">22 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The array reduce method is really powerful. But people often run into trouble as soon as they step beyond the basic examples. Simple things like addition and multiplication are fine. But as soon as you try it with something more complicated, it breaks. Using it with anything other than numbers starts to get really confusing. I think this is because the examples in most tutorials mask some of what's going on. This article looks at some of the more interesting things you can do with .reduce() that better show how it works.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Functional JavaScript: How to use array reduce for more than just numbers</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">22 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The array reduce method is really powerful. But people often run into trouble as soon as they step beyond the basic examples. Simple things like addition and multiplication are fine. But as soon as you try it with something more complicated, it breaks. Using it with anything other than numbers starts to get really confusing. I think this is because the examples in most tutorials mask some of what's going on. This article looks at some of the more interesting things you can do with .reduce() that better show how it works.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Creating an emacs formatter the easy way</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">21 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Some weeks ago I discovered a really nice package for emacs called reformatter.el. This package allows to define reformat functions in a easy way.
 Most languages have a reformat tool. Elixir has mix format, Elm has elm format, python has black and so on. These formatters are convenient because they give uniformity to the code, but this is a topic for another post.
 Having these formatters integrated within our favorite editor is great.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Creating an emacs formatter the easy way</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">21 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>
Some weeks ago I discovered a really nice package for emacs called <a href="https://github.com/purcell/reformatter.el">reformatter.el</a>. This package allows to define reformat functions in a easy way.</p>
<p>
Most languages have a reformat tool. Elixir has <code class="verbatim">mix format</code>, Elm has <code class="verbatim">elm format</code>, python has <code class="verbatim">black</code> and so on. These formatters are convenient because they give uniformity to the code, but this is a topic for another post.</p>
<p>
Having these formatters integrated within our favorite editor is great. These are enough(at least for me) reasons to use <code class="verbatim">reformatter.el</code> so let&#39;s get into the code:</p>
<p>
<code class="verbatim">reformatter.el</code> has a simple macro that allows us to define a formatter with just a few lines.</p>
<p>
For this example we&#39;ll create a formatter for haskell using <code class="verbatim">hindent</code> <sup class="footnote-reference"><a id="footnote-reference-1" href="#footnote-1">1</a></sup>.</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(reformatter-define haskell-format
  :program <span style="color:#e6db74">&#34;hindent&#34;</span>)</code></pre></div>
</div>
<p>
We just need to define the command that will be used to format the code. In this case <code class="verbatim">hindent</code>. This will create some useful functions:</p>
<ul>
<li>
<p>haskell-format</p>
</li>
<li>
<p>haskell-format-buffer</p>
</li>
<li>
<p>haskell-format-region</p>
</li>
<li>
<p>haskell-format-on-save-mode</p>
</li>
</ul>
<p>These functions can be used with a key-binding:</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(<span style="color:#a6e22e">define-key</span> haskell-mode-map (kbd <span style="color:#e6db74">&#34;C-c C-f&#34;</span>) <span style="color:#e6db74">&#39;haskell-format-buffer</span>)</code></pre></div>
</div>
<p>
Also we can setup emacs to run the formatter when the file is saved, for example put this code in your <code class="verbatim">.dir-locals.el</code> and it will do the work.</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(haskell-mode (mode <span style="color:#f92672">.</span> haskell-format-on-save))</code></pre></div>
</div>
<p>
The program used to format our code needs to be able to read from <code class="verbatim">stdin</code> and return the formatted code to <code class="verbatim">stdout</code>. In this case <code class="verbatim">hindent</code> does it by default.</p>
<p>
In some cases the formatter doesn&#39;t do this by default. For those cases we can pass extra arguments to the command using <code class="verbatim">:args</code> key in the formatter macro. For example <code class="verbatim">elixir format</code> receive a file or a pattern by default but we can change that using <code class="verbatim">mix format -</code>, now it will read from <code class="verbatim">stdin</code>, so we need to pass these parameters to our formatter. The code should be:</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(reformatter-define elixir-format
  :program <span style="color:#e6db74">&#34;mix&#34;</span>
  :args <span style="color:#f92672">&#39;</span>(<span style="color:#e6db74">&#34;format&#34;</span> <span style="color:#e6db74">&#34;-&#34;</span>))</code></pre></div>
</div>
<p>
Now it will work properly.</p>
<p>
This package is very useful if you don&#39;t want to install a external package just for formatting. I replaced <code class="verbatim">hindent-mode</code> (haskell formatter) and a custom elixir formatter with this package. Also this package is used in <code class="verbatim">elm-mode</code> package.</p>
<div class="footnotes">
<hr class="footnotes-separatator">
<div class="footnote-definitions">
<div class="footnote-definition">
<sup id="footnote-1"><a href="#footnote-reference-1">1</a></sup>
<div class="footnote-body">
<p><a href="https://github.com/chrisdone/hindent">https://github.com/chrisdone/hindent</a></p>
</div>
</div>
</div>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">I Now Work Professionally in Common Lisp O_o</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">20 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I&rsquo;ve been paid to work on Common Lisp projects for a company for three
months already. I didn&rsquo;t expect it :) And we did hire !</p>

<p>My Github profile shows a good part of what my experience is. I am a
regular &ldquo;full stack developper&rdquo;, with 7 years of professional
experience. I worked on diverse Python and Javascript projects for
huge to small companies, private and public. When I re-discovered
Common Lisp, I saw it solved a lot of problems I had developing and
deploying medium to large software, and it promised to solve all of
them (we&rsquo;re nearly there :D ). I started to write about my experience
on this blog and I contributed to open source projects, of which a lot
of documentation effort. It is this public activity that drew the
attention of the guys at <a href="http://atlas.engineer/">Atlas</a>, who
contacted me, without a job announce. We developed and we maintain
a proprietary and successful web application that paid the bills, in
Common Lisp of course, and we work hard on other projects, such as the
<a href="http://next.atlas.engineer/">Next browser</a>.</p>

<p>So, I can only encourage you to start a Common Lisp project, to come
enhance libraries and documentation and to write about it !  There are
few official job announces, some are posted on reddit, and some jobs
just won&rsquo;t have a public announce. You&rsquo;d better be ready.</p>

<p>For the curious, our web app is rather classic, it uses the Caveman
web framework and is deployed on DigitalOcean. We do deploy with zero
downtime, as CL permits, for trivial updates (we are more cautious
otherwise). I&rsquo;ll post its name in the comments if/when I know I can.</p>

<p>Happy lisping.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Folding the DOM</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">19 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        In this post, we'll explore a technique we can use to "fold" a DOM node, like folding a letter in real-life. On that journey, we'll learn a lot about 3D transforms and CSS animation techniques!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">JIRA Migration</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">16 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Clojure has been very fortunate to receive infrastructure support from <a href="https://www.atlassian.com">Atlassian</a> (for JIRA and Confluence) and <a href="https://www.contegix.com/">Contegix</a> (for hosting) for many years. The Confluence and JIRA instances were not kept up to date, and have grown increasingly hard to maintain. Recently, we decided to shut down Confluence (content was either moved to <a href="https://clojure.org">clojure.org</a> or <a href="https://archive.clojure.org/design-wiki/display/design/Home.html">archived</a>) and we are now preparing to migrate from our old JIRA instance into a new cloud-hosted instance. Many thanks to Atlassian again for supporting our efforts in this.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_user_migration"><a class="anchor" href="#_user_migration"></a>User migration</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Due to the large number of users, it is not feasible for us to move everyone, and we&#8217;ve decided to migrate all users that have edited tickets in the past (changed a description, added a patch, etc) - this will move user names and emails, not passwords. When the import happens, email invites will go out for users in the new system based on the email address in the old system. Initially these users will not have access to projects.</p>
</div>
<div class="paragraph">
<p>Users that created or commented on tickets in the past (but did not edit) will not automatically be migrated. We are planning to leverage JIRA Service Desk to create a new path for language users to file tickets without needing an account. These incoming tickets can be triaged and turned into JIRA tickets as needed. We are also looking at a new process to obtain a contributor account and gain access to the system for commenting or other work. Stay tuned for more on that.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_backup_and_import"><a class="anchor" href="#_backup_and_import"></a>Backup and import</h2>
<div class="sectionbody">
<div class="paragraph">
<p>After users have been loaded, a backup of the old system and import into the new system will occur. All projects, issues, attachments, comments, etc will be preserved. This will be done on a per-project basis until the migration is complete and might take a while to fully import and verify.</p>
</div>
<div class="paragraph">
<p>After that, there will be some work to enable access for different project administrators and users before the system is fully available.</p>
</div>
<div class="paragraph">
<p>We will put the old system into a read-only mode once the backup and import has started. Once the import is complete, the old system will be shut down. Redirect rules will be set up for the old Confluence and JIRA urls to point to the new Confluence archive and new JIRA system so that old links will continue to work.</p>
</div>
<div class="paragraph">
<p>Please be patient as we make the transition. Thanks!</p>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">April 2019 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">16 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Here is our final Q1 monthly update from projects, Neanderthal and Aleph - thanks so much for all your hard work this quarter.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Elegant error handling with the JavaScript Either Monad</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">15 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        JavaScript gives us a built-in language feature for handling exceptions: try…catch statements. And they're better than littering our code with if-statements. But they can be problematic. And they are not the only way to handle errors. In this article, we’ll take a look at using the ‘Either monad’ as an alternative to try…catch.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Elegant error handling with the JavaScript Either Monad</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">15 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        JavaScript gives us a built-in language feature for handling exceptions: try…catch statements. And they're better than littering our code with if-statements. But they can be problematic. And they are not the only way to handle errors. In this article, we’ll take a look at using the ‘Either monad’ as an alternative to try…catch.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://4.bp.blogspot.com/-h-d-Ai9N9Xs/XNhh2T2FkgI/AAAAAAAAluI/WeZcN18SxHggyxIRU7MKS4aLjpMceCy8ACLcBGAs/s640/java-costo.jpg" alt="Java no es gratuito">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Java no es gratuito</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">14 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-h-d-Ai9N9Xs/XNhh2T2FkgI/AAAAAAAAluI/WeZcN18SxHggyxIRU7MKS4aLjpMceCy8ACLcBGAs/s1600/java-costo.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Java no es gratuito" border="0" data-original-height="900" data-original-width="1600" height="360" src="https://4.bp.blogspot.com/-h-d-Ai9N9Xs/XNhh2T2FkgI/AAAAAAAAluI/WeZcN18SxHggyxIRU7MKS4aLjpMceCy8ACLcBGAs/s640/java-costo.jpg" title="Java no es gratuito" width="640" /></a></div><div><br /></div><div>Java ha evolucionado a un paso siempre desigual con cada versión, lo que hace que sea odiado y amado por la comunidad de desarrolladores. El otro tema que tiene Java es que Oracle es el dueño del lenguaje, y aunque sigue siendo Open Source, tiene sus propias restricciones para poder usarlo. En este video les explico por qué Java no es gratuito en una parte importante de sus componentes, ya que es importante saberlo para poder crear aplicaciones con otras necesidades y aplicaciones.</div><div class="separator" style="clear: both; text-align: center;"><iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/IeoggneYckg/0.jpg" src="https://www.youtube.com/embed/IeoggneYckg?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div><div><br /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=wB1G9Hb2qaM:gt80C--rcbM:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=wB1G9Hb2qaM:gt80C--rcbM:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=wB1G9Hb2qaM:gt80C--rcbM:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=wB1G9Hb2qaM:gt80C--rcbM:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=wB1G9Hb2qaM:gt80C--rcbM:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=wB1G9Hb2qaM:gt80C--rcbM:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=wB1G9Hb2qaM:gt80C--rcbM:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=wB1G9Hb2qaM:gt80C--rcbM:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=wB1G9Hb2qaM:gt80C--rcbM:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=wB1G9Hb2qaM:gt80C--rcbM:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=wB1G9Hb2qaM:gt80C--rcbM:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=wB1G9Hb2qaM:gt80C--rcbM:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=wB1G9Hb2qaM:gt80C--rcbM:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=wB1G9Hb2qaM:gt80C--rcbM:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/wB1G9Hb2qaM" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/133-everythingyoudosucks.png" alt="everythingyoudosuckscon.io">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">everythingyoudosuckscon.io</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">14 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/133-everythingyoudosucks.png" alt="Everythingyoudosuckscon.io" title="This is not the future I was promised." /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://3.bp.blogspot.com/-oOQNjL0kw0A/XNhgxHsdgQI/AAAAAAAAluA/xhF3ogWmnLAZVCLMeS3KcNEfJ8JTZMpZgCLcBGAs/s640/lenguajes-2019.jpeg" alt="¿Cómo elegir cuál lenguaje de programación aprender ?">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">¿Cómo elegir cuál lenguaje de programación aprender ?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">13 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"><a href="https://3.bp.blogspot.com/-oOQNjL0kw0A/XNhgxHsdgQI/AAAAAAAAluA/xhF3ogWmnLAZVCLMeS3KcNEfJ8JTZMpZgCLcBGAs/s1600/lenguajes-2019.jpeg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="¿Cómo elegir cuál lenguaje de programación aprender en 2019?" border="0" data-original-height="533" data-original-width="800" height="426" src="https://3.bp.blogspot.com/-oOQNjL0kw0A/XNhgxHsdgQI/AAAAAAAAluA/xhF3ogWmnLAZVCLMeS3KcNEfJ8JTZMpZgCLcBGAs/s640/lenguajes-2019.jpeg" title="¿Cómo elegir cuál lenguaje de programación aprender en 2019?" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;"><br /></td></tr></tbody></table><br />Si estás buscando razones para poder empezar con un lenguaje de programación, este post te va a interesar. Te voy a comentar algunas razones por las cuales es mejor empezar en el mundo del desarrollo con algunos lenguajes y después con otros.<br /><h2>Lenguajes de propósito común</h2><div>Los lenguajes de propósito común son aquellos que no están orientados a un tema específico. Los puedes usar para hacer aplicaciones web, sistemas, aplicaciones con interfaz gráfica, etc, por lo que aprender uno de estos facilita la aplicación a varias utilidades.</div><div><br /></div><div><b>Python:</b> es uno de los lenguajes más fáciles para empezar con programación. Su sintaxis también es muy simple, por lo que puedes entender bien cómo va funcionando el código y las estructuras, además de que Python poco a poco se convierte en el lenguaje preferido para la gente que empieza con programación.</div><div><br /></div><div><b>Javascript:</b> es un real competidor a sentarse en el trono de los lenguajes favoritos para empezar. Javascript ha evolucionado de forma impresionante en unos pocos años para poder ser utilizado en cualquier plataforma y ecosistema presente hoy en día. No hay nada que no se pueda hacer con Javscript, y como menciono, su evolución va avanzando de forma increíblemente rápida, pero obviamente si lo que quieres es tener un enfoque un poco más web, este lenguaje te puede ayudar mucho.</div><div><br /></div><div><b>Ruby:</b> es un lenguaje con la característica de que tiene soporte de muchos paradigmas de programación, como la lineal, la orientada a objetos y funcional. Su sintaxis es más parecido a una estructura de conversación que los anteriores, y te dejará compilar el código aunque tenga errores, por lo que es bastante amigable para poder empezar.</div><div><br /></div><div><b>Java:</b> es el lenguaje que más gustos divide a los programadores. Para muchos ya es un lenguaje que no ha evolucionado de la misma forma que los demás, pero otros creen que es de los lenguajes más maduros. La realidad es que si quieres iniciar con un lenguaje que te explique de forma muy visual la programación orientada a objetos este es el mejor. Aprender Java es fácil, quizá verás que tiene mucho código para hacer cosas sencillas, pero también hay una razón para ello, y si logras entender ese concepto prácticamente Java lo dominas en unas cuentas semanas.</div><h2>Lenguajes de propósito específico</h2><div>Si queremos aprender algo específico podemos usar de referencia algunos de los siguientes lenguajes para empezar por ese camino:</div><div><br /></div><div><b>Machine Learning:</b> los dos más populares son Python y R, lenguajes que por su simpleza en el código son más eficientes para realizar cálculos estadísticos.</div><div><br /></div><div><b>Desarrollo móvil:</b> para desarrollar aplicaciones móviles nativas tenemos Swift para iOS y Java y Kotlin para Android. Kotlin especialmente toma mucha referencia de Java y le quita el código que no es necesario, por lo que también es buen candidato para hacer apps sin siquiera saber programar.</div><div><br /></div><div><b>Startups:</b> si tu enfoque es construir algo rápido y funcional Ruby tiene esa ventaja. Ruby es muy usado en empresas que empiezan por la flexibilidad de construir aplicaciones de forma muy rápida y que pueden seguir programando sobre la marcha.</div><h2>Lenguajes que tienes que evitar al empezar</h2><div>Si bien hay lenguajes muy populares hoy en día, mi recomendación es evitarlos ya que o cumplen un propósito demasiado específico, que quizá ni siquiera te interese usar, o tienen una complejidad más elevada para aprender, por lo que puede que te desilusionen si decides elegir uno de ellos.</div><div><br /></div><div>Entre los ejemplos está Go, Scala, Perl, Typescript, C++. Typescript especialmente le agrega complejidad a Javascript, y se entiende que para llegar ahí, entiendes cómo funciona Javascript y las deficiencias que tiene por las que tienes que cubrir con Typescript. C++ es en definitiva la opción si lo que quieres es administrar memoria y objetos de forma detallada y completa en un lenguaje de programación.</div><div><br /></div><div><br /></div><div><br /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=4bDymxsCDds:FjBpG0VgHQk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=4bDymxsCDds:FjBpG0VgHQk:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=4bDymxsCDds:FjBpG0VgHQk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=4bDymxsCDds:FjBpG0VgHQk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=4bDymxsCDds:FjBpG0VgHQk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=4bDymxsCDds:FjBpG0VgHQk:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=4bDymxsCDds:FjBpG0VgHQk:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=4bDymxsCDds:FjBpG0VgHQk:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=4bDymxsCDds:FjBpG0VgHQk:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=4bDymxsCDds:FjBpG0VgHQk:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=4bDymxsCDds:FjBpG0VgHQk:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=4bDymxsCDds:FjBpG0VgHQk:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=4bDymxsCDds:FjBpG0VgHQk:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=4bDymxsCDds:FjBpG0VgHQk:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/4bDymxsCDds" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hacer una PWA con Angular</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Óscar Lijó</a> <span class="article__date">08 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Hoy en día se hace mucho hincapié en las aplicaciones web progresivas o PWA, hoy voy a explicar como hacer una PWA con Angular. En primer lugar, por si no has escuchado hablar nunca de lo que son las PWA y las ventajas que tienen, voy a hablar un poco de ellas. ¿Qué es una&#8230;</p>
<p>La entrada <a rel="nofollow" href="https://www.oscarlijo.com/blog/hacer-una-pwa-con-angular/">Hacer una PWA con Angular</a> aparece primero en <a rel="nofollow" href="https://www.oscarlijo.com/blog">Óscar Lijó</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to run async JavaScript functions in sequence or parallel</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">08 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The async and await keywords are a great addition to Javascript. They make it easier to read (and write) code that runs asynchronously. But they can still be confusing. Asynchronous programming is hard. Anyone who tells you differently is either lying or selling something. But there are some simple patterns you can learn that will make life easier.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to run async JavaScript functions in sequence or parallel</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">08 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The async and await keywords are a great addition to Javascript. They make it easier to read (and write) code that runs asynchronously. But they can still be confusing. Asynchronous programming is hard. Anyone who tells you differently is either lying or selling something. But there are some simple patterns you can learn that will make life easier.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/132-deja-vu.png" alt="Deja vu">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Deja vu</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">07 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/132-deja-vu.png" alt="Deja vu" title="If you have been in a poker game for a while, and you still don’t know who the patsy is, you’re the patsy." /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to Let Google Know of Other Languages in Your Django Site</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">06 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>If you have a public facing Django site in multiple languages, you probably want to let Google and other search engines know about it.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-Z4uH6EPVIwI/XM8uFLRCuSI/AAAAAAAAlkI/xY7tyHALZk0XiEniO5L7cF-MiQyx-ZhQwCLcBGAs/s1600/POO.jpg" alt="10 principios de diseño para POO">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">10 principios de diseño para POO</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">06 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div><a href="https://1.bp.blogspot.com/-Z4uH6EPVIwI/XM8uFLRCuSI/AAAAAAAAlkI/xY7tyHALZk0XiEniO5L7cF-MiQyx-ZhQwCLcBGAs/s1600/POO.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="300" data-original-width="400" src="https://1.bp.blogspot.com/-Z4uH6EPVIwI/XM8uFLRCuSI/AAAAAAAAlkI/xY7tyHALZk0XiEniO5L7cF-MiQyx-ZhQwCLcBGAs/s1600/POO.jpg" /></a></div>Empezando a programar con el paradigma de Objetos es un tema muy particular. Mucha gente cree que con el hecho de crear objetos y clases ya está aplicando el paradigma, pero en realidad no. El paradigma consiste no en un aspecto técnico, sino en un aspecto funcional, que puedas adaptarte a una forma de programar, en vez de utilizar formas de programación que cualquier lenguaje puede incluir.<div>En este post les comparto los 10 principios de diseño para la programación orientada a objetos, esperando que les sirva para mejorar la forma en que hacen código y lo usan.</div><div><br /></div><h2>1. DRY (Don't repeat yourself)</h2><div>El principio de la POO es la de no repetir el código, hacer código reusable y abstracto, para que puedas usarlo de nuevo sin necesidad de volver a escribir desde cero. Si tu código es imposible de reusarlo en otra aplicación, o tienes que programar ciertas partes de nuevo porque no se puede adecuar, es un síntoma de que necesitas hacer funciones más abstractas, más genéricas para que puedan ser extendidas con requerimientos más puntuales.</div><div><br /></div><h2>2. Encapusla</h2><div>No hay mucha gente que entienda la importancia de la encapsulación, pero es muy simple. Aprende a encapsular el alcance de tus clases. La forma más fácil de hacerlo es poniendo privadas las variables y métodos que son exclusivos de tu clase, y poniendo públicos los métodos que pueden ser usados por otros objetos. Hay más formas de encapsular el código, pero esos dos son los básicos.</div><div><br /></div><h2>3. Principio de diseño abierto-cerrado</h2><div>Este principio dice que las clases, métodos y funciones deben estar abiertos para extender su funcionalidad, pero cerrados para ser modificados. Esto significa que tu código debería ser modificado casi nunca pero sí debería servir como base para extenderlo, es decir, para usar herencia, para usar interfaces, para ser la base de nuevas clases, a fin de que nunca llegues a modificar tu código existente para crear nuevo, sino crear código sobre la base que ya tienes.</div><div><br /></div><div>Esto podemos verlo como si fuera una caja negra, donde tu debes hacer que tu código sea imposible de modificar y solo pueda ser usado desde sus métodos públicos para poder ser extendido.</div><div><br /></div><h2>4. Principio de responsabilidad única</h2><div>Este principio hace referencia a que nuestras clases y métodos deben tener una sola tarea o actividad. Una clase que se encarga de operar datos no debería administrar componentes gráficos, ni un método que tiene que mandar un correo electrónico debería manejar funciones adicionales. Esto hace que tus funciones cumplan un solo propósito y hace más fácil que las puedas utilizar más adelante.</div><div><br /></div><h2>5. Inyección de dependencias</h2><div>Las dependencias es cuando en una clase necesitas otra para poder trabajar. Piensa en una clase que toma como base otra para mandar un mensaje de texto. La clase original tiene una dependencia y si quisieras usar esa clase pero no quisieras mandar un mensaje de texto hace que tengas que modificar el código para ello. La mejor forma de resolver un problema así es a través de la inyección de dependencias en donde en vez que que la clase original mande a llamar a la segunda clase, se le inyecte a través del uso de frameworks o interfaces para mandar a llamar a algo que después tiene que ser completado, y de esa forma no dependa de otras clases.</div><div><br /></div><h2>6. Composición sobre herencia</h2><div>La composición es justamente lo opuesto a la herencia, que es mandar a llamar objetos en vez de heredarlos. Esto es bueno en la medida en que a partir de una misma relación en vez de estar heredando clases y hacer una jerarquía grande, muchas veces para simplificar trabajar con objetos de una misma base en mejor hacerlo a través de la composición o creación de objetos. Para saber más sobre composición y asociación pueden leer <a href="http://www.cristalab.com/tutoriales/programacion-orientada-a-objetos-asociacion-vs-composicion-c89337l/" target="_blank">este artículo</a>.</div><div><br /></div><h2>7. Principio de sustitución Liskov</h2><div>Este principio dice que si tienes un objeto de subtipo S que deriva de un tipo T deberías tener la posibilidad de usar el objeto de tipo T de la misma forma que uses al subtipo S. Como ejemplo, tenemos que un objeto de tipo Perro deriva de un objeto de tipo Animal, y si tienes una función que necesita un tipo Perro como parámetro, si colocas un objeto de tipo Animal debería funcionar la clase de la misma forma, sin errores.&nbsp;</div><div><br /></div><h2>8. Principio de segregación de interfaces</h2><div>Este principio refiere a que no incluyamos métodos que no va a utilizar el programador en una interfaz. Cuando creamos interfaces podemos colorcar métodos que queremos que el programador use para extender su código, pero si metemos funciones que no va a usar o no siempre va a usar, estamos cayendo en este error de POO.&nbsp;</div><div><br /></div><h2>9. Programación de interfaces no implementaciones</h2><div>Tu código siempre debe estar enfocado a definir interfaces, no implementación de las mismas. Las interfaces ya nos dan una forma abstracta de poder hacer funciones genéricas que puedan ser usadas en muchos escenarios. Hay que mantener esa estrategia para crear código que puedas reusar.</div><div><br /></div><h2>10. Principios de delegación</h2><div>Este último principio dice que no hay que hacer todo el código nosotros, ya hay clases a las que le podemos delegar esa tarea, como por ejemplo comparar dos objetos. Todos los objetos tienen la clase equals() por lo cual es innecesario implementar un nuevo método para esa funcionalidad. Es un ejemplo básico pero nos dice que hay que conocer los métodos de los objetos para saber qué ya hay código hecho que podemos usar y no todo a fuerza lo tenemos que implementar desde cero.<div class="separator" style="clear: both; text-align: center;"><br /></div></div><div><br /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=evZbDtyJqjw:fCGCWqxsxxU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=evZbDtyJqjw:fCGCWqxsxxU:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=evZbDtyJqjw:fCGCWqxsxxU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=evZbDtyJqjw:fCGCWqxsxxU:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=evZbDtyJqjw:fCGCWqxsxxU:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=evZbDtyJqjw:fCGCWqxsxxU:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=evZbDtyJqjw:fCGCWqxsxxU:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=evZbDtyJqjw:fCGCWqxsxxU:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=evZbDtyJqjw:fCGCWqxsxxU:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=evZbDtyJqjw:fCGCWqxsxxU:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=evZbDtyJqjw:fCGCWqxsxxU:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=evZbDtyJqjw:fCGCWqxsxxU:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=evZbDtyJqjw:fCGCWqxsxxU:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=evZbDtyJqjw:fCGCWqxsxxU:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/evZbDtyJqjw" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">End of Year Review 2018-19</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">04 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I work as a front-end web and JavaScript developer on a contract basis. My services are provided through a limited company, Studio Zeffa. Since the company&rsquo;s financial year has just concluded, I&rsquo;m continuing the tradition from last year and writing a post to review the past year&rsquo;s work.
Projects In the period 1st April 2018 - 31st March 2019 I worked on the following projects:
Development of the Postsaver and Polesaver smartphone apps to guide the installation of these products in the field.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">End of Year Review 2018-19</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">04 05 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I work as a front-end web and JavaScript developer on a contract basis. My services are provided through a limited company, Studio Zeffa. Since the company&rsquo;s financial year has just concluded, I&rsquo;m continuing the tradition from last year and writing a post to review the past year&rsquo;s work.
Projects In the period 1st April 2018 - 31st March 2019 I worked on the following projects:
Development of the Postsaver and Polesaver smartphone apps to guide the installation of these products in the field.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q2 2019 Funding Announcement</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">30 04 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together is happy to announce that for Q2 of 2019 (May-July) we are funding two projects: Boot with Matthew Ratzke, and Fireplace with Tim Pope.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/131-bug-free.png" alt="Bug Free">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Bug Free</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">30 04 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/131-bug-free.png" alt="Bug Free" title="If you can't find the any key on your keyboard please use the power button." /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="A quantum bug in Firefox Quantum">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">A quantum bug in Firefox Quantum</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">29 04 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        DevTools - how we tracked down an observant-dependent bug.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/130-curiosity.png" alt="Curiosity">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Curiosity</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">23 04 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/130-curiosity.png" alt="Curiosity" title="The deeper you dig, the harder it is to get out the hole" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">March 2019 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">18 04 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The second month of updates from Neanderthal and Aleph is here. Thanks for your continued support of Clojurists Together!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://2.bp.blogspot.com/-XDXSvi3AP5c/XLOEEOkmPQI/AAAAAAAAlgM/eqVonPeGjig0ETP9qSP37-hXNlUdpECGQCLcBGAs/s640/download.jpeg" alt="7 consejos para crear logotipos en 2019">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">7 consejos para crear logotipos en 2019</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">16 04 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-XDXSvi3AP5c/XLOEEOkmPQI/AAAAAAAAlgM/eqVonPeGjig0ETP9qSP37-hXNlUdpECGQCLcBGAs/s1600/download.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="7 consejos para crear logotipos en 2019" border="0" data-original-height="174" data-original-width="290" height="384" src="https://2.bp.blogspot.com/-XDXSvi3AP5c/XLOEEOkmPQI/AAAAAAAAlgM/eqVonPeGjig0ETP9qSP37-hXNlUdpECGQCLcBGAs/s640/download.jpeg" title="7 consejos para crear logotipos en 2019" width="640" /></a></div><div><br /></div>Encontré este artículo de&nbsp;<a href="https://www.customlogocases.com/blog/logo-design-tips/" target="_blank">Logo Design Guide:7 Tips Moving into 2019</a>, donde nos platican de tips para crear logotipos en 2019. Es interesante ver como muchas de las tendencias de logotipos consisten en hacer muy sencillos los logos, o no ponerle mucha creatividad. El hecho de que sean así las tendencias no significa que tu próximo diseño tenga que ser igual. Es por eso que les comparto de esos 7 tips lo más importante que debes notar cuando empiezas con un diseño de logotipo.<div><br /></div><div>Parte 1: No olvides los fundamentos</div><div><ul><li><b>Conoce tu marca</b>: siempre recuerda que el logotipo debe representar a tu marca, identificarse y ser único. Al final tu marca y logotipo deben transmitir el mismo mensaje</li><li><b>Obten inspiración</b>: busca nuevas formas, colores y mensajes, no te bases solo en las tendencias o en lo que todos están implementando justo ahora. Crea algo que sea moderno sin tener que ser repetitivo o parecido a algo que ya se ha visto antes.</li><li><b>Inicia un tablero de humor:</b> usa servicios como Pinterest para empezar a ver imágenes de diferentes logotipos, tratando de identificar lo que te gusta de cada uno de ellos, y de ahí partir para crear algo adecuado para ti.</li><li><b>Investiga tu audiencia:</b> identifica para quién es ese logotipo. No todos los logotipos funcionan para todas las personas, así que identifica qué tipo de personas verían tu logo y sentirían lo mismo que tu, y que otras a lo mejor pueden interpretar otro mensaje que quizá necesites corregir.</li></ul></div><div><br /></div><div>Parte 2: 7 tips para crear logotipos excelente</div><div><ul><li><b>Identifica el tipo de logo:</b> los hay desde solo poner tipografía, hasta colocar mascotas o formas identificables</li><li><b>Escoge una esquema de colores:</b> usa colores que coincidan con tu marca y las sensaciones que transmite. No todos deben ser colores vivos, también puedes usar esquema de grises o blanco y negro.</li><li><b>Identifica un tipo de fuente:</b> tanto las serifas o sin serifas o las personalizadas son importantes para dar más elegancia o más soltura al mensaje que das en el logo</li><li><b>Haz un logo único:</b> es imposible crear un logo que no se base en algo ya existente, pero trata que incluso tomando elementos que ya se han visto antes parezca nuevo.</li><li><b>¿Cómo están desempeñándose otros diseños?:</b> hay logotipos con doble mensaje en el diseño, o que tienen un toque característico que los diferencia muy claramente. Aprende a identificar qué es lo que caracteriza a un buen logo existente y de ahí parte para darle autenticidad al tuyo.</li><li><b>Manténlo simple y flexible:</b> no te enredes tanto, siempre lo más simple va a ser lo mejor, pero trata de que se pueda adaptar a nuevos formatos y se vea fresco con el paso de los años.</li><li><b>Publica tu trabajo pero no esperes un éxito instantáneo:</b> el éxito de un logo no depende de que sea admirado al instante, sino que empiece a ser reconocido a lo largo del tiempo, así que no te limites en medir el éxito de tu logo al instante.</li></ul></div><div><br /></div><div><br /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=uYrllGeelg4:vt7cIwSwGp8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=uYrllGeelg4:vt7cIwSwGp8:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=uYrllGeelg4:vt7cIwSwGp8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=uYrllGeelg4:vt7cIwSwGp8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=uYrllGeelg4:vt7cIwSwGp8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=uYrllGeelg4:vt7cIwSwGp8:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=uYrllGeelg4:vt7cIwSwGp8:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=uYrllGeelg4:vt7cIwSwGp8:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=uYrllGeelg4:vt7cIwSwGp8:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=uYrllGeelg4:vt7cIwSwGp8:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=uYrllGeelg4:vt7cIwSwGp8:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=uYrllGeelg4:vt7cIwSwGp8:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=uYrllGeelg4:vt7cIwSwGp8:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=uYrllGeelg4:vt7cIwSwGp8:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/uYrllGeelg4" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/129-conflict-management.png" alt="Conflict Management">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Conflict Management</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">16 04 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/129-conflict-management.png" alt="Conflict Management" title="The aim is to enhance learning" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://4.bp.blogspot.com/-WSBlIKLhdQs/XLN92Oyo-fI/AAAAAAAAlgA/wdmfuGAHraU4T8ZS8K71mrG_LXPx3gNVQCLcBGAs/s640/1_Q2t-jgIzVx_w1Cyy1YlbNw.png" alt="Comparando frameworks para front-end">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Comparando frameworks para front-end</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">15 04 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-WSBlIKLhdQs/XLN92Oyo-fI/AAAAAAAAlgA/wdmfuGAHraU4T8ZS8K71mrG_LXPx3gNVQCLcBGAs/s1600/1_Q2t-jgIzVx_w1Cyy1YlbNw.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Comparando frameworks para front-end" border="0" data-original-height="650" data-original-width="1100" height="378" src="https://4.bp.blogspot.com/-WSBlIKLhdQs/XLN92Oyo-fI/AAAAAAAAlgA/wdmfuGAHraU4T8ZS8K71mrG_LXPx3gNVQCLcBGAs/s640/1_Q2t-jgIzVx_w1Cyy1YlbNw.png" title="Comparando frameworks para front-end" width="640" /></a></div><br />Me encuentro este interesantísimo artículo de <a href="https://medium.freecodecamp.org/a-realworld-comparison-of-front-end-frameworks-with-benchmarks-2019-update-4be0d3c78075" target="_blank">FreeCodeCamp</a>, en el cual comparan la velocidad y tamaño de algunos de los frameworks más famosos que hay para front-end. Si bien cada uno de ellos está enfocado en dar un resultado más o menos parecido, creo que muchos se han preguntado si estos frameworks son realmente un alivio para la gente que diseña aplicaciones web, o solo es un sobre costo que se añade por el hecho de tener un código más ordenado y con posibilidades de mantenerlo mejor.<br /><div><br /></div><div>El análisis que les presento muestra algunas estadísticas que el autor tomó para medir el impacto de cada framework. En primer lugar el construyó la misma aplicación para los siguientes frameworks:</div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-USb_61DbpXk/XLN9ULQXl-I/AAAAAAAAlfo/PYYCgyKrhxQ-10dqsNZIYrmrlQAX-s3XwCLcBGAs/s1600/1_JCpxiVgoupqzByhtlLv2LQ.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Comparando frameworks para front-end" border="0" data-original-height="1205" data-original-width="1600" height="482" src="https://3.bp.blogspot.com/-USb_61DbpXk/XLN9ULQXl-I/AAAAAAAAlfo/PYYCgyKrhxQ-10dqsNZIYrmrlQAX-s3XwCLcBGAs/s640/1_JCpxiVgoupqzByhtlLv2LQ.png" title="Comparando frameworks para front-end" width="640" /></a></div></div><div>Después de eso empezó con sus métricas.</div><div><br /></div><h2>Rendimiento</h2><div>Es quizá el punto más importante para todos. De nada sirve tener un framework si el rendimiento del mismo se ve afectado. Siempre hay que tener en cuenta que el rendimiento más óptimo debería ser el poder crear nuestras aplicaciones sin necesidad de un framework. Si acudimos a ellos es porque deberíamos suponer que mucho del <i>tunning</i> de ese rendimiento ya lo trabaja ese framework. El resultado es como sigue:</div><div><a href="https://2.bp.blogspot.com/-ueOyWyDLX4I/XLN9TyMZfII/AAAAAAAAlfk/pXROGmTMCnoJkRaFY-khrnwtkFzMjckPQCLcBGAs/s1600/1_NIXLXDG15whg_NR8yzWjXQ.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="Comparando frameworks para front-end" border="0" data-original-height="897" data-original-width="1600" height="358" src="https://2.bp.blogspot.com/-ueOyWyDLX4I/XLN9TyMZfII/AAAAAAAAlfk/pXROGmTMCnoJkRaFY-khrnwtkFzMjckPQCLcBGAs/s640/1_NIXLXDG15whg_NR8yzWjXQ.png" title="Comparando frameworks para front-end" width="640" /></a></div><div>La mayoría de los frameworks corren por arriba de los 90 puntos, eso quiere decir que prácticamente en cuanto carga tu sitio o aplicación web, también lo hace el framework y sus componentes, a excepción de AngularJS que tiene el desempeño más bajo.</div><div><br /></div><h2>Tamaño</h2><div>El tamaño es la cantidad de kb que tiene que transferirse para poder cargar tu aplicación web. Entre más grande sea mayor va a ser el tiempo de carga.<br /><a href="https://3.bp.blogspot.com/-JtILs5XEIKQ/XLN9TzrZYaI/AAAAAAAAlfg/qg_qobA-B-Yyk2WD-8weggxM3WkrAZXVwCLcBGAs/s1600/1_JT5MV8kiP2LSV0l19reLSQ.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="Comparando frameworks para front-end" border="0" data-original-height="1089" data-original-width="1600" height="434" src="https://3.bp.blogspot.com/-JtILs5XEIKQ/XLN9TzrZYaI/AAAAAAAAlfg/qg_qobA-B-Yyk2WD-8weggxM3WkrAZXVwCLcBGAs/s640/1_JT5MV8kiP2LSV0l19reLSQ.png" title="Comparando frameworks para front-end" width="640" /></a><br /><br /><br /></div><div><br /></div><div>Mientras que hay frameworks que solo tienen 9kb de transferencia, hay otros como AngularJS que transfieren hasta 300kb. Esto en perspectiva podría parecer muchísimo, pero también dependiendo de la calidad de la conexión a internet es que se afecta mucho más esa transferencia.</div><div><br /></div><h2>Líneas de código</h2><div>Las líneas de código es de los parámetros más importantes para un desarrollador. No tiene sentido que tengas que tener más líneas de código solo por usar un framework, si el objetivo inicial es justo simplificar ese proceso de creación con menos líneas.<br /><br /><a href="https://3.bp.blogspot.com/-G5Cv3IkWW4E/XLN9UoxNEqI/AAAAAAAAlfs/bsyPFnpoVwkl35w8RiOlIC63pTsWLAK-gCLcBGAs/s1600/1_yjATvFxmv21w8Em_hxm7_w.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="Comparando frameworks para front-end" border="0" data-original-height="1047" data-original-width="1600" height="418" src="https://3.bp.blogspot.com/-G5Cv3IkWW4E/XLN9UoxNEqI/AAAAAAAAlfs/bsyPFnpoVwkl35w8RiOlIC63pTsWLAK-gCLcBGAs/s640/1_yjATvFxmv21w8Em_hxm7_w.png" title="Comparando frameworks para front-end" width="640" /></a></div><div><br /></div><div>En la imagen podemos ver que mientras para re-frame un proyecto requirió de 968 líneas de código, el mismo en Angular con ngrx y nx requirió 4,210 líneas de código, es decir, poco más de 4 veces, entonces aunque mucho código lo podrías generar y otro hacerlo tu, la realidad es que se entiende que más líneas de código podría aumentar el tamaño de tu proyecto, y en consecuencia hacerlo un poco más pesado.</div><h2>Conclusión</h2><div>Como mencionan en el artículo, no es muy fácil hacer comparaciones de peras con peras y manzanas con manzanas. Es importante notar que podría haber un sesgo pero los datos nos revelan mucha información. Lo que más me sorprende de esas gráficas es que por ejemplo, Vue, React y Angular, a pesar de que son los frameworks más usados, no son ni los más rápidos ni los más pequeños. Hay frameworks que son más ligeros, y si te interesa usar uno pero te interesa cuidar estas tres métricas la respuesta es que puedes optar por utilizar uno diferente a los 3 más populares.</div><div><br /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=Nief14EPgII:p-YCS4B-4g8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Nief14EPgII:p-YCS4B-4g8:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Nief14EPgII:p-YCS4B-4g8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=Nief14EPgII:p-YCS4B-4g8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Nief14EPgII:p-YCS4B-4g8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=Nief14EPgII:p-YCS4B-4g8:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Nief14EPgII:p-YCS4B-4g8:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Nief14EPgII:p-YCS4B-4g8:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Nief14EPgII:p-YCS4B-4g8:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=Nief14EPgII:p-YCS4B-4g8:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Nief14EPgII:p-YCS4B-4g8:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Nief14EPgII:p-YCS4B-4g8:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=Nief14EPgII:p-YCS4B-4g8:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=Nief14EPgII:p-YCS4B-4g8:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/Nief14EPgII" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How do you compose JavaScript functions with multiple parameters?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">15 04 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        As functional programmers, we like to piece our programs together out of small pieces. Our main tool for this is composition. We take an input, process it through a function, then pass it on to another function. And this all works great so long as all our functions take exactly one argument. Which never happens. So what do we do? In general, we turn to a set of tools called combinators. This article focusses on a particular combinator called lift.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How do you compose JavaScript functions with multiple parameters?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">15 04 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        As functional programmers, we like to piece our programs together out of small pieces. Our main tool for this is composition. We take an input, process it through a function, then pass it on to another function. And this all works great so long as all our functions take exactly one argument. Which never happens. So what do we do? In general, we turn to a set of tools called combinators. This article focusses on a particular combinator called lift.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to Create an Index in Django Without Downtime</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">09 04 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>If you ever had to maintain a traffic heavy Django site, you probably had to deal with graceful migrations. In the article I explain what atomic and reversible migrations are, how to execute "raw" SQL in migrations the right way, and how using a little known migration command we can completely alter the Django migrations built-in behavior.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Lazy loading nativo</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Óscar Lijó</a> <span class="article__date">09 04 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Haciéndome eco de la reciente publicación de Addy Osmani en su blog, nos encontramos con que dentro de poco el Chrome va a implementar una manera de conseguir hacer lazy loading nativo. Esta es una noticia fantástica. Pero el notición sería que el atributo que van a usar fuera recogido por el estándar de HTML&#8230;</p>
<p>La entrada <a rel="nofollow" href="https://www.oscarlijo.com/blog/lazy-loading-nativo/">Lazy loading nativo</a> aparece primero en <a rel="nofollow" href="https://www.oscarlijo.com/blog">Óscar Lijó</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/128-code-review.png" alt="Code Review">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Code Review</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">09 04 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/128-code-review.png" alt="Code Review" title="Maybe you are not that good" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://2.bp.blogspot.com/-KSLbuxKunr4/XKpYkHj8fkI/AAAAAAAAlec/xcinytGZfIESaavMwdqjfg7NXlyU95nwACLcBGAs/s1600/11-trucos-consola-chrome-javascript.jpg" alt="11 Trucos para la consola de Javascript de Google Chrome">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">11 Trucos para la consola de Javascript de Google Chrome</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">08 04 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody><tr><td style="text-align: center;"><a href="https://2.bp.blogspot.com/-KSLbuxKunr4/XKpYkHj8fkI/AAAAAAAAlec/xcinytGZfIESaavMwdqjfg7NXlyU95nwACLcBGAs/s1600/11-trucos-consola-chrome-javascript.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img alt="11 Trucos para la consola de Javascript de Google Chrome" border="0" data-original-height="720" data-original-width="1280" src="https://2.bp.blogspot.com/-KSLbuxKunr4/XKpYkHj8fkI/AAAAAAAAlec/xcinytGZfIESaavMwdqjfg7NXlyU95nwACLcBGAs/s1600/11-trucos-consola-chrome-javascript.jpg" title="11 Trucos para la consola de Javascript de Google Chrome" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;"><br /></td></tr></tbody></table><br />La consola de Google Chrome tiene muchas funcionalidades que nos pueden ayudar de forma muy interesante en nuestro debugging. En este post les presento algunos de los trucos más interesantes que seguramente les van a servir la próxima vez que tengan que desarrollar una aplicación con Javascript.<div><br /></div><div class="separator" style="clear: both; text-align: center;"><iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/EO3CHe7BWuI/0.jpg" src="https://www.youtube.com/embed/EO3CHe7BWuI?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div><div><br /><h2><b>Estilizar mensajes de consola</b></h2><div><a href="https://3.bp.blogspot.com/-RtoOolFtYYk/XKpYc17bafI/AAAAAAAAld4/by4u0ynuvhggbx-TD85XBeKJEWYoZDMgwCLcBGAs/s1600/consola-01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="303" data-original-width="1279" src="https://3.bp.blogspot.com/-RtoOolFtYYk/XKpYc17bafI/AAAAAAAAld4/by4u0ynuvhggbx-TD85XBeKJEWYoZDMgwCLcBGAs/s1600/consola-01.jpg" /></a></div><div>Por defecto en la consola de Chrome los mensajes aparecen sin formato, pero si lo que necesitas es tener estilos para diferenciar ciertos mensajes basta con ingresar '%c' al inicio del mensaje de un console.log y colocar como un parámetro adicional los estilos CSS que quieres poner.</div><div><br /></div><div><script src="https://gist.github.com/marcosrivasr/c8f62a94e4d0c4bc11096dc1681599a8.js"></script></div><div><br /></div><h2>Mostrar JSON como tabla</h2><div><a href="https://3.bp.blogspot.com/-fDUQxs90aVM/XKpYc-ndTWI/AAAAAAAAld8/4L-uZyCo-i8qNdUnsdG72v12Fo2VxpaSACLcBGAs/s1600/consola-02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="429" data-original-width="1278" src="https://3.bp.blogspot.com/-fDUQxs90aVM/XKpYc-ndTWI/AAAAAAAAld8/4L-uZyCo-i8qNdUnsdG72v12Fo2VxpaSACLcBGAs/s1600/consola-02.jpg" /></a></div><div>De forma sencilla podemos mostrar un JSON en formato de tabla con el siguiente script:</div><div><br /></div><div><script src="https://gist.github.com/marcosrivasr/7f60a8abd18b2d2847d81534225eb467.js"></script></div><div><br /></div><h2>Obtener las llaves de un arreglo</h2><div><a href="https://1.bp.blogspot.com/-OSNpzqQHCRI/XKpYdQjgXiI/AAAAAAAAleE/YtMNkC0sPSYwV8MPcB1LsRVZ64fduVAJgCLcBGAs/s1600/consola-04.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="152" data-original-width="626" src="https://1.bp.blogspot.com/-OSNpzqQHCRI/XKpYdQjgXiI/AAAAAAAAleE/YtMNkC0sPSYwV8MPcB1LsRVZ64fduVAJgCLcBGAs/s1600/consola-04.jpg" /></a></div><div>Dado un arreglo se pueden extraer las llaves o claves de la siguiente forma:</div><div><br /></div><div><script src="https://gist.github.com/marcosrivasr/a6d45818827e4e8e4e86b8ef250089d5.js"></script></div><div><br /></div><h2>Obtener el elemento seleccionado&nbsp;</h2><div>Podemos hacer referencia al elemento HTML seleccionado con el símbolo $0, y poder navegar por el historico de elementos seleccionados con $1, $2,etc</div><div><br /></div><h2>Referenciar objetos HTML&nbsp;</h2><div>Tradicionalmente usamos document.getElementById() o querySelector() para hacer referencia a objetos. En la consola de Chrome podemos hacer referencia usando la simbología de $('selector'), muy parecido a como se hace con jQuery, pero esta es una forma nativa de hacerlo en la consola de Chrome.</div><div><br /></div><div></div><div><br /></div><h2>Obtener eventos configurados en elemento HTML</h2><div><a href="https://1.bp.blogspot.com/-2aaDGXtE4ck/XKpYdrIG7tI/AAAAAAAAleI/eetwjucwfTM2F7JfDf4gpFlOz5nr4DyWgCLcBGAs/s1600/consola-05.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="423" data-original-width="1068" src="https://1.bp.blogspot.com/-2aaDGXtE4ck/XKpYdrIG7tI/AAAAAAAAleI/eetwjucwfTM2F7JfDf4gpFlOz5nr4DyWgCLcBGAs/s1600/consola-05.jpg" /></a></div><div>Se pueden ver de forma sencilla los eventos configurados en un elemento HTML así:</div><div><br /></div><div><script src="https://gist.github.com/marcosrivasr/ece2aa14561e0a6b51d4333912a5c713.js"></script></div><div><br /></div><h2>Monitorear todos los eventos sobre un elemento HTML</h2><div><a href="https://3.bp.blogspot.com/-U2AuDWjV2lw/XKpYeXTCfhI/AAAAAAAAleM/8FX1lkY2SEo3kkvxHxNmfc9HJZ_8A0QuwCLcBGAs/s1600/consola-06.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="574" data-original-width="1112" src="https://3.bp.blogspot.com/-U2AuDWjV2lw/XKpYeXTCfhI/AAAAAAAAleM/8FX1lkY2SEo3kkvxHxNmfc9HJZ_8A0QuwCLcBGAs/s1600/consola-06.jpg" /></a></div><div>Se pueden monitorear todos los eventos sobre un elemento específico, usando dos comandos: monitorEvents() y unmonitorEvents()</div><div><br /></div><div><script src="https://gist.github.com/marcosrivasr/c8957b00edd67671119096576f049cc6.js"></script></div><div><br /></div><h2>Medir tiempo de ejecución de un procedimiento</h2><div><a href="https://3.bp.blogspot.com/-fvbCMpU4l94/XKpYehTtZTI/AAAAAAAAleQ/E6qKZOW-3Dw2JUY7BSyzNGUSwBhTnnP6wCLcBGAs/s1600/consola-07.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="81" data-original-width="680" src="https://3.bp.blogspot.com/-fvbCMpU4l94/XKpYehTtZTI/AAAAAAAAleQ/E6qKZOW-3Dw2JUY7BSyzNGUSwBhTnnP6wCLcBGAs/s1600/consola-07.jpg" /></a></div><div>Puedes calcular el tiempo que tarda un procedimiento en ejecutarse usando dos funciones: console.time() y console.timeEnd()</div><div><br /></div><div><script src="https://gist.github.com/marcosrivasr/757678b76490112343a74900b451114b.js"></script></div><div><br /></div><div><br /></div><h2>Mostrar todas las propiedades de un elemento HTML</h2><div><a href="https://3.bp.blogspot.com/-_Ss6_UKfMMg/XKpYfB1O_pI/AAAAAAAAleU/ZOrnIOHxt0Y-Zb5lc150lG37ptSXXoiXACLcBGAs/s1600/consola-08.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="583" data-original-width="974" src="https://3.bp.blogspot.com/-_Ss6_UKfMMg/XKpYfB1O_pI/AAAAAAAAleU/ZOrnIOHxt0Y-Zb5lc150lG37ptSXXoiXACLcBGAs/s1600/consola-08.jpg" /></a></div><div>Usando la función dir(selector) se puede mostrar todo lo que contiene un elemento HTML</div><div><br /></div><h2>Hacer referencia a la última expresión resultante</h2><div><a href="https://3.bp.blogspot.com/-vRMowNyh_Ns/XKpYfrOVayI/AAAAAAAAleY/re7uVmAveMEeHPnstK_nkzudK3wuRPirQCLcBGAs/s1600/consola-09.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="108" data-original-width="474" src="https://3.bp.blogspot.com/-vRMowNyh_Ns/XKpYfrOVayI/AAAAAAAAleY/re7uVmAveMEeHPnstK_nkzudK3wuRPirQCLcBGAs/s1600/consola-09.jpg" /></a></div><div>La última expresión en la consola también puede asignarse a una variable $_ la cual siempre tendrá el valor más reciente calculado dentro de la misma.</div><div><br /></div><div><br /></div><div><br /></div></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=8Mq3cVjfdu4:2P9S9D9bOi8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8Mq3cVjfdu4:2P9S9D9bOi8:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8Mq3cVjfdu4:2P9S9D9bOi8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=8Mq3cVjfdu4:2P9S9D9bOi8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8Mq3cVjfdu4:2P9S9D9bOi8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=8Mq3cVjfdu4:2P9S9D9bOi8:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8Mq3cVjfdu4:2P9S9D9bOi8:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8Mq3cVjfdu4:2P9S9D9bOi8:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8Mq3cVjfdu4:2P9S9D9bOi8:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=8Mq3cVjfdu4:2P9S9D9bOi8:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8Mq3cVjfdu4:2P9S9D9bOi8:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8Mq3cVjfdu4:2P9S9D9bOi8:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=8Mq3cVjfdu4:2P9S9D9bOi8:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=8Mq3cVjfdu4:2P9S9D9bOi8:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/8Mq3cVjfdu4" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hyperreals *R: Mutabilidad de&amp;#160;Listas</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">07 04 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="admonition info">
<p class="admonition-title">Info</p>
<p>Puedes visionar este art&#237;culo y descarg&#225;rtelo como notebook ipython en <a href="http://nbviewer.jupyter.org/5177340">http://nbviewer.jupyter.org/5177340</a></p>
</div>
<p>Mucha gente, cuando se enfrenta por primera vez al lenguaje python, no entiende bien el concepto de <em>&#8220;inmutabilidad&#8221;</em> que tanto repite la documentaci&#243;n al tratar de diferenciar algunos tipos contenedores como tuplas, listas, conjuntos y&nbsp;diccionarios.</p>
<p>Por lo general, la gente formada en lenguajes de programaci&#243;n cl&#225;sicos tiene la idea de que las variables son porciones de memoria donde colocar valores. Que una variable no se &#233;so, <em>variable</em>, resulta un contrasentido. Han visto <em>constantes</em>, pero s&#243;lo sirven para inicializar variables y poco m&#225;s. Si en su carrera hubieran sido formados en alg&#250;n lenguaje funcional se dar&#237;an cuenta que hay quienes piensan que las variables que cambian de valor son las raras, que lo m&#225;s natural es que una variable conserve su valor inicial, o sea, que sea&nbsp;inmutable.</p>
<p>Por poner un ejemplo, el siguiente c&#243;digo est&#225; basado en una pregunta reciente en la lista <a href="http://docs.python.org/3.3/library/copy.html" title="M&#243;dulo copy">python-es</a>. Tenemos una lista de pares y queremos quitar las parejas repetidas con orden&nbsp;cambiado:</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">quitar_dup</span><span class="p">(</span><span class="n">lista</span><span class="p">):</span>

    <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">lista</span><span class="p">:</span>

        <span class="n">item</span><span class="o">.</span><span class="n">reverse</span><span class="p">()</span>

        <span class="k">if</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">lista</span><span class="p">:</span>
            <span class="n">lista</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">lista</span>

<span class="n">L</span><span class="o">=</span><span class="p">[[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">],</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">]]</span>

<span class="nb">print</span> <span class="n">quitar_dup</span><span class="p">(</span><span class="n">L</span><span class="p">)</span>  <span class="c1">#res: [[1, 3], [3, 1]]</span>
</code></pre></div>

<p>A simple vista, el c&#243;digo parece correcto, pero tenemos dos operaciones que pueden mutar listas: <code>.reverse()</code> y <code>.remove()</code>. De hecho, el resultado es incorrecto: <code>[[1, 3], [3, 1]]</code></p>
<p>A medida que recorremos la lista en el bucle <code>for</code>, la lista se va modificando, lo que da lugar a resultados inesperados. Si no lo ves bien, basta a&#241;adir algunos <code>prints</code> en lugares estrat&#233;gicos para que comprobar lo que pasa. De hecho, s&#243;lo existen dos iteraciones para cuatro elementos que tiene la&nbsp;lista.</p>
<p>Otro tipo de casos son cuando pasamos listas a&nbsp;funciones:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">l</span><span class="p">):</span>
<span class="o">...</span>   <span class="k">if</span> <span class="n">a</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">l</span><span class="p">:</span>
<span class="o">...</span>     <span class="n">l</span> <span class="o">+=</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span>
<span class="o">...</span>   <span class="k">return</span> <span class="n">l</span>
<span class="o">...</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">L</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">add</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">L</span><span class="p">)</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">add</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="n">L</span><span class="p">)</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">L</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span>
</code></pre></div>

<p>Como efecto colateral, la funci&#243;n ha modificado la lista pasada como argumento, algo que no es siempre deseable. El problema se agrava m&#225;s si empleamos listas en valores por&nbsp;defecto:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">l</span><span class="o">=</span><span class="p">[]):</span>
<span class="o">...</span>   <span class="k">if</span> <span class="n">a</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">l</span><span class="p">:</span>
<span class="o">...</span>     <span class="n">l</span> <span class="o">+=</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span>
<span class="o">...</span>   <span class="k">return</span> <span class="n">l</span>
<span class="o">...</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">add</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">add</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">add</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="p">[])</span>
<span class="p">[</span><span class="mi">3</span><span class="p">]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">add</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span>
</code></pre></div>

<p>Como se puede ver, aunque intentemos <em>resetear</em> el valor por defecto, la funci&#243;n tiene un efecto memoria que es imposible de eliminar. Este efecto es a veces buscado, pero en general debe ser siempre evitado ya que desvirt&#250;a el sentido que tiene dar valores por&nbsp;defecto.</p>
<p>Estos efectos son todav&#237;a m&#225;s perniciosos con la <em>funciones lambda</em>. Al carecer de una <em>clausura</em> como las funciones, la evaluaci&#243;n de una funci&#243;n lambda depende del <em>scope</em> donde han sido definidas. Por ejemplo, observa esta creaci&#243;n de una lista de&nbsp;funciones:</p>
<div class="highlight"><pre><span></span><code><span class="n">fns</span> <span class="o">=</span> <span class="p">[]</span>

<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
    <span class="n">fns</span><span class="o">.</span><span class="n">append</span><span class="p">(</span> <span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span> <span class="o">+</span> <span class="n">i</span><span class="p">)</span>

<span class="nb">print</span> <span class="n">fns</span><span class="p">[</span><span class="mi">1</span><span class="p">](</span><span class="mi">10</span><span class="p">)</span>
<span class="nb">print</span> <span class="n">fns</span><span class="p">[</span><span class="mi">2</span><span class="p">](</span><span class="mi">10</span><span class="p">)</span>
</code></pre></div>

<p>Siempre a&#241;ade <code>4</code> al argumento, que es el valor de <code>i</code> al acabar el bucle, independientemente de qu&#233; valor ten&#237;a esta variable en el momento de crear la funci&#243;n lambda. No es de extra&#241;ar que se recomiende dejar de usar estas&nbsp;funciones.</p>
<p>Por &#250;ltimo, otro efecto funesto de la mutabilidad de las listas aparece en la creaci&#243;n de <em>listas multidimensionales</em> (aka <em>matrices</em>). Una forma r&#225;pida de crear una matriz de 2x2 es: <code>[[0]*2]*2</code>. El problema aqu&#237; est&#225; en que cuando clonamos listas, en lugar de copiar los elementos, los enlaza entre s&#237;. Quiz&#225;s se vea mejor si hacemos alguna&nbsp;operaci&#243;n:</p>
<div class="highlight"><pre><span></span><code>&gt;&gt;&gt; l = [[0]*2]*2
[[0, 0], [0, 0]]
&gt;&gt;&gt; l[0][0]
0
&gt;&gt;&gt; l[0][0] = 1
&gt;&gt;&gt; l
[[1, 0], [1, 0]]
&gt;&gt;&gt; l[0] is l[1]
True
</code></pre></div>

<p>Los elementos <code>l[0]</code> y <code>l[1]</code> son el mismo elemento. Que los elementos de una lista puedan estar <em>entrelazados</em> resulta muy interante para algunos algoritmos de b&#250;squedas. Pero hay que conocer bien lo que estamos haciendo si no queremos llevarnos alguna&nbsp;sorpresa.</p>
<h2>Recomendaciones para hacer c&#243;digo&nbsp;funcional</h2>
<h3>Copia de&nbsp;listas</h3>
<p>En funciones y m&#233;todos, si recibimos una lista como argumento, la primera acci&#243;n defensiva que deber&#237;amos hacer es copiar la lista en una variable local y trabajar solo con la variable local desde ese momento. Con una asignaci&#243;n directa no se realiza una copia, m&#225;s bien estar&#237;amos <em>enlazando</em> una nueva referenciasin solucionar&nbsp;nada.</p>
<p>La forma consensuada entre programadores python de copiar una lista es con la operaci&#243;n de <em>spliting</em> <code>L[:]</code>, aunque sirven otras operaciones idempotentes como <code>L*1</code> &#243; <code>L+[]</code><sup id="fnref:1"><a class="footnote-ref" href="https://blog.ch3m4.org/feeds/python.atom.xml#fn:1">1</a></sup>. Para listas de elementos entrelazados tendremos que acudir a otros mecanismos de copia como los que ofrece el <a href="http://docs.python.org/3.3/library/copy.html" title="M&#243;dulo copy">m&#243;dulo <code>copy</code></a>, aunque no ser&#225; frecuente que lo&nbsp;necesitemos.</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">lista</span><span class="p">):</span>
  <span class="n">l</span> <span class="o">=</span> <span class="n">lista</span><span class="p">[:]</span>
  <span class="k">if</span> <span class="n">a</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">l</span><span class="p">:</span>
    <span class="n">l</span> <span class="o">+=</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span>
  <span class="k">return</span> <span class="n">l</span>
</code></pre></div>

<p>En cuanto a los argumentos por defecto, lo mejor es no usar nunca una lista para tal cosa. Una buena estrategia defensiva consiste en usar <code>None</code> de esta&nbsp;forma:</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">lista</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
  <span class="n">l</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">if</span> <span class="n">lista</span> <span class="ow">is</span> <span class="kc">None</span> <span class="k">else</span> <span class="n">lista</span><span class="p">[:]</span>
  <span class="k">if</span> <span class="n">a</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">l</span><span class="p">:</span>
    <span class="n">l</span> <span class="o">+=</span> <span class="p">[</span><span class="n">a</span><span class="p">]</span>
  <span class="k">return</span> <span class="n">l</span>
</code></pre></div>

<h3>Operaciones inmutables con&nbsp;listas</h3>
<p>En cuanto a evitar las operaciones que mutan listas, siempre hay alternativas inmutables de todas estas operaciones. El siguiente cuadro puede servir como&nbsp;referencia:</p>
<table>
<thead>
<tr>
<th>Mutable</th>
<th>Inmutable</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>L.append(item)</code></td>
<td><code>L+[item]</code></td>
</tr>
<tr>
<td><code>L.extend(sequence)</code></td>
<td><code>L + list(sequence)</code></td>
</tr>
<tr>
<td><code>L.insert(index, item)</code></td>
<td><code>L[:index] + [item] + L[index:]</code></td>
</tr>
<tr>
<td><code>L.reverse()</code></td>
<td><code>L[::-1]</code></td>
</tr>
<tr>
<td><code>L.sort()</code></td>
<td><code>sorted(L)</code></td>
</tr>
<tr>
<td><code>item = L.pop()</code></td>
<td><code>item,L = L[-1],L[:-1]</code></td>
</tr>
<tr>
<td><code>item = L.pop(0)</code></td>
<td><code>item,L = L[0],L[1:]</code></td>
</tr>
<tr>
<td><code>item = L.pop(index)</code></td>
<td><code>item, L = L[item], L[:item]+L[item+1:]</code></td>
</tr>
<tr>
<td><code>L.remove(item)</code></td>
<td><code>L=L[:item]+L[item+1:]</code></td>
</tr>
<tr>
<td><code>L[i:j] = K</code></td>
<td><code>L[:i] + K + L[j:]</code></td>
</tr>
</tbody>
</table>
<p>A la hora de decidir qu&#233; versi&#243;n usar, la versi&#243;n inmutable es m&#225;s apropiada para programaci&#243;n funcional y resulta incluos m&#225;s intuitiva de interpretar. No es extra&#241;o ver errores de c&#243;digo donde se espera resultados de las operaciones <code>.sort()</code> o <code>.reverse()</code>, que siempre devuelven <code>None</code>. Para el int&#233;rprete de python no hay error, pero a veces nos ser&#225; dif&#237;cil darnos cuenta de estos&nbsp;errores:</p>
<p><em><span class="caps">MODO</span> ERR&#211;NEO: machacamos la lista con&nbsp;None</em></p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">l</span> <span class="o">=</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">l_2</span> <span class="o">=</span> <span class="p">[</span><span class="n">x</span><span class="o">*</span><span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">l</span><span class="o">.</span><span class="n">sort</span><span class="p">()]</span>
<span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span>
  <span class="n">File</span> <span class="s2">&quot;&lt;stdin&gt;&quot;</span><span class="p">,</span> <span class="n">line</span> <span class="mi">1</span><span class="p">,</span> <span class="ow">in</span> <span class="o">&lt;</span><span class="n">module</span><span class="o">&gt;</span>
<span class="ne">TypeError</span><span class="p">:</span> <span class="s1">'NoneType'</span> <span class="nb">object</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">iterable</span>
</code></pre></div>

<p><em><span class="caps">MODO</span> <span class="caps">CORRECTO</span></em></p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">l</span> <span class="o">=</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">l_2</span> <span class="o">=</span> <span class="p">[</span><span class="n">x</span><span class="o">*</span><span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">l</span><span class="p">)]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">l_2</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">16</span><span class="p">,</span> <span class="mi">25</span><span class="p">]</span>
</code></pre></div>

<div class="footnote">
<hr />
<ol>
<li id="fn:1">
<p>De hecho, la operaci&#243;n <code>L*1</code> es m&#225;s eficiente que <code>L[:]</code>.&#160;<a class="footnote-backref" href="https://blog.ch3m4.org/feeds/python.atom.xml#fnref:1" title="Jump back to footnote 1 in the text">&#8617;</a></p>
</li>
</ol>
</div>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q2 2019 Survey Results and Call for Proposals</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">07 04 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Thanks so much for your support and feedback in the latest survey. We value your opinions and always take suggestions into account as we make changes from quarter to quarter. Project applications for our Q2 2019 round close on 15th Apr, midnight PST. The selections will be announced shortly afterwards. The Q2 2019 projects will start on May 1.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Eliminar elementos de un array en Javascript</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Óscar Lijó</a> <span class="article__date">04 04 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Eliminar elementos de un array en Javascript es una tarea habitual para los que desarrollamos en este lenguaje. De hecho, para hacerlo existen una gran cantidad de maneras distintas, según cual sea la necesidad. Seguramente algunas te sonarán y otras no tanto. Pero al final de este post tendrás un cuadro completo de los métodos&#8230;</p>
<p>La entrada <a rel="nofollow" href="https://www.oscarlijo.com/blog/eliminar-elementos-de-un-array-en-javascript/">Eliminar elementos de un array en Javascript</a> aparece primero en <a rel="nofollow" href="https://www.oscarlijo.com/blog">Óscar Lijó</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-5WrsE6_k7hU/XKEhulK9KSI/AAAAAAAAla8/qcV3qfK7P9s8yS_StZZbWKpZp5TspYfhQCLcBGAs/s640/degradados-01.jpg" alt="11 ejemplos de sitios web con degradados">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">11 ejemplos de sitios web con degradados</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">03 04 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <span class="fullpost"></span>En esta ocasión les presento<b> 11 ejemplos de degradados en sitios web</b> que pueden usar como referencia para sus proyectos. Los degradados, a pesar de lo que pudiéramos pensar, se expresan de varias formas, desde degradados tenues hasta con los colores muy definidos. No existe una regla específica para usarlos, y como vemos en cada uno de los sitios web, tampoco hay un límite siempre y cuando se combine adecuadamente con los demás elementos que componen el sitio.<span class="fullpost"><h2><span style="mso-fareast-font-family: &quot;Times New Roman&quot;;"><a href="https://dribbble.com/shots/4176694--1/attachments/955096" target="_blank"><span style="mso-fareast-font-family: &quot;Times New Roman&quot;; mso-fareast-theme-font: major-fareast;">Gradient Banner</span></a></span></h2><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-5WrsE6_k7hU/XKEhulK9KSI/AAAAAAAAla8/qcV3qfK7P9s8yS_StZZbWKpZp5TspYfhQCLcBGAs/s1600/degradados-01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="510" data-original-width="850" height="384" src="https://1.bp.blogspot.com/-5WrsE6_k7hU/XKEhulK9KSI/AAAAAAAAla8/qcV3qfK7P9s8yS_StZZbWKpZp5TspYfhQCLcBGAs/s640/degradados-01.jpg" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><br />  <br /><h2><a href="https://www.atomic.ie/dna/manifesto/" target="_blank">The HR Manifesto</a></h2><br /><div style="margin-bottom: 18.75pt; vertical-align: baseline;">&nbsp;<a href="https://2.bp.blogspot.com/-l4HDj6WBDbQ/XKEhujsW5SI/AAAAAAAAla0/kREBeeP1XgMaDYM_bz2_IduoPZ9Rv2Q4wCLcBGAs/s1600/degradados-02.jpg" imageanchor="1" style="-webkit-text-stroke-width: 0px; color: #0066cc; font-family: &quot;inherit&quot;,serif; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: 0.53px; margin-left: 1em; margin-right: 1em; orphans: 2; text-align: center; text-decoration: underline; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><img border="0" data-original-height="510" data-original-width="850" height="384" src="https://2.bp.blogspot.com/-l4HDj6WBDbQ/XKEhujsW5SI/AAAAAAAAla0/kREBeeP1XgMaDYM_bz2_IduoPZ9Rv2Q4wCLcBGAs/s640/degradados-02.jpg" width="640" /></a></div><br /><div style="margin-bottom: 18.75pt; vertical-align: baseline;"><br /></div><br /><h2><a href="https://dribbble.com/shots/5367995-Grabient-Landing-Page" target="_blank">Grabient Landing Page</a></h2><br />&nbsp;<a href="https://3.bp.blogspot.com/-q2IfOSPmzgY/XKEhupMQQaI/AAAAAAAAla4/31pgqV-MijMKXENt6gxQjCMzsDEdSzbIQCLcBGAs/s1600/degradados-03.jpg" imageanchor="1" style="-webkit-text-stroke-width: 0px; color: #0066cc; font-family: &quot;inherit&quot;,serif; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: 0.53px; margin-left: 1em; margin-right: 1em; orphans: 2; text-align: center; text-decoration: underline; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><img border="0" data-original-height="510" data-original-width="850" height="384" src="https://3.bp.blogspot.com/-q2IfOSPmzgY/XKEhupMQQaI/AAAAAAAAla4/31pgqV-MijMKXENt6gxQjCMzsDEdSzbIQCLcBGAs/s640/degradados-03.jpg" width="640" /></a><br />  <br /><br />  <br /><h2><a href="https://dribbble.com/shots/5249168-D25-Video-Production/attachments/1139193" target="_blank">D25/Video Production</a></h2><br /><div style="margin-bottom: 18.75pt; vertical-align: baseline;"><span style="color: #444444; font-family: &quot;inherit&quot;,serif; font-size: 12.0pt; letter-spacing: .4pt; mso-bidi-font-family: &quot;Times New Roman&quot;; mso-fareast-font-family: &quot;Times New Roman&quot;;">&nbsp;<a href="https://4.bp.blogspot.com/-VTi_hL91JFU/XKEhuxh2d4I/AAAAAAAAlbE/Hs_anvjIEN8sC7tqnVBxTa-xD6kGFTCbgCLcBGAs/s1600/degradados-04.jpg" imageanchor="1" style="-webkit-text-stroke-width: 0px; color: #0066cc; font-family: &quot;inherit&quot;,serif; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: 0.53px; margin-left: 1em; margin-right: 1em; orphans: 2; text-align: center; text-decoration: underline; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><img border="0" data-original-height="510" data-original-width="850" height="384" src="https://4.bp.blogspot.com/-VTi_hL91JFU/XKEhuxh2d4I/AAAAAAAAlbE/Hs_anvjIEN8sC7tqnVBxTa-xD6kGFTCbgCLcBGAs/s640/degradados-04.jpg" width="640" /></a></span></div><br /><div style="margin-bottom: 18.75pt; vertical-align: baseline;"><br /></div><br /><h2><a href="https://dribbble.com/shots/5492890-Landing-centexus-Full-Preview/attachments/1188282" target="_blank">Centexus Landing Page</a></h2><br />&nbsp;<a href="https://2.bp.blogspot.com/-rqTtmqEssgc/XKEhvIzeWII/AAAAAAAAlbA/1Ug2iuFmhEswIvDnHMSgcZZew3kK6byGACLcBGAs/s1600/degradados-05.jpg" imageanchor="1" style="-webkit-text-stroke-width: 0px; color: #0066cc; font-family: &quot;inherit&quot;,serif; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: 0.53px; margin-left: 1em; margin-right: 1em; orphans: 2; text-align: center; text-decoration: underline; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><img border="0" data-original-height="510" data-original-width="850" height="384" src="https://2.bp.blogspot.com/-rqTtmqEssgc/XKEhvIzeWII/AAAAAAAAlbA/1Ug2iuFmhEswIvDnHMSgcZZew3kK6byGACLcBGAs/s640/degradados-05.jpg" width="640" /></a><br />  <br /><br />  <br /><h2><a href="https://www.behance.net/gallery/74991069/Ninety-Nine-Seconds-Game-Prototype" target="_blank">Ninety Nine Seconds Game Prototype</a></h2><br /><br />  <br /><div style="margin-bottom: 18.75pt; vertical-align: baseline;"><span style="color: #444444; font-family: &quot;inherit&quot;,serif; font-size: 12.0pt; letter-spacing: .4pt; mso-bidi-font-family: &quot;Times New Roman&quot;; mso-fareast-font-family: &quot;Times New Roman&quot;;">&nbsp;<a href="https://1.bp.blogspot.com/-yKmJWVssJfY/XKEhv3nIFII/AAAAAAAAlbI/PKrom20WoIcnxT2qcDseynpTaw4ZlDpWQCLcBGAs/s1600/degradados-06.jpg" imageanchor="1" style="-webkit-text-stroke-width: 0px; color: #0066cc; font-family: &quot;inherit&quot;,serif; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: 0.53px; margin-left: 1em; margin-right: 1em; orphans: 2; text-align: center; text-decoration: underline; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><img border="0" data-original-height="510" data-original-width="850" height="384" src="https://1.bp.blogspot.com/-yKmJWVssJfY/XKEhv3nIFII/AAAAAAAAlbI/PKrom20WoIcnxT2qcDseynpTaw4ZlDpWQCLcBGAs/s640/degradados-06.jpg" width="640" /></a></span></div><br /><h2><a href="https://dribbble.com/shots/5475627-DIY-Course-Landing-Page/attachments/1184864" target="_blank">DIY Course Landing Page</a></h2><br /><div style="margin-bottom: 18.75pt; vertical-align: baseline;"><span style="color: #444444; font-family: &quot;inherit&quot;,serif; font-size: 12.0pt; letter-spacing: .4pt; mso-bidi-font-family: &quot;Times New Roman&quot;; mso-fareast-font-family: &quot;Times New Roman&quot;;">&nbsp;<a href="https://3.bp.blogspot.com/-fZdQfxcavm0/XKEhwEJFGQI/AAAAAAAAlbM/SgBo3tyR0FQSWHMATB31NhdiBChedem9wCLcBGAs/s1600/degradados-07.jpg" imageanchor="1" style="-webkit-text-stroke-width: 0px; color: #0066cc; font-family: &quot;inherit&quot;,serif; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: 0.53px; margin-left: 1em; margin-right: 1em; orphans: 2; text-align: center; text-decoration: underline; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><img border="0" data-original-height="510" data-original-width="850" height="384" src="https://3.bp.blogspot.com/-fZdQfxcavm0/XKEhwEJFGQI/AAAAAAAAlbM/SgBo3tyR0FQSWHMATB31NhdiBChedem9wCLcBGAs/s640/degradados-07.jpg" width="640" /></a></span></div><br /><div style="margin-bottom: 18.75pt; vertical-align: baseline;"><br /></div><br /><h2><a href="https://dribbble.com/shots/5374044-Natoni-Landing-Page" target="_blank">Natoni Landing Page</a></h2><br />&nbsp;<a href="https://4.bp.blogspot.com/-Xi06uREU4po/XKEhwei_WHI/AAAAAAAAlbQ/kx7Nh5hxVp8EniOdaTGJRIULUjUGC_b1ACLcBGAs/s1600/degradados-08.jpg" imageanchor="1" style="-webkit-text-stroke-width: 0px; color: #0066cc; font-family: &quot;inherit&quot;,serif; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: 0.53px; margin-left: 1em; margin-right: 1em; orphans: 2; text-align: center; text-decoration: underline; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><img border="0" data-original-height="510" data-original-width="850" height="384" src="https://4.bp.blogspot.com/-Xi06uREU4po/XKEhwei_WHI/AAAAAAAAlbQ/kx7Nh5hxVp8EniOdaTGJRIULUjUGC_b1ACLcBGAs/s640/degradados-08.jpg" width="640" /></a><br />  <br /><div style="margin-bottom: 18.75pt; vertical-align: baseline;"><br /></div><br /><h2><a href="https://dribbble.com/shots/3087035-Bitframemedia-com-Logo" target="_blank">Bitframemedia Logo</a></h2><br /><div style="margin-bottom: 18.75pt; vertical-align: baseline;"><span style="color: #444444; font-family: &quot;inherit&quot;,serif; font-size: 12.0pt; letter-spacing: .4pt; mso-bidi-font-family: &quot;Times New Roman&quot;; mso-fareast-font-family: &quot;Times New Roman&quot;;">&nbsp;<a href="https://1.bp.blogspot.com/-_uHQgeVxWDk/XKEhwfl2U0I/AAAAAAAAlbU/2NNhHCORDG09CDgpsp2HWPp__O8PVicBQCLcBGAs/s1600/degradados-09.jpg" imageanchor="1" style="-webkit-text-stroke-width: 0px; color: #0066cc; font-family: &quot;inherit&quot;,serif; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: 0.53px; margin-left: 1em; margin-right: 1em; orphans: 2; text-align: center; text-decoration: underline; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><img border="0" data-original-height="510" data-original-width="850" height="384" src="https://1.bp.blogspot.com/-_uHQgeVxWDk/XKEhwfl2U0I/AAAAAAAAlbU/2NNhHCORDG09CDgpsp2HWPp__O8PVicBQCLcBGAs/s640/degradados-09.jpg" width="640" /></a></span></div><br /><div style="margin-bottom: 18.75pt; vertical-align: baseline;"><br /></div><br /><h2><a href="https://dribbble.com/shots/3955245--TinyMind-landing-page/attachments/903372" target="_blank">TinyMind Landing Page</a></h2><br /><div style="margin-bottom: 18.75pt; vertical-align: baseline;"><span style="color: #444444; font-family: &quot;inherit&quot;,serif; font-size: 12.0pt; letter-spacing: .4pt; mso-bidi-font-family: &quot;Times New Roman&quot;; mso-fareast-font-family: &quot;Times New Roman&quot;;">&nbsp;<a href="https://1.bp.blogspot.com/-FVgbPLUwM-c/XKEhwbsbIVI/AAAAAAAAlbY/AZzUcY2gXB8-e_daAKFiCFUUbkM3u-EzACLcBGAs/s1600/degradados-10.jpg" imageanchor="1" style="-webkit-text-stroke-width: 0px; color: #0066cc; font-family: &quot;inherit&quot;,serif; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: 0.53px; margin-left: 1em; margin-right: 1em; orphans: 2; text-align: center; text-decoration: underline; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><img border="0" data-original-height="510" data-original-width="850" height="384" src="https://1.bp.blogspot.com/-FVgbPLUwM-c/XKEhwbsbIVI/AAAAAAAAlbY/AZzUcY2gXB8-e_daAKFiCFUUbkM3u-EzACLcBGAs/s640/degradados-10.jpg" width="640" /></a></span></div><br /><div style="margin-bottom: 18.75pt; vertical-align: baseline;"><br /></div><br /><h2><a href="https://dribbble.com/shots/4046664-Mindfulness-App-Onboarding-Screens/attachments/927437" target="_blank">Mindfulness App Onboarding Screens</a></h2><div><a href="https://1.bp.blogspot.com/-Pi46Y3RFCpA/XKEhwzMe_EI/AAAAAAAAlbc/_Eq-c-PEVRUycNgm3H-W5Zh5udb1sRqTgCLcBGAs/s1600/degradados-11.jpg" imageanchor="1" style="-webkit-text-stroke-width: 0px; color: #0066cc; font-family: &quot;inherit&quot;,serif; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: 0.53px; margin-left: 1em; margin-right: 1em; orphans: 2; text-align: center; text-decoration: underline; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><img border="0" data-original-height="510" data-original-width="850" height="384" src="https://1.bp.blogspot.com/-Pi46Y3RFCpA/XKEhwzMe_EI/AAAAAAAAlbc/_Eq-c-PEVRUycNgm3H-W5Zh5udb1sRqTgCLcBGAs/s640/degradados-11.jpg" width="640" /></a><b></b><i></i><u></u><sub></sub><sup></sup><strike></strike></div></span><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=OhDVnMGp4b0:OxLJ9jsRkhk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=OhDVnMGp4b0:OxLJ9jsRkhk:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=OhDVnMGp4b0:OxLJ9jsRkhk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=OhDVnMGp4b0:OxLJ9jsRkhk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=OhDVnMGp4b0:OxLJ9jsRkhk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=OhDVnMGp4b0:OxLJ9jsRkhk:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=OhDVnMGp4b0:OxLJ9jsRkhk:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=OhDVnMGp4b0:OxLJ9jsRkhk:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=OhDVnMGp4b0:OxLJ9jsRkhk:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=OhDVnMGp4b0:OxLJ9jsRkhk:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=OhDVnMGp4b0:OxLJ9jsRkhk:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=OhDVnMGp4b0:OxLJ9jsRkhk:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=OhDVnMGp4b0:OxLJ9jsRkhk:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=OhDVnMGp4b0:OxLJ9jsRkhk:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/OhDVnMGp4b0" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://2.bp.blogspot.com/-bA5Y5yaGw1U/XKEdQACm9ZI/AAAAAAAAlao/I3fRDmMGEiU0nXkbNC6ZR9RAmRKSNoWTgCLcBGAs/s640/como-vender-proyectos.jpg" alt="Cómo vender proyctos como freelancer">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cómo vender proyctos como freelancer</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">02 04 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-bA5Y5yaGw1U/XKEdQACm9ZI/AAAAAAAAlao/I3fRDmMGEiU0nXkbNC6ZR9RAmRKSNoWTgCLcBGAs/s1600/como-vender-proyectos.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Cómo vender proyctos como freelancer" border="0" data-original-height="710" data-original-width="1279" height="354" src="https://2.bp.blogspot.com/-bA5Y5yaGw1U/XKEdQACm9ZI/AAAAAAAAlao/I3fRDmMGEiU0nXkbNC6ZR9RAmRKSNoWTgCLcBGAs/s640/como-vender-proyectos.jpg" title="Cómo vender proyctos como freelancer" width="640" /></a></div><span lang="ES-MX" style="mso-ansi-language: ES-MX;"><br /></span> <span lang="ES-MX" style="mso-ansi-language: ES-MX;">Para aquellos que empiezan su carrera de freelancer y no saben cómo iniciar su proceso de venta de proyectos, este es el video perfecto para ustedes. No es que sea un arte, pero sí se necesita cierta habilidad para poder vender nuestros proyectos, empezando con buscar a clientes potenciales.</span><br /><span lang="ES-MX" style="mso-ansi-language: ES-MX;">Una vez que sepas a qué tipo de clientes les vas a vender, necesitas saber tu modelo de negocios. En este video les comparto uno de ellos, que es de los más populares actualmente, que es el modelo de servicios. Si te quieres iniciar a vender proyectos la mejor forma es con un esquema de servicios, en donde distribuyes tus costos a lo largo de suscripciones con tus clientes, de tal forma que en vez de que te paguen una sola vez, te paguen constantemente para que tu les sigas ayudando de forma indefinida, o al menos hasta que ya no necesite tus servicios.</span><br /><span lang="ES-MX" style="mso-ansi-language: ES-MX;">El modelo de suscripciones es usado por muchísimos servicios como Netflix o Spotify, y te permite a ti como desarrollador tener presencia con tus clientes de forma constante, a través de seguimiento de proyectos, de soporte o de otros beneficios que harán que te paguen también una cantidad pequeña mensualmente, y que al final para ti es un ingreso que solamente se distribuye a lo largo del tiempo.</span><br /><span lang="ES-MX" style="mso-ansi-language: ES-MX;"><br /><iframe width="1278" height="719" src="https://www.youtube.com/embed/oJ1cjBh-Qog" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><br /></span><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=VQjEFC8c7Us:0oa_o4E01sU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=VQjEFC8c7Us:0oa_o4E01sU:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=VQjEFC8c7Us:0oa_o4E01sU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=VQjEFC8c7Us:0oa_o4E01sU:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=VQjEFC8c7Us:0oa_o4E01sU:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=VQjEFC8c7Us:0oa_o4E01sU:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=VQjEFC8c7Us:0oa_o4E01sU:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=VQjEFC8c7Us:0oa_o4E01sU:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=VQjEFC8c7Us:0oa_o4E01sU:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=VQjEFC8c7Us:0oa_o4E01sU:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=VQjEFC8c7Us:0oa_o4E01sU:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=VQjEFC8c7Us:0oa_o4E01sU:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=VQjEFC8c7Us:0oa_o4E01sU:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=VQjEFC8c7Us:0oa_o4E01sU:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/VQjEFC8c7Us" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/127-end-of-the-line.png" alt="End of the line">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">End of the line</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">02 04 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/127-end-of-the-line.png" alt="End of the line" title="When you just know you ca do a better job than the guy before." /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://3.bp.blogspot.com/-Ouln6vefoFg/XKERuGZm1oI/AAAAAAAAlaQ/bAw5ieluSS4GHmc1tbqnu1vlV0oAINBbQCLcBGAs/s640/1_Fx02PelDSr5cU6bqA5-0UQ.jpg" alt="3 habilidades importantes que necesitas como desarrollador">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">3 habilidades importantes que necesitas como desarrollador</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">01 04 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div style="text-align: center;">&nbsp;<a href="https://3.bp.blogspot.com/-Ouln6vefoFg/XKERuGZm1oI/AAAAAAAAlaQ/bAw5ieluSS4GHmc1tbqnu1vlV0oAINBbQCLcBGAs/s1600/1_Fx02PelDSr5cU6bqA5-0UQ.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="531" data-original-width="800" height="424" src="https://3.bp.blogspot.com/-Ouln6vefoFg/XKERuGZm1oI/AAAAAAAAlaQ/bAw5ieluSS4GHmc1tbqnu1vlV0oAINBbQCLcBGAs/s640/1_Fx02PelDSr5cU6bqA5-0UQ.jpg" width="640" /></a></div><span lang="ES-MX" style="mso-ansi-language: ES-MX;"><br /></span><span lang="ES-MX" style="mso-ansi-language: ES-MX;">La escuela nos enseña ciertas habilidades y tecnologías que nos deben servir en nuestra vida, sin embargo, queda en nosotros seguir el aprendizaje necesario para seguir conociendo lo más nuevo en nuestro entorno. Para un estudiante de ingeniería que desea tener un trabajo como desarrollador o ingeniero en sistemas la cosa no es diferente. Hay habilidades y tecnologías que no aprenderá en la escuela, y es importante desarrollarlas y aprenderlas, porque van a servir de una forma u otra.</span><br /><br /><span lang="ES-MX" style="mso-ansi-language: ES-MX;">Vamos a aprender cuáles son esas habilidades que no nos enseñan en la escuela, pero de todas formas necesitamos aprender.</span><br /><span lang="ES-MX" style="mso-ansi-language: ES-MX;"></span><br /><a name='more'></a><span lang="ES-MX" style="mso-ansi-language: ES-MX;"><br /></span><br /><br /><h2>Git</h2><div style="text-align: center;"><a href="https://1.bp.blogspot.com/-nDnj9iYVs8E/XKERt5LBQ9I/AAAAAAAAlaM/-7gY-IniDEoLxvj0P6X_A34MD-lPVVXmQCLcBGAs/s1600/0_VHgxUC9DIEzgJ2s7.png" imageanchor="1" style="-webkit-text-stroke-width: 0px; color: #0066cc; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-left: 1em; margin-right: 1em; orphans: 2; text-align: center; text-decoration: underline; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><img border="0" data-original-height="665" data-original-width="800" height="266" src="https://1.bp.blogspot.com/-nDnj9iYVs8E/XKERt5LBQ9I/AAAAAAAAlaM/-7gY-IniDEoLxvj0P6X_A34MD-lPVVXmQCLcBGAs/s320/0_VHgxUC9DIEzgJ2s7.png" width="320" /></a><b></b><i></i><u></u><sub></sub><sup></sup><strike></strike></div><b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br /><span lang="ES-MX" style="mso-ansi-language: ES-MX;">Git es una de las tecnologías que deberías conocer sin importar si te la enseñan o no en la escuela. Desarrollar la habilidad de versionar tu código, hacer modificaciones y darle un mantenimiento adecuado por medio de branches es una habilidad que, aunque pareciera sorprendente, no todos los desarrolladores saber hacer. Conocer Git te va a dar no una ventaja, sino te va a dar lo indispensable que se necesita en cualquier rol de desarrollo y que no te dicen que lo necesitas hasta que lo tienes que ocupar.</span><br /><br /><h2><span lang="ES-MX" style="mso-ansi-language: ES-MX;">Comunicación</span></h2><div style="text-align: center;"><span lang="ES-MX" style="mso-ansi-language: ES-MX;"><a href="https://3.bp.blogspot.com/-IIY1s_VonUo/XKERt1Dt0EI/AAAAAAAAlaI/Jq0A_Bl97nIXn3KYnM5BGLTTFPNXSo2rACLcBGAs/s1600/0_69KR6RhuQeo_LdEM.jpg" imageanchor="1" style="-webkit-text-stroke-width: 0px; color: #0066cc; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-left: 1em; margin-right: 1em; orphans: 2; text-align: center; text-decoration: underline; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><img border="0" data-original-height="667" data-original-width="1000" height="426" src="https://3.bp.blogspot.com/-IIY1s_VonUo/XKERt1Dt0EI/AAAAAAAAlaI/Jq0A_Bl97nIXn3KYnM5BGLTTFPNXSo2rACLcBGAs/s640/0_69KR6RhuQeo_LdEM.jpg" width="640" /></a><b></b><i></i><u></u><sub></sub><sup></sup><strike></strike></span></div><b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br /><span lang="ES-MX" style="mso-ansi-language: ES-MX;">Aprender a comunicarse es una habilidad que no nos enseñan en ningún lado. Cada persona, organización y yo diría que hasta región donde estemos tiene su propia forma de comunicarse, pero es indispensable saber hacerlo para poder obtener resultados. Un problema común de comunicación es saber pedir las cosas, quizá que algún colaborador nos ayude con nuestro código. Algo tan simple como eso puede ser interpretado como que no tienes los conocimientos, o tienes flojera, o quieres que alguien más haga tu trabajo.</span><br /><br /><span lang="ES-MX" style="mso-ansi-language: ES-MX;">Un ejemplo de comunicación efectiva para pedir apoyo en el ejemplo anterior es que se maneje un mensaje de contexto. Si en vez de ir directo a pedir apoyo, se explica todo lo que ya hiciste para llegar al punto donde no puedes avanzar, quizá la otra persona en vez de negarte el apoyo pueda entender que no estás pidiendo ayuda por flojo, sino porque ya recorriste una serie de pasos y nada funcionó. Esto le da un incentivo de poder serte útil y a la vez no crea que está haciendo tu trabajo.</span><br /><br /><h2><span lang="ES-MX" style="mso-ansi-language: ES-MX;">Escribir</span></h2><div style="text-align: center;"><span lang="ES-MX" style="mso-ansi-language: ES-MX;"><a href="https://1.bp.blogspot.com/-5cTmGXb8AWM/XKERttjxqfI/AAAAAAAAlaE/Zzqlr5BiT0Eh3tdfoZsgVy7KgGM-0Lt5wCLcBGAs/s1600/0_9om4XqZe7QBtANDL.jpg" imageanchor="1" style="-webkit-text-stroke-width: 0px; color: #0066cc; font-family: Times New Roman; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; margin-left: 1em; margin-right: 1em; orphans: 2; text-align: center; text-decoration: underline; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px;"><img border="0" data-original-height="667" data-original-width="1000" height="426" src="https://1.bp.blogspot.com/-5cTmGXb8AWM/XKERttjxqfI/AAAAAAAAlaE/Zzqlr5BiT0Eh3tdfoZsgVy7KgGM-0Lt5wCLcBGAs/s640/0_9om4XqZe7QBtANDL.jpg" width="640" /></a><b></b><i></i><u></u><sub></sub><sup></sup><strike></strike></span></div><b></b><i></i><u></u><sub></sub><sup></sup><strike></strike><br /><span lang="ES-MX" style="mso-ansi-language: ES-MX;">Para muchos escribir es plasmar sus pensamientos en un correo o una carta, y la realidad es que no. Escribir correctamente tiene que ver con saber transmitir un mensaje a un grupo de personas, y que esas personas tengan el mismo significado al leer tu mensaje. No todos podemos tener las estructuras gramaticales para elaborar textos complejos, pero sí deberíamos tener la capacidad de redactar un mensaje de tal forma que la intención que tenga se pueda transmitir, y nosotros obtengamos una respuesta.</span><br /><br /><span lang="ES-MX" style="mso-ansi-language: ES-MX;">A nivel de código es importante saber documentar nuestros proyectos, saber documentar errores y poder pedir apoyo usando la técnica de comunicación que mencioné en el punto anterior. Dar mensajes claros en pocas palabras siempre va a ser el objetivo al momento de escribir, ya que la gente no perderá tiempo leyendo un texto sin saber qué es lo que estás queriendo decir o pedir.</span><br /><br /><br /><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=IUCXtkVF9TI:A4XITh2FtI4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=IUCXtkVF9TI:A4XITh2FtI4:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=IUCXtkVF9TI:A4XITh2FtI4:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=IUCXtkVF9TI:A4XITh2FtI4:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=IUCXtkVF9TI:A4XITh2FtI4:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=IUCXtkVF9TI:A4XITh2FtI4:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=IUCXtkVF9TI:A4XITh2FtI4:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=IUCXtkVF9TI:A4XITh2FtI4:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=IUCXtkVF9TI:A4XITh2FtI4:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=IUCXtkVF9TI:A4XITh2FtI4:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=IUCXtkVF9TI:A4XITh2FtI4:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=IUCXtkVF9TI:A4XITh2FtI4:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=IUCXtkVF9TI:A4XITh2FtI4:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=IUCXtkVF9TI:A4XITh2FtI4:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/IUCXtkVF9TI" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Codecademy vs. The BBC Micro</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Two-Bit History</a> <span class="article__date">31 03 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        In the late 1970s, the computer, which for decades had been a mysterious, hulking machine that only did the bidding of corporate overlords, suddenly became something the average person could buy and take home. An enthusiastic minority saw how great this was and rushed to get a computer of their own. For many more people, the arrival of the microcomputer triggered helpless anxiety about the future. An ad from a magazine at the time promised that a home computer would “give your child an unfair advantage in school.” It showed a boy in a smart blazer and tie eagerly raising his hand to answer a question, while behind him his dim-witted classmates look on sullenly. The ad and others like it implied that the world was changing quickly and, if you did not immediately learn how to use one of these intimidating new devices, you and your family would be left behind.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Como hacer una redirección en Javascript</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Óscar Lijó</a> <span class="article__date">27 03 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Para hacer una redirección en Javascript tenemos diferentes métodos. Y prácticamente todos hacen lo mismo, pero hay matices. Veamos las dos maneras clásicas de hacerlo. La primera es usando window.location.replace(...) y es la manera más correcta de hacerlo. La razón es sencilla estamos hablando de hacer una redirección en Javascript, no de hacer una navegación.&#8230;</p>
<p>La entrada <a rel="nofollow" href="https://www.oscarlijo.com/blog/como-hacer-una-redireccion-en-javascript/">Como hacer una redirección en Javascript</a> aparece primero en <a rel="nofollow" href="https://www.oscarlijo.com/blog">Óscar Lijó</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/126-possible-code-contents.png" alt="Possible Code Contents">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Possible Code Contents</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">26 03 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/126-possible-code-contents.png" alt="Possible Code Contents" title="Once you see it - it will bother you for the rest of your day." /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.atareao.es/wp-content/uploads/2019/03/un-bot-con-Pyhton-1024x683.jpg" alt="El Atareao: Un bot en Python para Telegram (y en una sola l&amp;#237;nea)">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">El Atareao: Un bot en Python para Telegram (y en una sola l&amp;#237;nea)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">22 03 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Hace unos pocos d&#237;as Angel, en <strong>uGeek</strong>, public&#243; un interesante art&#237;culo sobre como <a href="https://ugeek.github.io/blog/post/2019-03-14-crea-un-bot-de-telegram-con-bash-y-una-sola-linea-de-terminal.html">crear un bot de telegram con Bash</a>. Igualmente, por mi parte, la semana anterior hab&#237;a publicado un art&#237;culo sobre como pod&#237;as <a href="https://www.atareao.es/tutorial/crea-tu-propio-bot-para-telegram/un-bot-de-telegram-con-php/">crear tu propio bot con PHP</a>. En este contexto y en el <a href="https://t.me/uGeekPodcast">grupo de telegram de uGeek</a>, coment&#233; que se pod&#237;a hacer de forma similar, <em>un bot en Python para Telegram</em>. Fue justo en ese momento, donde Pedro, <a href="https://twitter.com/mosqueteroweb">MosqueteroWeb</a>, nos propuso un duelo.</p>



<p>Y es que no lo puedo evitar. Ya lo coment&#233; en el cap&#237;tulo n&#250;mero 1 del podcast titulado <a href="https://www.atareao.es/podcast/sobre-el-peligro-de-las-apuestas-podcast/">el peligro de las apuestas</a>. Y es que no puedo resistirme a un reto. Y esta es la raz&#243;n de este nuevo art&#237;culo, que ir&#225; encasillado en el tutorial sobre bots para Telegram.</p>



<p>En este nuevo cap&#237;tulo del tutorial, te explicar&#233; <strong>como puedes utilizar Python para enviar mensajes, im&#225;genes y audios</strong>, de forma relativamente sencilla a un canal o grupo de Telegram. Eso si, el objetivo de este cap&#237;tulo es hacerlo sin ninguna librer&#237;a extra.</p>



<figure class="wp-block-image"><a class="highslide" href="https://www.atareao.es/wp-content/uploads/2019/03/un-bot-con-Pyhton.jpg"><img alt="Un bot de Telegram en Python (y en una sola l&#237;nea)" class="wp-image-13952" src="https://www.atareao.es/wp-content/uploads/2019/03/un-bot-con-Pyhton-1024x683.jpg" /></a></figure>



<span id="more-13951"></span>



<h2>Un bot en Python para Telegram</h2>



<p>Tal y como te he comentado en la introducci&#243;n, el objetivo de este nuevo cap&#237;tulo del tutorial es implementar un bot en Python, <strong>sin necesidad de utilizar ninguna librer&#237;a externa</strong>. Me refiero claramente a una librer&#237;a cuyo objetivo sea facilitar el acceso a la API de bots de Telegram. Comento este punto, porque si que utilizar&#233; una librer&#237;a para realizar las llamadas <em>GET</em> y <em>POST</em>, me refiero a <a href="http://docs.python-requests.org/en/master/">Requests</a>.</p>



<p>Por otro lado, lo que ver&#225;s en este cap&#237;tulo no es un bot en si. Se trata de llamadas a la API. <strong>Implementar un bot</strong>, considero que es <strong>algo mas</strong> complejo <strong>que una simple llamada</strong>. Un bot, deber&#237;a permitir interactuar con el usuario. Es decir, el bot debe ser capaz de responder ante las acciones del usuario. Incluso, implementar botones, para facilitar esa interrelaci&#243;n entre bot y usuario.</p>



<p>Ahora bien, esto &#250;ltimo, esta interrelaci&#243;n no es mas que seguir el cap&#237;tulo 10 de este tutorial en el que te explico lo relacionado con <a href="https://www.atareao.es/tutorial/crea-tu-propio-bot-para-telegram/flask-y-nginx-webhooks-y-telegram/">bots, Flask y Nginx</a>.</p>



<h3>Requests</h3>



<p><strong>Requests</strong> es una librer&#237;a para HTTP, liberada bajo licencia Apache2, que tal y como la definen sus propios desarrolladores, <em>escrita en Python para seres humanos</em>. La ventaja de utilizar esta librer&#237;a es que evita las complicaciones de trabajar con HTTP, haciendo que una llamada sea muy, pero que muy, sencilla.</p>



<p>Esta librer&#237;a est&#225; disponible tanto para las versiones 2 y 3 de Python. Sin embargo, lo recomendable es utilizar Python 3, y en este sentido, utilizar&#233; esta versi&#243;n.</p>



<p>Instalar <code>Requests</code> para Python 3 en Ubuntu, y en derivadas de Debian, es tan sencillo como ejecutar,</p>



<pre class="wp-block-code"><code>sudo apt install python3-requests</code></pre>



<p>Aunque dependiendo de lo que quieras hacer, es posible que lo recomendable sea crearte un <a href="https://www.atareao.es/como/entorno-virtual-en-python-como-y-para-que/">entorno virtual en Python</a>, lo que te permitir&#225; olvidarte del sistema en el que est&#233;s trabajando.</p>



<h3>Pasos previos</h3>



<p>Con independencia del lenguaje de programaci&#243;n o si utilizas librer&#237;a o no, es necesario crear el bot. Con este objetivo, Telegram dispone de un bot para crer bots. Se trata de <strong>BotFather</strong>. Te recomiendo que leas el primer cap&#237;tulo del tutorial sobre <a href="https://www.atareao.es/tutorial/crea-tu-propio-bot-para-telegram/">crear tu propio bot para Telegram</a>.</p>



<h3>Enviar mensajes a Telegram con tu bot en Python</h3>



<p>Una vez te he comentado los puntos de partida, y ya has creado tu bot con BotFather, ya puedes enviar tu mensaje. En python es tan sencillo como crear un archivo de texto, que puede ser <code>mensaje.py</code>, con el siguiente contenido,</p>



<pre class="wp-block-code"><code>#!/usr/bin/env python3
import requests

requests.post('https://api.telegram.org/bot&lt;TOKEN>/sendMessage',
              data={'chat_id': '&lt;CHAT_ID>', 'text': '&lt;TEXTO>'})</code></pre>



<p>Donde,</p>



<ul><li><code>&lt;TOKEN&gt;</code> token que te ha propocionado BotFather.</li><li><code>&lt;CHAT_ID&gt;</code> identificador del canal o grupo donde env&#237;as el mensaje.</li><li><code>&lt;TEXTO&gt;</code> texto del mensaje que quieres enviar.</li></ul>



<p>Como ves, <strong>el compromiso lo he cumplido</strong>, en una l&#237;nea he conseguido enviar un mensaje sin necesidad de librer&#237;as externas, a excepci&#243;n de <code>Requests</code>. Si, es <strong>realmente sencillo</strong>.</p>



<p>Si quieres ver la respuesta de Telegram, hay que modificar ligeramente el <code>script</code>, tal y como te indico a continuaci&#243;n,</p>



<pre class="wp-block-code"><code>#!/usr/bin/env python3
import requests

r = requests.post('https://api.telegram.org/bot&lt;TOKEN>/sendMessage',
              data={'chat_id': '&lt;CHAT_ID>', 'text': '&lt;TEXTO>'})
print(r.text)</code></pre>



<p>Dado que lo que nos devuelve es un <code>json</code>, si quieres aprovechar las facilidades que te da Python, puedes utilizar directamente el m&#243;dulo <code>json</code> para conocer si la respuesta es correcta. As&#237;, de nuevo, modificamos el script, a&#241;adiendo estas matizaciones,</p>



<pre class="wp-block-code"><code>#!/usr/bin/env python3
import requests
import json

r = requests.post('https://api.telegram.org/bot&lt;TOKEN>/sendMessage',
                  data={'chat_id': '&lt;CHAT_ID>', 'text': '&lt;TEXTO>'})
data = json.loads(r.text)
print(data['ok'])</code></pre>



<h4>Par&#225;metros opcionales</h4>



<p>Adem&#225;s del par&#225;metro <code>text</code> tambi&#233;n se pueden enviar algunos par&#225;metros opcionales que te van a permitir adaptar el mensaje a tus necesidades. Estos par&#225;metros, comunes a otros m&#233;todos, son los siguientes,</p>



<ul><li><code>parse_mode</code> se refiere al formato del mensaje. Aqu&#237; tienes dos opciones o <code>Markdown</code> o <code>HTML</code>. Mi consejo es que utilices <code>HTML</code> porque en mi caso he tenido algunos problemas con el gui&#243;n bajo del markdown.</li><li><code>disable_web_page_preview</code>. Cuando se ponen enlaces en los mensajes, Telegram por defecto te muestra una previsualizaci&#243;n de la p&#225;gina correspondiente. Con esta opci&#243;n puedes habilitar o deshabilitar esa previsualizaci&#243;n.</li><li><code>disable_notification</code>. Cada vez que recibes un mensaje en un grupo un canal, como bien sabes, recibes una notificaci&#243;n, salvo que lo hayas limitado temporal o definitivamente. Sin embargo, tu puedes con este par&#225;metro que no se envie notificaci&#243;n.</li><li><code>reply_to_message_id</code>. Esto par&#225;metro lo puedes utilizar para el caso de que est&#233;s respondiendo a otro mensaje. Por ejemplo, te puede ser de utilidad para una cadena de mensajes.</li><li><code>reply_markup</code>. En esta opci&#243;n puedes introducir par&#225;metros adicionales, como puede ser un teclado en l&#237;nea. Esto lo veremos en un cap&#237;tulo posterior.</li></ul>



<h4>Pasando argumentos</h4>



<p>Esta soluci&#243;n <strong>para enviar siempre el mismo mensaje</strong> no est&#225; mal. Sin embargo, si lo que queremos es enviar diferentes mensajes a diferentes canales, lo suyo es que pasemos, tanto el identificador del canal o grupo, como el mensaje al script. Igualmente esto es muy sencillo. Tan solo tenemos que introducir algunas ligeras modificaciones en nuestro script.</p>



<pre class="wp-block-code"><code>#!/usr/bin/env python3
import requests
import sys

if __name__ == '__main__':
    if len(sys.argv) > 2:
        requests.post('https://api.telegram.org/bot&lt;TOKEN>/sendMessage',
                      data={'chat_id': sys.argv[1], 'text': sys.argv[2]})</code></pre>



<p>Como primer par&#225;metro pasaremos el <strong>identificador</strong> del chat, mientras que como segundo par&#225;metro el texto. En este caso el texto debe ir entre comillas.</p>



<h3>Enviar im&#225;genes a Telegram con tu bot en Python</h3>



<p>Una vez que ya has visto lo sencillo que es enviar un mensaje de texto utilizando Python, vamos a algo ligeramente mas complicado. Vamos a <strong>enviar una imagen</strong>. En este caso tenemos dos opciones, o bien, enviamos la <em>url</em> de la imagen, en el caso de que ya est&#233; en subida a alg&#250;n servidor, o como segunda opci&#243;n la subimos. Esto, con <code>requests</code> es realmente sencillo.</p>



<ul><li>Primer caso. Utilizamos una imagen disponible en alg&#250;n alojamiento web,</li></ul>



<pre class="wp-block-code"><code>requests.post('https://api.telegram.org/bot&lt;TOKEN>/sendPhoto',
              data={'chat_id': &lt;CHAT_ID>, 'photo': &lt;PHOTO_URL>, 'caption': &lt;TEXT>})</code></pre>



<p>En este caso debes indicar la <strong>ruta donde est&#225; alojada la imagen,</strong> as&#237; como el t&#237;tulo o un texto que acompa&#241;e la imagen. Esto &#250;ltimo es opcional, si no le quieres a&#241;adir un texto, simplemente, no pongas ese &#250;ltimo par&#225;metro.</p>



<ul><li>Segundo caso. Subimos nuestra propia imagen,</li></ul>



<pre class="wp-block-code"><code>requests.post('https://api.telegram.org/bot&lt;TOKEN>/sendPhoto',
              files={'photo': (&lt;ARCHIVO>, open(&lt;ARCHIVO>, 'rb'))},
              data={'chat_id': &lt;CHAT_ID>, 'caption': &lt;TEXT>})</code></pre>



<p>Aqu&#237; <code>&lt;ARCHIVO&gt;</code> se corresponde con la ruta donde se encuentra el archivo de la imagen que queremos subir a Telegram.</p>



<p><strong>&#191;F&#225;cil verdad?</strong></p>



<h3>Enviar audio y voz a Telegram con tu bot en Python</h3>



<p>Una vez hemos superado las opciones para enviar mensajes e im&#225;genes, vamos al siguiente paso, de este art&#237;culo, que es <strong>enviar audio</strong>.</p>



<p>En este caso, tambi&#233;n tienes <strong>dos opciones</strong> para enviar audio. La primera de las opciones es enviarla <strong>como un mensaje de voz</strong>, mientras que la segunda es como un <strong>archivo</strong> de audio. As&#237;, en el primer caso, como mensaje de voz ser&#237;a tal y como ves a continuaci&#243;n,</p>



<pre class="wp-block-code"><code>requests.post('https://api.telegram.org/bot&lt;TOKEN>/sendVoice',
              files={'voice': (&lt;ARCHIVO>, open(&lt;ARCHIVO>, 'rb')),
                     'thumb': (&lt;ARCHIVO2>, open(&lt;ARCHIVO2>, 'rb'))},
              data={'chat_id': &lt;CHAT_ID>, 'caption': &lt;TEXT>})</code></pre>



<p>En este caso, tambi&#233;n es posible a&#241;adir un par&#225;metro extra que es la duraci&#243;n del mensaje de voz en segundos. Para esto utiliza <code>duration</code>.</p>



<p>Mientras que el segundo, como archivo de audio, ser&#225; de la siguiente forma,</p>



<pre class="wp-block-code"><code>requests.post('https://api.telegram.org/bot&lt;TOKEN>/sendAudio',
              files={'audio': (&lt;ARCHIVO>, open(&lt;ARCHIVO>, 'rb')),
                     'thumb': (&lt;ARCHIVO2>, open(&lt;ARCHIVO2>, 'rb'))},
              data={'chat_id': &lt;CHAT_ID>, 'caption': &lt;TEXT>})</code></pre>



<p>Adem&#225;s de los par&#225;metros anteriores, es posible enviar un nuevo un <strong>nuevo</strong> <strong>archivo</strong>. Este tipo de archivo es lo que se conoce como una <strong>miniatura</strong> o en ingl&#233;s <code>thumbnail</code>. Y es la t&#237;pica imagen que acompa&#241;a al mensaje de voz. Aunque lo cierto es que lo he visto en pocas ocasiones.</p>



<p>La parte de la miniatura es completamente opcional, y por tanto la puede omitir. Al igual que en otros casos, tambi&#233;n se puede utilizar un enlace a una imagen que ya est&#233; disponible desde un servidor. As&#237;, en ese caso, el m&#233;todo tendr&#237;a el siguiente aspecto,</p>



<pre class="wp-block-code"><code>requests.post('https://api.telegram.org/bot&lt;TOKEN>/sendAudio',
              files={'voice': (&lt;ARCHIVO>, open(&lt;ARCHIVO>, 'rb'))},
              data={'chat_id': &lt;CHAT_ID>, 'caption': &lt;TEXT>, 'thumb': &lt;THUMB>})</code></pre>



<p>Indicarte que las <strong>caracter&#237;sticas</strong> de las miniaturas est&#225;n fijadas. En este sentido <strong>el archivo tiene que ser en formato</strong> <code>JPEG</code> y tener un peso m&#225;ximo de 200 kB, y unas dimensiones iguales o inferiores a 90 px.</p>



<p>En ambos casos la parte del t&#237;tulo es opcional, con lo que de nuevo, la puedes omitir. Adem&#225;s es posible, a&#241;adir algunos par&#225;metros opcionales, como puede ser el formato del texto. En cualquier caso, te recomiendo una visita a la <a href="https://core.telegram.org/bots/api">documentaci&#243;n de la API de bots</a>, para tener siempre la &#250;ltima documentaci&#243;n.</p>



<h3>Enviar una video nota</h3>



<p>Desde hace recientemente poco, en referencia a la publicaci&#243;n de este cap&#237;tulo del tutorial, <strong>es posible enviar v&#237;deos desde Telegram</strong> con una duraci&#243;n inferior a un minuto. El m&#233;todo que tienes que utilizar ser&#225; el siguiente,</p>



<pre class="wp-block-code"><code>requests.post('https://api.telegram.org/bot&lt;TOKEN>/sendVideoNote',
              files={'video_note': (&lt;ARCHIVO>, open(&lt;ARCHIVO>, 'rb')),
                     'thumb': (&lt;ARCHIVO2>, open(&lt;ARCHIVO2>, 'rb'))},
              data={'chat_id': &lt;CHAT_ID>, 'caption': &lt;TEXT>,
                    'duration': &lt;DURATION>, 'length': &lt;LENGTH>})</code></pre>



<p><strong>Los &#250;nicos par&#225;metros obligatorios son el archivo de v&#237;deo y el identificador del chat</strong>. El resto de par&#225;metros son totalmente opcionales. Como ves, aqu&#237; he incluido dos nuevos. Por un lado la duraci&#243;n del v&#237;deo y la dimensi&#243;n del v&#237;deo. Este caso se corresponde con el di&#225;metro.</p>



<h3>Enviar cualquier tipo de archivo a Telegram con tu bot en Python</h3>



<p>Si en lugar de una imagen o un audio quieres enviar cualquier otro tipo de documento, existe un m&#233;todo espec&#237;fico para ello. El uso es el siguiente,</p>



<pre class="wp-block-code"><code>requests.post('https://api.telegram.org/bot&lt;TOKEN>/sendDocument',
              files={'document': (&lt;ARCHIVO>, open(&lt;ARCHIVO>, 'rb')),
                     'thumb': (&lt;ARCHIVO2>, open(&lt;ARCHIVO2>, 'rb'))},
              data={'chat_id': &lt;CHAT_ID>, 'caption': &lt;TEXT>})</code></pre>



<p>Al igual que en el caso de enviar un archivo de audio, tambi&#233;n es posible <strong>mostrar una peque&#241;a miniatura</strong> que se corresponda con el documento que estamos enviando. De nuevo, esto es completamente opcional.</p>



<h2>Conclusiones</h2>



<p>Como puedes ver, <strong>en una s&#243;la l&#237;nea de c&#243;digo, o casi</strong>, es posible enviar un mensaje utilizando los bots de Telegram. La cuesti&#243;n es que poco a poco, esto se va complicando a medida que quieres enviar otro tipo de archivos y documento. Aunque tampoco en exceso, como tu mismo has visto.</p>



<p>Dado lo extenso de los m&#233;todos del API de bots de Telegram, <strong>dejo para un nuevo cap&#237;tulo otros m&#233;todos</strong>, que seguro te ser&#225;n de utilidad. Y para un tercer cap&#237;tulo dentro de esta mini serie, el uso de teclados en l&#237;nea.</p>
<p>La entrada <a href="https://www.atareao.es/tutorial/crea-tu-propio-bot-para-telegram/bot-en-python-para-telegram/" rel="nofollow">Un bot en Python para Telegram (y en una sola l&#237;nea)</a> aparece primero en <a href="https://www.atareao.es" rel="nofollow">El atareao</a>.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Mezclar colores con CSS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Óscar Lijó</a> <span class="article__date">21 03 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Mezclar colores con CSS es un tema del que no se suele hablar mucho. Y eso que seguro que todos tenemos claros que mezclando colores obtenemos colores nuevos.Ya desde pequeños en el colegio jugábamos a mezclar colores con ceras o lápices. Luego fuimos aprendiendo que si mezclamos todos los colores de la paleta obtenemos negro&#8230;</p>
<p>La entrada <a rel="nofollow" href="https://www.oscarlijo.com/blog/mezclar-colores-con-css/">Mezclar colores con CSS</a> aparece primero en <a rel="nofollow" href="https://www.oscarlijo.com/blog">Óscar Lijó</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hypermedia REST</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Óscar Lijó</a> <span class="article__date">20 03 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Hypermedia REST es una manera de enfocar nuestras API REST. Actualmente existe un gran debate acerca cual es la mejor manera de construir una API. Entre las distintas tecnologías que existen podemos destacar SOAP y REST como las más conocidas tradicionalmente. Y posiblemente GraphQL como la especificación moderna mas prometedora. De hecho si quieres saber&#8230;</p>
<p>La entrada <a rel="nofollow" href="https://www.oscarlijo.com/blog/hypermedia-rest/">Hypermedia REST</a> aparece primero en <a rel="nofollow" href="https://www.oscarlijo.com/blog">Óscar Lijó</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/125-sprint.png" alt="Sprint">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Sprint</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">19 03 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/125-sprint.png" alt="Sprint" title="Sprint" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/media/2019/fathom-screenshot.png" alt="Stepping down from Fathom">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Stepping down from Fathom</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Danny van Kooten</a> <span class="article__date">17 03 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I have an announcement to make. Less than a year ago, Paul Jarvis and I <a href="https://dannyvankooten.com/reviving-ana-as-fathom/">started working on Fathom</a> (simple and transparent website analytics).</p>

<p>We managed to make a lot of progress during our first year and I’m more than a little proud of what Fathom is today. I’m running it on most of my sites and I’d say it’s very much a viable alternative for Google Analytics for a lot of websites already.</p>

<p><img src="/media/2019/fathom-screenshot.png" alt="Fathom screenshot" /></p>

<p>The open-source community around Fathom is very much alive and kicking. The <a href="https://github.com/usefathom/fathom">GitHub repository for Fathom</a> currently boosts over 5.000 GitHub stars and Fathom has been a <a href="https://github.com/trending/go">trending Go project</a> for pretty much every week over the last year!</p>

<p>And the <a href="https://hub.docker.com/r/usefathom/fathom/">Docker image</a> has been pulled over a million times, even though Fathom is already a single (embedded) binary that is super easy to deploy to your infrastructure of choice. There’s even a <a href="https://www.youtube.com/watch?v=KE0NKODYEAM">one-click installer if you’re on DigitalOcean</a>.</p>

<p>The software we built itself proved very effective in terms of performance. A single $5 VPS can easily handle tens of millions of pageviews per month, as proved by some of the bigger customers on Fathom’s PRO plans.</p>

<h3 id="stepping-down">Stepping down</h3>

<p>To think that Fathom would be so well received and grow so rapidly during its first year is amazing and I’m super proud to have been a part of that.</p>

<p>Have been, because going forward, I will not be actively involved with Fathom anymore. <strong>Fathom itself is not going anywhere though.</strong> Paul is now joined by <a href="https://twitter.com/JackEllis">Jack Ellis</a> with whom he will be continuing the project. Having seen them work together during the handover phase, I completely trust in their abilities to keep making Fathom better.</p>

<p>I am a little sad to leave Fathom behind but juggling its responsibilities with being a newbie dad and running <a href="https://www.mc4wp.com/">Mailchimp for WordPress</a> while also wanting to spend less time behind a computer proved way harder than anticipated.</p>

<p>At the same time, I’m stoked to see <a href="https://trello.com/b/x2aBwH2J/fathom-roadmap">their plans</a> unfold over the next few months. I’m confident they will take good care of what we managed to build over the past year.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">TIL how to interactively fix a failing test</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">12 03 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I knew it was possible, but I got to try it recently.</p>

<p>Here I run a test with <code>fiveam</code>. It fails. I tell <code>fiveam</code> to enter
the debugger on failures with</p>

<pre><code>(setf 5am:*on-error* :debug)
</code></pre>

<p>so we have an immediate feedback and we can re-run the test from where
it left off by choosing the appropriate restart.</p>

<iframe width="560" height="315" src="https://www.youtube.com/embed/KsHxgP3SRTs" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<p>Other test frameworks like <a href="https://github.com/Shinmera/parachute">Parachute</a> allow that.</p>

<p>This is one of the things that make development in Common Lisp
enjoyable and faster than with other workflows. Also, it&rsquo;s built-in,
there is no fancy editor plugin or configuration.</p>

<hr />

<p>In the debugger:</p>

<ul>
<li><code>&lt;enter&gt;</code> on a backtrace shows more of it</li>
<li><code>v</code> on a backtrace goes to the corresponding line or function.</li>
<li>more options with the menu.</li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">February 2019 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">12 03 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        This month we present the first update from our new projects, Neanderthal and Aleph. Thanks to everyone for your continued support of Clojurists Together!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to Use Grouping Sets in Django</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">09 03 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>How we cut a heavy admin dashboard response time in half with advanced SQL and some Django hackery. I recently had the pleasure of optimizing an old dashboard. The solution we came up with required some advanced SQL that Django does not support out of the box. In this article I present the solution, how we got to it, and a word of caution.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Olimpia Valencia</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">07 03 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-70jNJELpYI4/XHw1vsFgUjI/AAAAAAAAlRY/4M0_1SQdTDc8WkBxv8t2cavEl6O8B9CegCLcBGAs/s320/github-mata-jquery.jpg" alt="Github deja de dar soporte a jQuery">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Github deja de dar soporte a jQuery</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">06 03 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-70jNJELpYI4/XHw1vsFgUjI/AAAAAAAAlRY/4M0_1SQdTDc8WkBxv8t2cavEl6O8B9CegCLcBGAs/s1600/github-mata-jquery.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="716" data-original-width="1263" height="181" src="https://1.bp.blogspot.com/-70jNJELpYI4/XHw1vsFgUjI/AAAAAAAAlRY/4M0_1SQdTDc8WkBxv8t2cavEl6O8B9CegCLcBGAs/s320/github-mata-jquery.jpg" width="320" /></a></div><div>Github deja de dar soporte a jQuery, con lo que pasa a ser otro servicio que empezó a usar jQuery para poder dar servicio a todos sus usuarios y repositorios, pero ahora ya está dejando de lado la librería para poder usar frameworks modernos que no dependan tanto de una sola implementación.</div><div>En este video les explico las ventajas de migrar de jQuery, y los retos a los que se está enfrentando el equipo de desarrollo de Github al querer modernizar su sitio.</div><div class="separator" style="clear: both; text-align: center;"><iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/dJR5HOcNZBc/0.jpg" src="https://www.youtube.com/embed/dJR5HOcNZBc?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div><div>No olviden <a href="https://www.youtube.com/channel/UCOD6LXgeBoeiUZTsPLdG-0g" target="_blank">suscribirse a mi canal de Youtube</a> para ver todo el contenido adicional que se genera para los desarrolladores y diseñadores web</div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=f4WbvOuXL2o:kzzpYY07X-Q:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=f4WbvOuXL2o:kzzpYY07X-Q:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=f4WbvOuXL2o:kzzpYY07X-Q:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=f4WbvOuXL2o:kzzpYY07X-Q:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=f4WbvOuXL2o:kzzpYY07X-Q:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=f4WbvOuXL2o:kzzpYY07X-Q:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=f4WbvOuXL2o:kzzpYY07X-Q:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=f4WbvOuXL2o:kzzpYY07X-Q:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=f4WbvOuXL2o:kzzpYY07X-Q:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=f4WbvOuXL2o:kzzpYY07X-Q:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=f4WbvOuXL2o:kzzpYY07X-Q:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=f4WbvOuXL2o:kzzpYY07X-Q:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=f4WbvOuXL2o:kzzpYY07X-Q:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=f4WbvOuXL2o:kzzpYY07X-Q:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/f4WbvOuXL2o" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://4.bp.blogspot.com/-t0HqOHyqtko/XHwxjLSWWeI/AAAAAAAAlRM/9VYKglkew9AUpzasFXDZyiNenGtSHY8uQCLcBGAs/s640/animaciones-web-portada.gif" alt="10 sitios web con animaciones impresionantes">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">10 sitios web con animaciones impresionantes</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blog de Diseño Web Vida MRR</a> <span class="article__date">05 03 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-t0HqOHyqtko/XHwxjLSWWeI/AAAAAAAAlRM/9VYKglkew9AUpzasFXDZyiNenGtSHY8uQCLcBGAs/s1600/animaciones-web-portada.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="248" data-original-width="480" height="330" src="https://4.bp.blogspot.com/-t0HqOHyqtko/XHwxjLSWWeI/AAAAAAAAlRM/9VYKglkew9AUpzasFXDZyiNenGtSHY8uQCLcBGAs/s640/animaciones-web-portada.gif" width="640" /></a></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Se pueden hacer diferentes tipos de animaciones en un sitio web, desde las básicas con CSS, las complejas usando Javascript, pero los sitios web que les presento llevan a otro nivel este tema. Les presento <b>10 sitios web con animaciones impresionantes,</b> donde combinan CSS, SVG, WebGL y otras técnicas de animación para crear estos increíbles efectos de navegación en los sitios web</div><div class="separator" style="clear: both; text-align: left;"><a href="https://2019.lesanimals.digital/en" rel="noopener noreferrer" style="-webkit-text-stroke-width: 0px; border-bottom-color: currentColor; border-bottom-style: none; border-bottom-width: 0px; border-image-outset: 0; border-image-repeat: stretch; border-image-slice: 100%; border-image-source: none; border-image-width: 1; border-left-color: currentColor; border-left-style: none; border-left-width: 0px; border-right-color: currentColor; border-right-style: none; border-right-width: 0px; border-top-color: currentColor; border-top-style: none; border-top-width: 0px; box-sizing: border-box; color: #f68320; font-family: inherit; font-size: 100%; font-style: inherit; font-variant: normal; font-weight: inherit; letter-spacing: 0.5px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; outline-color: invert; outline-style: none; outline-width: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; vertical-align: baseline; white-space: normal; word-spacing: 0px;" target="_blank">Les Animals</a><b></b><i></i><u></u><sub></sub><sup></sup><strike></strike></div><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-iesLlPet4-I/XHwq-Fe74bI/AAAAAAAAlQQ/0cKT_MBaz-cGyl55vAkS2A2jdT5zM2lxACLcBGAs/s1600/sitios-web-animaciones-01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="506" data-original-width="844" height="380" src="https://2.bp.blogspot.com/-iesLlPet4-I/XHwq-Fe74bI/AAAAAAAAlQQ/0cKT_MBaz-cGyl55vAkS2A2jdT5zM2lxACLcBGAs/s640/sitios-web-animaciones-01.jpg" width="640" /></a></div><div class="separator" style="clear: both; text-align: left;"><a href="https://cheshirecat.inthehiddencity.com/" rel="noopener noreferrer" style="-webkit-text-stroke-width: 0px; border-bottom-color: currentColor; border-bottom-style: none; border-bottom-width: 0px; border-image-outset: 0; border-image-repeat: stretch; border-image-slice: 100%; border-image-source: none; border-image-width: 1; border-left-color: currentColor; border-left-style: none; border-left-width: 0px; border-right-color: currentColor; border-right-style: none; border-right-width: 0px; border-top-color: currentColor; border-top-style: none; border-top-width: 0px; box-sizing: border-box; color: #f68320; font-family: inherit; font-size: 100%; font-style: inherit; font-variant: normal; font-weight: inherit; letter-spacing: 0.5px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; outline-color: invert; outline-style: none; outline-width: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-align: left; text-decoration: underline; text-indent: 0px; text-transform: none; vertical-align: baseline; white-space: normal; word-spacing: 0px;" target="_blank">The Hunt for the Cheshire Cat</a><b></b><i></i><u></u><sub></sub><sup></sup><strike></strike></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-jdd7dPysxSg/XHwq-PqOFoI/AAAAAAAAlQU/MaZnE6Ji2sQfaxzLcWt6vVeJ4zDImBnRQCLcBGAs/s1600/sitios-web-animaciones-02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="510" data-original-width="848" height="384" src="https://2.bp.blogspot.com/-jdd7dPysxSg/XHwq-PqOFoI/AAAAAAAAlQU/MaZnE6Ji2sQfaxzLcWt6vVeJ4zDImBnRQCLcBGAs/s640/sitios-web-animaciones-02.jpg" width="640" /></a></div><a href="http://www.60fps.fr/" rel="noopener noreferrer" style="-webkit-text-stroke-width: 0px; border-bottom-color: currentColor; border-bottom-style: none; border-bottom-width: 0px; border-image-outset: 0; border-image-repeat: stretch; border-image-slice: 100%; border-image-source: none; border-image-width: 1; border-left-color: currentColor; border-left-style: none; border-left-width: 0px; border-right-color: currentColor; border-right-style: none; border-right-width: 0px; border-top-color: currentColor; border-top-style: none; border-top-width: 0px; box-sizing: border-box; color: #f68320; font-family: inherit; font-size: 100%; font-style: inherit; font-variant: normal; font-weight: inherit; letter-spacing: 0.5px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; outline-color: invert; outline-style: none; outline-width: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; vertical-align: baseline; white-space: normal; word-spacing: 0px;" target="_blank">60 FPS</a><div class="separator" style="clear: both; text-align: left;"><br /></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/--eVIgp1iHWc/XHwq-U5bZ6I/AAAAAAAAlQY/WdDQ7xg5UHosZdwV_1xoQ59efq42SSgmwCLcBGAs/s1600/sitios-web-animaciones-03.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="508" data-original-width="845" height="384" src="https://4.bp.blogspot.com/--eVIgp1iHWc/XHwq-U5bZ6I/AAAAAAAAlQY/WdDQ7xg5UHosZdwV_1xoQ59efq42SSgmwCLcBGAs/s640/sitios-web-animaciones-03.jpg" width="640" /></a></div><a href="https://spire.com/" rel="noopener noreferrer" style="-webkit-text-stroke-width: 0px; border-bottom-color: currentColor; border-bottom-style: none; border-bottom-width: 0px; border-image-outset: 0; border-image-repeat: stretch; border-image-slice: 100%; border-image-source: none; border-image-width: 1; border-left-color: currentColor; border-left-style: none; border-left-width: 0px; border-right-color: currentColor; border-right-style: none; border-right-width: 0px; border-top-color: currentColor; border-top-style: none; border-top-width: 0px; box-sizing: border-box; color: #f68320; font-family: inherit; font-size: 100%; font-style: inherit; font-variant: normal; font-weight: inherit; letter-spacing: 0.5px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; outline-color: invert; outline-style: none; outline-width: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; vertical-align: baseline; white-space: normal; word-spacing: 0px;" target="_blank">Spire</a><div class="separator" style="clear: both; text-align: left;"><br /></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-fPbw9_3eNCA/XHwq-k97nrI/AAAAAAAAlQc/MItbRw6c34c-ztDCxJ2w2q42Ulu56GwMQCLcBGAs/s1600/sitios-web-animaciones-04.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="504" data-original-width="842" height="382" src="https://4.bp.blogspot.com/-fPbw9_3eNCA/XHwq-k97nrI/AAAAAAAAlQc/MItbRw6c34c-ztDCxJ2w2q42Ulu56GwMQCLcBGAs/s640/sitios-web-animaciones-04.jpg" width="640" /></a></div><div class="separator" style="clear: both; text-align: left;"><a href="https://www.nicocherubin.com/" rel="noopener noreferrer" style="-webkit-text-stroke-width: 0px; border-bottom-color: currentColor; border-bottom-style: none; border-bottom-width: 0px; border-image-outset: 0; border-image-repeat: stretch; border-image-slice: 100%; border-image-source: none; border-image-width: 1; border-left-color: currentColor; border-left-style: none; border-left-width: 0px; border-right-color: currentColor; border-right-style: none; border-right-width: 0px; border-top-color: currentColor; border-top-style: none; border-top-width: 0px; box-sizing: border-box; color: #f68320; font-family: inherit; font-size: 100%; font-style: inherit; font-variant: normal; font-weight: inherit; letter-spacing: 0.5px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; outline-color: invert; outline-style: none; outline-width: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-align: left; text-decoration: underline; text-indent: 0px; text-transform: none; vertical-align: baseline; white-space: normal; word-spacing: 0px;" target="_blank">Nico Cherubin</a><b></b><i></i><u></u><sub></sub><sup></sup><strike></strike></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-AwQB8ToDhQ0/XHwq-1L68MI/AAAAAAAAlQk/k0v5qBzooBAthPrdo9sT9pNMCCjlrhSPgCLcBGAs/s1600/sitios-web-animaciones-05.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="503" data-original-width="842" height="382" src="https://2.bp.blogspot.com/-AwQB8ToDhQ0/XHwq-1L68MI/AAAAAAAAlQk/k0v5qBzooBAthPrdo9sT9pNMCCjlrhSPgCLcBGAs/s640/sitios-web-animaciones-05.jpg" width="640" /></a></div><div class="separator" style="clear: both; text-align: left;"><a href="https://pelizzari.com/" rel="noopener noreferrer" style="-webkit-text-stroke-width: 0px; border-bottom-color: currentColor; border-bottom-style: none; border-bottom-width: 0px; border-image-outset: 0; border-image-repeat: stretch; border-image-slice: 100%; border-image-source: none; border-image-width: 1; border-left-color: currentColor; border-left-style: none; border-left-width: 0px; border-right-color: currentColor; border-right-style: none; border-right-width: 0px; border-top-color: currentColor; border-top-style: none; border-top-width: 0px; box-sizing: border-box; color: #f68320; font-family: inherit; font-size: 100%; font-style: inherit; font-variant: normal; font-weight: inherit; letter-spacing: 0.5px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; outline-color: invert; outline-style: none; outline-width: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; vertical-align: baseline; white-space: normal; word-spacing: 0px;" target="_blank">Pelizzari Studio</a><b></b><i></i><u></u><sub></sub><sup></sup><strike></strike></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-Hgw5Xohng6k/XHwq-xsuZtI/AAAAAAAAlQg/pfeefeDDSNEDQPpo_UIxUvpKDlxUoExsACLcBGAs/s1600/sitios-web-animaciones-06.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="502" data-original-width="843" height="380" src="https://2.bp.blogspot.com/-Hgw5Xohng6k/XHwq-xsuZtI/AAAAAAAAlQg/pfeefeDDSNEDQPpo_UIxUvpKDlxUoExsACLcBGAs/s640/sitios-web-animaciones-06.jpg" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>&nbsp;<a href="https://activetheory.net/" rel="noopener noreferrer" style="-webkit-text-stroke-width: 0px; border-bottom-color: currentColor; border-bottom-style: none; border-bottom-width: 0px; border-image-outset: 0; border-image-repeat: stretch; border-image-slice: 100%; border-image-source: none; border-image-width: 1; border-left-color: currentColor; border-left-style: none; border-left-width: 0px; border-right-color: currentColor; border-right-style: none; border-right-width: 0px; border-top-color: currentColor; border-top-style: none; border-top-width: 0px; box-sizing: border-box; color: #f68320; font-family: inherit; font-size: 100%; font-style: inherit; font-variant: normal; font-weight: inherit; letter-spacing: 0.5px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; outline-color: invert; outline-style: none; outline-width: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; vertical-align: baseline; white-space: normal; word-spacing: 0px;" target="_blank">Active Theory</a><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-Zxib0kKLH3E/XHwq_AqgRCI/AAAAAAAAlQo/U1_mIHH-iNcN_UOglIQzOn328uXqhmjgQCLcBGAs/s1600/sitios-web-animaciones-07.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="502" data-original-width="838" height="382" src="https://4.bp.blogspot.com/-Zxib0kKLH3E/XHwq_AqgRCI/AAAAAAAAlQo/U1_mIHH-iNcN_UOglIQzOn328uXqhmjgQCLcBGAs/s640/sitios-web-animaciones-07.jpg" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>&nbsp;<a href="https://teatrlalka.pl/" rel="noopener noreferrer" style="-webkit-text-stroke-width: 0px; border-bottom-color: currentColor; border-bottom-style: none; border-bottom-width: 0px; border-image-outset: 0; border-image-repeat: stretch; border-image-slice: 100%; border-image-source: none; border-image-width: 1; border-left-color: currentColor; border-left-style: none; border-left-width: 0px; border-right-color: currentColor; border-right-style: none; border-right-width: 0px; border-top-color: currentColor; border-top-style: none; border-top-width: 0px; box-sizing: border-box; color: #f68320; font-family: inherit; font-size: 100%; font-style: inherit; font-variant: normal; font-weight: inherit; letter-spacing: 0.5px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; outline-color: invert; outline-style: none; outline-width: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; vertical-align: baseline; white-space: normal; word-spacing: 0px;" target="_blank">Teatr Lalka</a><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-IS51Enr1cNc/XHwq_q0IEAI/AAAAAAAAlQs/HI9jaKsxPPgttAKPyoet9shNBmky6p6YACLcBGAs/s1600/sitios-web-animaciones-08.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="508" data-original-width="843" height="384" src="https://3.bp.blogspot.com/-IS51Enr1cNc/XHwq_q0IEAI/AAAAAAAAlQs/HI9jaKsxPPgttAKPyoet9shNBmky6p6YACLcBGAs/s640/sitios-web-animaciones-08.jpg" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>&nbsp;<a href="https://deanbradshaw.com/" rel="noopener noreferrer" style="-webkit-text-stroke-width: 0px; border-bottom-color: currentColor; border-bottom-style: none; border-bottom-width: 0px; border-image-outset: 0; border-image-repeat: stretch; border-image-slice: 100%; border-image-source: none; border-image-width: 1; border-left-color: currentColor; border-left-style: none; border-left-width: 0px; border-right-color: currentColor; border-right-style: none; border-right-width: 0px; border-top-color: currentColor; border-top-style: none; border-top-width: 0px; box-sizing: border-box; color: #f68320; font-family: inherit; font-size: 100%; font-style: inherit; font-variant: normal; font-weight: inherit; letter-spacing: 0.5px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; outline-color: invert; outline-style: none; outline-width: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; vertical-align: baseline; white-space: normal; word-spacing: 0px;" target="_blank">Dean Bradshaw Photography</a><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-Ej276eumaUg/XHwq_pjMPBI/AAAAAAAAlQw/y2zlGr3wGfY1DegYVAG0zyC0M2Xx8nkGgCLcBGAs/s1600/sitios-web-animaciones-09.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="508" data-original-width="843" height="384" src="https://1.bp.blogspot.com/-Ej276eumaUg/XHwq_pjMPBI/AAAAAAAAlQw/y2zlGr3wGfY1DegYVAG0zyC0M2Xx8nkGgCLcBGAs/s640/sitios-web-animaciones-09.jpg" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>&nbsp;<a href="http://nlf.geex-arts.com/" rel="noopener noreferrer" style="-webkit-text-stroke-width: 0px; border-bottom-color: currentColor; border-bottom-style: none; border-bottom-width: 0px; border-image-outset: 0; border-image-repeat: stretch; border-image-slice: 100%; border-image-source: none; border-image-width: 1; border-left-color: currentColor; border-left-style: none; border-left-width: 0px; border-right-color: currentColor; border-right-style: none; border-right-width: 0px; border-top-color: currentColor; border-top-style: none; border-top-width: 0px; box-sizing: border-box; color: #f68320; font-family: inherit; font-size: 100%; font-style: inherit; font-variant: normal; font-weight: inherit; letter-spacing: 0.5px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; orphans: 2; outline-color: invert; outline-style: none; outline-width: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-align: left; text-decoration: underline; text-indent: 0px; text-transform: none; vertical-align: baseline; white-space: normal; word-spacing: 0px;" target="_blank">Next Level Fairs</a><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/--ndnQOz0NJU/XHwq_65lONI/AAAAAAAAlQ0/oJ32kWEDs3APnRa7BEq5yaZErOoOPECtwCLcBGAs/s1600/sitios-web-animaciones-10.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="506" data-original-width="847" height="382" src="https://1.bp.blogspot.com/--ndnQOz0NJU/XHwq_65lONI/AAAAAAAAlQ0/oJ32kWEDs3APnRa7BEq5yaZErOoOPECtwCLcBGAs/s640/sitios-web-animaciones-10.jpg" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/vidamrr?a=KnjUo2nFAyM:EUi0_Lqv5qU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=KnjUo2nFAyM:EUi0_Lqv5qU:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=63t7Ie-LG7Y" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=KnjUo2nFAyM:EUi0_Lqv5qU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=KnjUo2nFAyM:EUi0_Lqv5qU:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=KnjUo2nFAyM:EUi0_Lqv5qU:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=KnjUo2nFAyM:EUi0_Lqv5qU:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=KnjUo2nFAyM:EUi0_Lqv5qU:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=KnjUo2nFAyM:EUi0_Lqv5qU:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=KnjUo2nFAyM:EUi0_Lqv5qU:KwTdNBX3Jqk"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=KnjUo2nFAyM:EUi0_Lqv5qU:KwTdNBX3Jqk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=KnjUo2nFAyM:EUi0_Lqv5qU:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=l6gmwiTKsz0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=KnjUo2nFAyM:EUi0_Lqv5qU:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/vidamrr?i=KnjUo2nFAyM:EUi0_Lqv5qU:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/vidamrr?a=KnjUo2nFAyM:EUi0_Lqv5qU:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/vidamrr?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/vidamrr/~4/KnjUo2nFAyM" height="1" width="1" alt=""/>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/124-new-model.png" alt="New Model">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">New Model</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">05 03 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/124-new-model.png" alt="New Model" title="New Model" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">These Years in Common Lisp 2018</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">28 02 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>It&rsquo;s been already a little more than a year that I began my Lisp
journey. I made quaterly news digests, mainly from reddit&rsquo;s
feed:</p>

<ul>
<li><a href="/blog/these-months-in-common-lisp-q1-2018/">Q1 2018</a> - <a href="/blog/these-months-in-common-lisp-q2-2018/">Q2 2018</a> - <a href="/blog/these-months-in-common-lisp-q3-2018/">Q3 2018</a> - <a href="/blog/these-months-in-common-lisp-q4-2018/">Q4 2018</a></li>
</ul>

<p>Time has come for a yearly overview ! What happened in the Common Lisp
world ? Are there (or groundbreaking promising useful fun) projects,
articles, discussions, tutorials ?</p>

<p>No need to say, I won&rsquo;t reference everything we find in the quaterly
posts, which don&rsquo;t list all new projects appearing on Quicklisp (we
can find these in the
<a href="http://blog.quicklisp.org">monthly Quicklisp releases</a>) or Github.</p>

<p>I hope this overview will sharpen your interest on what is in my
opinion an under-sold and still very promising language and plateform,
that I happen to like more and more (and sooo more than Python ;) ).</p>

<p>Happy discoveries.</p>

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-generate-toc again -->

<p><strong>Table of Contents</strong></p>

<ul>
<li><a href="#documentation">Documentation</a></li>
<li><a href="#implementations">Implementations</a></li>
<li><a href="#projects">Projects</a>

<ul>
<li><a href="#new-projects">New projects</a></li>
<li><a href="#web">Web</a></li>
<li><a href="#gui">GUI</a></li>
<li><a href="#package-management">Package management</a></li>
<li><a href="#deployment">Deployment</a></li>
<li><a href="#music">Music</a></li>
<li><a href="#rediscoveries">(re)Discoveries</a></li>
</ul></li>
<li><a href="#articles">Articles</a></li>
<li><a href="#other-screencasts">Other screencasts</a></li>
<li><a href="#discussion">Discussion</a>

<ul>
<li><a href="#learning-lisp">Learning Lisp</a></li>
<li><a href="#common-lisp-vs-">Common Lisp VS &hellip;</a></li>
</ul></li>
</ul>

<!-- markdown-toc end -->

<h1 id="documentation">Documentation</h1>

<p>Common Lisp&rsquo;s online documentation could be more thorough and
welcoming. Fortunately, a few of us revived some projects and work on
it -my favourite project being the Common Lisp Coobook. This year, we
got tutorials on:</p>

<ul>
<li><a href="https://lispcookbook.github.io/cl-cookbook/data-structures.html">Datastructures</a></li>
<li><a href="https://lispcookbook.github.io/cl-cookbook/debugging.html">Debugging</a>, including how to interactively debug a spacecraft,</li>
<li><a href="https://lispcookbook.github.io/cl-cookbook/clos.html">the Common Lisp Object System (CLOS)</a></li>
<li><a href="https://lispcookbook.github.io/cl-cookbook/iteration.html">Loop, iteration, mapping</a></li>
<li><a href="https://lispcookbook.github.io/cl-cookbook/databases.html">Database access and persistence</a></li>
<li><a href="https://lispcookbook.github.io/cl-cookbook/error_handling.html">Error and condition handling</a></li>
<li><a href="https://lispcookbook.github.io/cl-cookbook/numbers.html">Numbers</a> and <a href="https://lispcookbook.github.io/cl-cookbook/arrays.html">multidimensional arrays</a></li>
<li><a href="https://lispcookbook.github.io/cl-cookbook/scripting.html">Scripting and building self-contained executables</a></li>
<li><a href="https://lispcookbook.github.io/cl-cookbook/type.html">Working with types</a></li>
</ul>

<p>along with many improvements on other pages, like on <a href="https://lispcookbook.github.io/cl-cookbook/getting-started.html">getting started</a> and <a href="https://lispcookbook.github.io/cl-cookbook/editor-support.html">editor support</a>.</p>

<p>Which brings me to it: the editors situation is much more open than
you think:</p>

<ul>
<li>The editor of choice is still <strong>Emacs</strong> with Slime (or
Sly),</li>
<li>However, we can get started with Emacs and Lisp in 3 clicks with <strong>Portacle</strong>, a <em>self-contained batteries-included sbcl-included portable</em> Emacs tailored for CL,</li>
<li>For <strong>Vim</strong> and <strong>NeoVim</strong> we have SLIMV, VLIME, and plugins can be written for NeoVim using <a href="https://github.com/adolenc/cl-neovim">cl-neovim</a>.</li>
<li>Or if we want an editor written in  cl, there&rsquo;s the self-contained <strong>Lem</strong> editor, which also works for Python, Go, Rust, Nim, Scheme, HTML, JSX, along with a directory mode, an experimental LSP mode, calc-mode, and more,</li>
<li>Not to forget that Mac Os X users can use the <a href="https://ccl.clozure.com/docs/ccl.html#the-clozure-cl-ide">Clozure Common Lisp IDE</a></li>
<li>All editions of LispWorks (including the free) include the <a href="http://www.lispworks.com/products/ide.html">LW IDE</a></li>
<li>For users of <strong>Eclipse IDE</strong>, there is the Dandelion plugin</li>
<li>For popular editors, the experience is getting very good on <strong>Atom</strong> and the popular <strong>Visual Studio Code</strong> can be made to work with CL using <a href="https://github.com/cxxxr/cl-lsp">cl-lsp</a>.</li>
<li>We have an <strong>ipython-like REPL</strong> (cl-repl),</li>
<li>and for interactive notebooks, we have <strong>Jupyter kernels</strong> and yet another
notebook (Darkmatter).</li>
</ul>

<p>A very welcome improvement is the Common Lisp fundation&rsquo;s website:
<a href="https://common-lisp.net/">https://common-lisp.net/</a> It got a massive update and is now
attractive. We had <a href="http://lisp-lang.org/">http://lisp-lang.org/</a> (don&rsquo;t miss its success
stories section (did you know that pgloader was re-written from Python to CL ? :) )), but common-lisp.net was a googlers&rsquo; honey pot.</p>

<p>This website uses two &ldquo;awesome&rdquo; lists that were created or massively
furnished last year:</p>

<ul>
<li>the <a href="https://github.com/CodyReichert/awesome-cl">Awesome-CL</a> list,
updated with hundreds of commits, which hopefully makes for a more
discoverable and appealing ecosystem, and</li>
<li><a href="https://github.com/azzamsa/awesome-lisp-companies">Awesome Lisp Companies</a>:
it was needed because Lispers didn&rsquo;t know a lot of companies using
CL appart from IRobot, Google&rsquo;s ITA (powering
<a href="http://kayak.com/">Kayak</a>, <a href="http://orbitz.com/">Orbitz</a> and
others), Grammatech, YCombinator, Siscog or other dead ones.</li>
</ul>

<p>Other places to learn Common Lisp include:</p>

<ul>
<li><a href="https://www.reddit.com/r/lisp/comments/a9at82/clexercise_common_lisp_learning_system_running_on/">cl-exercise: a Common Lisp Learning System running on browsers</a></li>
<li>coding schools, like <a href="https://open.kattis.com/help">Kattis</a></li>
<li>and competitive Programming websites like CodeForces,
HackerEarth, HackerRank, and CodeChef.</li>
<li>lastly, <a href="https://github.com/norvig/paip-lisp">Peter Norvig&rsquo;s book Paradigms of Artificial Intelligence Programming is available on Github</a></li>
</ul>

<p>We also regularly have new screencasts to enjoy:</p>

<ul>
<li>a lot being from <a href="https://github.com/cbaggers/">Baggers</a>: he does the following and he streams live nearly weekly

<ul>
<li><a href="https://www.youtube.com/playlist?list=PL2VAYZE_4wRJi_vgpjsH75kMhN4KsuzR_">little bits of Lisp</a>: short videos to learn Lisp basics</li>
<li><a href="https://www.youtube.com/results?search_query=lots+of+bits+of+lisp+">lots of bits of Lisp</a>: long videos to dive deep in advanced subjects (macros, CFFI,…)</li>
<li><a href="https://www.youtube.com/watch?v=82o5NeyZtvw&amp;list=PL2VAYZE_4wRITJBv6saaKouj4sWSG1FcS">Pushing pixels with Lisp</a>: mostly working with OpenGL</li>
<li>and <a href="https://www.youtube.com/user/CBaggers/playlists">more</a> !</li>
</ul></li>
<li><a href="https://www.youtube.com/playlist?list=PLkDl6Irujx9MtJPRRP5KBH40SGCenztPW">Shinmera</a>
has lots of videos too, we can see him working on game engines,
games, his libraries, Qt applications and more,</li>
<li>the <a href="https://www.youtube.com/watch?v=z7V5BL6W3CA">CL study group</a> (here, an introduction to Screamer, a non-deterministic programming library)</li>
</ul>

<h1 id="implementations">Implementations</h1>

<p>Time is good for Common Lisp implementations. Most date back from
decades and already proved what they can do (remember, SBCL is a
descendant of the Lisp that went to space). Hence the lack of hype,
IMO. Yet, many are in active development, and keep improving. As
<code>/u/defunkydrummer</code> observed:</p>

<blockquote>
<p>We are lucky to live in a time where Lisp development is still ongoing, many teams carrying the flag of open-source Lisp:</p>

<ul>
<li>SBCL (new release today)</li>
<li>SICL (last commit 2 hours ago)</li>
<li>ECL (last commit, yesterday),</li>
<li>CLASP (last commit 2 days ago)</li>
<li>CCL (last commit 7 days ago),</li>
<li>CLISP (two weeks ago),</li>
<li>CMUCL (1 month ago)</li>
<li>ABCL (3 months ago)</li>
</ul>
</blockquote>

<p>SBCL has monthly releases. If you read the release notes, you might worry:</p>

<blockquote>
<p>the amount of changes in each release is decreasing these years</p>
</blockquote>

<p>but, as <code>/u/baggers</code> notes:</p>

<blockquote>
<p>I think the commits tell a slightly different tale though. There is always a lot of background &lsquo;making stuff better&rsquo; work than won&rsquo;t appear as the explanation would either be ultra internal and specific or would be super vague and very similar each month (for example &lsquo;stuff is slightly faster&rsquo;).</p>

<p>For one that would be overly specific <a href="https://github.com/sbcl/sbcl/commit/adc83086ff26c46e647b22d76fe22d57889b6ace">this one</a> might make for a good example. It&rsquo;s grand work, but doesn&rsquo;t surface in any specific lisp feature, stuff is just better.</p>
</blockquote>

<p>Furthermore, a maintainer:</p>

<blockquote>
<p>Or the developers are too lazy to describe their changes.</p>
</blockquote>

<p>which isn&rsquo;t a good reason ;)</p>

<p>We got a new release of Corman Lisp, a high performance Windows/32bit specific implementation with a built in IDE,</p>

<p>we have CLASP, targetting C++ through LLVM (see <a href="https://www.youtube.com/watch?v=mbdXeRBbgDM&amp;app=desktop">“Lessons Learned Implementing Common Lisp with LLVM”</a>), built with the Cleavir compiler, part of SICL, a very
new implementation of Common Lisp with fresh ideas,</p>

<p>we have ABCL targetting the JVM, Embedable Common Lisp, without
forgetting active commercial ones, like LispWorks and AllegroCL. While
I&rsquo;m at it, you might want to have a look at
<a href="https://wukix.com/mocl">MOCL</a> for IOs, Android and OSx.</p>

<p>We got a nice talk by Clozure Common Lisp&rsquo;s maintainer:
<a href="http://thisoldlisp.com/">this Old Lisp</a> (this one may be the second
most used implementation, particularly good for development &ndash; super fast
compilation times (I heard it compiles itself in seconds), <a href="https://ccl.clozure.com/manual/chapter4.3.html#Advising">advising</a>, <a href="https://ccl.clozure.com/manual/chapter4.12.html#watched-objects">watched objects</a>, its own <a href="https://ccl.clozure.com/docs/ccl.html#the-clozure-cl-ide">IDE</a>).</p>

<p>Last note, a SBCL maintainer started a RISC-V port: <a href="http://christophe.rhodes.io/notes/blog/posts/2018/first_riscy_steps/">First RISCy Steps &ndash; Porting SBCL to the RISC-V</a></p>

<p>So: welcome to this new world. It&rsquo;s bigger than I thought, for sure.</p>

<h1 id="projects">Projects</h1>

<p>I only list some projects that can be of interest to anybody. For the full stuff see the quaterly posts !</p>

<!-- I fear that it would be seen as representative of the CL new tools and libraries.  -->

<h2 id="new-projects">New projects</h2>

<ul>
<li><a href="https://www.reddit.com/r/lisp/comments/a954yf/next_browser_120_is_out/">Next browser 1.2.0 is out!</a>: a browser exposing all its internals to CL. Be productive.</li>
<li><a href="https://hub.docker.com/r/drmeister/cando/">CANDO - A Computational Chemistry programming environment integrating Common Lisp and C++ based on the Jupyter notebook</a></li>
<li><a href="https://github.com/tarballs-are-good/coalton">Coalton, a dialect of ML embedded in Common Lisp (alpha)</a></li>
<li><a href="https://github.com/terminal625/sucle">Voxel game engine (Minecraft)</a> - a Minecraft engine. Allows for interactive changes.</li>
<li><a href="https://github.com/emotiq/emotiq">Emotiq - blockchain in Common Lisp</a></li>
<li><a href="https://sjl.bitbucket.io/temperance/">Temperance - logic programming (in development, reached v1.0.0)</a></li>
<li><a href="https://github.com/rigetticomputing/magicl">MAGICL: Matrix Algebra proGrams In Common Lisp - Rigetti Computing</a> (quantum computing)</li>
<li><a href="https://github.com/bradleyjensen/shcl">SHCL: An Unholy Union of POSIX Shell and Common Lisp</a> (<a href="https://www.reddit.com/r/lisp/comments/8kpbcz/shcl_an_unholy_union_of_posix_shell_and_common/">reddit</a>)</li>
<li><a href="https://jscl-project.github.io/">JSCL 0.7.0 now supports CLOS thanks to the work of vlad-km</a></li>
<li><a href="cl-torrents 0.9 - readline interface and 1337x.to scraper">cl-torrents 0.9 - readline interface and 1337x.to scraper</a> - a simple tool to search for torrents on popular trackers. My first CL app. Web and GUI interfaces in the making.</li>
<li><a href="https://vimeo.com/237947324">Introducing Seed: An Interactive Software Environment in Common Lisp</a></li>
<li><a href="https://common-lisp.net/project/tovero/">Tovero is a 3D modeling system for Common Lisp</a></li>
<li><a href="https://gitlab.com/jgkamat/rmsbolt">RMSBolt: See what your compiler is going inside of Emacs (has minimal support for Common Lisp)</a></li>
<li><a href="https://www.michaelfiano.com/projects/pngload/">pngload: A PNG (Portable Network Graphics) image format decoder</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9brkej/clvep_a_video_effects_processor/">cl-vep: a video effects processor</a></li>
<li><a href="https://github.com/tarballs-are-good/algebraic-data-library/">algebraic-data-library</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/8f6wez/petalisp_elegant_high_performance_computing/">Petalisp</a>: Elegant High Performance Computing</li>
<li><a href="https://github.com/vseloved/wiki-lang-detect">wiki-lang-detect</a>: Text language identification using Wikipedia data</li>
<li><a href="https://github.com/privet-kitty/dufy">Dufy, a color library</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/8gzm4w/ppath_a_path_manipulation_library/">ppath, a path manipulation library</a></li>
<li><a href="http://compbio.ucdenver.edu/Hunter_lab/Hunter/cl-statistics.lisp">cl-statistics.lisp</a></li>
<li><a href="https://github.com/luksamuk/powerlisp">Powerlisp: A simple tool to automate your work with dmenu/rofi</a></li>
<li><a href="https://github.com/gschjetne/json-mop">json-mop</a>: A metaclass for bridging CLOS and JSON objects</li>
<li><a href="https://github.com/obicons/clsh">clsh</a>: a set of Lispy bindings for running and composing *nix processes</li>
<li><a href="https://github.com/pcostanza/filtered-functions">filtered-functions</a> - enables the use of arbitrary predicates for selecting and applying methods.</li>
</ul>

<h2 id="web">Web</h2>

<ul>
<li><a href="http://40ants.com/weblocks/quickstart.html">Weblocks&rsquo; new quickstart</a> -
Weblocks is an isomorphic web frameworks that allows to write
interactive web apps without writing Javascript (nor writing code that
transpiles to JS). It is seeing a massive update right now. Being Lisp,
we can build a self-contained executable of our web app, send it to
the server, run it and see it from the outside.</li>
<li><a href="https://github.com/CodyReichert/awesome-cl#email">three email libraries</a></li>
<li><a href="https://github.com/reddit-archive/reddit1.0">reddit1.0 source code</a> (<a href="https://www.reddit.com/r/Common_Lisp/comments/886yeu/reddit10/">comments</a>), then <a href="https://www.reddit.com/r/Common_Lisp/comments/8ata3c/reddit_code_runs_on_sbcl/">Reddit&rsquo;s code runs on SBCL</a>. See also <a href="https://www.reddit.com/r/programming/comments/883vzs/old_reddit_source_code/">reddit</a>.</li>
<li><a href="http://blog.klipse.tech/lisp/2018/05/07/blog-common-lisp.html">Interactive Common Lisp code snippets in any web page</a></li>
<li><a href="https://github.com/Arboreta/arboreta-wasm">arboreta-wasm - Common Lisp tooling for WebAssembly</a></li>
</ul>

<p>For web libraries, see <a href="https://github.com/CodyReichert/awesome-cl#network-and-internet">https://github.com/CodyReichert/awesome-cl#network-and-internet</a></p>

<h2 id="gui">GUI</h2>

<ul>
<li><a href="https://notabug.org/cage/nodgui">nodgui - yet another Tcl/Tk-based GUI package for Common Lisp</a> (based on Ltk, with syntax sugar and more meta-widgets)</li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/au0dmv/more_iup_gui_stuff/">IUP bindings GUI stuff</a> (in the works)</li>
<li><a href="http://en.ystok.ru/products/ywidgets/">YstokWidgets Professional Edition</a></li>
<li><a href="https://common-lisp.net/~loliveira/ediware/midgets/doc/">MIDGETS - A collection of CAPI widgets and utilities</a></li>
<li><a href="https://github.com/stacksmith/subtext">subtext: A mostly-text-based UI bridges Common Lisp objects and runs of text. Minimal text-based user interface</a></li>
<li><a href="https://github.com/fjames86/ftw">ftw: Common Lisp Win32 GUI library</a></li>
<li><a href="https://github.com/plkrueger/CocoaInterface">Cocoa interface code written in Lisp for use with Clozure Common Lisp</a></li>
<li><a href="https://common-lisp.net/project/mcclim/posts/McCLIM-097-Imbolc-release.html">McCLIM 0.9.7 &ldquo;Imbolc&rdquo; release</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/a31oxr/demo_sbcl_script_using_gtk/">Demo SBCL script using Gtk</a></li>
<li><a href="https://github.com/defunkydrummer/abcl-jazz">Demo ABCL script using Java Swing</a></li>
</ul>

<p>for GUI libraries: <a href="https://github.com/CodyReichert/awesome-cl#gui">https://github.com/CodyReichert/awesome-cl#gui</a></p>

<h2 id="package-management">Package management</h2>

<p>Quicklisp is the de facto package manager, but new projects come to
complement it and bypass its limitations:</p>

<ul>
<li><a href="http://40ants.com/posts/Second-version-of-Ultralisporg-is-available-now.html">the second version of Ultralisp is available</a> - Ultralisp is an important project that fills a gap. It is a quicklisp distribution which updates every 5 minutes. It is also a Weblocks application!</li>
<li><a href="https://lisp.com.br/quicksys/">quicksys</a> - installs systems from multiple Quicklisp distributions.</li>
</ul>

<p>For more options, see <a href="https://github.com/fukamachi/qlot">Qlot</a> (install and pin libraries locally, like
Python&rsquo;s virtualenv) and <a href="https://github.com/roswell/roswell/">Roswell</a>.</p>

<h2 id="deployment">Deployment</h2>

<ul>
<li><a href="https://github.com/apache/thrift/commits/master">Apache Thrift gains CL support</a></li>
<li><a href="https://github.com/hjudt/s2i-lisp">s2i-lisp: Common Lisp + Quicklisp OpenShift Build Image</a></li>
<li><a href="https://github.com/fisxoj/lisp-images">lisp-images: Docker images for common lisp development</a> (with some others, see the awesome-list)</li>
<li><a href="https://hub.docker.com/r/eshamster/cl-devel2/">A docker container for CL development</a> (also <a href="https://hub.docker.com/r/daewok/lisp-devel/">lisp-devel</a>, <a href="https://lispcookbook.github.io/cl-cookbook/testing.html#gitlab-ci">CI on CL Cookbook</a>)</li>
<li><a href="https://github.com/xh4/cube">Kubernetes Client Library for Common Lisp</a></li>
<li><a href="https://gitlab.com/duncan-bayne/heroku-buildpack-common-lisp">Heroku buildpack for Common Lisp</a></li>
<li><a href="https://github.com/y2q-actionman/cl-aws-custom-runtime-test">cl-aws-custom-runtime</a> - An example of using Common Lisp (SBCL) as a custom runtime on AWS lambda.</li>
<li><a href="https://github.com/deadtrickster/prometheus.cl">prometheus.cl</a> - Prometheus.io client. Grafana dashboard for SBCL and Hunchentoot metrics (memory, threads, requests per second,…).</li>
</ul>

<p>We can also deploy apps on Digital Ocean, and no need to say that
deploying a
<a href="https://lispcookbook.github.io/cl-cookbook/scripting.html#building-a-self-contained-executable">self-contained executable</a>
is easy,
<a href="https://lispcookbook.github.io/cl-cookbook/debugging.html#remote-debugging">connecting to a remote instance</a>
too.</p>

<h2 id="music">Music</h2>

<ul>
<li><a href="https://github.com/MegaLoler/Music">Music: Music framework for musical expression in Common Lisp with a focus on music theory (built from scratch, on development)</a></li>
<li><a href="https://michaelgogins.tumblr.com/post/178126207468/composing-in-lisp">Composing in Lisp with Csound</a></li>
<li><a href="https://lisp-journey.gitlab.io/blog/shuffletron-lisp-music-player-for-the-terminal/">Shuffletron, a Common Lisp Music Player for the terminal</a></li>
</ul>

<p>see also <a href="https://github.com/CodyReichert/awesome-cl#audio">audio and music composition software</a></p>

<h2 id="re-discoveries">(re)Discoveries</h2>

<ul>
<li><a href="https://github.com/lmj/lfarm">lfarm - a library for distributing work across machines (on top of lparallel and usocket)</a></li>
<li><a href="https://github.com/nikodemus/screamer">Screamer - nondeterministic programming. Augment Common Lisp with practically all of the functionality of both Prolog and constraint logic programming languages (10 yo, Nikodemus)</a></li>
<li><a href="https://github.com/sellout/quid-pro-quo">quid-pro-quo: a contract programming library in the style of Eiffel’s Design by Contract</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/7mji50/cells_spreadsheetlike_expressiveness_for_clos/">Cells, spreadsheet-like expressiveness for CLOS</a></li>
<li><a href="https://github.com/mkoeppe/cl-bibtex">cl-bibtex: A compatible re-implementation of the BibTeX program in Common Lisp, with a BST-to-CL compiler</a></li>
<li><a href="https://github.com/y2q-actionman/with-c-syntax">C language syntax embedded in Common Lisp</a></li>
<li><a href="https://gitlab.common-lisp.net/gendl/gendl">gendl - Generative Programming and Knowledge-based Engineering (KBE) system embedded in Common Lisp</a></li>
<li><a href="http://cram-system.org/doc/ide">Cognitive Robot Abstract Machine = Common Lisp + ROS</a></li>
<li><a href="https://scymtym.github.io/esrap/">Esrap - a packrat parser for Common Lisp</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/7oaum4/cmera_a_commonlisp_sourcetosource_compiler_to/">C-Mera, a Common Lisp source-to-source compiler to generate C/C++</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/882mz4/clbench_common_lisp_benchmarking_suite/">cl-bench - Common Lisp benchmarking suite</a></li>
<li><a href="http://faculty.hampshire.edu/lspector/qgame.html">QGAME: Quantum and Gate Measurement Emulator</a></li>
</ul>

<h1 id="articles">Articles</h1>

<ul>
<li><a href="http://stevelosh.com/blog/2018/08/a-road-to-common-lisp/">A Road to Common Lisp</a> (<a href="https://news.ycombinator.com/item?id=17852194">hacker news comments</a>). You should read this one.</li>
<li><a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5952920/">How the strengths of Lisp-family languages facilitate building complex and flexible bioinformatics applications</a></li>
<li><a href="https://lisper.in/nlp-date-parser">Writing a natural language date and time parser - internals of the Common Lisp library Chronicity</a></li>
<li><a href="https://www.darkchestnut.com/2018/hunchentoot_custom_sessions/">Implementing Hunchentoot custom sessions</a></li>
<li><a href="https://lisp-journey.gitlab.io/blog/overview-of-documentation-generators/">Overview of Documentation Generators (codex, coo, declt, staple, cldomain)</a>
<!-- - [Challenging myself to learn Common Lisp in one month](https://github.com/TomLisankie/Learning-Lisp) --></li>
<li><a href="https://fourier.github.io/lisp/2019/01/02/reflex-map.html">Converter of maps from Reflex Arena to QuakeWorld. cl-yacc, 3d-matrices</a></li>
<li><a href="https://two-wrongs.com/debugging-common-lisp-in-slime.html">Debugging Common Lisp in Slime</a></li>
<li><a href="https://www-fourier.ujf-grenoble.fr/~sergerar/Papers/Packaging.pdf">Packages in Common Lisp, a tutorial (pdf)</a></li>
<li><a href="https://www.darkchestnut.com/2018/how-to-write-5am-test-fixtures/">How to write test fixtures for FiveAM - Dark Chestnut</a></li>
<li><a href="https://allegrograph.com/franz-and-semantic-web-company-partner-to-create-a-noam-chomsky-knowledge-graph/">Franz and Semantic Web Co. Partner to Create a Noam Chomsky Knowledge Graph</a></li>
<li><a href="http://notes.eatonphil.com/compiler-basics-lisp-to-assembly.html">Compiler basics: lisp to assembly</a></li>
<li><a href="https://www.webofstories.com/play/marvin.minsky/44">Marvin Minsky - Scientist - The beauty of the Lisp language</a></li>
<li><a href="http://www.newresalhaider.com/post/common-treasure/">Excavating a Common Treasure: Common Lisp</a></li>
<li><a href="http://stevelosh.com/blog/2018/07/fun-with-macros-if-let/">Fun with Macros: If-Let and When-Let / Steve Losh</a></li>
<li><a href="https://openresearch-repository.anu.edu.au/bitstream/1885/144603/1/Sorensen%20Thesis%202018.pdf">Extempore - The design, implementation and application of a cyber-physical programming language, Andrew Sorensen, Thesis, 2018 (PDF)</a></li>
<li><a href="https://m00natic.github.io/lisp/manual-jit.html">Uniform Structured Syntax, Metaprogramming and Run-time Compilation</a></li>
<li><a href="https://z0ltan.wordpress.com/2018/08/04/simple-expression-evaluator-comparison-between-haskell-rust-and-common-lisp/">Simple expression evaluator comparison between Haskell, Rust, and Common Lisp</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/98s5zp/lisping_at_jpl/">Lisping at JPL</a></li>
</ul>

<p>and also</p>

<ul>
<li><a href="https://www.reddit.com/r/lisp/comments/8bshzw/lisp_jazz_aikido_three_expressions_of_a_single/">Lisp, Jazz, Aikido: Three Expressions of a Single Essence</a></li>
<li><a href="https://biolisp.github.io/#why-lisp">Why lisp - biolisp</a></li>
<li><a href="http://stevelosh.com/blog/2018/05/fun-with-macros-gathering/">Fun with Macros: Gathering / Steve Losh</a></li>
<li><a href="http://can3p.github.io/blog/2018/06/19/client-writeup-intro/">Experience writing a full featured livejournal blog client in Common Lisp</a>. Part 2: <a href="http://can3p.github.io/blog/2018/06/22/client-writeup-logic/">client logic</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/8o2c1y/the_uncommon_lisp_approach_to_operations_research/">The (Un)common Lisp approach to Operations Research (2012)</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/8jq465/alien_return_of_alien_technology_to_classical/">Alien: Return of Alien Technology to Classical Planning </a></li>
<li><a href="https://blog.teknik.io/phoe/p/1633">Emacs + ECL on Android</a></li>
<li><a href="https://lisp-journey.gitlab.io/blog/generice-consistent-access-of-data-structures-dotted-path/">Generic, consistent and dotted access of data structures with Access - lisp-journey</a> (<a href="https://www.reddit.com/r/Common_Lisp/comments/7pysmx/generic_consistent_and_dotted_access_of_data/">reddit</a>)</li>
<li><a href="https://medium.com/@MartinCracauer/llvms-garbage-collection-facilities-and-sbcl-s-generational-gc-a13eedfb1b31">LLVM’s garbage collection facilities and SBCL’s generational GC</a></li>
<li><a href="https://lisp-journey.gitlab.io/blog/snippets-functional-style-more/">A bunch of utilities from (again) sjl: higher order functions, sequences, debugging, profiling.</a></li>
<li><a href="http://langnostic.inaimathi.ca/posts/the-return-of-cl-notebook">The return of cl-notebook</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/7rsfyn/testing_the_series_common_lisp_package/">Testing the SERIES package</a></li>
</ul>

<p>On games:</p>

<ul>
<li><a href="https://reader.tymoon.eu/article/370">About Making Games in Lisp - Gamedev</a></li>
<li><a href="https://defungames.com/2018/12/creating-a-non-trivial-lisp-game-in-2018/">Creating a (Non-Trivial) Lisp Game in 2018</a> (they just launched a <a href="https://www.kickstarter.com/projects/defungames/spycursion-hacking-espionage-edutainment-mmo">Crowdfunding</a>)</li>
<li><a href="https://old.reddit.com/r/Common_Lisp/comments/93g3p2/a_story_of_defun_games/">A Story of (defun games ())</a></li>
<li><a href="https://lthms.xyz/blog/lisp-journey-getting-started">Getting Started With trivial-gamekit</a></li>
</ul>

<h1 id="other-screencasts">Other screencasts</h1>

<ul>
<li><a href="https://www.youtube.com/watch?v=dw-y3vNDRWk">Lisp, The Quantum Programmer&rsquo;s Choice - Computerphile episode 2</a></li>
<li><a href="https://www.youtube.com/watch?v=9VIT_Ml2v-Q">McCLIM + Maxima: plot manipulation</a></li>
<li><a href="https://www.youtube.com/watch?v=AvC82EjoPYU">McCLIM + Maxima: vector demo</a></li>
<li><a href="https://www.youtube.com/watch?v=CbfHpLUPL7E">Comfy Lisp Programming - Project &ldquo;Wikify&rdquo; | Episode 2 @ 10am PST </a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/8ubnkn/common_lisp_and_c17_live_coding_stream_tinycdn/">Common lisp and C++17 Live coding stream | TinyCDN CFFI Interop | Episode 13</a></li>
<li><a href="https://www.youtube.com/watch?v=XT7JYPtWMd8">Growing a Lisp compiler - Amsterdam Lisp</a></li>
<li><a href="https://www.youtube.com/watch?v=bl8jQ2wRh6k">Web Development in Emacs, Common Lisp and Clojurescript - Potato (Slack-like)</a></li>
</ul>

<h1 id="discussion">Discussion</h1>

<ul>
<li><a href="https://www.reddit.com/r/lisp/comments/a7156w/lisp_and_the_remote_agent/">Lisp and the remote agent - aka Lisp in a spacecraft - with an AMA of Ron Garret</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/a5ggd4/how_to_make_common_lisp_popular/">How to make (Common) Lisp popular?</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/9r9xy6/feedback_from_a_new_lispworks_user/">Feedback from a new LispWorks user</a> (<a href="https://www.reddit.com/r/lisp/comments/9qh3op/how_is_lispworks_the_company_doing/">how is LispWorks the company going ?</a>)</li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/a3r4hb/how_do_you_normally_use_a_program_once_written/">How do you normally use a program once written ?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/a10629/structs_vs_parametric_polymorphism_an_answer_to/">Structs vs Parametric Polymorphism (an answer to the &ldquo;switching from Common Lisp to Julia - thoughts ?&rdquo; post)</a> also <a href="https://www.reddit.com/r/lisp/comments/9y425b/switching_from_common_lisp_to_julia_your_thoughts/">this discussion</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/9os171/how_to_work_on_a_project_and_make_sure/">How to work on a project and make sure dependencies are tracked correctly?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/a2hkq0/does_anyone_else_hate_loop_cl/">Does anyone else hate LOOP?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9xd4gy/what_does_it_take_to_understand_the_true_power_of/">What does it take to understand the true power of Lisp?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9qfrxe/how_lisp_made_your_life_easier/">How did Lisp make your life easier ?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9zpts4/should_local_variables_be_avoided_when_possible/">Should local variables be avoided when possible when doing functional programming?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9upt86/abcl/">Is ABCL an active project and does it support JRE 1.11?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9q68y8/has_the_gnu_coreutils_ever_been_implemented_in/">Has the Gnu Coreutils ever been implemented in Lisp? If not, would that be a worthwhile project?</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/8bn7f9/common_lisp_and_machine_learning_these_days/">Common Lisp and Machine Learning these days</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/7z7wuq/has_anyone_considered_or_started_a_project_to/">Has anyone considered or started a project to write a CL implementation in WebAssembly?</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/7s53qi/what_do_you_recommend_to_work_with_sql_databases/">What do you recommend to work with SQL databases ? What&rsquo;s your experience with Mito ?</a> and <a href="https://www.reddit.com/r/Common_Lisp/comments/7ozdcf/sqliteonly_interface_clsqlite_or_cldbi/">sqlite only interface: cl-sqlite or cl-dbi ?</a>
and <a href="https://www.reddit.com/r/lisp/comments/7iebty/ask_rlisp_is_there_any_lightweight_orm_that/">is there an ORM that generates classes from table definitions ?</a></li>
</ul>

<h2 id="learning-lisp">Learning Lisp</h2>

<ul>
<li><a href="https://www.reddit.com/r/lisp/comments/9er4mo/i_want_to_try_lisp_how_should_i_begin/">I want to try Lisp, how should I begin?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9b7v56/what_lisp_dialect_for_real_world_applications/">What lisp dialect for &ldquo;real world&rdquo; applications?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/8w8cr1/what_do_commercial_lisps_offer_that_frees_dont/">What do commercial Lisps offer that frees don&rsquo;t?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9kiji7/which_nonclojure_lisp_to_learn_first/">Which (non-Clojure) Lisp to learn first?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9k2vmi/can_cl_implement_clojures_keyword_as_function/">Can CL implement Clojure&rsquo;s keyword as function syntax?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/8jzpzw/why_did_you_decide_to_learn_lisp/">Why did you decide to learn Lisp?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/8j9ing/how_do_you_go_about_starting_a_common_lisp/">How do you go about starting a Common Lisp Project? A beginner looking for pointers.</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/86ze0t/as_a_newbie_what_i_will_miss_if_i_choose_racket/">As a newbie, what I will miss if I choose Racket over Common Lisp? Or if I happen to learn both at somepoint in future, choosing Racket/Common Lisp now would make sense?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/7lf149/what_can_other_languages_do_that_lisp_cant/">What can other languages do that Lisp can&rsquo;t ?</a></li>
</ul>

<h2 id="common-lisp-vs">Common Lisp VS &hellip;</h2>

<!-- not sure if listing some of those is constructive, really; and the Clojure vs Common Lisp wars are getting really tiring...  and this coming from an active flamer (defunkydrummer) -->

<ul>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/ac9mm9/how_common_lisp_community_survived_without_the/">How did the Common Lisp community survived without the equivalent of clojure.spec ?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/8wdw2r/is_there_a_lisp_that_is_considered_excellent/">Is there a Lisp that is considered &ldquo;excellent&rdquo; about error handling ?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9lhbnx/lisp_dialect_survey/">Lisp Dialect survey</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9i5mmp/the_julia_challenge/">the Julia challenge</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9g07to/python_pitfalls/">Python pitfalls ?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9lpssp/how_a_common_lisp_programmer_views_users_of_other/">How a Common Lisp programmer views users of other languages (humor)</a></li>
<li><a href="http://med.miami.edu/news/miller-school-researchers-help-push-the-limits-of-programming-languages-in-">Miller School Researchers Help Push the Limits of Programming Languages in Biology</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/8mcts3/lisp_vs_java_thought_you_guys_might_find_this/">Lisp vs Java (thought you guys might find this humorous)</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/8q6gaa/what_other_languages_besides_lisp_do_you_enjoy/">What other languages besides Lisp do you enjoy programming in?</a></li>
</ul>

<hr />

<p>Enjoy the material, and see you soon !</p>

<hr />

<p>thanks to <code>/u/defunkydrummer</code> for proofreading.</p>

<p>fix or improve this article <a href="https://gitlab.com/lisp-journey/lisp-journey.gitlab.io/issues">on Gitlab</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/123-yagni.png" alt="YAGNI">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">YAGNI</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">26 02 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/123-yagni.png" alt="YAGNI" title="YAGNI" /></p>

<p>Community request (with bugs)
<img src="https://www.monkeyuser.com/assets/images/2019/123-yagni-bugs.png" alt="YAGNI" title="YAGNI" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="Updating our tracking prevalence metrics">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Updating our tracking prevalence metrics</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">21 02 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Metrics that make more sense.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/122-nine-to-five.png" alt="9 to 5">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">9 to 5</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">19 02 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/122-nine-to-five.png" alt="9 to 5" title="9 to 5" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="Adblockers Performance Study">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Adblockers Performance Study</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">14 02 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Blocking all ads faster than the blink of an eye.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/121-quick-fix.png" alt="Quick Fix">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Quick Fix</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">12 02 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/121-quick-fix.png" alt="Quick Fix" title="Quick Fix" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">January 2019 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">11 02 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        We are happy to announce the conclusion of Q4 2018 and the beginning of our Q1 2019 funding round where we are funding Aleph and Neanderthal. These are the final progress reports for projects Datascript and Kaocha. Special thanks to Nikita and Arne for all your hard work!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Schibsted, patrocinador Platinum. Saca lo mejor de ti con el reto de Schibsted Spain</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FrontFest</a> <span class="article__date">08 02 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        En Schibsted Spain cada día lo damos todo, por eso, hemos preparado un reto muy tech para el FRONTFEST. Y es que, nuestro ADN es digital, un código binario en el que combinamos pasión y compromiso que nos ha llevado a estar en la vanguardia de las tecnologías web. Por eso, pásate por nuestro stand y saca lo mejor de ti para resolver el reto tech que te planteamos. Pero primero, ¿conoces Schibsted Spain?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Conoce Ryanair Labs, patrocinador Gold del FrontFest 2019</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FrontFest</a> <span class="article__date">06 02 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Ryanair Labs Madrid es el tercer lab tecnológico de Ryanair, abierto en 2017 y continuando con la expansión de nuestros equipos de diseño y desarrollo que comenzó en Dublín en 2014 y en Wroclaw en 2016.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Paradigma, patrocinador Platinum. SOMOS DISTINTOS, SOMOS PARADIGMA</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FrontFest</a> <span class="article__date">05 02 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Paradigma Digital somos una empresa tecnológica con más de 500 profesionales. Desde nuestras oficinas en Pozuelo, trabajamos a diario para conseguir reinventar el futuro digital de las grandes compañías.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/120-pivoting.png" alt="Pivoting">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Pivoting</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">05 02 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/120-pivoting.png" alt="Pivoting" title="Pivoting" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">State of Clojure 2019 Results</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">04 02 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Welcome to the annual State of Clojure survey results! Every year we survey Clojure and ClojureScript developers to evaluate the state of the language and its users. Thank you to everyone that took the time to complete the survey and provide your input. This year, we had 2461 respondents. Some highlights:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Clojure is used by many <a href="#work">companies</a> for web development, commercial services, and enterprise apps in a broad set of domains including financial services, enterprise software, retail, advertising, health care, and more.</p>
</li>
<li>
<p>Clojure is <a href="#strengths">valued</a> for its idiomatic support for functional programming, immutable data, interactive REPL, and ease of development.</p>
</li>
<li>
<p>Clojure and its <a href="#community">community</a> are active and vibrant, as seen in the many thriving discussion forums, conferences, and user groups, with active involvement in community library development.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>For more details and the <a href="https://www.surveymonkey.com/results/SM-S9JVNXNQV/">full results</a>, see below.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="work"><a class="anchor" href="#work"></a>A Language for Work</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In the first Clojure survey in 2010, 27% of respondents reported using Clojure for work and 33% for serious hobby projects. This number has steadily grown over the years and we now see 66% using it at work and 54% using it for serious hobby projects.</p>
</div>
<div class="paragraph">
<p>Clojure is being used in a wide variety of domains - web development (81%) and open source (48%) of course, but also building and delivering commercial services (31%) and enterprise apps (22%). This work occurs in a wide variety of industries - financial services, enterprise software, consumer software, retail, media/advertising, healthcare, education, and many more.</p>
</div>
<div class="paragraph">
<p>For the last four years, the percentage of Clojure developers in 1-10 person companies has fallen, this year to 35% (compared to 44% 3 years ago). We saw increases in developers working at companies sized 1000+ and 11-100. We also saw the number of consumers of these Clojure projects as less "in team" and more "outside team" or "outside the organization".</p>
</div>
<div class="paragraph">
<p>We added a new question this year to gauge the general experience level of Clojure developers. Almost half of Clojure users (49%) had 11 or more years of experience with 21% having 21 years or more. A recent <a href="https://snyk.io/blog/jvm-ecosystem-report-2018-processes-you/">JVM ecosystem survey</a> asked a similar question and for comparison saw 42% had 11 or more years of experience and only 3% had 21 or more years. Clojure developers tend to be more experienced on average than other JVM developers.</p>
</div>
<div class="paragraph">
<p>Survey comments said:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>"Thanks to Clojure and ClojureScript I can make a living building and maintaining large systems and delivering complex solutions on time. Thank you!"</p>
</li>
<li>
<p>"Clojure is thoughtfully designed and stable. It’s a dynamic, functional lisp that can actually be sold to the bosses. (A sentence I never thought I would write)."</p>
</li>
<li>
<p>"There is no way my team could pull all the rabbits out of hats that we do working in any other language. The only thing I ever seriously worry about, about Clojure, is how to ensure I get to work in Clojure and with Clojurists again should my current gig come to an end."</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Hundreds of <a href="xref/../../../../../community/companies">companies</a> and tens of thousands of Clojure developers are working in Clojure or ClojureScript every day, using it as the foundation of their business. The survey indicates that Clojure developers are increasingly using it more for work, at bigger companies, impacting ever larger groups of users.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="strengths"><a class="anchor" href="#strengths"></a>Strengths of Clojure</h2>
<div class="sectionbody">
<div class="paragraph">
<p>For years we have asked people what aspects of Clojure were most important to them. These answers are remarkably consistent and this year was no different. However it is good to reexamine these strengths to see why developers value Clojure. The big four that are always at the top of the list are: functional programming, immutability, the REPL, and ease of development. These traits are interrelated. Language support for immutable persistent data structures makes functional programming idiomatic and effective. A REPL on a live, growing system, with data loaded, is a great way for developers to try their new code in context as it is written, improving quality.</p>
</div>
<div class="paragraph">
<p>Other important features include host compatibility / interop (allowing us to take full advantage of the underlying platform and its libraries, whether that&#8217;s the JVM or JavaScript), the community, runtime performance, expressive syntax, concurrency support, and a shared language across tiers.</p>
</div>
<div class="paragraph">
<p>Some comments about the language:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>"Quality permeates Clojure. Language design, library design, interactive development, community architecture experience, all top notch."</p>
</li>
<li>
<p>"Clojure/script is allowing me to create things that would be impossible in other languages."</p>
</li>
<li>
<p>"Clojure is beautiful, functional and concise. It really rejuvenated my love for programming."</p>
</li>
<li>
<p>"I really appreciate the well thought out design of Clojure. We feel that Clojure gives us distinct advantages while providing a language with minimum disruption."</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="community"><a class="anchor" href="#community"></a>Vibrant Community</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The Clojure community is active, growing, and always helpful. Over the years, the primary communication mechanisms have changed along with the industry varying from IRC to the mailing lists to in recent years, Slack. We&#8217;ve been tracking this for a couple years now. Slack continues to be strong with 64% of respondents using it (note that this may be biased by where we advertised the survey!). The Clojure subreddit continued its strong rise to 55% use. ClojureTV on YouTube was a new answer this year but almost half are using it to watch Clojure videos. The official Clojure mailing lists had another drop this year as people shift away from "old school" mailing lists. And the original place where communication happened for Clojure is IRC which continued to fall out of use, now at only 7%.</p>
</div>
<div class="paragraph">
<p>We also added a new question to gauge how users of Clojure interact with the ecosystem. 96% reported being happy users of the language and libraries, 65% were building services or products, 51% were advocating for Clojure in their organization. More than a quarter (28%) were active in helping new users (something very common to see on Slack, Reddit, or the mailing lists). And 25% reported creating or maintaining open source libraries, filing issues on libraries (17%), or providing pull requests for fixes (15%).</p>
</div>
<div class="paragraph">
<p>Some quotes from users:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>"It’s been great watching the ecosystem converge on excellence these past years, thanks so much for all the work and careful design!"</p>
</li>
<li>
<p>"I love how the community continues to improve, and people generally are friendly."</p>
</li>
<li>
<p>"Thanks for a great language, a steady hand at the wheel, and a passionate community!"</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_data"><a class="anchor" href="#_the_data"></a>The Data</h2>
<div class="sectionbody">
<div class="paragraph">
<p>If you&#8217;d like to dig into the full results, you can find the complete set of data from this and former years here:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://www.surveymonkey.com/results/SM-S9JVNXNQV/">2019</a></p>
</li>
<li>
<p><a href="https://www.surveymonkey.com/results/SM-9BC5FNJ68/">2018</a></p>
</li>
<li>
<p><a href="https://www.surveymonkey.com/results/SM-7K6NXJY3/">2016</a></p>
</li>
<li>
<p><a href="http://blog.cognitect.com/blog/2016/1/28/state-of-clojure-2015-survey-results">2015</a></p>
</li>
<li>
<p><a href="http://blog.cognitect.com/blog/2014/10/20/results-of-2014-state-of-clojure-and-clojurescript-survey">2014</a></p>
</li>
<li>
<p><a href="http://cemerick.com/2013/11/18/results-of-the-2013-state-of-clojure-clojurescript-survey/">2013</a></p>
</li>
<li>
<p><a href="http://cemerick.com/2012/08/06/results-of-the-2012-state-of-clojure-survey/">2012</a></p>
</li>
<li>
<p><a href="http://cemerick.com/2011/07/11/results-of-the-2011-state-of-clojure-survey/">2011</a></p>
</li>
<li>
<p><a href="http://cemerick.com/2010/06/07/results-from-the-state-of-clojure-summer-2010-survey/">2010</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Thanks again for using Clojure and ClojureScript and participating in the survey!</p>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">En BABEL buscamos gente como tu, ¿nos conocemos?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FrontFest</a> <span class="article__date">04 02 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ¿Qué me encontraré en BABEL?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/media/2019/symfony-debug-bar.png" alt="Moving from Go to PHP again">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Moving from Go to PHP again</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Danny van Kooten</a> <span class="article__date">03 02 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Remember when <a href="/laravel-to-golang/">I ditched Laravel for Golang</a>?</p>

<p>Well, after 2 years on Go, our shop applications are powered by PHP again.</p>

<p><strong>Why?! You already said it was probably a bad business decision, and then you spend even more time on it?!</strong> Well, yeah, several reasons actually.</p>

<h3 id="php-improved-a-lot">PHP improved a lot</h3>

<p>PHP improved a lot during the last 3 years. It added <a href="https://secure.php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration">scalar argument type declarations</a>, <a href="https://secure.php.net/manual/en/functions.returning-values.php#functions.returning-values.type-declaration">return type declarations</a>, <a href="https://wiki.php.net/rfc/multiple-catch">multi-catch exceptions</a>, impressive <a href="http://www.zend.com/en/resources/php7_infographic">performance improvements</a> and many more general improvements.</p>

<h3 id="symfony4-is-a-game-changer">Symfony4 is a game changer</h3>

<p>I’ve always been a big fan of <a href="https://symfony.com/doc/current/contributing/code/bc.html">Symfony’s compatibility promise</a> and their impressive 13-year track record proves they mean it.</p>

<p>So when <a href="https://symfony.com/4">Symfony4</a> was released and I heard good things about it, I took it for a test drive by implementing a tiny part of our application in it.</p>

<p>Conclusion: it’s great. Really, really great.</p>

<p>A lot of effort went into simplifying the setup, making it a lot faster to bootstrap a Symfony application with much less work required configuring bundles. It’s now rivaling Laravel’s rapid development while at the same time encouraging decent development practices to ensure you don’t shoot yourself in the foot. And <a href="http://www.phpbenchmarks.com/en/">it performs really well</a>.</p>

<p>It was relatively easy to port our old Laravel application to Symfony, implement some new features the Go version of our application offered and undo some of the shortcuts I took earlier (most of them because of Laravel’s global helpers).</p>

<p>A nice side effect is that I’ve managed to substantially increase our test coverage in the process. Writing the same application in terms of functionality for a <del>second</del> third time really helps in that regard.</p>

<p><img src="/media/2019/symfony-debug-bar.png" alt="Symfony's debug bar" /></p>

<p>Symfony’s debug bar is an amazing tool. It shows you what happened during the journey from request to response, notifies you of warnings &amp; deprecations and comes with a built-in profiler that you can easily hook into to benchmark parts of your own code.</p>

<p><img src="/media/2019/symfony-profiler.jpg" alt="Symfony's profiler" /></p>

<p>After learning <a href="https://symfony.com/doc/current/forms.html">Symfony’s Form component</a>, I’d rather not go without it again. It makes it trivial to render an accessible form that can be re-used in several places, validating the form upon submit and then populating a PHP object from the form data safely.</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$user</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="nf">getUser</span><span class="p">();</span>
<span class="nv">$form</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="nf">createForm</span><span class="p">(</span><span class="nc">UserBillingInfoType</span><span class="o">::</span><span class="n">class</span><span class="p">,</span> <span class="nv">$user</span><span class="p">)</span>
             <span class="o">-&gt;</span><span class="nf">handleRequest</span><span class="p">(</span><span class="nv">$request</span><span class="p">);</span>

<span class="k">if</span> <span class="p">(</span><span class="nv">$form</span><span class="o">-&gt;</span><span class="nf">isSubmitted</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="nv">$form</span><span class="o">-&gt;</span><span class="nf">isValid</span><span class="p">())</span> <span class="p">{</span>
    <span class="c1">// $user is already populated with the form values at this point</span>
    <span class="c1">// it's valid, so we can update the database and redirect the user now</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Doctrine is another piece of software that really improved our overall application. Your models (<a href="https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/basic-mapping.html#basic-mapping">entities</a>) are normal PHP classes and relations (<a href="https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-associations.html#working-with-associations">associations</a>) are normal references, making it easy to test your domain logic without having to worry about the database implementation.</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$user</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">User</span><span class="p">();</span>
<span class="nv">$user</span><span class="o">-&gt;</span><span class="nf">addLicense</span><span class="p">(</span><span class="k">new</span> <span class="nc">License</span><span class="p">());</span>
<span class="nv">$manager</span><span class="o">-&gt;</span><span class="nf">persist</span><span class="p">(</span><span class="nv">$user</span><span class="p">);</span> <span class="c1">// both user and its license will be saved</span>
</code></pre></div></div>

<p>In Doctrine all operations are wrapped in a SQL transaction by default. That’s a big plus for me as it guarantees atomicity, which involved more work to get right in Eloquent.</p>

<h3 id="go-is-still-great">Go is (still) great</h3>

<p>Honestly, Go is great. Its simplicity is refreshing and you can’t get anywhere near that kind of performance using PHP <sup class="muted">1</sup>. I would still pick it if we need a small API or something that requires high throughput.</p>

<p>Our shops however are more monolithic with a lot of server-side rendering. While that’s certainly doable in Go (as the last 2 years proved), it’s more maintainable for us to do it in PHP right now.</p>

<blockquote>
  <p>Side note: without the experience gained from our years on Go, I probably wouldn’t have started <a href="https://dannyvankooten.com/reviving-ana-as-fathom/">Fathom</a>. So perhaps it wasn’t such a bad business decision after all?</p>
</blockquote>

<h3 id="making-the-correct-business-decision">Making the correct business decision</h3>

<p>One reason not mentioned so far is that over the last year or so, I’ve been approached by several companies interested to take over one of our products.</p>

<p>They were a little surprised to hear our stack involved Golang and some flat out told us they’d prefer PHP, because that’s what most of our products (<a href="https://www.mc4wp.com/">mc4wp.com</a>, <a href="https://boxzillaplugin.com">boxzillaplugin.com</a> and <a href="https://www.htmlformsplugin.com/">htmlformsplugin.com</a>) rely upon. And I don’t blame them.</p>

<hr />

<p><small><sup>1</sup> Just for fun, I compared apples and oranges again by benchmarking the login page (which doesn't hit any database) for both application versions using <a href="https://www.joedog.org/siege-home/">Siege</a>.</small></p>

<p><small>The Symfony application (PHP 7.3, OPcache enabled, optimized autoloader) handles about 1470 req/s. The Go application (compiled using Go v1.11) averages about 18600 req/s.</small></p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">ING, patrocinador Gold del FrontFest 2019</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FrontFest</a> <span class="article__date">03 02 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ING es un banco con alma de startup en el que trabajamos más de mil profesionales. A través de metodologías Agile tenemos el objetivo de poner a disposición de nuestros clientes los mejores productos y servicios en el menor tiempo posible.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">¿Conoces The Cocktail? Es patrocinador del Frontfest 2019</h1>
                            <h2 class="article__feed"><a target="_blank" href="">FrontFest</a> <span class="article__date">02 02 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Fundada en 2003 por Alberto Knapp, The Cocktail somos una consultora especializada en el diseño y ejecución de proyectos de transformación digital, mediante un enfoque integrado de desarrollo de estrategia, diseño, tecnología, datos y análisis. Estamos en Madrid, Oviedo, Londres, Ciudad de México y Bogotá, y desde junio de 2017 formamos parte del grupo WPP, potenciando nuestra propuesta a nivel internacional.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">OOP Before OOP with Simula</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Two-Bit History</a> <span class="article__date">31 01 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Imagine that you are sitting on the grassy bank of a river. Ahead of you, the water flows past swiftly. The afternoon sun has put you in an idle, philosophical mood, and you begin to wonder whether the river in front of you really exists at all. Sure, large volumes of water are going by only a few feet away. But what is this thing that you are calling a “river”? After all, the water you see is here and then gone, to be replaced only by more and different water. It doesn’t seem like the word “river” refers to any fixed thing in front of you at all. In 2009, Rich Hickey, the creator of Clojure, gave an excellent talk about why this philosophical quandary poses a problem for the object-oriented programming paradigm. He argues that we think of an object in a computer program the same way we think of a river—we imagine that the object has a fixed identity, even though many or all of the object’s properties will change over time. Doing this is a mistake, because we have no way of distinguishing between an object instance in one state and the same object instance in another state. We have no explicit notion of time in our programs. We just breezily use the same name everywhere and hope that the object is in the state we expect it to be in when we reference it. Inevitably, we write bugs.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/119-code-entropy.png" alt="Code Entropy">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Code Entropy</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">29 01 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/119-code-entropy.png" alt="Code Entropy" title="Code Entropy" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">My Story: How to Accidentally Self-Publish a Book</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Jovica Ilic</a> <span class="article__date">26 01 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Intro This is the first part of a post which will guide you through the entire process of writing and self publishing a book for the first time. It&#8217;s about my book called Mastering Vim Quickly: From WTF to OMG in no time. The idea Vim is a very powerful text editor, used mainly by sysadmins,... <a class="more-link" href="https://jovicailic.org/2019/01/accidentally-publish-a-book/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a rel="nofollow" href="https://jovicailic.org/2019/01/accidentally-publish-a-book/">My Story: How to Accidentally Self-Publish a Book</a> appeared first on <a rel="nofollow" href="https://jovicailic.org">Jovica Ilic</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q1 2019 Funding Announcement</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">23 01 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together is happy to announce that for Q1 of 2019 (February-April) we are funding two projects: Neanderthal with Dragan Djuric, and Aleph with Oleksii Kachaiev.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Gray streams</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">22 01 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>This is a copy of <a href="http://www.nhplace.com/kent/CL/Issues/stream-definition-by-user.html">http://www.nhplace.com/kent/CL/Issues/stream-definition-by-user.html</a> with syntax highlighting.</p>

<p>FAILED Issue STREAM-DEFINITION-BY-USER (&ldquo;Gray Streams&rdquo;)</p>

<p>This is the writeup of failed issue STREAM-DEFINITION-BY-USER. Because it did not pass, it has no official standing other than as a historical document.</p>

<p>NOTES:</p>

<ul>
<li><p>Several vendors have implemented this proposal anyway, so if you&rsquo;d like to use this facility, you might check to see if it&rsquo;s available in your implementation of choice in spite of not being part the &ldquo;official&rdquo; standard.</p></li>

<li><p>The facility described here is commonly referred to as &ldquo;Gray Streams&rdquo;, after David Gray, who wrote the proposal—please do not write this as &ldquo;Grey Streams&rdquo;!</p></li>

<li><p>Another facility of note that came later and may be available in some implementations is Franz&rsquo;s &ldquo;Simple Streams&rdquo;. It is newer and addresses a broader range of issues, but its availability in this or that implementation may be different.</p></li>
</ul>

<p><a href="http://www.nhplace.com/kent/CL/Issues/stream-definition-by-user-notes.html">Click here to see my personal notes on this issue.</a>
&ndash;Kent Pitman (10-Mar-2001)</p>

<p>Issue:      STREAM-DEFINITION-BY-USER</p>

<p>References: CLtL pages 329-332, 378-381, and 384-385.</p>

<p>Related issues: STREAM-INFO, CLOSED-STREAM-FUNCTIONS, STREAM-ACCESS,
        STREAM-CAPABILITIES</p>

<p>Category:   ADDITION</p>

<p>Edit history:   Version 1, 22-Mar-89 by David N. Gray</p>

<p>Status:     For discussion and evaluation; not proposed for
        inclusion in the standard at this time.</p>

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-generate-toc again -->

<p><strong>Table of Contents</strong></p>

<ul>
<li><a href="#problem-description">Problem description</a></li>
<li><a href="#proposal-stream-definition-by-usergeneric-functions">Proposal <code>stream-definition-by-user:generic-functions</code></a>

<ul>
<li><a href="#overview">Overview</a></li>
<li><a href="#character-input">Character input:</a></li>
<li><a href="#character-output">Character output</a></li>
</ul></li>
<li><a href="#rationale">Rationale</a></li>
<li><a href="#current-practice">Current practice</a></li>
<li><a href="#examples">Examples</a></li>
<li><a href="#cost-to-implementors">Cost to Implementors</a></li>
<li><a href="#cost-to-users">Cost to Users</a></li>
<li><a href="#cost-of-non-adoption">Cost of non-adoption</a></li>
<li><a href="#performance-impact">Performance impact</a></li>
<li><a href="#benefits">Benefits</a></li>
<li><a href="#esthetics">Esthetics</a></li>
<li><a href="#discussion">Discussion</a></li>
</ul>

<!-- markdown-toc end -->

<h1 id="problem-description">Problem description</h1>

<p>Common Lisp does not provide a standard way for users to define their
  own streams for use by the standard I/O functions.  This impedes the
  development of window systems for Common Lisp because, while there are
  standard Common Lisp I/O functions and there are beginning to be
  standard window systems, there is no portable way to connect them
  together to make a portable Common Lisp window system.</p>

<p>There are also many applications where users might want to define
  their own filter streams for doing things like printer device control,
  report formatting, character code translation, or
  encryption/decryption.</p>

<h1 id="proposal-stream-definition-by-user-generic-functions">Proposal <code>stream-definition-by-user:generic-functions</code></h1>

<h2 id="overview">Overview</h2>

<p>Define a set of generic functions for performing I/O.  These functions
  will have methods that specialize on the stream argument; they would
  be used by the existing I/O functions.  Users could write additional
  methods for them in order to support their own stream classes.</p>

<p>Define a set of classes to be used as the superclass of a stream class
  in order to provide some default methods.</p>

<p>## Classes</p>

<p>The following classes are to be used as super classes of user-defined
  stream classes.  They are not intended to be directly instantiated; they
  just provide places to hang default methods.</p>

<p><code>fundamental-stream</code>              [Class]</p>

<pre><code>This class is a subclass of `stream` and of `standard-object`.  `streamp`
will return true for an instance of any class that includes this.  (It
may return true for some other things also.)
</code></pre>

<p><code>fundamental-input-stream</code>            [Class]</p>

<pre><code>A subclass of `fundamental-stream`.  Its inclusion causes `input-stream-p`
to return true.
</code></pre>

<p><code>fundamental-output-stream</code>           [Class]</p>

<pre><code>A subclass of `fundamental-stream`.  Its inclusion causes `output-stream-p`
to return true.  Bi-direction streams may be formed by including both
`fundamental-output-stream` and `fundamental-input-stream`.
</code></pre>

<p><code>fundamental-character-stream</code>            [Class]</p>

<pre><code>A subclass of `fundamental-stream`.  It provides a method for
`stream-element-type` which returns `character`.
</code></pre>

<p><code>fundamental-binary-stream</code>           [Class]</p>

<pre><code>A subclass of `fundamental-stream`.  Any instantiable class that
includes this needs to define a method for `stream-element-type`.
</code></pre>

<p><code>fundamental-character-input-stream</code>      [Class]</p>

<pre><code>Includes `fundamental-input-stream` and `fundamental-character-stream`.
It provides default methods for several generic functions used for
character input.
</code></pre>

<p><code>fundamental-character-output-stream</code>     [Class]</p>

<pre><code>Includes `fundamental-output-stream` and `fundamental-character-stream`.
It provides default methods for several generic functions used for
character output.
</code></pre>

<p><code>fundamental-binary-input-stream</code>     [Class]</p>

<pre><code>Includes `fundamental-input-stream` and `fundamental-binary-stream`.
</code></pre>

<p><code>fundamental-binary-output-stream</code>        [Class]</p>

<pre><code>Includes `fundamental-output-stream` and `fundamental-binary-stream`.
</code></pre>

<h2 id="character-input">Character input</h2>

<p>A character input stream can be created by defining a class that
  includes <code>fundamental-character-input-stream</code> and defining methods for the
  generic functions below.</p>

<p><code>stream-read-char</code>  stream            [Generic Function]</p>

<pre><code>This reads one character from the stream.  It returns either a
character object, or the symbol :EOF if the stream is at end-of-file.
Every subclass of `fundamental-character-input-stream` must define a
method for this function.

Note that for all of these generic functions, the stream argument
must be a stream object, not T or NIL.
</code></pre>

<p><code>stream-unread-char</code>  stream  character       [Generic Function]</p>

<pre><code>Un-does the last call to `stream-read-char`, as in `unread-char`.  Returns
NIL.  Every subclass of `fundamental-character-input-stream` must define
a method for this function.
</code></pre>

<p><code>stream-read-char-no-hang</code>  stream        [Generic Function]</p>

<pre><code>This is used to implement `read-char-no-hang`.  It returns either a
character, or NIL if no input is currently available, or :EOF if
end-of-file is reached.  The default method provided by
`fundamental-character-input-stream` simply calls `stream-read-char`; this
is sufficient for file streams, but interactive streams should define
their own method.
</code></pre>

<p><code>stream-peek-char</code>  stream            [Generic Function]</p>

<pre><code>Used to implement `peek-char`; this corresponds to peek-type of NIL.
It returns either a character or :EOF.  The default method
calls `stream-read-char` and `stream-unread-char`.
</code></pre>

<p><code>stream-listen</code>  stream               [Generic Function]</p>

<pre><code>Used by `listen`.  Returns true or false.  The default method uses
`stream-read-char-no-hang` and `stream-unread-char`.  Most streams should
define their own method since it will usually be trivial and will
always be more efficient than the default method.
</code></pre>

<p><code>stream-read-line</code>  stream            [Generic Function]</p>

<pre><code>Used by `read-line`.  A string is returned as the first value.  The
second value is true if the string was terminated by end-of-file
instead of the end of a line.  The default method uses repeated
calls to `stream-read-char`.
</code></pre>

<p><code>stream-clear-input</code>  stream          [Generic Function]</p>

<pre><code>Implements `clear-input` for the stream, returning NIL.  The default
method does nothing.
</code></pre>

<h2 id="character-output">Character output</h2>

<p>A character output stream can be created by defining a class that
  includes <code>fundamental-character-output-stream</code> and defining methods for the
  generic functions below.</p>

<p><code>stream-write-char</code>  stream character     [Generic Function]</p>

<pre><code>Writes character to the stream and returns the character.  Every
subclass of `fundamental-character-output-stream` must have a method
defined for this function.
</code></pre>

<p><code>stream-line-column</code>  stream          [Generic Function]</p>

<pre><code>This function returns the column number where the next character
will be written, or NIL if that is not meaningful for this stream.
The first column on a line is numbered 0.  This function is used in
the implementation of `pprint` and the FORMAT ~T directive.  For every
character output stream class that is defined, a method must be
defined for this function, although it is permissible for it to
always return NIL.
</code></pre>

<p><code>stream-start-line-p</code>  stream         [Generic Function]</p>

<pre><code>This is a predicate which returns T if the stream is positioned at the
beginning of a line, else NIL.  It is permissible to always return
NIL.  This is used in the implementation of `fresh-line`.  Note that
while a value of 0 from `stream-line-column` also indicates the
beginning of a line, there are cases where `stream-start-line-p` can be
meaningfully implemented although `stream-line-column` can't be.  For
example, for a window using variable-width characters, the column
number isn't very meaningful, but the beginning of the line does have
a clear meaning.  The default method for `stream-start-line-p` on class
`fundamental-character-output-stream` uses `stream-line-column`, so if
that is defined to return `nil`, then a method should be provided for
either `stream-start-line-p` or `stream-fresh-line`.
</code></pre>

<p><code>stream-write-string</code> stream string &amp;optional start end [Generic Function]</p>

<pre><code>This is used by `write-string`.  It writes the string to the stream,
optionally delimited by start and end, which default to 0 and NIL.
The string argument is returned.  The default method provided by
`fundamental-character-output-stream` uses repeated calls to
`stream-write-char`.
</code></pre>

<p><code>stream-terpri</code>  stream               [Generic Function]</p>

<pre><code>Writes an end of line, as for `terpri`.  Returns NIL.  The default
method does (`stream-write-char` stream #\NEWLINE).
</code></pre>

<p><code>stream-fresh-line</code>  stream           [Generic Function]</p>

<pre><code>Used by `fresh-line`.  The default method uses `stream-start-line-p` and
`stream-terpri`.
</code></pre>

<p><code>stream-finish-output</code>  stream            [Generic Function]</p>

<pre><code>Implements `finish-output`.  The default method does nothing.
</code></pre>

<p><code>stream-force-output</code>  stream         [Generic Function]</p>

<pre><code>Implements `force-output`.  The default method does nothing.
</code></pre>

<p><code>stream-clear-output</code>  stream         [Generic Function]</p>

<pre><code>Implements `clear-output`.  The default method does nothing.
</code></pre>

<p><code>stream-advance-to-column</code>  stream column [Generic Function]</p>

<pre><code>Writes enough blank space so that the next character will be written
at the specified column.  Returns true if the operation is
successful, or NIL if it is not supported for this stream.
This is intended for use by by `pprint` and FORMAT ~T.  The default
method uses `stream-line-column` and repeated calls to
`stream-write-char` with a #\SPACE character; it returns NIL if
`stream-line-column` returns NIL.
</code></pre>

<p>## Other functions</p>

<p><code>close</code>  stream &amp;key abort            [Generic Function]</p>

<pre><code>The existing function `close` is redefined to be a generic function, but
otherwise behaves the same.  The default method provided by class
`fundamental-stream` sets a flag for `open-stream-p`.  The value returned
by `close` will be as specified by the issue `closed-stream-operations`.
</code></pre>

<p><code>open-stream-p</code> stream                [Generic Function]</p>

<pre><code>This function [from proposal `stream-access]` is made generic.  A
default method is provided by class `fundamental-stream` which returns
true if `close` has not been called on the stream.
</code></pre>

<p><code>streamp</code>  object             [Generic Function]</p>

<p><code>input-stream-p</code>  stream          [Generic Function]</p>

<p><code>output-stream-p</code>  stream         [Generic Function]</p>

<pre><code>These three existing predicates may optionally be implemented as
generic functions for implementations that want to permit users to
define streams that are not `standard-object`s.  Normally, the default
methods provided by classes `fundamental-input-stream` and
`fundamental-output-stream` are sufficient.  Note that, for example,
(INPUT-STREAM-P x) is not equivalent to (TYPEP x
'FUNDAMENTAL-INPUT-STREAM) because implementations may have
additional ways of defining their own streams even if they don't
make that visible by making these predicates generic.
</code></pre>

<p><code>stream-element-type</code>  stream         [Generic Function]</p>

<pre><code>This existing function is made generic, but otherwise behaves the
same.  Class `fundamental-character-stream` provides a default method
which returns `character`.
</code></pre>

<p><code>pathname</code> and <code>truename</code> are also permitted to be implemented as generic
  functions.  There is no default method since these are not valid for
  all streams.</p>

<p>## Binary streams:</p>

<pre><code>Binary streams can be created by defining a class that includes either
`fundamental-binary-input-stream` or `fundamental-binary-output-stream`
(or both) and defining a method for `stream-element-type` and for one or
both of the following generic functions.
</code></pre>

<p><code>stream-read-byte</code>  stream            [Generic Function]</p>

<pre><code>Used by `read-byte`; returns either an integer, or the symbol :EOF if the
stream is at end-of-file.
</code></pre>

<p><code>stream-write-byte</code> stream integer        [Generic Function]</p>

<pre><code>Implements `write-byte`; writes the integer to the stream and returns
the integer as the result.
</code></pre>

<h1 id="rationale">Rationale</h1>

<p>The existing I/O functions cannot be made generic because, in nearly
  every case, the stream argument is optional, and therefore cannot be
  specialized.  Therefore, it is necessary to define a lower-level
  generic function to be used by the existing function.  It also isn&rsquo;t
  appropriate to specialize on the second argument of <code>print-object</code> because
  it is a higher-level function &ndash; even when the first argument is a
  character or a string, it needs to format it in accordance with
  <code>*PRINT-ESCAPE*</code>.</p>

<p>In order to make the meaning as obvious as possible, the names of the
  generic functions have been formed by prefixing &ldquo;<code>stream-</code>&rdquo; to the
  corresponding non-generic function.</p>

<p>Having the generic input functions just return :EOF at end-of-file, with
  the higher-level functions handling the eof-error-p and eof-value
  arguments, simplifies the generic function interface and makes it more
  efficient by not needing to pass through those arguments.  Note that the
  functions that use this convention can only return a character or
  integer as a stream element, so there is no possibility of ambiguity.</p>

<p>Functions <code>stream-line-column</code>, <code>stream-start-line-p</code>, and
  <code>stream-advance-to-column</code> may appear to be a reincarnation of the
  defeated proposal <code>stream-info</code>, but the motivation here is different.
  This interface needs to be defined if user-defined streams are to be
  able to be used by <code>pprint</code> and FORMAT ~T, which could be viewed as a
  separate question from whether the user can call then on
  system-defined streams.</p>

<h1 id="current-practice">Current practice</h1>

<p>No one currently supports exactly this proposal, but this is very
  similar to the stream interface used in <code>clue</code>.</p>

<p>On descendants of the MIT Lisp Machine, streams can be implemented
  by users as either flavors, with methods to accept the various
  messages corresponding to the I/O operations, or as functions, which
  take a message keyword as their first argument.</p>

<h1 id="examples">Examples</h1>

<pre><code class="language-lisp">  ;;;; Here is an example of how the default methods could be
  ;;;; implemented (omitting the most trivial ones):

  (defmethod STREAM-PEEK-CHAR ((stream fundamental-character-input-stream))
    (let ((character (stream-read-char stream)))
      (unless (eq character :eof)
	(stream-unread-char stream character))
      character))

  (defmethod STREAM-LISTEN ((stream fundamental-character-input-stream))
    (let ((char (stream-read-char-no-hang stream)))
      (and (not (null char))
	   (not (eq char :eof))
	   (progn (stream-unread-char stream char) t))))

  (defmethod STREAM-READ-LINE ((stream fundamental-character-input-stream))
    (let ((line (make-array 64 :element-type 'string-char
			    :fill-pointer 0 :adjustable t)))
      (loop (let ((character (stream-read-char stream)))
	      (if (eq character :eof)
		  (return (values line t))
		(if (eql character #\newline)
		    (return (values line nil))
		  (vector-push-extend character line)))))))

  (defmethod STREAM-START-LINE-P ((stream fundamental-character-output-stream))
    (equal (stream-line-column stream) 0))

  (defmethod STREAM-WRITE-STRING ((stream fundamental-character-output-stream)
				  string &amp;optional (start 0)
				  (end (length string)))
    (do ((i start (1+ i)))
	((&gt;= i end) string)
      (stream-write-char stream (char string i))))

  (defmethod STREAM-TERPRI ((stream fundamental-character-output-stream))
    (stream-write-char stream #\newline)
    nil)

  (defmethod STREAM-FRESH-LINE ((stream fundamental-character-output-stream))
    (if (stream-start-line-p stream)
	nil
      (progn (stream-terpri stream) t)))

  (defmethod STREAM-ADVANCE-TO-COLUMN ((stream fundamental-character-output-stream)
				       column)
    (let ((current (stream-line-column stream)))
      (unless (null current)
	(dotimes (i (- current column) t)
	  (stream-write-char stream #\space)))))

  (defmethod INPUT-STREAM-P ((stream fundamental-input-stream)) t)
  (defmethod INPUT-STREAM-P ((stream fundamental-output-stream))
    ;; allow the two classes to be mixed in either order
    (typep stream 'fundamental-input-stream))
  (defmethod OUTPUT-STREAM-P ((stream fundamental-output-stream)) t)
  (defmethod OUTPUT-STREAM-P ((stream fundamental-input-stream))
    (typep stream 'fundamental-output-stream))

  ;;;; Following is an example of how the existing I/O functions could
  ;;;; be implemented using standard Common Lisp and the generic
  ;;;; functions specified above.  The standard functions being defined
  ;;;; are in upper case.

  ;;  Internal helper functions

  (proclaim '(inline decode-read-arg decode-print-arg check-for-eof))
  (defun decode-read-arg (arg)
    (cond ((null arg) *standard-input*)
	  ((eq arg t) *terminal-io*)
	  (t arg)))

  (defun decode-print-arg (arg)
    (cond ((null arg) *standard-output*)
	  ((eq arg t) *terminal-io*)
	  (t arg)))

  (defun check-for-eof (value stream eof-errorp eof-value)
    (if (eq value :eof)
	(report-eof stream eof-errorp eof-value)
      value))

  (defun report-eof (stream eof-errorp eof-value)
    (if eof-errorp
	(error 'end-of-file :stream stream)
      eof-value))

  ;;;  Common Lisp input functions

  (defun READ-CHAR (&amp;optional input-stream (eof-errorp t) eof-value recursive-p)
    (declare (ignore recursive-p)) ; a mistake in CLtL?
    (let ((stream (decode-read-arg input-stream)))
      (check-for-eof (stream-read-char stream) stream eof-errorp eof-value)))

  (defun PEEK-CHAR (&amp;optional peek-type input-stream (eof-errorp t)
			eof-value recursive-p)
    (declare (ignore recursive-p))
    (let ((stream (decode-read-arg input-stream)))
      (if (null peek-type)
	  (check-for-eof (stream-peek-char stream) stream eof-errorp eof-value)
        (loop
	  (let ((value (stream-peek-char stream)))
	    (if (eq value :eof)
		(return (report-eof stream eof-errorp eof-value))
	      (if (if (eq peek-type t)
		      (not (member value '(#\space #\tab #\newline
					   #\page #\return #\linefeed)))
		    (char= peek-type value))
		  (return value)
		(stream-read-char stream))))))))

  (defun UNREAD-CHAR (character &amp;optional input-stream)
    (stream-unread-char (decode-read-arg input-stream) character))

  (defun LISTEN (&amp;optional input-stream)
    (stream-listen (decode-read-arg input-stream)))

  (defun READ-LINE (&amp;optional input-stream (eof-error-p t)
			eof-value recursive-p)
    (declare (ignore recursive-p))
    (let ((stream (decode-read-arg input-stream)))
      (multiple-value-bind (string eofp)
	  (stream-read-line stream)
	(if eofp
	    (if (= (length string) 0)
		(report-eof stream eof-error-p eof-value)
	      (values string t))
	  (values string nil)))))

  (defun CLEAR-INPUT (&amp;optional input-stream)
    (stream-clear-input (decode-read-arg input-stream)))

  (defun READ-CHAR-NO-HANG (&amp;optional input-stream (eof-errorp t)
				eof-value recursive-p)
    (declare (ignore recursive-p))
    (let ((stream (decode-read-arg input-stream)))
      (check-for-eof (stream-read-char-no-hang stream)
		     stream eof-errorp eof-value)))

  ;;;  Common Lisp output functions

  (defun WRITE-CHAR (character &amp;optional output-stream)
     (stream-write-char (decode-print-arg output-stream) character))

  (defun FRESH-LINE (&amp;optional output-stream)
    (stream-fresh-line (decode-print-arg output-stream)))

  (defun TERPRI (&amp;optional output-stream)
    (stream-terpri (decode-print-arg output-stream)))

  (defun WRITE-STRING (string &amp;optional output-stream &amp;key (start 0) end)
    (stream-write-string (decode-print-arg output-stream) string start end))

  (defun WRITE-LINE (string &amp;optional output-stream &amp;key (start 0) end)
    (let ((stream (decode-print-arg output-stream)))
      (stream-write-string stream string start end)
      (stream-terpri stream)
      string))

  (defun FORCE-OUTPUT (&amp;optional stream)
    (stream-force-output (decode-print-arg stream)))

  (defun FINISH-OUTPUT (&amp;optional stream)
    (stream-finish-output (decode-print-arg stream)))

  (defun CLEAR-OUTPUT (&amp;optional stream)
    (stream-clear-output (decode-print-arg stream)))

  ;;;  Binary streams

  (defun READ-BYTE (binary-input-stream &amp;optional (eof-errorp t) eof-value)
    (check-for-eof (stream-read-byte binary-input-stream)
		   binary-input-stream eof-errorp eof-value))

  (defun WRITE-BYTE (integer binary-output-stream)
    (stream-write-byte binary-output-stream integer))

  ;;;  String streams

  (defclass string-input-stream (fundamental-character-input-stream)
    ((string :initarg :string :type string)
     (index :initarg :start :type fixnum)
     (end :initarg :end :type fixnum)
     ))

  (defun MAKE-STRING-INPUT-STREAM (string &amp;optional (start 0) end)
    (make-instance 'string-input-stream :string string
		   :start start :end (or end (length string))))

  (defmethod stream-read-char ((stream string-input-stream))
    (with-slots (index end string) stream
      (if (&gt;= index end)
	  :eof
	(prog1 (char string index)
	       (incf index)))))

  (defmethod stream-unread-char ((stream string-input-stream) character)
    (with-slots (index end string) stream
      (decf index)
      (assert (eql (char string index) character))
      nil))

  (defmethod stream-read-line ((stream string-input-stream))
    (with-slots (index end string) stream
      (let* ((endline (position #\newline string :start index :end end))
	     (line (subseq string index endline)))
	(if endline
	    (progn (setq index (1+ endline))
		   (values line nil))
	  (progn (setq index end)
		 (values line t))))))

  (defclass string-output-stream (fundamental-character-output-stream)
    ((string :initform nil :initarg :string)))

  (defun MAKE-STRING-OUTPUT-STREAM ()
    (make-instance 'string-output-stream))

  (defun GET-OUTPUT-STREAM-STRING (stream)
    (with-slots (string) stream
      (if (null string)
	  &quot;&quot;
	(prog1 string (setq string nil)))))

  (defmethod stream-write-char ((stream string-output-stream) character)
    (with-slots (string) stream
      (when (null string)
	(setq string (make-array 64. :element-type 'string-char
				 :fill-pointer 0 :adjustable t)))
      (vector-push-extend character string)
      character))

  (defmethod stream-line-column ((stream string-output-stream))
    (with-slots (string) stream
      (if (null string)
	  0
	(let ((nx (position #\newline string :from-end t)))
	  (if (null nx)
	      (length string)
	    (- (length string) nx 1))
	  ))))
</code></pre>

<h1 id="cost-to-implementors">Cost to Implementors</h1>

<p>Given that CLOS is supported, adding the above generic functions and
  methods is easy, since most of the code is included in the examples
  above.  The hard part would be re-writing existing I/O functionality in
  terms of methods on these new generic functions.  That could be
  simplified if methods can be defined to forward the operations to the
  old representation of streams.  For a new implementation, the cost could
  be zero since an approach similar to this would likely be used anyway.</p>

<h1 id="cost-to-users">Cost to Users</h1>

<p>None; this is an upward-compatible addition.   Users won&rsquo;t even
  need to know anything about this unless they actually need this feature.</p>

<h1 id="cost-of-non-adoption">Cost of non-adoption</h1>

<p>Development of portable I/O extensions will be discouraged.</p>

<h1 id="performance-impact">Performance impact</h1>

<p>This shouldn&rsquo;t affect performance of new implementations (assuming an
  efficient CLOS implementation), but it could slow down I/O if it were
  clumsily grafted on top of an existing implementation.</p>

<h1 id="benefits">Benefits</h1>

<p>A broader domain of programs that can be written portably.</p>

<h1 id="esthetics">Esthetics</h1>

<p>This seems to be a simple, straight-forward approach.</p>

<h1 id="discussion">Discussion</h1>

<p>This proposal incorporates suggestions made by several people in
  response to an earlier outline.  So far, no one has expressed opposition
  to the concept.  There are some differences of opinion about whether
  certain operations should have default methods or required methods:
  <code>stream-listen</code>, <code>stream-read-char-no-hang</code>, <code>stream-line-column</code>,
  and <code>stream-start-line-p</code>.</p>

<p>An experimental prototype of this has been successfully implemented on
  the Explorer.</p>

<p>This proposal does not provide sufficient capability to implement
  forwarding streams such as for <code>make-synonym-stream</code>,
  <code>make-broadcast-stream</code>, <code>make-concatenated-stream</code>, <code>make-two-way-stream</code>, or
  <code>make-echo-stream</code>.  The generic function approach does not lend itself as
  well to that as a message passing model where the intermediary does not
  need to know what all the possible messages are.  A possible way of
  extending it for that would be to define a class</p>

<pre><code class="language-lisp">    (defclass stream-generic-function (standard-generic-function) ())
</code></pre>

<p>to be used as the :generic-function-class option for all of the I/O
  generic functions.  This would then permit doing something like</p>

<pre><code class="language-lisp">  (defmethod no-applicable-method ((gfun stream-generic-function) &amp;rest args)
    (if (streamp (first args))
	(apply #'stream-operation-not-handled (first args) gfun (rest args))
      (call-next-method)))
</code></pre>

<p>where stream-operation-not-handled is a generic function whose default
  method signals an error, but forwarding streams can define methods that
  will create a method to handle the unexpected operation.  (Perhaps
  <code>no-applicable-method</code> should be changed to take two required arguments
  since all generic functions need at least one required argument, and
  that would make it unnecessary to define a new generic function class
  just to be able to write this one method.)</p>

<p>Another thing that is not addressed here is a way to cause an instance
  of a user-defined stream class to be created from a call to the <code>open</code>
  function.  That should be part of a separate issue for generic functions
  on pathnames.  If that capability were available, then <code>pathname</code> and
  <code>truename</code> should be required to be generic functions.</p>

<p>An earlier draft defined just two classes, <code>fundamental-input-stream</code> and
  <code>fundamental-output-stream</code>, that were used for both character and binary
  streams.  It isn&rsquo;t clear whether that simple approach is sufficient or
  whether the larger set of classes is really needed.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/118-meeting.png" alt="Meeting">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Meeting</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">22 01 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/118-meeting.png" alt="Meeting" title="Meeting" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Running Luminus on Dokku</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">19 01 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Luminus provides a great way to get up and running with a Clojure web application. However, building your app is only half the work. Once you've got your app working, the next step is to host it somewhere so that the users can access it.</p><p>Cloud platforms, such as AWS, are a popular choice for deploying large scale solutions. On the other hand, VPS services like Digital Ocean and Linode provide a more economical alternative for small scale applications. The downside of running your own VPS is that managing it can be labor intensive. This is where <a href='http://dokku.viewdocs.io/dokku/'>Dokku</a> comes in. It's a private PaaS modelled on Heroku that you can use to provision a VPS.</p><p>Let's take a look at what's involved in provisioning a Digital Ocean droplet with Dokku and deploying a Luminus web app to it.</p><h3 id="set&#95;up&#95;the&#95;server">Set up the server</h3><p>Let's create a droplet with Ubuntu LTS (18.0.4 at the time of writing) and SSH into it. We'll need to add new APT repositories before we install Dokku.  </p><ol><li>add the universe repository <code>sudo add-apt-repository universe</code></li><li>add the key <code>wget -nv -O - https://packagecloud.io/dokku/dokku/gpgkey | apt-key add -</code></li><li>add the Dokku repo <code>echo &quot;deb https://packagecloud.io/dokku/dokku/ubuntu/ bionic main&quot; &gt; /etc/apt/sources.list.d/dokku.list</code></li></ol><p>Once the repositories are added, we'll need to update the dependencies and install Dokku.</p><ol><li>update dependencies <code>sudo apt-get update &amp;&amp; sudo apt-get upgrade</code></li><li>install dokku <code>apt-get install dokku</code></li></ol><p>Once Dokku is installed, we'll create an application and a Postgres database instance.</p><ul><li>create the app <code>dokku apps:create myapp</code></li><li>install <a href='https://github.com/dokku/dokku-postgres'>dokku-postgres plugin</a> <code>sudo dokku plugin:install https://github.com/dokku/dokku-postgres.git</code></li><li>create the db <code>dokku postgres:create mydb</code></li><li>link the db to the app <code>dokku postgres:link mydb myapp</code></li></ul><p>We're now ready to deploy the app.</p><h3 id="create&#95;a&#95;new&#95;luminus&#95;application">Create a new Luminus application</h3><p>Let's create a Luminus application on your local machine.</p><ol><li><code>lein new luminus myapp +postgres</code></li><li><code>cd myapp</code></li></ol><p>Let's update the app to run migrations on startup by updating the <code>myapp.core/start-app</code> function to run the migrations.</p><pre><code class="clojure">&#40;defn start-app &#91;args&#93;
  &#40;doseq &#91;component &#40;-&gt; args
                        &#40;parse-opts cli-options&#41;
                        mount/start-with-args
                        :started&#41;&#93;
    &#40;log/info component &quot;started&quot;&#41;&#41;

  ;;run migrations  
  &#40;migrations/migrate &#91;&quot;migrate&quot;&#93; &#40;select-keys env &#91;:database-url&#93;&#41;&#41;

  &#40;.addShutdownHook &#40;Runtime/getRuntime&#41; &#40;Thread. stop-app&#41;&#41;&#41;
</code></pre><p>Next, we need to update <code>env/prod/resources/logback.xml</code> to use <code>STDOUT</code> for the logs:</p><pre><code class="xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;configuration&gt;
    &lt;statusListener class=&quot;ch.qos.logback.core.status.NopStatusListener&quot; /&gt;
    &lt;appender name=&quot;STDOUT&quot; class=&quot;ch.qos.logback.core.ConsoleAppender&quot;&gt;
        &lt;!-- encoders are assigned the type
             ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --&gt;
        &lt;encoder&gt;
            &lt;charset&gt;UTF-8&lt;/charset&gt;
            &lt;pattern&gt;%date{ISO8601} &#91;%thread&#93; %-5level %logger{36} - %msg %n&lt;/pattern&gt;
        &lt;/encoder&gt;
    &lt;/appender&gt;
    &lt;logger name=&quot;org.apache.http&quot; level=&quot;warn&quot; /&gt;
    &lt;logger name=&quot;org.xnio.nio&quot; level=&quot;warn&quot; /&gt;
    &lt;logger name=&quot;com.zaxxer.hikari&quot; level=&quot;warn&quot; /&gt;
    &lt;root level=&quot;INFO&quot;&gt;
        &lt;appender-ref ref=&quot;STDOUT&quot; /&gt;
    &lt;/root&gt;
&lt;/configuration&gt;
</code></pre><h3 id="deploy&#95;the&#95;application&#95;to&#95;dokku">Deploy the application to Dokku</h3><p>We're now ready to deploy the app. First, we'll need to create a Git repo and add the app contents to it.</p><ol><li><code>git init</code></li><li><code>git add .gitignore Procfile project.clj README.md src/&#42; env/&#42; test/&#42; resources/&#42;</code></li><li><code>git commit -a -m &quot;initial commit&quot;</code></li></ol><p>Note that you do not want to check in <code>Dockerfile</code> that's generated by the template. Dokku will use it as the preferred strategy for creating the container.</p><p>Next, we'll add the remote for the Dokku repository on the server and push the project to the remote. Dokku will automatically build the project once it's pushed, and deploy the application when the build is successful.</p><ol><li><code>git remote add dokku dokku@&lt;server name&gt;:myapp</code></li><li><code>git push dokku master</code></li></ol><p>The app will be pushed to the server where it will be compiled and run. If everything went well you should see output that looks something like the following:</p><pre><code>...
-----&gt; Building with Leiningen
       Running: lein uberjar
       Compiling sample.app
       2019-01-18 01:10:30.857:INFO::main: Logging initialized @6674ms to org.eclipse.jetty.util.log.StdErrLog
       Created /tmp/build/target/myapp-1.0.1.jar
       Created /tmp/build/target/myapp.jar
...
=====&gt; web=1
...
-----&gt; Waiting for 10 seconds ...
-----&gt; Default container check successful!
-----&gt; Running post-deploy
-----&gt; Configuring myapp.&lt;server name&gt;...&#40;using built-in template&#41;
-----&gt; Creating http nginx.conf
-----&gt; Running nginx-pre-reload
       Reloading nginx
-----&gt; Setting config vars
       DOKKU&#95;APP&#95;RESTORE:  1
=====&gt; 8dc31ac11011111117f71e4311111ca5962cf316411d5f0125e87bbac26
=====&gt; Application deployed:
       http://myapp.&lt;server name&gt;

To http://&lt;server name&gt;:myapp
   6dcab39..1c0c8b7  master -&gt; master
</code></pre><p>We can check the status of the application in the logs by running <code>dokku logs myapp</code> command on the server. The output should looks something like the following.</p><pre><code class="Setting JAVA_TOOL_OPTIONS defaults based on dyno size. Custom settings will override them.">Picked up JAVA&#95;TOOL&#95;OPTIONS: -Xmx300m -Xss512k -XX:CICompilerCount=2 -Dfile.encoding=UTF-8
2019-01-19 19:09:48,258 &#91;main&#93; INFO  myapp.env -
-=&#91;myapp started successfully&#93;=-
2019-01-19 19:09:50,490 &#91;main&#93; INFO  luminus.http-server - starting HTTP server on port 5000
2019-01-19 19:09:50,628 &#91;main&#93; INFO  org.xnio - XNIO version 3.3.6.Final
2019-01-19 19:09:51,236 &#91;main&#93; INFO  org.projectodd.wunderboss.web.Web - Registered web context /
2019-01-19 19:09:51,242 &#91;main&#93; INFO  myapp.core - #'myapp.config/env started
2019-01-19 19:09:51,243 &#91;main&#93; INFO  myapp.core - #'myapp.db.core/&#42;db&#42; started
2019-01-19 19:09:51,243 &#91;main&#93; INFO  myapp.core - #'myapp.handler/init-app started
2019-01-19 19:09:51,244 &#91;main&#93; INFO  myapp.core - #'myapp.handler/app started
2019-01-19 19:09:51,249 &#91;main&#93; INFO  myapp.core - #'myapp.core/http-server started
2019-01-19 19:09:51,249 &#91;main&#93; INFO  myapp.core - #'myapp.core/repl-server started
2019-01-19 19:09:51,250 &#91;main&#93; INFO  myapp.core - running migrations
2019-01-19 19:09:51,257 &#91;main&#93; INFO  migratus.core - Starting migrations
2019-01-19 19:09:51,418 &#91;main&#93; INFO  migratus.database - creating migration table 'schema&#95;migrations'
2019-01-19 19:09:51,992 &#91;main&#93; INFO  migratus.core - Running up for &#91;20190118214013&#93;
2019-01-19 19:09:51,997 &#91;main&#93; INFO  migratus.core - Up 20190118214013-add-users-table
2019-01-19 19:09:52,099 &#91;main&#93; INFO  migratus.core - Ending migrations
</code></pre><p>You should now be able to check your application in the browser by navigating to <code>http://&lt;server name&gt;</code>.</p><h3 id="troubleshooting&#95;the&#95;database">Troubleshooting the database</h3><p>The startup logs for the application indicate that it was able to connect to the database and run the migrations successfully. Let's confirm this is the case by connecting a <code>psql</code> shell to the database container on the server.</p><pre><code>dokku postgres:connect mydb
mydb=# \d
               List of relations
 Schema |       Name        | Type  |  Owner
--------+-------------------+-------+----------
 public | schema&#95;migrations | table | postgres
 public | users             | table | postgres
&#40;2 rows&#41;
</code></pre><p>We can see that the database contains the <code>schema&#95;migrations</code> table and the <code>users</code> table that were created when the app migrations ran.</p><p>Sometimes it might be useful to connect a more advanced client such as <a href='https://dbeaver.io/'>DBeaver</a>. This can done by exposing the database on the server using the following command.</p><pre><code>sudo dokku postgres:expose mydb 5000
</code></pre><p>Next, we'll enter the container for the application to get the database connection details.</p><pre><code>dokku enter myapp web
echo $DATABASE&#95;URL
</code></pre><p>The <code>DATABASE&#95;URL</code> environment variable in the container will contain the connection string that looks as follows.</p><pre><code>postgres://postgres:&lt;password&gt;@dokku-postgres-mydb:5432/mydb
</code></pre><p>We can now map the port to the local machine using SSH, and connect to the database as if it was running on the local machine using the connection settings above.</p><pre><code>ssh -L 5432:localhost:5000 &lt;server name&gt;
</code></pre><h3 id="set&#95;up&#95;https&#95;using&#95;let's&#95;encrypt">Set up HTTPS using Let's Encrypt</h3><p>As the last step we'll set up HTTPS for the application using <a href='https://github.com/dokku/dokku-letsencrypt'>dokku-letsencrypt</a> plugin. We'll set the app to run on the root domain on the server.</p><ol><li>add the root domain to the app <code>dokku domains:add myapp &lt;server name&gt;</code></li><li>remove the subdomain from the app <code>dokku domains:remove myapp myapp.&lt;server name&gt;</code></li><li>install the plugin <code>sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git</code></li><li>set the email for renewal warnings <code>dokku config:set --no-restart myapp DOKKU&#95;LETSENCRYPT&#95;EMAIL=&lt;your email&gt;</code></li><li>add HTTPS to the app <code>sudo dokku letsencrypt myapp</code></li><li>set up auto-renew for the certificate <code>dokku letsencrypt:auto-renew</code></li></ol><p>That's all there is to it. The application is now deployed to the droplet, it's hooked up to the database, and it's using Let's Encrypt SSL/TLS Certificates.</p><p>Any further updates to the application simply involve committing the changes to the local Git repo and pushing them to the server as we did with our initial deploy.</p><p>I recommend taking look at the <a href='http://dokku.viewdocs.io/dokku/getting-started/installation/'>official documentation</a> on the Dokku site for more information about Dokku. I think it provides an excellent solution for running your VPS. If you're evaluating different options for deploying your Clojure apps give Dokku a look.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">December 2018 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">16 01 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Thanks again to those who participated in our Q1 2019 survey, we greatly value your feedback.
Project applications for our Q1 2019 round close on 15th Jan, midnight PST. The selections will be announced shortly afterwards. The Q1 2019 projects will start on February 1.
This month we have updates again from Datascript and Kaocha.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">These Months in Common Lisp Q4 2018</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">15 01 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<ul>
<li><a href="https://lisp-journey.gitlab.io/blog/these-months-in-common-lisp-q1-2018/">Q1 2018</a></li>
<li><a href="https://lisp-journey.gitlab.io/blog/these-months-in-common-lisp-q2-2018/">Q2 2018</a></li>
<li><a href="https://lisp-journey.gitlab.io/blog/these-months-in-common-lisp-q3-2018/">Q3 2018</a></li>
</ul>

<p>I wanted to do this for a year and here we are ! I don&rsquo;t think I&rsquo;ll
carry on, with this format at least.</p>

<p>If I missed anything crucial: you have comments and PRs: <a href="https://gitlab.com/lisp-journey/lisp-journey.gitlab.io/">https://gitlab.com/lisp-journey/lisp-journey.gitlab.io/</a></p>

<p>Happy (re)discoveries !</p>

<h1 id="documentation">Documentation</h1>

<ul>
<li><a href="https://lispcookbook.github.io/cl-cookbook/debugging.html">Debugging – the Common Lisp Cookbook</a></li>
<li><a href="https://lispcookbook.github.io/cl-cookbook/iteration.html">Loop, iteration, mapping – the Common Lisp Cookbook</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/a9at82/clexercise_common_lisp_learning_system_running_on/">cl-exercise: Common Lisp Learning System running on browsers</a></li>
</ul>

<h1 id="announcements">Announcements</h1>

<ul>
<li>various <a href="http://www.sbcl.org/all-news.html">SBCL releases</a> (from 1.4.13 to 1.4.15) (<a href="https://www.reddit.com/r/lisp/comments/9s6nen/sbcl_1413_released/">not many changes you think ?</a>)</li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/aaxp2c/release_corman_lisp_31_sharplisperscormanlisp/">Release of Corman Lisp 3.1 (Windows)</a>, with <a href="https://chaoticlab.io/lisp/update/2018/12/30/corman-3-1-release.html">personal notes</a> (also <a href="https://www.reddit.com/r/Common_Lisp/comments/a3hhpa/the_upcoming_release_of_corman_lisp_31_issue_40/">this thread</a>)</li>
<li><a href="https://european-lisp-symposium.org/2019/index.html">European Lisp Symposium 2019 - Call for Papers</a></li>
<li><a href="https://github.com/Ragnaroek/dandelion">Dandelion, Eclipse IDE plugin, updated for SBCL 1.4.10</a></li>
<li><a href="http://blog.quicklisp.org/2018/12/december-2018-quicklisp-dist-update-now.html">December Quicklisp update</a>, <a href="http://blog.quicklisp.org/2018/10/october-2018-quicklisp-dist-update-now.html">october</a></li>
<li><a href="https://open.kattis.com/help">Common Lisp is now available to use at Kattis</a></li>
</ul>

<h1 id="projects">Projects</h1>

<ul>
<li><a href="https://hub.docker.com/r/drmeister/cando/">CANDO - A Computational Chemistry programming environment integrating Common Lisp and C++ based on the Jupyter notebook</a></li>
<li><a href="https://github.com/tarballs-are-good/coalton">Coalton, a dialect of ML embedded in Common Lisp (alpha)</a></li>
<li><a href="Ulubis - A Wayland compositor written in Common Lisp">Ulubis - A Wayland compositor written in Common Lisp</a></li>
<li><a href="https://gitlab.com/DataLinkDroid/iso-8601-date">ISO 8601 date/time library</a></li>
<li><a href="https://github.com/terminal625/sucle">Voxel game engine (Minecraft)</a></li>
<li><a href="https://gitlab.com/Theemacsshibe/magrathea">magrathea: chaotic-neutral web security for Hunchentoot</a></li>
<li><a href="https://github.com/fjames86/schannel">schannel: Common Lisp Windows SChannel API</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/9qguq3/qbase64_a_fast_and_flexible_base64_encoderdecoder/">qbase64: A fast and flexible base64 encoder/decoder in Lisp</a></li>
<li><a href="https://addons.mozilla.org/en-US/firefox/addon/beautify-practical-common-lisp/">Beautify Practical Common Lisp, Firefox extension</a></li>
<li><a href="https://github.com/alex-gutev/static-dispatch/">static-dispatch: Static generic function dispatch. The purpose is to provide an optimization in cases where the usual dynamic dispatch is too slow, and the dynamic features are not required</a></li>
<li><a href="https://github.com/akamai/cl-http2-protocol">cl-http2-protocol: HTTP/2 interop library in Common Lisp</a></li>
<li><a href="cl-punch: Scala-like and CL21-like anonymous lambda literal">cl-punch: Scala-like and CL21-like anonymous lambda literal</a> See other <a href="https://github.com/CodyReichert/awesome-cl#lambda-shorthands">lambda shorthands</a>.</li>
<li><a href="http://www.ccs.neu.edu/home/dorai/mbe/mbe-lsp.html">Scheme macros for Common Lisp</a></li>
<li><a href="https://github.com/patrikhaslum/INVAL">The INVAL plan validator, and other PDDL tools</a></li>
<li><a href="https://gitlab.com/DataLinkDroid/slk-581">Australian Government statistics collection library</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/aaxsas/easybind_easy_local_binding_for_common_lisp/">Easy local bindings</a></li>
<li><a href="https://gitlab.com/stacksmith/cl-fm">cl-fm - a file manager using cl-cffi-gtk (seems staling. &ldquo;not ready for prime time&rdquo;)</a></li>
<li><a href="https://github.com/rpav/cl-interval">cl-intervals: Intervals and interval trees for Common Lisp</a></li>
</ul>

<p>GUI:</p>

<ul>
<li><a href="https://notabug.org/cage/nodgui">nodgui - yet another Tcl/Tk-based GUI package for Common Lisp</a></li>
<li><a href="http://en.ystok.ru/products/ywidgets/">YstokWidgets Professional Edition</a></li>
<li><a href="https://common-lisp.net/~loliveira/ediware/midgets/doc/">MIDGETS - A collection of CAPI widgets and utilities</a></li>
<li><a href="https://github.com/stacksmith/subtext">subtext: A mostly-text-based UI bridges Common Lisp objects and runs of text. Minimal text-based user interface</a></li>
</ul>

<p>Developer utilities:</p>

<ul>
<li><a href="https://github.com/hjudt/s2i-lisp">s2i-lisp: Common Lisp + Quicklisp OpenShift Build Image</a></li>
<li><a href="https://github.com/fisxoj/lisp-images">lisp-images: Docker images for common lisp development</a> (with some others, see the awesome-list)</li>
<li><a href="https://gitlab.com/HiPhish/quicklisp.nvim">Quicklisp.nvim - Common Lisp package management within Neovim</a></li>
</ul>

<p>New releases:</p>

<ul>
<li><a href="https://jscl-project.github.io/">JSCL 0.7.0 now supports CLOS thanks to the work of vlad-km</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/a954yf/next_browser_120_is_out/">Next browser 1.2.0 is out!</a></li>
<li><a href="https://github.com/cxxxr/lem/releases">Lem editor 1.5 released with executables, rust-mode, nim-mode, html-mode, jsx, calc-mode, ncurses for windows, experimental lsp-mode, support for async processes, python and scheme repl and more</a></li>
</ul>

<p>(re)discoveries:</p>

<ul>
<li><a href="https://github.com/mmontone/cl-rest-server">cl-rest-server: Serve REST APIs from Common Lisp, Swagger support </a></li>
<li><a href="https://github.com/lmj/lfarm">lfarm - a library for distributing work across machines (on top of lparallel and usocket)</a></li>
<li><a href="https://github.com/willijar/cl-docutils">cl-docutils: implementation of Docutils. Includes a parser for the reStructured format, writers to html and latex</a></li>
<li><a href="https://github.com/tarballs-are-good/formulador">formulador: render math formulas in 2D in your terminal!</a></li>
<li><a href="https://github.com/mkoeppe/cl-bibtex">cl-bibtex: A compatible re-implementation of the BibTeX program in Common Lisp, with a BST-to-CL compiler</a></li>
<li><a href="https://bitbucket.org/budden/clcon/wiki/Screenshots">clcon - a Common Lisp editor (tcl/tk, mostly russian)</a></li>
<li><a href="https://github.com/y2q-actionman/with-c-syntax">C language syntax embedded in Common Lisp</a></li>
</ul>

<h1 id="articles">Articles</h1>

<ul>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/9pf2nd/this_old_lisp/">This Old Lisp (on CCL)</a></li>
<li><a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5952920/">How the strengths of Lisp-family languages facilitate building complex and flexible bioinformatics applications</a></li>
<li><a href="https://lisper.in/nlp-date-parser">Writing a natural language date and time parser - internals of the Common Lisp library Chronicity</a></li>
<li><a href="https://nl.movim.eu/?blog/phoe%40movim.eu/a9391f4b-485e-4f3a-ae02-051a5fc65ed1">validate-superclass explained</a></li>
<li><a href="https://nl.movim.eu/?blog/phoe%40movim.eu/cffi-arrays-versus-static-vectors-a-comparison-SCutJQ">CFFI arrays versus STATIC-VECTORS: a comparison</a></li>
<li><a href="https://nl.movim.eu/?blog/phoe%40movim.eu/82419fb5-a24c-4350-a9c8-c7ae8c6aa2a6">Dumping Common Lisp streams</a></li>
<li><a href="https://nl.movim.eu/?blog/phoe%40movim.eu/killing-common-lisp-methods-and-classes-b23ADB">Killing Common Lisp methods and classes</a></li>
<li><a href="http://eshamster.hatenablog.com/entry/play-define-method-combination-01">Funny method combinations</a></li>
<li><a href="https://www.darkchestnut.com/2018/hunchentoot_custom_sessions/">Implementing Hunchentoot custom sessions</a></li>
<li><a href="https://lisp-journey.gitlab.io/blog/overview-of-documentation-generators/">Overview of Documentation Generators (codex, coo, declt, staple, cldomain)</a></li>
<li><a href="https://github.com/TomLisankie/Learning-Lisp">Challenging myself to learn Common Lisp in one month</a></li>
<li><a href="https://fourier.github.io/lisp/2019/01/02/reflex-map.html">Converter of maps from Reflex Arena to QuakeWorld. cl-yacc, 3d-matrices</a></li>
<li><a href="https://two-wrongs.com/debugging-common-lisp-in-slime.html">Debugging Common Lisp in Slime</a></li>
<li><a href="https://www-fourier.ujf-grenoble.fr/~sergerar/Papers/Packaging.pdf">Packages in Common Lisp, a tutorial (pdf)</a></li>
<li><a href="https://www.darkchestnut.com/2018/how-to-write-5am-test-fixtures/">How to write test fixtures for FiveAM - Dark Chestnut</a></li>
<li><a href="https://allegrograph.com/franz-and-semantic-web-company-partner-to-create-a-noam-chomsky-knowledge-graph/">Franz and Semantic Web Co. Partner to Create a Noam Chomsky Knowledge Graph</a></li>
<li><a href="https://michaelgogins.tumblr.com/post/178126207468/composing-in-lisp">Composing in Lisp with Csound</a> (see also <a href="https://github.com/CodyReichert/awesome-cl#audio">audio and music composition software</a>)</li>
<li><a href="https://terranostra.one/posts/Blogging-with-Lisp.html">Blogging with Lisp</a></li>
<li><a href="http://notes.eatonphil.com/compiler-basics-lisp-to-assembly.html">Compiler basics: lisp to assembly</a></li>
<li><a href="https://www.webofstories.com/play/marvin.minsky/44">Marvin Minsky - Scientist - The beauty of the Lisp language</a></li>
</ul>

<p>GUIs:</p>

<ul>
<li><a href="https://common-lisp.net/project/mcclim/posts/Yule-progress-report.html">McCLIM Yule progress report - towards 1.0</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/a31oxr/demo_sbcl_script_using_gtk/">Demo SBCL script using Gtk</a></li>
</ul>

<p>On games:</p>

<ul>
<li><a href="http://techsnuffle.com/2018/12/07/reasons-why-lisp-games-suffer-corrections">Baggers responds to &lsquo;Reasons why Lisp games suffer&rsquo;</a></li>
<li><a href="https://reader.tymoon.eu/article/370">About Making Games in Lisp - Gamedev</a></li>
<li><a href="Creating a (Non-Trivial) Lisp Game in 2018">Creating a (Non-Trivial) Lisp Game in 2018</a></li>
</ul>

<h1 id="discussion">Discussion</h1>

<ul>
<li><a href="https://www.reddit.com/r/lisp/comments/a7156w/lisp_and_the_remote_agent/">Lisp and the remote agent - with an AMA of Ron Garret</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/a5ggd4/how_to_make_common_lisp_popular/">How to make (Common) Lisp popular?</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/9r9xy6/feedback_from_a_new_lispworks_user/">Feedback from a new LispWorks user</a> (<a href="https://www.reddit.com/r/lisp/comments/9qh3op/how_is_lispworks_the_company_doing/">how is LispWorks the company going ?</a>)</li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/a3r4hb/how_do_you_normally_use_a_program_once_written/">How do you normally use a program once written ?</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/9q6bum/how_does_common_lisp_implement_hot_code_reloading/">How does Common Lisp implement hot code reloading?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/a10629/structs_vs_parametric_polymorphism_an_answer_to/">Structs vs Parametric Polymorphism (an answer to the &ldquo;switching from Common Lisp to Julia - thoughts ?&rdquo; post)</a> also <a href="https://www.reddit.com/r/lisp/comments/9y425b/switching_from_common_lisp_to_julia_your_thoughts/">this discussion</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/9os171/how_to_work_on_a_project_and_make_sure/">How to work on a project and make sure dependencies are tracked correctly?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/a2hkq0/does_anyone_else_hate_loop_cl/">Does anyone else hate LOOP?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9xd4gy/what_does_it_take_to_understand_the_true_power_of/">What does it take to understand the true power of Lisp?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9qfrxe/how_lisp_made_your_life_easier/">How did Lisp make your life easier ?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9zpts4/should_local_variables_be_avoided_when_possible/">Should local variables be avoided when possible when doing functional programming?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9upt86/abcl/">Is ABCL an active project and does it support JRE 1.11?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9q68y8/has_the_gnu_coreutils_ever_been_implemented_in/">Has the Gnu Coreutils ever been implemented in Lisp? If not, would that be a worthwhile project?</a></li>
<li><a href="https://sirherrbatka.github.io/blog/2018/10/14/classes-are-not-interactions/">&ldquo;Classes are not interactions!&rdquo; by shka</a></li>
</ul>

<h1 id="screencasts">Screencasts</h1>

<ul>
<li><a href="https://www.youtube.com/watch?v=mbdXeRBbgDM&amp;app=desktop">2018 LLVM Developers’ Meeting: C. Schafmeister “Lessons Learned Implementing Common Lisp with LLVM”</a></li>
<li><a href="https://www.youtube.com/channel/UCMV8p6Lb-bd6UZtTc_QD4zA">A pile of parens</a></li>
<li><a href="https://youtu.be/pZO6HSKHWLg">Pushing Pixels with Lisp - 61 - Stenciling (Failed attempt)</a></li>
</ul>

<h1 id="common-lisp-vs">Common Lisp VS &hellip;</h1>

<ul>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/ac9mm9/how_common_lisp_community_survived_without_the/">How did the Common Lisp community survived without the equivalent of clojure.spec ?</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/117-great-expectations.png" alt="Great Expectations">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Great Expectations</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">15 01 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/117-great-expectations.png" alt="Great Expectations" title="Great Expectations" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">It&#39;s Time to Own My Own Content</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">13 01 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I started writing about two years ago. Back then, I used to read a lot on Medium. When I finally felt the urge to write something, it made sense to publish there as well. Medium provided me with a platform, an audience, and constant reinforcements in the form of stats, likes and comments. It motivated me to keep writing. Despite it's many advantages, I feel Medium is lacking in some areas.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Why Deftask Chose Common Lisp</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">11 01 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>We heard about <a href="https://github.com/deftask/">Deftask</a>, a task
management app for teams, a few days ago, in an article about the
<a href="https://lisper.in/nlp-date-parser">internals of the Chronicity library</a>. Deftask
uses Common Lisp for its backend and its command-line app. This
reasonates with the fact that <a href="/blog/why-turtl-switched-from-lisp-to-js">Turtl doesn&rsquo;t use CL anymore</a>. So I
asked Deftask&rsquo;s author: why did you go with CL ?</p>

<hr />

<p>More than anything else, I think its down to fun and productivity. I
feel that I am at my most productive when I writing CL in Emacs+SLIME.
It is probably down to the edit-compile-debug cycle which is much
shorter in CL compared to other languages. I originally worked on CL
way back in 2006-08 when I was with Cleartrip. Since then, I have
worked on a number of platforms (frontend js, node, iOS, C, Java,
etc.) but always wanted to go back to writing CL full time.</p>

<p>So when I left my last job a little over a year back, I had already
made up my mind that the next thing I build would be in CL.</p>

<p>The lack of libraries (or rather, well supported libraries) is a
problem, but honestly after over eight years of not working on Lisp,
it doesn&rsquo;t bother me much.</p>

<blockquote>
<p>Did you already build software/services in CL, apart
the libraries we can see on your github profile ?</p>
</blockquote>

<p>As I mentioned I worked at Cleartrip for a little over two years. I
was part of the team that managed the flight search engine,
Unfortunately most of what we did there is gone forever. A small
sliver of our work there resulted in <a href="https://lisper.in/restarts">https://lisper.in/restarts</a>
(backstory: <a href="https://www.reddit.com/r/lisp/comments/7k85sf/a_tutorial_on_conditions_and_restarts/">https://www.reddit.com/r/lisp/comments/7k85sf/a_tutorial_on_conditions_and_restarts/</a>).</p>

<blockquote>
<p>Did you have enough libraries to build your service ? How&rsquo;s deployment and
maintenance going ?</p>
</blockquote>

<p>Well you could say I had enough libraries. Although I still ended up
writing a mini web framework on top of Hunchentoot. Another thing I
wrote is my own Lisp-to-SQL converter. Hope to open source both of
these one day. Apart from that I use drakma, postmodern, djula, plump,
lparallel, cl-json to name a few (alongwith the usual suspects like
alexandria and local-time).</p>

<p>Deployment and maintenance is extremely simple - I just update the
relevant git branch and restart the service. At some point when the
restarts become costly I might add the ability to reload changed code
in the running service.</p>

<hr />

<p>Thanks to him !</p>

<p>Below the backstory from reddit:</p>

<hr />

<p>Hey that was written by me! (Aside: I redirected the page to point to the latest version of this post on my new blog)</p>

<p>Fun fact: I wrote this post way back in 2008 while working for an online travel portal. This was based on some actual work we&rsquo;d done there. At that time, flight travel in India had started to boom. This I think went hand in hand with a bunch of online travel companies (including ours) gaining a lot of momentum.</p>

<p>To be more competitive, a couple of airlines decided that they wanted to introduce new discounted fares much more frequently than they were doing earlier. The only problem was that they were unable to upload their wonky fare rules in the GDS properly, so they started distributing excel sheets to travel agents with manual instructions on how to apply them.</p>

<p>So our business team starts sending these sheets over to us, and initially, the frequency was low so we just manually hard coded these rules. However then they started sending these sheets every week or so which made our life hell. So we asked asked our business team to &ldquo;translate&rdquo; the airline&rsquo;s excel sheets and instructions into a csv, which was subsequently interpreted by a simple rules engine that we wrote.</p>

<p>The only problem? Well, as anyone who&rsquo;s dealt with manually created CSVs will tell you, there were a lot of errors. This didn&rsquo;t really help matters much. We then added a couple of restarts to our CSV parser which allowed us to correct these issues interactively. This made life much better for us &ndash; it was a lot easier than, say, getting a list of errors in a terminal and switching back and forth between the terminal window and the editor to correct them.</p>

<p>Later on we plonked the CSV parser behind hunchentoot and asked our bizdev guy to upload the file there. A handle-bind around the parser collected all the errors in one go and showed them in a nicely formatted way in the browser (see the last section of the post). And so it was no longer our problem :-)</p>

<p>Eventually these airlines decided they wanted to update fare rules daily. Thankfully our &ldquo;business rules engine&rdquo; was upto the task. Due to automatic feedback, our friend in bizdev became an expert at uploading the fare rules as soon as they came in. And for quite some time, we were the only ones who could show these cheap fares within minutes of them coming in (if I remember correctly, other portals would take hours to upload the same rules).</p>

<p>Ours was a small team, and we had to manage this in addition to a lot of other things. If it weren&rsquo;t for CL&rsquo;s condition system, I doubt we could have solved this as smoothly as we did. In particular, interactive restarts allowed us (devs) to correct CSV errors without wasting a lot of our own time, and without needing to build a full-fledged UI for a non-dev. And when the time did come for a UI, it was dead easy to write a web fontend on top of it.</p>

<blockquote>
<p>Q: Did you ever work or need an optimal solution to the Tavelling Salesman Problem?</p>
</blockquote>

<p>Nope. Domestic flight travel in India is simple&hellip; point to point or max over two legs. For international flights we used QPX.</p>

<p>(QPX was ITA software&rsquo;s flight search engine. Probably among the biggest software systems written in Lisp. It now powers Google Flights (I think).)</p>

<hr />

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Why Turtl Switched From CL to Js</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">11 01 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Turtl is a very well done, secure collaborative notebook web app.</p>

<ul>
<li><a href="https://turtlapp">https://turtlapp</a></li>
</ul>

<p>Its api backend is built in Common Lisp:</p>

<ul>
<li><a href="https://github.com/turtl/api/">https://github.com/turtl/api/</a></li>
</ul>

<p>It is based on many async libraries the developer wrote for Turtl,
like the <a href="https://github.com/orthecreedence/wookie">Wookie</a> async HTTP
server.</p>

<p>&ldquo;is&rdquo; ? No, was :/ Even though this repository is still maintained
(latest commit: 2nd of december 2018), it is deprecated and the
<a href="https://github.com/turtl/server">new server</a> is written in NodeJS. I
asked Andrew for the reasons behind this, here&rsquo;s his answer.</p>

<p>(in a hurry to spread FUD ? Don&rsquo;t miss this posts&rsquo;s twin,
<a href="/blog/why-deftask-chose-common-lisp">Why Deftask chose Common Lisp</a>
;) See also some
<a href="https://github.com/azzamsa/awesome-lisp-companies">companies using Common Lisp</a>)</p>

<hr />

<p>It was not an easy decision to replace CL with javascript. I find CL
to be elegant, fast, stable, and above all else, easy to debug (having
the ability to rewrite the program as it&rsquo;s running is insanely
useful). In fact, I still miss lisp and ask myself all the time if I
made the right choice.</p>

<p>I think I did, though.</p>

<p>The path I went with CL was a hard one. I wanted to be able to use
asynchronous programming because for the type of work I do (a lot of
making APIs that talk to other services with very little CPU work)
it&rsquo;s hard to get much more performant. So I embarked on creating
cl-async/cl-libuv (originally cl-libevent) and wookie, along with a
few other drivers. Everything I built worked great (and still works
great, as far as I can tell) however when things did go wrong, there
was nobody to run ideas by and nobody to really help me&hellip;I had built
all these things myself, and I also had to be responsible for fixing
them when they broke. On top of having to maintain everything (and it
did break from time to time) there is not much in the way of packages
to help me out. For instance, there&rsquo;s a package to upload files to S3,
but it&rsquo;s not async at all&hellip;I had to build this from scratch. There
are more cases of this as well.</p>

<p>With CL, it felt like I was constantly fighting the tide. I was
constantly battling just to get basic things working that are already
solved problems in other languages (Node).</p>

<p>There was help and support from the community along the way, but I was
mostly fighting it alone. I think the straw that broke the camel&rsquo;s
back was when a few people started making copycat projects that added
no real value (other than benchmarking fast) but stole mindshare from
all the work I had put in. It was the &ldquo;well, that project is not
exactly what I want so I&rsquo;ll make my own from scratch&rdquo; mindset that
everyone always warned about when I was starting with CL (but I
ignored). I had really hoped the community would have helped propel
the async ecosystem I was building forward, but I just don&rsquo;t think
there&rsquo;s enough people using CL for that to happen.</p>

<p>So between having to maintain everything myself and people putting out
worthless copycat projects that ended up going nowhere, I didn&rsquo;t have
the energy anymore.</p>

<p>Honestly, it took me about a week of work, just nights and weekends,
to reprogram the server in javascript. Granted, most of the &ldquo;how
should this work?&rdquo; architecture stuff was already done so it was more
of a rewrite than a build-from-scratch situation, but Node is fast to
build APIs in. I&rsquo;m decently fluent in javascript and the amount
packages available is so immense that it just made sense.</p>

<p>On top of being fast to build in, it&rsquo;s a well-traveled road. I don&rsquo;t
have people emailing me six times a day asking how to install the
server like I did with CL. I don&rsquo;t have to make weird custom loaders
to run the app on any hosting providers&hellip;everyone supports Node. I
don&rsquo;t have to deal with weird FFI errors or libuv nuances. I don&rsquo;t
have to deal with quicklisp&rsquo;s &ldquo;all or nothing&rdquo; packaging that doesn&rsquo;t
support version pinning. I don&rsquo;t have to restart the server every 20
days because of some memory leak I have yet to track down somewhere
between cl-libuv, cl-async, wookie, and turtl. There&rsquo;s a whole set of
bullshit I just don&rsquo;t have to deal with anymore.</p>

<p>So I do miss lisp. I&rsquo;d eventually like to build more things in it
(like games). But I don&rsquo;t think I&rsquo;ll ever touch web stuff in CL again,
and the whole journey left a bitter taste in my mouth. Sure I could
have dropped the async thing and just done a threaded server in
hunchentoot and cl-postgres. But once I decided I was going to
reprogram everything anyway, it just made sense to go with Node.</p>

<p>I took on more work than I could realistically manage, and hoped that
the community would help&hellip;but the CL community is small enough that
it was a losing bet and I got burned out.</p>

<p>Hopefully none of this discourages you. CL is a great language. The
community is a mix though. Some of the people in the community are
smart and dedicated, and work on cool projects at a pace they can
maintain. You won&rsquo;t see articles about these projects, and many will
only have a handful of stars on Github (don&rsquo;t measure CL projects by
stars). Seek these projects and these people out, and build things
with them. There is a quiet corner of the internet, with a handful of
people building amazing things in lisp.</p>

<hr />

<p>Before commenting on this, I think we must realize what he achieved,
and that he went the hard way.</p>

<p>Now don&rsquo;t miss <a href="/blog/why-deftask-chose-common-lisp">Why Deftask chose Common Lisp</a> !</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Introducing Replic: an executable and a library to build a readline app in no time</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">09 01 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>When I started dabbling in CL, I tried to build a readline application
to see how it goes. I found
<a href="https://github.com/vindarel/cl-readline">cl-readline</a> (I&rsquo;m only the
new maintainer) and it went smoothly. So I built a second and a third
app, and found many things to refactor and provide out of the box: now
comes <a href="https://github.com/vindarel/replic/">replic</a>.</p>

<p>It comes as a library (now in Quicklisp, since 2018-01) and as an
executable. The library does the following for you:</p>

<ul>
<li>it builds the repl loop, catches a C-c, a C-d, errors,</li>
<li>it asks confirmation to quit,</li>
<li>it asks depending on a .conf and a lispy config file,</li>
<li>it reads parameters from a config file,</li>
<li>it prints the help of all or one command (with optional highlighting),</li>
<li>and more importantly it handles the completion of commands and of their arguments.</li>
</ul>

<p>For example, instead of this &ldquo;repl&rdquo; loop:</p>

<pre><code class="language-lisp">  (handler-case
      (do ((i 0 (1+ i))
           (text &quot;&quot;)
           (verb &quot;&quot;)
           (function nil)
           (variable nil)
           (args &quot;&quot;))
          ((string= &quot;quit&quot; (str:trim text)))

        (handler-case
            (setf text
                  (rl:readline :prompt (prompt)
                               :add-history t))
          (#+sbcl sb-sys:interactive-interrupt ()
                  (progn
                    (when (confirm)
                      (uiop:quit)))))

        (if (string= text &quot;NIL&quot;)
            ;; that's a C-d, a blank input is just &quot;&quot;.
            (when (confirm)
              (uiop:quit)))

        (unless (str:blank? text)
          (setf verb (first (str:words text)))
          (setf function (if (replic.completion:is-function verb)
                             ;; might do better than this or.
                             (replic.completion:get-function verb)))
          (setf variable (if (replic.completion:is-variable verb)
                             (replic.completion:get-variable verb)))
          (setf args (rest (str:words text)))


          (if (and verb function)
              (handler-case
                  ;; Call the function.
                  (apply function args)
                (#+sbcl sb-sys:interactive-interrupt (c)
                        (declare (ignore c))
                        (terpri))
                (error (c) (format t &quot;Error: ~a~&amp;&quot; c)))

              (if variable
                  (format t &quot;~a~&amp;&quot; (symbol-value variable))
                  (format t &quot;No command or variable bound to ~a~&amp;&quot; verb)))

          (finish-output)

          (when (and *history*
                     *write-history*)
            (rl:write-history &quot;/tmp/readline_history&quot;))
          ))

    (error (c)
      (format t &quot;~&amp;Unknown error: ~&amp;~a~&amp;&quot; c)))
</code></pre>

<p>you call:</p>

<pre><code class="language-lisp">(replic:repl)
</code></pre>

<p>To turn all exported functions of a package into commands, use</p>

<pre><code>(replic:functions-to-commands :my-package)
</code></pre>

<p>and you can find them into the readline app.</p>

<p>Setting the completion of commands is easy, we use
<code>(replic.completion:add-completion &quot;my-function&quot; &lt;list-or-lambda&gt;</code>. For example:</p>

<pre><code class="language-lisp">(in-package :replic.user)

(defparameter *names* '()
  &quot;List of names (string) given to `hello`. Will be autocompleted by `goodbye`.&quot;)

(defun hello (name)
  &quot;Takes only one argument. Adds the given name to the global
  `*names*` variable, used to complete arguments of `goodbye`.
  &quot;
  (format t &quot;hello ~a~&amp;&quot; name)
  (push name *names*))

(defun goodbye (name)
  &quot;Says goodbye to name, where `name` should be completed from what was given to `hello`.&quot;
  (format t &quot;goodbye ~a~&amp;&quot; name))

(replic.completion:add-completion &quot;goodbye&quot; (lambda () *names*))

(export '(hello goodbye))
</code></pre>

<p>This example can be used with the <em>executable</em>. What it does is read
your code from a lisp file (<code>~/.replic.lisp</code> or an argument on the
command line) and it turns the exported functions into commands, for
which we can specify custom completion.</p>

<p>For more details, see the readme.</p>

<hr />

<p>I use this currently in three apps of mine (like
<a href="https://github.com/vindarel/cl-torrents">cl-torrents</a>). It&rsquo;s
simple. It could be more: it could infer the arguments&rsquo; type, do fuzzy
completion, maybe integrate a Lisp editor (Lem) or a lispy shell
(shcl), separate the commands in apps, expose hooks, have a set of
built-in shell related utilities, highlight the input line, it could
be web-based,…</p>

<p>For now it&rsquo;s going smoothly.</p>

<p>I&rsquo;ll finish by recalling that it&rsquo;s amazing to be able to ship
self-contained executables to users !</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q1 2019 Survey Results and Call for Proposals</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">08 01 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Happy New Year Clojurists Together community!
Thanks so much for your support and feedback in the latest survey. We value your opinions and always take suggestions into account as we make changes from quarter to quarter.
Project applications for our Q1 2019 round close on 15th Jan, midnight PST. The selections will be announced shortly afterwards. The Q1 2019 projects will start on February 1.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2019/116-library-unboxing.png" alt="Library Unboxing">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Library Unboxing</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">08 01 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2019/116-library-unboxing.png" alt="Library Unboxing" title="Library Unboxing" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">State of Clojure 2019 Survey</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">07 01 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div class="paragraph">
<p>It&#8217;s time for the annual State of Clojure Community Survey!</p>
</div>
<div class="paragraph">
<p>If you are a user of Clojure or ClojureScript, we are greatly interested in your responses to the following survey:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://www.surveymonkey.com/r/clojure2019">State of Clojure 2019</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The survey contains four pages:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>General questions applicable to any user of Clojure or ClojureScript</p>
</li>
<li>
<p>Questions specific to JVM Clojure (skip if not applicable)</p>
</li>
<li>
<p>Questions specific to ClojureScript (skip if not applicable)</p>
</li>
<li>
<p>Final comments</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>The survey will close January 22nd, after which all of the data will be released with some analysis. We greatly appreciate your input!</p>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Modeling Polymorphism in Django</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">01 01 2019</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Modeling polymorphism in relational databases is a challenging task. In this article, we present several modeling techniques to represent polymorphic objects in a relational database using the Django object-relational mapping (ORM).</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Ideas para conseguir unos regalos más ecos</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">31 12 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Save and Restore Window Configuration in Emacs</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">25 12 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        When we are using emacs sometimes we often open many buffers in different windows at the same time, for example we can have a buffer for a opened file, another for seeing test results and so on.
 There are some tools to manage &#34;sessions&#34; but I wanted something simple and I also wanted to learn a little bit more of elisp so here is the result.
(defvar window-snapshots &#39;()) (defun save-window-snapshot () &#34;Save the current window configuration into `window-snapshots` alist.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Save and Restore Window Configuration in Emacs</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">25 12 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>
When we are using <code class="verbatim">emacs</code> sometimes we often open many buffers in different windows at the same time, for example we can have a buffer for a opened file, another for seeing test results and so on.</p>
<p>
There are some tools to manage &#34;sessions&#34; but I wanted something simple and I also wanted to learn a little bit more of <code class="verbatim">elisp</code> so here is the result.</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defvar window-snapshots <span style="color:#f92672">&#39;</span>())

(defun save-window-snapshot ()
  <span style="color:#e6db74">&#34;Save the current window configuration into `window-snapshots` alist.&#34;</span>
  (interactive)
  (let ((key (<span style="color:#a6e22e">read-string</span> <span style="color:#e6db74">&#34;Enter a name for the snapshot: &#34;</span>)))
    (setf (alist-get key window-snapshots) (<span style="color:#a6e22e">current-window-configuration</span>))
    (<span style="color:#a6e22e">message</span> <span style="color:#e6db74">&#34;%s window snapshot saved!&#34;</span> key)))

(defun get-window-snapshot (key)
  <span style="color:#e6db74">&#34;Given a KEY return the saved value in `window-snapshots` alist.&#34;</span>
  (let ((value (<span style="color:#a6e22e">assoc</span> key window-snapshots)))
    (<span style="color:#a6e22e">cdr</span> value)))

(defun restore-window-snapshot ()
  <span style="color:#e6db74">&#34;Restore a window snapshot from the window-snapshots alist.&#34;</span>
  (interactive)
  (let* ((snapshot-name (<span style="color:#a6e22e">completing-read</span> <span style="color:#e6db74">&#34;Choose snapshot: &#34;</span> (<span style="color:#a6e22e">mapcar</span> <span style="color:#a6e22e">#&#39;car</span> window-snapshots)))
	 (snapshot (get-window-snapshot snapshot-name)))
    (if snapshot
	(<span style="color:#a6e22e">set-window-configuration</span> snapshot)
      (<span style="color:#a6e22e">message</span> <span style="color:#e6db74">&#34;Snapshot %s not found&#34;</span> snapshot-name))))</code></pre></div>
</div>
<p>
The code basically do 3 things:</p>
<ul>
<li>
<p>Define an <code class="verbatim">alist</code> where window configurations will be saved</p>
</li>
<li>
<p>Save the current window configuration using a name to be identified later.</p>
</li>
<li>
<p>Restore any of the saved configurations by selecting it from a list</p>
</li>
</ul>
<p>Now let&#39;s get into the details:</p>
<div id="outline-container-headline-1" class="outline-2">
<h2 id="headline-1">
Save the current window configuration
</h2>
<div id="outline-text-headline-1" class="outline-text-2">
<p>
We will use the function <code class="verbatim">current-window-configuration</code> to get the current state of the windows and put this value in an <code class="verbatim">alist</code> called <code class="verbatim">window-snapshots</code>. Also it should asks for a name so we can search for it later.</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defvar window-snapshots <span style="color:#f92672">&#39;</span>())

(defun save-window-snapshot ()
  <span style="color:#e6db74">&#34;Save the current window configuration into `window-snapshots` alist.&#34;</span>
  (interactive)
  (let ((key (<span style="color:#a6e22e">read-string</span> <span style="color:#e6db74">&#34;Enter a name for the snapshot: &#34;</span>)))
    (setf (alist-get key window-snapshots) (<span style="color:#a6e22e">current-window-configuration</span>))
    (<span style="color:#a6e22e">message</span> <span style="color:#e6db74">&#34;%s window snapshot saved!&#34;</span> key)))</code></pre></div>
</div>
</div>
</div>
<div id="outline-container-headline-2" class="outline-2">
<h2 id="headline-2">
Restore a window configuration
</h2>
<div id="outline-text-headline-2" class="outline-text-2">
<p>
We will use <code class="verbatim">completing-read</code> to select one of the saved snapshots from an interactive list. It will use <code class="verbatim">helm</code> <sup class="footnote-reference"><a id="footnote-reference-1" href="#footnote-1">1</a></sup> or <code class="verbatim">ivy</code> <sup class="footnote-reference"><a id="footnote-reference-2" href="#footnote-2">2</a></sup> if any of those are installed otherwise it will show the options in the <code class="verbatim">minibuffer</code>.</p>
<p>
This will show the <code class="verbatim">name</code> used before and retrieve the value of the window configuration. Then it will apply the configuration using <code class="verbatim">set-window-configuration</code>.</p>
<div class="src src-emacs-lisp">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-emacs-lisp" data-lang="emacs-lisp">(defun get-window-snapshot (key)
  <span style="color:#e6db74">&#34;Given a KEY return the saved value in `window-snapshots` alist.&#34;</span>
  (let ((value (<span style="color:#a6e22e">assoc</span> key window-snapshots)))
    (<span style="color:#a6e22e">cdr</span> value)))

(defun restore-window-snapshot ()
  <span style="color:#e6db74">&#34;Restore a window snapshot from the window-snapshots alist.&#34;</span>
  (interactive)
  (let* ((snapshot-name (<span style="color:#a6e22e">completing-read</span> <span style="color:#e6db74">&#34;Choose snapshot: &#34;</span> (<span style="color:#a6e22e">mapcar</span> <span style="color:#a6e22e">#&#39;car</span> window-snapshots)))
	 (snapshot (get-window-snapshot snapshot-name)))
    (if snapshot
	(<span style="color:#a6e22e">set-window-configuration</span> snapshot)
      (<span style="color:#a6e22e">message</span> <span style="color:#e6db74">&#34;Snapshot %s not found&#34;</span> snapshot-name))))</code></pre></div>
</div>
</div>
</div>
<div class="footnotes">
<hr class="footnotes-separatator">
<div class="footnote-definitions">
<div class="footnote-definition">
<sup id="footnote-1"><a href="#footnote-reference-1">1</a></sup>
<div class="footnote-body">
<p><a href="https://emacs-helm.github.io/helm/">https://emacs-helm.github.io/helm/</a></p>
</div>
</div>
<div class="footnote-definition">
<sup id="footnote-2"><a href="#footnote-reference-2">2</a></sup>
<div class="footnote-body">
<p><a href="https://github.com/abo-abo/swiper/">https://github.com/abo-abo/swiper/</a></p>
</div>
</div>
</div>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://slimbook.es/images/imagetuto/term_volume.jpg" alt="Como forzar el volumen del sistema en Ubuntu cuando se oye muy bajo.">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Como forzar el volumen del sistema en Ubuntu cuando se oye muy bajo.</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Soporte - SLIMBOOK: ultrabooks, portátiles y ordenadores GNU/Linux</a> <span class="article__date">24 12 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Si nuestro volumen del sistema es muy bajo incluso aunque pongamos los altavoces al 100% existe la posibilidad de forzar al sistema a aumentar el volumen por encima del máximo. Para ello primero tenemos que instalar el programa que se comunica con el hardware de nuestro equipo.</p>
<pre xml:lang="bash" lines="false">[code]sudo apt install pulseaudio-utils[/code]</pre>
<p>Después de instalar el programa debemos reiniciar el sistema para que los cambios surjan efecto. Para forzar el volumen del sistema por encima del 100% usaremos el siguiente comando:</p>
<pre xml:lang="bash" lines="false">[code]pactl set-sink-volume 0 175%[/code]</pre>
<p>Con esto el volumen de nuestro sistema estará configurado al 175% (por encima de este valor se distorsiona mucho el sonido). El "0" es el indice de la tarjeta de sonido sobre la que estamos aplicando los cambios, para ver las tarjetas de sonido disponibles para nuestro sistema solo tenemos que introducir el siguiente comando:</p>
<pre xml:lang="bash" lines="false">[code]pacmd list-sinks | grep -e 'name:' -e 'index'[/code]</pre>
<p>&#160;<img src="https://slimbook.es/images/imagetuto/term_volume.jpg" alt="term volume" /></p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://slimbook.es/images/imagetuto/bios_pro2_1.jpg" alt="Como activar/desactivar el arranque UEFI en el PRO 2">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Como activar/desactivar el arranque UEFI en el PRO 2</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Soporte - SLIMBOOK: ultrabooks, portátiles y ordenadores GNU/Linux</a> <span class="article__date">24 12 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Una vez dentro de la BIOS (Si no sabes como entrar a la BIOS puedes ver&#160;<a href="https://slimbook.es/en/tutoriales/slimbook/207-como-acceder-a-la-bios-del-pro-excalibur-y-one" target="_blank">este tutorial</a>):</p>
<p>Para activar/desactivar el arranque UEFI iremos hacia la pestaña "Boot" usando las flechas, dentro de Boot seleccionaremos "UEFI Setting".</p>
<p><img src="https://slimbook.es/images/imagetuto/bios_pro2_1.jpg" alt="bios pro2 1" /></p>
<p>Una vez dentro podemos activar/desactivar el UEFI Boot.</p>
<p><img src="https://slimbook.es/images/imagetuto/bios_pro2_2.jpg" alt="bios pro2 2" /></p>
<p>Luego nos iremos a la pestaña "Save &#38; Exit" y pulsaremos en "Save Changes and Exit" o pulsaremos directamente la tecla"F10" para guardar y salir.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://slimbook.es/images/imagetuto/bios_curve_1.jpg" alt="Como activar/desactivar el arranque UEFI en el Curve">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Como activar/desactivar el arranque UEFI en el Curve</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Soporte - SLIMBOOK: ultrabooks, portátiles y ordenadores GNU/Linux</a> <span class="article__date">24 12 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Una vez dentro de la BIOS (Si no sabes como entrar a la BIOS puedes ver&#160;<a href="https://slimbook.es/en/tutoriales/slimbook/207-como-acceder-a-la-bios-del-pro-excalibur-y-one" target="_blank">este tutorial</a>):</p>
<p>Para activar/desactivar el arranque UEFI iremos hacia la pestaña "Chipset" usando las flechas, dentro de Chipset seleccionaremos "CSM Configuration".</p>
<p><img src="https://slimbook.es/images/imagetuto/bios_curve_1.jpg" alt="bios curve 1" /></p>
<p>Una vez dentro podemos cambiar el Boot option filter.</p>
<p><img src="https://slimbook.es/images/imagetuto/bios_curve_2.jpg" alt="bios curve 2" /></p>
<p>Luego nos iremos a la pestaña "Save &#38; Exit" y pulsaremos en "Save Changes and Exit" o pulsaremos directamente la tecla"F10" para guardar y salir.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Projects</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">24 12 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Python libraries    Project Description     Serpost Fetch tracking data from Peruvian postal service Serpost using a tracking number     jr_tools Upload and configure reports in Jasper Server. It uses a yaml based configuration file to define the reports, files, parameters, etc and upload them to Jasper Server through its API      Odoo modules    Project Description     l10n_pe_import_rxh Read an RxH(a Peruvian invoice emitted by freelance workers) XML document and import its content to Odoo, this module convert the RxH into a supplier invoice     tracking_serpost_purchase Integrate Serpost tracking data in purchase orders     tracking_serpost_sale Integrate Serpost tracking data in sale orders      Emacs packages    Project Description     linkode.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Mujer Científica.</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">23 12 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How We Solved a Storage Problem in PostgreSQL Without Adding a Single Byte of Storage</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">21 12 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>A while back we started getting alerts in the middle of the night on low disk space. A quick investigation led us to one of our ETL tasks. Every night the task was fired to eliminate duplicate dumps, and free up some space. This is a short story about how we found our silver bullet and solved the issue without adding a single byte of storage.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Escape The Office (The Game)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">21 12 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div style="text-align:center">Escape the office. Merry X-Mas everybody</div>

<div id="container"></div>
<script type="text/javascript" src="/assets/games/escape/vendor.bundle.js"></script>

<script type="text/javascript" src="/assets/games/escape/bundle.js"></script>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://github.com/sharplispers/log4cl/raw/master/images/screenshot-15.png" alt="Debugging in Common Lisp">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Debugging in Common Lisp</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">20 12 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>You entered this new world of Lisp and now wonder: how can we debug
what&rsquo;s going on ?  How is it more interactive than in other platforms
?  What does bring the interactive debugger appart from stacktraces ?</p>

<p><em>note</em>: this tutorial is available on the <a href="https://lispcookbook.github.io/cl-cookbook/debugging.html">Common Lisp Cookbook</a> and it will receive updates there.</p>

<p>If you want step-by-step examples of interactive debugging with nice
screenshots and gifs, see the blog posts in the References section
below.</p>

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-generate-toc again -->

<p><strong>Table of Contents</strong></p>

<ul>
<li><a href="#print-debugging">Print debugging</a></li>
<li><a href="#logging">Logging</a></li>
<li><a href="#using-the-powerful-repl">Using the powerful REPL</a></li>
<li><a href="#inspect-and-describe">Inspect and describe</a></li>
<li><a href="#the-interactive-debugger">The interactive debugger</a></li>
<li><a href="#trace">Trace</a>

<ul>
<li><a href="#tracing-method-invocation">Tracing method invocation</a></li>
</ul></li>
<li><a href="#step">Step</a></li>
<li><a href="#break">Break</a>

<ul>
<li><a href="#breakpoints-in-slime">Breakpoints in Slime</a></li>
</ul></li>
<li><a href="#advise-and-watch">Advise and watch</a></li>
<li><a href="#unit-tests">Unit tests</a></li>
<li><a href="#references">References</a></li>
</ul>

<!-- markdown-toc end -->

<h2 id="print-debugging">Print debugging</h2>

<p>Well of course we can use the famous technique of &ldquo;print
debugging&rdquo;. Let&rsquo;s just recap a few print functions.</p>

<p><code>print</code> works, it prints a READable representation of its argument,
which means what is <code>print</code>ed can be <code>read</code> back in by the Lisp
reader.</p>

<p><code>princ</code> focuses on an <em>aesthetic</em> representation.</p>

<p><code>format t &quot;~a&quot; …)</code>, with the <em>aesthetic</em> directive, prints a string (in <code>t</code>, the standard output
stream) and returns nil, whereas <code>format nil …</code> doesn&rsquo;t print anything
and returns a string. With many format controls we can print several
variables at once.</p>

<h2 id="logging">Logging</h2>

<p>Logging is a good evolution from print debugging ;)</p>

<p><a href="https://github.com/sharplispers/log4cl/">log4cl</a> is the popular,
de-facto logging library but it isn&rsquo;t the only one. Download it:</p>

<pre><code>(ql:quickload :log4cl)
</code></pre>

<p>and let&rsquo;s have a dummy variable:</p>

<pre><code>(defvar *foo* '(:a :b :c))
</code></pre>

<p>We can use log4cl with its <code>log</code> nickname, then it is as simple to use as:</p>

<pre><code class="language-lisp">(log:info *foo*)
;; &lt;INFO&gt; [13:36:49] cl-user () - *FOO*: (:A :B :C)
</code></pre>

<p>We can interleave strings and expressions, with or without <code>format</code>
control strings:</p>

<pre><code class="language-lisp">(log:info &quot;foo is &quot; *foo*)
;; &lt;INFO&gt; [13:37:22] cl-user () - foo is *FOO*: (:A :B :C)
(log:info &quot;foo is ~{~a~}&quot; *foo*)
;; &lt;INFO&gt; [13:39:05] cl-user () - foo is ABC
</code></pre>

<p>With its companion library <code>log4slime</code>, we can interactively change
the log level:</p>

<ul>
<li>globally,</li>
<li>per package,</li>
<li>per function,</li>
<li>and by CLOS methods and CLOS hierarchy (before and after methods).</li>
</ul>

<p>It is very handy, when we have a lot of output, to turn off the
logging of functions or packages we know to work, and thus narrowing
our search to the right area. We can even save this configuration and
re-use it in another image, be it on another machine.</p>

<p>We can do all this through commands, keyboard shortcuts and also through a
menu or mouse clicks.</p>

<p><img src="https://github.com/sharplispers/log4cl/raw/master/images/screenshot-15.png" alt="&quot;changing the log level with log4slime&quot;" /></p>

<p>We invite you to read log4cl&rsquo;s readme.</p>

<h2 id="using-the-powerful-repl">Using the powerful REPL</h2>

<p>Part of the joy of Lisp is the excellent REPL. Its existence usually
delays the need to use other debugging tools, if it doesn&rsquo;t annihilate
them for the usual routine.</p>

<p>As soon as we define a function, we can try it in the REPL. In Slime,
compile a function with <code>C-c C-c</code> (the whole buffer with <code>C-c C-k</code>),
switch to the REPL with <code>C-c C-z</code> and try it. Eventually enter the
package you are working on with <code>(in-package :your-package)</code>.</p>

<p>The feedback is immediate. There is no need to recompile everything,
nor to restart any process, nor to create a main function and define
command line arguments for use in the shell (we can do this later on
when needed).</p>

<p>We usually need to create some data to test our function(s). This is a
subsequent art of the REPL existence and it may be a new discipline
for newcomers. A trick is to write the test data alongside your
functions but inside a <code>#+nil</code> declaration so that only you can
manually compile them:</p>

<pre><code class="language-lisp">    #+nil
    (progn
       (defvar *test-data* nil)
       (setf *test-data* (make-instance 'foo …)))
</code></pre>

<p>When you load this file, <code>*test-data*</code> won&rsquo;t exist, but you can
manually create it with a <code>C-c C-c</code> away.</p>

<p>We can define tests functions like this.</p>

<p>Some do similarly inside <code>#| … |#</code> comments.</p>

<p>All that being said, keep in mind to write unit tests when time comes ;)</p>

<h2 id="inspect-and-describe">Inspect and describe</h2>

<p>These two commands share the same goal, printing a description of an
object, <code>inspect</code> being the interactive one.</p>

<pre><code>(inspect *foo*)

The object is a proper list of length 3.
0. 0: :A
1. 1: :B

2. 2: :C
&gt; q
</code></pre>

<p>We can also, in editors that support it, right-click on any object in
the REPL and <code>inspect</code> them. We are presented a screen where we can
dive deep inside the data structure and even change it.</p>

<p>Let&rsquo;s have a quick look with a more interesting structure, an object:</p>

<pre><code class="language-lisp">(defclass foo ()
    ((a :accessor foo-a :initform '(:a :b :c))
     (b :accessor foo-b :initform :b)))
;; #&lt;STANDARD-CLASS FOO&gt;
(make-instance 'foo)
;; #&lt;FOO {100F2B6183}&gt;
</code></pre>

<p>We right-click on the <code>#&lt;FOO</code> object and choose &ldquo;inspect&rdquo;. We are
presented an interactive pane (in Slime):</p>

<pre><code>#&lt;FOO {100F2B6183}&gt;
--------------------
Class: #&lt;STANDARD-CLASS FOO&gt;
--------------------
 Group slots by inheritance [ ]
 Sort slots alphabetically  [X]

All Slots:
[ ]  A = (:A :B :C)
[ ]  B = :B

[set value]  [make unbound]
</code></pre>

<p>When we click or press enter on the line of slot A, we inspect it further:</p>

<pre><code>#&lt;CONS {100F5E2A07}&gt;
--------------------
A proper list:
0: :A
1: :B
2: :C
</code></pre>

<h2 id="the-interactive-debugger">The interactive debugger</h2>

<p>Whenever an exceptional situation happens (see
<a href="https://lispcookbook.github.io/cl-cookbook/error_handling.html">error handling</a>), the interactive debugger pops
up.</p>

<p>It presents the error message, available actions (<em>restarts</em>),
and the backtrace. A few remarks:</p>

<ul>
<li>the restarts are programmable, we can create our owns,</li>
<li>in Slime, press <code>v</code> on a stacktrace to be redirected to the source
file at the right line,</li>
<li>hit enter on a frame for more details,</li>
<li>we can explore the functionnality with the menu that should appear
in our editor. See below in &ldquo;break&rdquo; section for a few
more commands (eval in frame, etc).</li>
</ul>

<p>Usually your compiler will optimize things out and this will reduce
the amount of information available to the debugger. For example
sometimes we can&rsquo;t see intermediate variables of computations. You might
want to print a function argument (with <code>e</code> to &ldquo;eval in frame&rdquo;, see
below), but you keep getting a <code>Variable XYZ is unbound</code> error.</p>

<p>To fix this, we have to change the optimization choices with <code>declaim</code>, at the beginning of the file:</p>

<pre><code>(declaim (optimize (speed 0) (space 0) (debug 3)))
</code></pre>

<p>or with <code>declare</code>, inside a <code>defun</code>:</p>

<pre><code class="language-lisp">(defun my-fun (xyz)
  (declare (optimize (debug 3)))
  …)
</code></pre>

<p>and recompile the code. Now you should be able to see local variables such as<code>xyz</code>.</p>

<h2 id="trace">Trace</h2>

<p><a href="http://www.xach.com/clhs?q=trace">trace</a> allows us to see when a
function was called, what arguments it received, and the value it
returned.</p>

<pre><code class="language-lisp">(defun factorial (n)
  (if (plusp n)
    (* n (factorial (1- n)))
    1))
</code></pre>

<pre><code class="language-lisp">(trace factorial)

(factorial 2)
  0: (FACTORIAL 3)
    1: (FACTORIAL 2)
      2: (FACTORIAL 1)
        3: (FACTORIAL 0)
        3: FACTORIAL returned 1
      2: FACTORIAL returned 1
    1: FACTORIAL returned 2
  0: FACTORIAL returned 6
6

(untrace factorial)
</code></pre>

<p>To untrace all functions, just evaluate <code>(untrace)</code>.</p>

<p>In Slime we also have the shortcut <code>C-c M-t</code> to trace or untrace a
function.</p>

<p>If you don&rsquo;t see recursive calls, that may be because of the
compiler&rsquo;s optimizations. Try this before defining the function to be
traced:</p>

<pre><code>(declaim (optimize (debug 3)))
</code></pre>

<p>The output is printed to <code>*trace-output*</code> (see the CLHS).</p>

<p>In Slime, we also have an interactive trace dialog with <code>M-x
slime-trace-dialog</code> bound to <code>C-c T</code>.</p>

<h3 id="tracing-method-invocation">Tracing method invocation</h3>

<p>In SBCL, we can use <code>(trace foo :methods t)</code> to trace the execution order of method combination (before, after, around methods). For example:</p>

<pre><code class="language-lisp">(trace foo :methods t)

(foo 2.0d0)
  0: (FOO 2.0d0)
    1: ((SB-PCL::COMBINED-METHOD FOO) 2.0d0)
      2: ((METHOD FOO (FLOAT)) 2.0d0)
        3: ((METHOD FOO (T)) 2.0d0)
        3: (METHOD FOO (T)) returned 3
      2: (METHOD FOO (FLOAT)) returned 9
      2: ((METHOD FOO :AFTER (DOUBLE-FLOAT)) 2.0d0)
      2: (METHOD FOO :AFTER (DOUBLE-FLOAT)) returned DOUBLE
    1: (SB-PCL::COMBINED-METHOD FOO) returned 9
  0: FOO returned 9
9
</code></pre>

<p>See the <a href="https://lispcookbook.github.io/cl-cookbook/clos.html">CLOS</a> section for a tad more information.</p>

<h2 id="step">Step</h2>

<p><a href="http://www.xach.com/clhs?q=step">step</a> is an interactive command with
similar scope than <code>trace</code>. This:</p>

<pre><code>(step (factorial 2))
</code></pre>

<p>gives an interactive pane with the available restarts:</p>

<pre><code>Evaluating call:
  (FACTORIAL 2)
With arguments:
  2
   [Condition of type SB-EXT:STEP-FORM-CONDITION]

Restarts:
 0: [STEP-CONTINUE] Resume normal execution
 1: [STEP-OUT] Resume stepping after returning from this function
 2: [STEP-NEXT] Step over call
 3: [STEP-INTO] Step into call
 4: [RETRY] Retry SLIME REPL evaluation request.
 5: [*ABORT] Return to SLIME's top level.
 --more--

Backtrace:
  0: ((LAMBDA ()))
  1: (SB-INT:SIMPLE-EVAL-IN-LEXENV (LET ((SB-IMPL::*STEP-OUT* :MAYBE)) (UNWIND-PROTECT (SB-IMPL::WITH-STEPPING-ENABLED #))) #S(SB-KERNEL:LEXENV :FUNS NIL :VARS NIL :BLOCKS NIL :TAGS NIL :TYPE-RESTRICTIONS ..
  2: (SB-INT:SIMPLE-EVAL-IN-LEXENV (STEP (FACTORIAL 2)) #&lt;NULL-LEXENV&gt;)
  3: (EVAL (STEP (FACTORIAL 2)))
</code></pre>

<p>Stepping is useful, however it may be a sign that you need to simplify your function.</p>

<h2 id="break">Break</h2>

<p>A call to <a href="http://www.xach.com/clhs?q=break">break</a> makes the program
enter the debugger, from which we can inspect the call stack.</p>

<h3 id="breakpoints-in-slime">Breakpoints in Slime</h3>

<p>Look at the <code>SLDB</code> menu, it shows navigation keys and available
actions. Of which:</p>

<ul>
<li><code>e</code> (<em>sldb-eval-in-frame</em>) prompts for an expression and evaluates
it in the selected frame. This is how we can explore our
intermediate variables.</li>
<li><code>d</code> is similar with the addition of pretty printing the result.</li>
</ul>

<p>Once we are in a frame and detect a suspicious behavior, we can even
re-compile a function at runtime and resume the program execution from
where it stopped (using the &ldquo;step-continue&rdquo; restart).</p>

<h2 id="advise-and-watch">Advise and watch</h2>

<p><a href="http://www.xach.com/clhs?q=break">advise</a> and
<a href="http://www.xach.com/clhs?q=watch">watch</a> are available in some vendor
implementations, like LispWorks. They are not available in
SBCL. <code>advise</code> allows to modify a function without changing its
source, or to do something before or after its execution, like CLOS&rsquo;
method combination (befor, after around methods).</p>

<p><code>watch</code> allows to specify variables to be displayed in some GUI during
the program execution.</p>

<h2 id="unit-tests">Unit tests</h2>

<p>Last but not least, automatic testing of functions in isolation might
be what you&rsquo;re looking for ! See the <a href="https://lispcookbook.github.io/cl-cookbook/testing.html">testing</a> section and a list of
<a href="https://github.com/CodyReichert/awesome-cl#unit-testing">test frameworks and libraries</a>.</p>

<h2 id="references">References</h2>

<ul>
<li><a href="https://successful-lisp.blogspot.com/p/httpsdrive.html">&ldquo;How to understand and use Common Lisp&rdquo;</a>, chap. 30, David Lamkins (book download from author&rsquo;s site)</li>
<li><a href="https://malisper.me/debugging-lisp-part-1-recompilation/">Malisper: debugging Lisp series</a></li>
<li><a href="https://two-wrongs.com/debugging-common-lisp-in-slime.html">Two Wrongs: debugging Common Lisp in Slime</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure 1.10 release</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">17 12 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Clojure 1.10 focuses on two major areas: improved error reporting and Java compatibility.</p>
</div>
<div class="paragraph">
<p>Error reporting at the REPL now <a href="xref/../../../../../reference/repl_and_main#_error_printing">categorizes</a> errors based on their phase of execution (read, macroexpand, compile, etc). Errors carry additional information about location and context as data, and present phase-specific error messages with better location reporting. This functionality is built into the clojure.main REPL, but the functionality is also available to other REPLs and tools with the ability to use and/or modify the data to produce better error messages.</p>
</div>
<div class="paragraph">
<p>Clojure 1.10 now requires Java 8 or above and has been updated particularly for compatibility with Java 8 and Java 11. Changes included bytecode-related bug fixes, removed use of deprecated APIs, and updates related to the module system introduced in Java 9.</p>
</div>
<div class="paragraph">
<p>See the <a href="https://github.com/clojure/clojure/blob/master/changes.md#changes-to-clojure-in-version-110">change log</a> for a complete list of all fixes, enhancements, and new features in Clojure 1.10.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_contributors"><a class="anchor" href="#_contributors"></a>Contributors</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Thanks to all of the community members who contributed patches to Clojure 1.10 (first time contributors in bold):</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Alexander Kiel</strong></p>
</li>
<li>
<p><strong>Ben Bader</strong></p>
</li>
<li>
<p>Bruce Adams</p>
</li>
<li>
<p><strong>Cezary Kosko</strong></p>
</li>
<li>
<p>Erik Assum</p>
</li>
<li>
<p><strong>Eugene Kostenko</strong></p>
</li>
<li>
<p>Ghadi Shayban</p>
</li>
<li>
<p><strong>Gijs Stuurman</strong></p>
</li>
<li>
<p>Jozef Wagner</p>
</li>
<li>
<p><strong>Kwang Yul Seo</strong></p>
</li>
<li>
<p><strong>Matthew Gilliard</strong></p>
</li>
<li>
<p>Michał Marczyk</p>
</li>
<li>
<p>Nicola Mometto</p>
</li>
<li>
<p>Nikita Prokopov</p>
</li>
<li>
<p><strong>Sean Corfield</strong></p>
</li>
<li>
<p><strong>Sebastien Martel</strong></p>
</li>
<li>
<p>Shogo Ohta</p>
</li>
<li>
<p>Stuart Sierra</p>
</li>
</ul>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">November 2018 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">12 12 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        We are happy to close the month of November with a successful start to the fourth quarter at Clojurists Together. Our Q4 projects, Datascript and Kaocha, are well on their way.
In November we elected new board members at CT- thanks to everyone who participated in the elections. A warm welcome to Nola Stowe, Fumiko Hanreich, and Laurens Van Houtven!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/115-replace-all.png" alt="Replace All">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Replace All</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">12 12 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/115-replace-all.png" alt="Replace All" title="Replace All" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">VSCode + TypeScript + Prettier = Happy Developer</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">07 12 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Developing code in JavaScript is evolving at a rapid pace. Whereas once JavaScript was considered a little scripting language to make web pages a bit more dynamic, it is now (according to StackOverflow) the most popular language in the world, and is growing year-on-year in popularity.
This explosion in popularity has resulted in a wide ecosystem of tooling to make developing code with JavaScript easier and more efficient. In this post, we&rsquo;re going to be discussing four of these tools, and how to get them set up and working all together:
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">VSCode + TypeScript + Prettier = Happy Developer</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">07 12 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Developing code in JavaScript is evolving at a rapid pace. Whereas once JavaScript was considered a little scripting language to make web pages a bit more dynamic, it is now (according to StackOverflow) the most popular language in the world, and is growing year-on-year in popularity.
This explosion in popularity has resulted in a wide ecosystem of tooling to make developing code with JavaScript easier and more efficient. In this post, we&rsquo;re going to be discussing four of these tools, and how to get them set up and working all together:
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/ipad-smart-keyboard.png" alt="Instapaper iOS 7.7: iPad Pro, Smart Keyboard, and True Black">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Instapaper iOS 7.7: iPad Pro, Smart Keyboard, and True Black</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Instapaper</a> <span class="article__date">06 12 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Instapaper 7.7 is now live in the iOS App Store with support for iPad Pro, Smart Keyboard shortcuts, and a True Black theme for iPhone X devices.</p><p><b></b></p><p><figure class="tmblr-full" data-orig-height="461" data-orig-width="600" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/ipad-smart-keyboard.png"><img src="https://64.media.tumblr.com/17509730ce43ffa1e0d76ac007cb5961/tumblr_inline_pjbpdm0Gzw1rof3ra_540.png" width="600" alt="image" data-orig-height="461" data-orig-width="600" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/ipad-smart-keyboard.png"/></figure></p><p>For Smart Keyboards, Instapaper now supports the following shortcuts:</p><ul><li>▲ and ▼ to navigate through articles in list view, ◀ and ▶ to navigate through articles in grid view<br/></li><li>↩ to open article from list<br/></li><li>⌘+A to archive an article<br/></li><li>⌘+M to move an article<br/></li><li>⌘+D to delete an article<br/></li><li>⌘+◀ to navigate back<br/></li><li>⌘+F to perform a local, title-based search<br/></li><li>⌘+⇧+ F to trigger full-text search for <a href="https://instapaper.com/premium">Premium</a> users<br/></li><li>Esc to leave search<br/></li><li>Space and ⇧+space to page up and down in list or from inside article<br/></li></ul><p>In case you forget, holding ⌘ will bring up the list of shortcuts available on the current screen.<br/></p><p><b></b></p><p>It took a considerable amount of work to get basic navigational support for Smart Keyboards, so we created an open source library called <a href="https://github.com/Instapaper/IPShortcut">IPShortcut</a> that provides Smart Keyboard shortcuts for table views, collection views, and scroll views.</p><p><b></b></p><p><figure class="tmblr-full" data-orig-height="381" data-orig-width="600" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/trueblack.png"><img src="https://64.media.tumblr.com/3fec55ad74b3723e3c43117ddb4573b6/tumblr_inline_pjbpdnLA1b1rof3ra_540.png" width="600" alt="image" data-orig-height="381" data-orig-width="600" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/trueblack.png"/></figure></p><p>The new True Black theme takes advantage of the OLED screens for iPhone X, iPhone XS, and iPhone XS Max to offer an even better experience when reading in dark mode. Screens on these devices display black by turning those pixels off on the screen, which is particularly great for reading at night. To get started, just switch to the dark mode theme on one of these devices.</p><p><b></b></p><p>If you have any questions, feature requests, or issues you’d like us to sort out, please let us know at support@instapaper.com or <a href="https://twitter.com/@InstapaperHelp">@InstapaperHelp</a> on Twitter. We love hearing from you and we thank you for using Instapaper!</p><p>- Instapaper Team</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">One liner, Git from Lisp: commit every file of this repository</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">04 12 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Hey, pardon this very short post, it&rsquo;s just for the pleasure of
blogging, and to balance the usual lengthy ones.</p>

<p>I wanted to commit, one by one, every file of the current directory
(it&rsquo;s useless, don&rsquo;t ask).</p>

<p>I use <a href="https://shinmera.github.io/legit/">legit</a> as the interface to
Git, and this one-liner:</p>

<pre><code class="language-lisp">(dolist (file (uiop:directory-files &quot;./&quot;))
   (legit:git-add :paths (pathname file))
   (legit:git-commit :files (pathname file) :message (format nil &quot;add ~a&quot; (file-namestring file))))
</code></pre>

<p>I guessed the <code>:paths</code> and <code>:files</code> arguments with Slime&rsquo;s command
argument list which appears in the modline, I wanted a function to
convert a <code>/full/path/file.cl</code> to a name <code>file.cl</code> and tried the
completion for <code>file-…</code> and found the right thing without effort. I
saw on the complete documentation that <code>legit:commit</code> wanted a
repository object as first argument, which makes sense, but
<code>legit:git-commit</code> doesn&rsquo;t and I just iterate on the current working
directory (btw change it in Slime with the <code>,cd</code> command) so it was
shorter for me.</p>

<p>Just a one liner.</p>

<blockquote>
<p>Oh my god, I didn&rsquo;t know we can do this in Lisp !</p>
</blockquote>

<p>Of course we can :p</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/114-trial-and.png" alt="Trial And">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Trial And</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">04 12 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/114-trial-and.png" alt="Trial And" title="Trial And" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-aV7Mj5hBR-I/XAM3LKcU1BI/AAAAAAAATv0/RJ45Hk-3rPUWDCnLZfHCNeRX43mSchYaACLcBGAs/s320/Captura%2Brealizada%2Bel%2B2018-12-01%2B21.36.24.png" alt="La libertad de desarrollar...: Visualizando estadisticas de pokemon usando plotly ( gr&amp;#225;fica de radar)">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">La libertad de desarrollar...: Visualizando estadisticas de pokemon usando plotly ( gr&amp;#225;fica de radar)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">02 12 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><br />Luego de un tiempo sin escribir, retomo los art&#237;culos sobre Ciencia de Datos, ahora con visualizaci&#243;n de datos. Para ello se usar&#225; la estad&#237;stica de un repositorio de datos sobre los pokemon.<br /><br />El gr&#225;fico radar es un gr&#225;fico que consiste en una secuencia de radios equi-angulares, llamados radios, y cada radio representa una de las variables. La longitud de los datos de un radio es proporcional a la magnitud de la variable para el punto de datos en relaci&#243;n con la longitud m&#225;xima de la variable en todos los puntos de datos. Se dibuja una l&#237;nea que conecta con los valores de los datos para cada radio. Esto le da a la trama una apariencia de estrella&nbsp; (<a href="https://en.wikipedia.org/wiki/Radar_chart">wikipedia</a>).&nbsp; Pueden ver un ejemplo en la siguiente figura:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-aV7Mj5hBR-I/XAM3LKcU1BI/AAAAAAAATv0/RJ45Hk-3rPUWDCnLZfHCNeRX43mSchYaACLcBGAs/s1600/Captura%2Brealizada%2Bel%2B2018-12-01%2B21.36.24.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="308" src="https://1.bp.blogspot.com/-aV7Mj5hBR-I/XAM3LKcU1BI/AAAAAAAATv0/RJ45Hk-3rPUWDCnLZfHCNeRX43mSchYaACLcBGAs/s320/Captura%2Brealizada%2Bel%2B2018-12-01%2B21.36.24.png" width="320" /></a></div><br /><br />La idea es mostrar multiples variables sobre la informaci&#243;n que se tiene de los pokemons. El repositorio de datos de donde se obtiene los datos para trabajar es el sitio de <a href="https://www.kaggle.com/abcsds/pokemon/data">kaggle</a>.<br /><br /><br />La librer&#237;a de Python que se usar&#225; en este art&#237;culo para visualizar los datos usando la gr&#225;fica radar se llama plotly, en el <a href="https://plot.ly/python/">siguiente enlace</a> podr&#225;n ver una galer&#237;a de gr&#225;ficas usando python, ya que dicha librer&#237;a se puede usar tambi&#233;n en el Lenguaje R y en Javascript. Lo bueno de plotly es que maneja m&#225;s interactividad o dinamismo a las gr&#225;ficas, no son simples gr&#225;ficas est&#225;ticas.&nbsp; Plotly se puede usar en l&#237;nea o desconectado.<br /><br />La idea de hacer este art&#237;culo sobre visualizando estad&#237;sticas de pokemon usando plotly fue de un <a href="https://typewind.github.io/2017/09/29/radar-chart/">art&#237;culo</a> donde usan la gr&#225;fica radar pero con matplotlib.<br /><br /><br />El tutoral b&#225;sico de como usar la gr&#225;fica radar en plotly lo pueden ver en el siguiente <a href="https://plot.ly/python/radar-chart/">enlace</a>.<br /><br />Este art&#237;culo se basa en un notebook que se encuentra en <a href="https://www.kaggle.com/thebrownviking20/intermediate-visualization-tutorial-using-plotly">kaggle</a>.<br /><br />La informaci&#243;n que contiene el repositorio es la siguiente:<br /><br /><br /><ul><li>#: ID de cada pokemon.</li><li>Name: Nombre de cada pokemon.</li><li>Type 1: Cada pokemon tiene un tipo, esto determina su debilidad/resistencia a ataques.</li><li>Type 2: Algunos pokemon tienen dos tipos.</li><li>Total: Suma de todas las estad&#237;sticas.</li><li>HP: Hit point, o health.</li><li>Defense:&nbsp; Nivel de resistencia a los ataques.</li><li>SP Atk: ataque especial.</li><li>SP Def:&nbsp; Resistencia contra ataques especiales.</li><li>Speed: Velocidad en el ataque.</li></ul><br /><br /><br /><br /><div class="border-box-sizing" id="notebook" tabindex="-1"><div class="container" id="notebook-container"><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h1 id="Visualizaci&#243;n-de-estad&#237;stica-de-pokemon-usando-gr&#225;fica-de-radar">Visualizaci&#243;n de estad&#237;stica de pokemon usando gr&#225;fica de radar<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Visualizaci%C3%B3n-de-estad%C3%ADstica-de-pokemon-usando-gr%C3%A1fica-de-radar">&#182;</a></h1><h3 id="Enlaces-de-inter&#233;s">Enlaces de inter&#233;s<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Enlaces-de-inter%C3%A9s">&#182;</a></h3><a href="https://typewind.github.io/2017/09/29/radar-chart/">https://typewind.github.io/2017/09/29/radar-chart/</a><br /><a href="https://www.kaggle.com/abcsds/pokemon/data">https://www.kaggle.com/abcsds/pokemon/data</a><br /><a href="https://plot.ly/python/radar-chart/">https://plot.ly/python/radar-chart/</a><br /><a href="https://www.kaggle.com/thebrownviking20/intermediate-visualization-tutorial-using-plotly">https://www.kaggle.com/thebrownviking20/intermediate-visualization-tutorial-using-plotly</a></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Se-importa-las-librer&#237;as-necesarias">Se importa las librer&#237;as necesarias<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Se-importa-las-librer%C3%ADas-necesarias">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[1]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span><br /><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span><br /><span class="kn">import</span> <span class="nn">plotly.plotly</span> <span class="k">as</span> <span class="nn">py</span><br /><span class="kn">import</span> <span class="nn">plotly.graph_objs</span> <span class="k">as</span> <span class="nn">go</span><br /><span class="kn">import</span> <span class="nn">plotly</span><br /><br /><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span><br /><span class="kn">from</span> <span class="nn">plotly</span> <span class="k">import</span> <span class="n">tools</span><br /><span class="kn">from</span> <span class="nn">plotly.offline</span> <span class="k">import</span> <span class="n">init_notebook_mode</span><span class="p">,</span> <span class="n">iplot</span><br /><span class="n">init_notebook_mode</span><span class="p">(</span><span class="n">connected</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span><br /><span class="kn">import</span> <span class="nn">plotly.figure_factory</span> <span class="k">as</span> <span class="nn">ff</span><br /><span class="kn">from</span> <span class="nn">IPython.display</span> <span class="k">import</span> <span class="n">HTML</span><span class="p">,</span> <span class="n">Image</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_html rendered_html output_subarea "></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Se-lee-y-convierte-el-archivo-csv-de-los-datos-de-pokemon-en-un-dataframe">Se lee y convierte el archivo csv de los datos de pokemon en un dataframe<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Se-lee-y-convierte-el-archivo-csv-de-los-datos-de-pokemon-en-un-dataframe">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[2]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">df</span><span class="o">=</span><span class="n">pd</span><span class="o">.</span><span class="n">read_csv</span><span class="p">(</span><span class="s2">"./datos/Pokemon.csv"</span><span class="p">)</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Se-muestra-las-5-primeras-filas-de-datos">Se muestra las 5 primeras filas de datos<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Se-muestra-las-5-primeras-filas-de-datos">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[3]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">df</span><span class="o">.</span><span class="n">head</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[3]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>#</th>      <th>Name</th>      <th>Type 1</th>      <th>Type 2</th>      <th>Total</th>      <th>HP</th>      <th>Attack</th>      <th>Defense</th>      <th>Sp. Atk</th>      <th>Sp. Def</th>      <th>Speed</th>      <th>Generation</th>      <th>Legendary</th>    </tr></thead>  <tbody><tr>      <th>0</th>      <td>1</td>      <td>Bulbasaur</td>      <td>Grass</td>      <td>Poison</td>      <td>318</td>      <td>45</td>      <td>49</td>      <td>49</td>      <td>65</td>      <td>65</td>      <td>45</td>      <td>1</td>      <td>False</td>    </tr><tr>      <th>1</th>      <td>2</td>      <td>Ivysaur</td>      <td>Grass</td>      <td>Poison</td>      <td>405</td>      <td>60</td>      <td>62</td>      <td>63</td>      <td>80</td>      <td>80</td>      <td>60</td>      <td>1</td>      <td>False</td>    </tr><tr>      <th>2</th>      <td>3</td>      <td>Venusaur</td>      <td>Grass</td>      <td>Poison</td>      <td>525</td>      <td>80</td>      <td>82</td>      <td>83</td>      <td>100</td>      <td>100</td>      <td>80</td>      <td>1</td>      <td>False</td>    </tr><tr>      <th>3</th>      <td>3</td>      <td>VenusaurMega Venusaur</td>      <td>Grass</td>      <td>Poison</td>      <td>625</td>      <td>80</td>      <td>100</td>      <td>123</td>      <td>122</td>      <td>120</td>      <td>80</td>      <td>1</td>      <td>False</td>    </tr><tr>      <th>4</th>      <td>4</td>      <td>Charmander</td>      <td>Fire</td>      <td>NaN</td>      <td>309</td>      <td>39</td>      <td>52</td>      <td>43</td>      <td>60</td>      <td>50</td>      <td>65</td>      <td>1</td>      <td>False</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Se-muestra-el-tipo-de-dato-de-cada-columna-que-maneja-el-dataframe.">Se muestra el tipo de dato de cada columna que maneja el dataframe.<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Se-muestra-el-tipo-de-dato-de-cada-columna-que-maneja-el-dataframe.">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[4]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">df</span><span class="o">.</span><span class="n">info</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_subarea output_stream output_stdout output_text"><pre>&lt;class 'pandas.core.frame.DataFrame'&gt;<br />RangeIndex: 800 entries, 0 to 799<br />Data columns (total 13 columns):<br />#             800 non-null int64<br />Name          800 non-null object<br />Type 1        800 non-null object<br />Type 2        414 non-null object<br />Total         800 non-null int64<br />HP            800 non-null int64<br />Attack        800 non-null int64<br />Defense       800 non-null int64<br />Sp. Atk       800 non-null int64<br />Sp. Def       800 non-null int64<br />Speed         800 non-null int64<br />Generation    800 non-null int64<br />Legendary     800 non-null bool<br />dtypes: bool(1), int64(9), object(3)<br />memory usage: 75.9+ KB<br /></pre></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Se-visualiza-los-datos-de-un-s&#243;lo-pokemon">Se visualiza los datos de un s&#243;lo pokemon<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Se-visualiza-los-datos-de-un-s%C3%B3lo-pokemon">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[5]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Se busca los datos del pokemon Charizard</span><br /><span class="n">x</span> <span class="o">=</span> <span class="n">df</span><span class="p">[</span><span class="n">df</span><span class="p">[</span><span class="s2">"Name"</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"Charizard"</span><span class="p">]</span><br /><span class="c1">#Se crea la grafica scatterpolar donde se le pasa  las variables que se quiere graficar. HP, Ataque, defensa, SP atk, </span><br /><span class="c1">#Sp def, velocidad y se define los nombres de los ejes.</span><br /><span class="n">data</span> <span class="o">=</span> <span class="p">[</span><span class="n">go</span><span class="o">.</span><span class="n">Scatterpolar</span><span class="p">(</span><br />  <span class="n">r</span> <span class="o">=</span> <span class="p">[</span><span class="n">x</span><span class="p">[</span><span class="s1">'HP'</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">x</span><span class="p">[</span><span class="s1">'Attack'</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">x</span><span class="p">[</span><span class="s1">'Defense'</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">x</span><span class="p">[</span><span class="s1">'Sp. Atk'</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">x</span><span class="p">[</span><span class="s1">'Sp. Def'</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">x</span><span class="p">[</span><span class="s1">'Speed'</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">x</span><span class="p">[</span><span class="s2">"HP"</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">]],</span><br />  <span class="n">theta</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'HP'</span><span class="p">,</span><span class="s1">'Attack'</span><span class="p">,</span><span class="s1">'Defense'</span><span class="p">,</span><span class="s1">'Sp. Atk'</span><span class="p">,</span><span class="s1">'Sp. Def'</span><span class="p">,</span><span class="s1">'Speed'</span><span class="p">,</span><span class="s1">'HP'</span><span class="p">],</span><br />  <span class="n">fill</span> <span class="o">=</span> <span class="s1">'toself'</span><br /><span class="p">)]</span><br /><br /><span class="c1"># se crea el layout, donde se le pasa un diccionario  donde se define los ejes de los radios, que son visibles y</span><br /><span class="c1">#su rango en este caso desde 0 a 250, no se muestra legenda, y el t&#237;tulo de la gr&#225;fica.</span><br /><br /><span class="n">layout</span> <span class="o">=</span> <span class="n">go</span><span class="o">.</span><span class="n">Layout</span><span class="p">(</span><br />  <span class="n">polar</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><br />    <span class="n">radialaxis</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><br />      <span class="n">visible</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span><br />      <span class="nb">range</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">250</span><span class="p">]</span><br />    <span class="p">)</span><br />  <span class="p">),</span><br />  <span class="n">showlegend</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span><br />  <span class="n">title</span> <span class="o">=</span> <span class="s2">"Stats of </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">x</span><span class="o">.</span><span class="n">Name</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span><br /><span class="p">)</span><br /><span class="c1">#Se crea la instancia fig donde se pasa los datos y el layout.</span><br /><span class="n">fig</span> <span class="o">=</span> <span class="n">go</span><span class="o">.</span><span class="n">Figure</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="n">data</span><span class="p">,</span> <span class="n">layout</span><span class="o">=</span><span class="n">layout</span><span class="p">)</span><br /><span class="c1">#Se gr&#224;fica la gr&#225;fica</span><br /><span class="n">iplot</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="n">filename</span> <span class="o">=</span> <span class="s2">"Single Pokemon stats"</span><span class="p">)</span><br /></pre><pre><span class="p"><br /></span></pre><pre><span class="p"><br /></span></pre><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-BXw1opTcRQQ/XAND0XTrVPI/AAAAAAAATwE/ybkHvvBLrYoW4mNpPs73Ul-QJnH6snbvgCLcBGAs/s1600/charizard.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="267" src="https://4.bp.blogspot.com/-BXw1opTcRQQ/XAND0XTrVPI/AAAAAAAATwE/ybkHvvBLrYoW4mNpPs73Ul-QJnH6snbvgCLcBGAs/s320/charizard.png" width="320" /></a></div><pre><span class="p"><br /></span></pre></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Comparaci&#243;n-de-2-pokemons">Comparaci&#243;n de 2 pokemons<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Comparaci%C3%B3n-de-2-pokemons">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[6]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1"># Se crea una funci&#243;n donde se hace la comparaci&#243;n v&#237;a gr&#225;fica de la estad&#237;stica de dos pokemons.</span><br /><span class="k">def</span> <span class="nf">compare2pokemon</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">):</span><br />    <span class="c1">#Se  captura los datos de los dos pokemons</span><br />    <span class="n">x</span> <span class="o">=</span> <span class="n">df</span><span class="p">[</span><span class="n">df</span><span class="p">[</span><span class="s2">"Name"</span><span class="p">]</span> <span class="o">==</span> <span class="n">x</span><span class="p">]</span><br />    <span class="n">y</span> <span class="o">=</span> <span class="n">df</span><span class="p">[</span><span class="n">df</span><span class="p">[</span><span class="s2">"Name"</span><span class="p">]</span> <span class="o">==</span> <span class="n">y</span><span class="p">]</span><br /><br />    <span class="c1">#Se define lo que se quiere gr&#225;ficar del primer y segundo pokemon.</span><br />    <span class="n">trace0</span> <span class="o">=</span> <span class="n">go</span><span class="o">.</span><span class="n">Scatterpolar</span><span class="p">(</span><br />      <span class="n">r</span> <span class="o">=</span> <span class="p">[</span><span class="n">x</span><span class="p">[</span><span class="s1">'HP'</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">x</span><span class="p">[</span><span class="s1">'Attack'</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">x</span><span class="p">[</span><span class="s1">'Defense'</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">x</span><span class="p">[</span><span class="s1">'Sp. Atk'</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">x</span><span class="p">[</span><span class="s1">'Sp. Def'</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">x</span><span class="p">[</span><span class="s1">'Speed'</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">x</span><span class="p">[</span><span class="s2">"HP"</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">]],</span><br />      <span class="n">theta</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'HP'</span><span class="p">,</span><span class="s1">'Attack'</span><span class="p">,</span><span class="s1">'Defense'</span><span class="p">,</span><span class="s1">'Sp. Atk'</span><span class="p">,</span><span class="s1">'Sp. Def'</span><span class="p">,</span><span class="s1">'Speed'</span><span class="p">,</span><span class="s1">'HP'</span><span class="p">],</span><br />      <span class="n">fill</span> <span class="o">=</span> <span class="s1">'toself'</span><span class="p">,</span><br />      <span class="n">name</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="n">Name</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><br />    <span class="p">)</span><br /><br />    <span class="n">trace1</span> <span class="o">=</span> <span class="n">go</span><span class="o">.</span><span class="n">Scatterpolar</span><span class="p">(</span><br />      <span class="n">r</span> <span class="o">=</span> <span class="p">[</span><span class="n">y</span><span class="p">[</span><span class="s1">'HP'</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">y</span><span class="p">[</span><span class="s1">'Attack'</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">y</span><span class="p">[</span><span class="s1">'Defense'</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">y</span><span class="p">[</span><span class="s1">'Sp. Atk'</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">y</span><span class="p">[</span><span class="s1">'Sp. Def'</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">y</span><span class="p">[</span><span class="s1">'Speed'</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">y</span><span class="p">[</span><span class="s2">"HP"</span><span class="p">]</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">]],</span><br />      <span class="n">theta</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'HP'</span><span class="p">,</span><span class="s1">'Attack'</span><span class="p">,</span><span class="s1">'Defense'</span><span class="p">,</span><span class="s1">'Sp. Atk'</span><span class="p">,</span><span class="s1">'Sp. Def'</span><span class="p">,</span><span class="s1">'Speed'</span><span class="p">,</span><span class="s1">'HP'</span><span class="p">],</span><br />      <span class="n">fill</span> <span class="o">=</span> <span class="s1">'toself'</span><span class="p">,</span><br />      <span class="n">name</span> <span class="o">=</span> <span class="n">y</span><span class="o">.</span><span class="n">Name</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><br />    <span class="p">)</span><br />    <br />    <span class="c1">#se define data como una lista que contiene los datos de los dos pokemon</span><br />    <span class="n">data</span> <span class="o">=</span> <span class="p">[</span><span class="n">trace0</span><span class="p">,</span> <span class="n">trace1</span><span class="p">]</span><br /><br />    <span class="c1">#Se define el layout como en la gr&#225;fica anterior.</span><br />    <span class="n">layout</span> <span class="o">=</span> <span class="n">go</span><span class="o">.</span><span class="n">Layout</span><span class="p">(</span><br />      <span class="n">polar</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><br />        <span class="n">radialaxis</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><br />          <span class="n">visible</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span><br />          <span class="nb">range</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">200</span><span class="p">]</span><br />        <span class="p">)</span><br />      <span class="p">),</span><br />      <span class="n">showlegend</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span><br />      <span class="n">title</span> <span class="o">=</span> <span class="s2">"</span><span class="si">{}</span><span class="s2"> vs </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">x</span><span class="o">.</span><span class="n">Name</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">y</span><span class="o">.</span><span class="n">Name</span><span class="o">.</span><span class="n">values</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span><br />    <span class="p">)</span><br />    <span class="c1">#Se crea la instancia donde se pasa los datos y el layout</span><br />    <span class="n">fig</span> <span class="o">=</span> <span class="n">go</span><span class="o">.</span><span class="n">Figure</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="n">data</span><span class="p">,</span> <span class="n">layout</span><span class="o">=</span><span class="n">layout</span><span class="p">)</span><br />    <span class="c1">#Se crea la grafica.</span><br />    <span class="n">iplot</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="n">filename</span> <span class="o">=</span> <span class="s2">"Two Pokemon stats"</span><span class="p">)</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[7]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1"># Se compara primeape y muk</span><br /><span class="n">compare2pokemon</span><span class="p">(</span><span class="s2">"Primeape"</span><span class="p">,</span> <span class="s2">"Muk"</span><span class="p">)</span><br /></pre><pre><span class="p"><br /></span></pre><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-oX7WjACCmFg/XANDuYXXZPI/AAAAAAAATwA/1gwmeS-HlgsnVoa1zX31GJQusSBlVg5KgCLcBGAs/s1600/primeapevsmuk.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="160" src="https://4.bp.blogspot.com/-oX7WjACCmFg/XANDuYXXZPI/AAAAAAAATwA/1gwmeS-HlgsnVoa1zX31GJQusSBlVg5KgCLcBGAs/s320/primeapevsmuk.png" width="320" /></a></div><pre><span class="p"><br /></span></pre></div></div></div></div></div></div><br /><br />En siguientes art&#237;culos se seguir&#225; mostrando ejemplos de usos de la galer&#237;a de gr&#225;ficas de plotly.<br /><br /><br /></div></div>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">2018 Committee Election Results</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">30 11 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together has held our first election for people to serve on the committee. The members of Clojurists Together have elected Nola Stowe, Fumiko Hanreich, and Laurens Van Houtven.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="The Trackers Who Steal">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Trackers Who Steal</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">22 11 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        How WhoTracks.Me caught the trail of the MageCart hackers
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Object destructuring and currying in functional JavaScript</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">20 11 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Currying is one of the most formidable weapons in our functional programming arsenal. Combined with composition, it’s extremely powerful. But is currying useful if you’re doing object destructuring with your function parameters?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Object destructuring and currying in functional JavaScript</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">20 11 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Currying is one of the most formidable weapons in our functional programming arsenal. Combined with composition, it’s extremely powerful. But is currying useful if you’re doing object destructuring with your function parameters?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">2018 Committee Election Candidates</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">15 11 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Thanks to everyone who applied to join the Clojurists Together Committee. Here we present the nine candidates, their motivations for joining, and a brief biography so you can learn a little bit about each one. The candidates are (in a randomised order): Nola Stowe, Laurens Van Houtven, Vijay Kiran, Nicolas Modryzk, Ghadi Shayban, Ikuru Kyogoku John Stevenson, Travis McNeill, and Fumiko Hanreich.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/113-opinions.png" alt="Opinions">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Opinions</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">14 11 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/113-opinions.png" alt="Opinions" title="Opinions" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/cl-domain.png" alt="Overview of Documentation Generators">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Overview of Documentation Generators</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">07 11 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>I have a simple need: I&rsquo;d like to generate an html documentation from
my code. What options do we have ?</p>

<p>I searched for &ldquo;documentation tool&rdquo; on Quickdocs:
<a href="http://quickdocs.org/search?q=documentation%20tool">http://quickdocs.org/search?q=documentation%20tool</a>, from which I
remove old ones (clod, qbook, manifest).</p>

<p>I had two pure Lisp solutions working out of the box, two more are of
interest, and there&rsquo;s another non-Lisp of interest.</p>

<p><strong>update</strong>: just found out that <a href="http://quickdocs.org/qbook/">qbook</a>
(<a href="https://github.com/lisp-mirror/qbook">github mirror</a>)is used for the
documentation of Fiveam, which is pretty nice:
<a href="https://common-lisp.net/project/fiveam/docs/index.html">https://common-lisp.net/project/fiveam/docs/index.html</a> It can produce
html and latex. It uses docstrings and comments that start with 4
commas to structure the page
(<a href="https://github.com/sionescu/fiveam/blob/master/src/suite.lisp">exple in source</a>
that gives
<a href="https://common-lisp.net/project/fiveam/docs/Test_0020Suites.html">this</a>). Running
it has a lot of asdf deprecation warnings and it did not work out of
the box for me (&ldquo;The slot IT.BESE.QBOOK::GENERATOR is unbound in the object&rdquo;).</p>

<h2 id="codex">Codex</h2>

<p>Codex produces nice html but isn&rsquo;t automatic.</p>

<ul>
<li><a href="https://github.com/CommonDoc/codex">https://github.com/CommonDoc/codex</a> (by @eudoxia)</li>
<li>example: <a href="https://commondoc.github.io/codex/docs/tutorial.html">https://commondoc.github.io/codex/docs/tutorial.html</a></li>
<li>input fromat: <a href="http://commondoc.github.io/scriba/docs/reference.html">scriba</a> by default. No more format it seems.</li>
<li>output: multiple html files.</li>
<li>rendering: modern, colored, light, TOC on the side</li>
<li>granularity: good</li>
<li>link to CLHS: yes</li>
<li>totally automatic: no (one needs to create the documentation structure in <code>manual.lisp</code>, AFAIU).</li>
<li>used in the wild: yes</li>
</ul>

<p>Getting started: write a simple <code>docs/manifest.lisp</code> and <code>docs/manual.lisp</code>.</p>

<p>Am I mistaking ? It&rsquo;s exclusively manual. We must supply every
function/generic function/method/class/macro to document in
<code>manual.lisp</code>.</p>

<h2 id="coo">Coo</h2>

<p>Coo is a new tool in town, it works out of the box and it is actively developed !</p>

<ul>
<li><a href="https://github.com/fisxoj/coo">https://github.com/fisxoj/coo</a></li>
<li><a href="https://fisxoj.github.io/coo/">https://fisxoj.github.io/coo/</a></li>
<li>input: docstrings in <code>rst</code></li>
<li>output: multiple html</li>
<li>rendering: black &amp; white, no TOC (active development)</li>
<li>links to CLHS: yes, since yesterday :)</li>
<li>granularity: doesn&rsquo;t show class slots, doesn&rsquo;t show generic functions.</li>
<li>used in the wild: coo no, more probably cl-docutils.</li>
</ul>

<p>Based on <a href="https://github.com/willijar/cl-docutils">cl-docutils</a>.</p>

<p>Displays the functions&rsquo; documentation following their order in source (or not ? I saw exceptions).</p>

<p>It&rsquo;s straightforward:</p>

<pre><code>(coo:document-system :my-system)
</code></pre>

<p>and it produces html into <code>docs/</code>.</p>

<h2 id="staple-doesn-t-work-on-debian-s-sbcl-1-2-4">Staple (doesn&rsquo;t work on Debian&rsquo;s SBCL 1.2.4)</h2>

<p>You may be familiar with Staple since it&rsquo;s used by Shinmera in all his projects.</p>

<ul>
<li><a href="https://github.com/Shinmera/staple">https://github.com/Shinmera/staple</a></li>
<li>output: html. The documentation string is plain text (no markup, rendered in a <code>&lt;pre&gt;</code> tag).</li>
<li>cross-references</li>
<li>can use a template.</li>
<li>more features than listed here.</li>
</ul>

<p>It doesn&rsquo;t support SBCL 1.2.4, so my tests fell short (upgrading isn&rsquo;t
100% smooth here). If you&rsquo;re on SBCL &gt;= 1.4.8 Staple is a good option.</p>

<h2 id="declt">Declt</h2>

<p>Declt has higher goals than &ldquo;quick and easy&rdquo; documentation generator.</p>

<ul>
<li><a href="https://github.com/didierverna/declt">https://github.com/didierverna/declt</a></li>
<li><a href="https://www.lrde.epita.fr/~didier/software/lisp/declt/">https://www.lrde.epita.fr/~didier/software/lisp/declt/</a></li>
<li>output: a <code>.texi</code> file, that we can render into other formats (html, pdf).</li>
<li>cross-references: yes</li>
</ul>

<p>It didn&rsquo;t work out of the box (and had no explicit error information)
and it&rsquo;s also too involved for my use case.</p>

<h2 id="documentation-tool-not-for-general-use">Documentation-tool (not for general use)</h2>

<p>It&rsquo;s the template used for Edi Weitz software, like Hunchentoot.</p>

<ul>
<li><a href="https://edicl.github.io/documentation-template/">https://edicl.github.io/documentation-template/</a></li>
<li>output: one html file</li>
</ul>

<p>It works, but it thinks you publish an edicl software and has some hardcoded &ldquo;<a href="http://weitz.de/files/…&quot;">http://weitz.de/files/…&quot;</a> urls.</p>

<h2 id="tinaa-unmaintained">Tinaa (unmaintained)</h2>

<p>I liked the output, but it didn&rsquo;t work (asdf-related error), and it&rsquo;s unmaintained (authors&rsquo; words).</p>

<ul>
<li><a href="https://github.com/gwkkwg/tinaa">https://github.com/gwkkwg/tinaa</a></li>
<li><a href="https://common-lisp.net/project/tinaa/documentation/index.html">https://common-lisp.net/project/tinaa/documentation/index.html</a></li>
<li>output: html</li>
</ul>

<h2 id="see-also">See also</h2>

<h3 id="cl-domain-sphinx">cl-domain (Sphinx)</h3>

<p>Another excellent option is 40ants&rsquo; cldomain, which builds on Python&rsquo;s proven Sphinx:</p>

<blockquote>
<p>CLDomain is an extension for the Sphinx documentation generation tool that allow sphinx to generate documentation for Common Lisp libraries. Documentation is extracted from the various entity’s documentation strings, loaded from ASDF systems and associated internal packages.</p>
</blockquote>

<p>They use it for they new projects since around 3 years now.</p>

<ul>
<li><a href="https://github.com/40ants/cldomain">https://github.com/40ants/cldomain</a></li>
<li><a href="http://40ants.com/cldomain/">http://40ants.com/cldomain/</a></li>
<li>input: rst</li>
<li>output: many html</li>
<li>HyperSpec links: yes</li>
<li>requirements: Python, pip</li>
</ul>

<p><em>udate</em> 2019-01-22: extended example.</p>

<p>An example from <a href="https://github.com/40ants/cl-hamcrest/blob/master/docs/source/matchers.rst">cl-hamcrest</a>:</p>

<ul>
<li>we reference Lisp functions/methods/macros with RST directives:</li>
</ul>

<pre><code>Object matchers
===============

This kind of matchers checks some sort of properties on an object, etc.

.. cl:package:: hamcrest/matchers

.. cl:macro:: has-plist-entries
</code></pre>

<ul>
<li>they have RST docstrings, also with RST directives to include code blocks:</li>
</ul>

<pre><code class="language-lisp">(def-has-macro
    has-plist-entries
    &quot;Matches plist entries:

.. code-block:: common-lisp-repl

   TEST&gt; (let ((obj '(:foo :bar)))
           (assert-that obj
                        (has-plist-entries :foo \&quot;bar\&quot;
                                           :blah \&quot;minor\&quot;)))
     × Key :FOO has :BAR value, but \&quot;bar\&quot; was expected

This way you can test any number of plist's entries.&quot;

    :check-obj-type (check-if-list object)
    :get-key-value (let ((key-value (getf object key 'absent)))
                      (when (eql key-value 'absent)
                          …
</code></pre>

<ul>
<li>this produces a nice output (<a href="http://40ants.com/cl-hamcrest/matchers.html">here</a>):</li>
</ul>

<p><img src="/cl-domain.png" alt="" /></p>

<hr />

<p>I&rsquo;ll use and watch Coo !</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Join the Clojurists Together Committee</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">06 11 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        As we near the close of our first year at Clojurists Together, we are opening up elections for new committee positions. As part of our commitment to transparency and community governance, Clojurists Together holds annual elections. The Committee is responsible for governing the projects, selecting which projects are sponsored, administering the projects, and interacting with sponsors. This year, we had seven committee members:
 Toby Crawley Bridget Hillyer Maria Geller Devin Walters Daniel Solano Gómez Larry Staton Jr Daniel Compton (project leader)  Committee members are elected for a two-year term.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/112-last-push.png" alt="Last Push">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Last Push</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">06 11 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/112-last-push.png" alt="Last Push" title="Last Push" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Optimizing the Django Admin Paginator</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">05 11 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I often talk about making Django scale but what does it actually mean? It means getting consistent performance regardless of the amount of data. In this article we tackle The last nail in Django admin's scalability coffin - the paginator.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">October 2018 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">04 11 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together News We are happy to close the month of October with a successful third quarter at Clojurists Together. Earlier this month, we announced our new project selections for Q4, Datascript and Kaocha.
Welcome to all of our new members that joined this month. Special thanks to new Filter company members Pitch, AdGoji, and Funding Circle. It&rsquo;s because of your support that we can continue to grow at Clojurists Together.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/111-reminiscing.png" alt="Reminiscing">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Reminiscing</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">30 10 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/111-reminiscing.png" alt="Reminiscing" title="Reminiscing" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">We now have comments. Thanks, Utterances !</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">25 10 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>We just installed a comment system, and it isn&rsquo;t Disqus ! We just
discovered <a href="utterances">https://utteranc.es/</a>, a lightweight widget
based on Github issues. If it doesn&rsquo;t find an issue corresponding to
the current article, it will create one and post your comment
there. Simple :) You dreamed of it ? They did it.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/110-test-optimization.png" alt="Test Optimization">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Test Optimization</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">24 10 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/110-test-optimization.png" alt="Test Optimization" title="Test Optimization" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Sylvia A. Earle Premio Princesa de Asturias de la Concordia</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">20 10 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/109-priorities.png" alt="Priorities">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Priorities</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">17 10 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/109-priorities.png" alt="Priorities" title="Priorities" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://4.bp.blogspot.com/-u_QZqAGNI0Q/W8PMTPx2EOI/AAAAAAAATcE/egGlkwv-TacfR1kM2TTpTvNyja_HAKjBQCLcBGAs/s320/Captura%2Bde%2Bpantalla%2Bde%2B2018-10-14%2B19-07-33.png" alt="La libertad de desarrollar...: Analizando datos del cambio clim&amp;#225;tico y niveles de CO2 en la atmosfera con Python y pandas.">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">La libertad de desarrollar...: Analizando datos del cambio clim&amp;#225;tico y niveles de CO2 en la atmosfera con Python y pandas.</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">14 10 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Continuando con los art&#237;culos sobre ciencia de datos, esta vez se analizar&#225; datos sobre informaci&#243;n del clima global y por pa&#237;ses, as&#237; como los niveles de CO2.<br /><br />Estos datos y proyecto los encontr&#233; en el sitio <a href="https://www.kaggle.com/">kaggle</a>, este sitio es para publicar proyectos de ciencia de datos. Los datos para este art&#237;culo lo encuentran en el siguiente <a href="https://www.kaggle.com/derevirn/data-analysis-on-climate-change/data">enlace</a>.&nbsp;<span id="goog_1761011272"></span><a href="https://www.blogger.com/"></a><span id="goog_1761011273"></span><br /><br />El c&#243;digo de este art&#237;culo se basa en el art&#237;culo que se encuentra en kaggle sobre el tema en ingl&#233;s&nbsp;<a href="https://www.kaggle.com/derevirn/data-analysis-on-climate-change/notebook">Climate Change and CO2 levels in atmosphere</a>.<br /><br />En este art&#237;culo se explora los cambios globales de la temperatura media y el incremento de la concentraci&#243;n del CO2 en la atmosfera.<br /><br />Los datos se obtienen de los siguientes archivos:<br /><br /><ul><li>GlobalLandTemperaturesByCountry.csv: Contiene la informaci&#243;n de la temperatura por pa&#237;s.</li><li>GlobalTemperatures.csv: Contiene la informaci&#243;n global de la temperatura.</li><li>archive.csv: Contiene la informaci&#243;n de los niveles de CO2 en la atmosfera.</li></ul><br /><br />A continuaci&#243;n se muestra el notebook:<br /><br /><div class="border-box-sizing" id="notebook" tabindex="-1"><div class="container" id="notebook-container"><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><a href="https://www.kaggle.com/derevirn/data-analysis-on-climate-change/notebook">https://www.kaggle.com/derevirn/data-analysis-on-climate-change/notebook</a><br /><a href="https://www.kaggle.com/derevirn/data-analysis-on-climate-change/data">https://www.kaggle.com/derevirn/data-analysis-on-climate-change/data</a></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Se-importa-las-librer&#237;as-de-pantas,-matplotlib-y-seaborn.">Se importa las librer&#237;as de pantas, matplotlib y seaborn.<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Se-importa-las-librer%C3%ADas-de-pantas,-matplotlib-y-seaborn.">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[1]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span><br /><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span><br /><span class="kn">import</span> <span class="nn">seaborn</span> <span class="k">as</span> <span class="nn">sns</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Se-crea-los-dataframes-a-partir-de-los-archivos-csv.">Se crea los dataframes a partir de los archivos csv.<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Se-crea-los-dataframes-a-partir-de-los-archivos-csv.">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[2]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1"># Se crea el dataframe data_pais, data_vzla, data_global y co2_ppm</span><br /><br /><span class="n">data_pais</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">read_csv</span><span class="p">(</span><span class="s2">"./datos/GlobalLandTemperaturesByCountry.csv"</span><span class="p">)</span><br /><span class="c1">#Se crea una copia del dataframe obteniendo solo la informaci&#243;n de Venezuela.</span><br /><span class="n">data_vzla</span> <span class="o">=</span> <span class="n">data_pais</span><span class="p">[</span><span class="n">data_pais</span><span class="p">[</span><span class="s2">"Country"</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"Venezuela"</span><span class="p">]</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span><br /><span class="n">data_vzla</span><span class="p">[</span><span class="s2">"dt"</span><span class="p">]</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">to_datetime</span><span class="p">(</span><span class="n">data_vzla</span><span class="p">[</span><span class="s2">"dt"</span><span class="p">])</span><br /><br /><span class="c1">#Se crea una copia del dataframe obteniendo solo la informaci&#243;n de Argentina.</span><br /><span class="n">data_arg</span> <span class="o">=</span> <span class="n">data_pais</span><span class="p">[</span><span class="n">data_pais</span><span class="p">[</span><span class="s2">"Country"</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"Argentina"</span><span class="p">]</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span><br /><span class="n">data_arg</span><span class="p">[</span><span class="s2">"dt"</span><span class="p">]</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">to_datetime</span><span class="p">(</span><span class="n">data_arg</span><span class="p">[</span><span class="s2">"dt"</span><span class="p">])</span><br /><br /><span class="c1">#Se crea una copia del dataframe obteniendo solo la informaci&#243;n de USA.</span><br /><span class="n">data_canada</span> <span class="o">=</span> <span class="n">data_pais</span><span class="p">[</span><span class="n">data_pais</span><span class="p">[</span><span class="s2">"Country"</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"Canada"</span><span class="p">]</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span><br /><span class="n">data_canada</span><span class="p">[</span><span class="s2">"dt"</span><span class="p">]</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">to_datetime</span><span class="p">(</span><span class="n">data_canada</span><span class="p">[</span><span class="s2">"dt"</span><span class="p">])</span><br /><br /><span class="c1">#Se crea una copia del dataframe obteniendo solo la informaci&#243;n de Mexico.</span><br /><span class="n">data_mexico</span> <span class="o">=</span> <span class="n">data_pais</span><span class="p">[</span><span class="n">data_pais</span><span class="p">[</span><span class="s2">"Country"</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"Mexico"</span><span class="p">]</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span><br /><span class="n">data_mexico</span><span class="p">[</span><span class="s2">"dt"</span><span class="p">]</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">to_datetime</span><span class="p">(</span><span class="n">data_mexico</span><span class="p">[</span><span class="s2">"dt"</span><span class="p">])</span><br /><br /><span class="c1">#Se crea una copia del dataframe obteniendo solo la informaci&#243;n de Brasil.</span><br /><span class="n">data_brasil</span> <span class="o">=</span> <span class="n">data_pais</span><span class="p">[</span><span class="n">data_pais</span><span class="p">[</span><span class="s2">"Country"</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"Brazil"</span><span class="p">]</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span><br /><span class="n">data_brasil</span><span class="p">[</span><span class="s2">"dt"</span><span class="p">]</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">to_datetime</span><span class="p">(</span><span class="n">data_brasil</span><span class="p">[</span><span class="s2">"dt"</span><span class="p">])</span><br /><br /><span class="c1">#Se crea una copia del dataframe obteniendo solo la informaci&#243;n de Venezuela.</span><br /><span class="n">data_chile</span> <span class="o">=</span> <span class="n">data_pais</span><span class="p">[</span><span class="n">data_pais</span><span class="p">[</span><span class="s2">"Country"</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"Chile"</span><span class="p">]</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span><br /><span class="n">data_chile</span><span class="p">[</span><span class="s2">"dt"</span><span class="p">]</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">to_datetime</span><span class="p">(</span><span class="n">data_chile</span><span class="p">[</span><span class="s2">"dt"</span><span class="p">])</span><br /><br /><span class="c1">#Se crea el dataframe de la temperatura global. </span><br /><span class="n">data_global</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">read_csv</span><span class="p">(</span><span class="s2">"./datos/GlobalTemperatures.csv"</span><span class="p">)</span><br /><span class="c1">#Se modifica la fecha y hora como datetime.</span><br /><span class="n">data_global</span><span class="p">[</span><span class="s2">"dt"</span><span class="p">]</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">to_datetime</span><span class="p">(</span><span class="n">data_global</span><span class="p">[</span><span class="s2">"dt"</span><span class="p">])</span><br /><span class="c1">#Se crea el dataframe del co2.</span><br /><span class="n">co2_ppm</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">read_csv</span><span class="p">(</span><span class="s2">"./datos/archive.csv"</span><span class="p">)</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Los-dataframes-creados.">Los dataframes creados.<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Los-dataframes-creados.">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[3]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">data_pais</span><span class="o">.</span><span class="n">head</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[3]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>dt</th>      <th>AverageTemperature</th>      <th>AverageTemperatureUncertainty</th>      <th>Country</th>    </tr></thead>  <tbody><tr>      <th>0</th>      <td>1743-11-01</td>      <td>4.384</td>      <td>2.294</td>      <td>&#197;land</td>    </tr><tr>      <th>1</th>      <td>1743-12-01</td>      <td>NaN</td>      <td>NaN</td>      <td>&#197;land</td>    </tr><tr>      <th>2</th>      <td>1744-01-01</td>      <td>NaN</td>      <td>NaN</td>      <td>&#197;land</td>    </tr><tr>      <th>3</th>      <td>1744-02-01</td>      <td>NaN</td>      <td>NaN</td>      <td>&#197;land</td>    </tr><tr>      <th>4</th>      <td>1744-03-01</td>      <td>NaN</td>      <td>NaN</td>      <td>&#197;land</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html">Como se puede observar, se tiene la fecha, la temperatura promedio, la temperatura promedio de incertidumbre y pa&#237;s.</div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[4]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">data_pais</span><span class="o">.</span><span class="n">info</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_subarea output_stream output_stdout output_text"><pre>&lt;class 'pandas.core.frame.DataFrame'&gt;<br />RangeIndex: 577462 entries, 0 to 577461<br />Data columns (total 4 columns):<br />dt                               577462 non-null object<br />AverageTemperature               544811 non-null float64<br />AverageTemperatureUncertainty    545550 non-null float64<br />Country                          577462 non-null object<br />dtypes: float64(2), object(2)<br />memory usage: 17.6+ MB<br /></pre></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html">Los tipos de datos de las columnas son dt objeto, temperatura promedio y temperatura promedio de incertidumbre son float64 y country como objeto</div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Venezuela">Venezuela<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Venezuela">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[5]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">data_vzla</span><span class="o">.</span><span class="n">head</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[5]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>dt</th>      <th>AverageTemperature</th>      <th>AverageTemperatureUncertainty</th>      <th>Country</th>    </tr></thead>  <tbody><tr>      <th>562339</th>      <td>1824-01-01</td>      <td>24.613</td>      <td>0.824</td>      <td>Venezuela</td>    </tr><tr>      <th>562340</th>      <td>1824-02-01</td>      <td>24.670</td>      <td>2.017</td>      <td>Venezuela</td>    </tr><tr>      <th>562341</th>      <td>1824-03-01</td>      <td>25.527</td>      <td>1.065</td>      <td>Venezuela</td>    </tr><tr>      <th>562342</th>      <td>1824-04-01</td>      <td>25.732</td>      <td>1.771</td>      <td>Venezuela</td>    </tr><tr>      <th>562343</th>      <td>1824-05-01</td>      <td>24.999</td>      <td>1.157</td>      <td>Venezuela</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html">Se tiene la misma informaci&#243;n anterior pero s&#243;lo de Venezuela.</div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[6]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">data_vzla</span><span class="o">.</span><span class="n">describe</span><span class="p">()</span><span class="o">.</span><span class="n">T</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[6]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>count</th>      <th>mean</th>      <th>std</th>      <th>min</th>      <th>25%</th>      <th>50%</th>      <th>75%</th>      <th>max</th>    </tr></thead>  <tbody><tr>      <th>AverageTemperature</th>      <td>2086.0</td>      <td>25.025686</td>      <td>0.703189</td>      <td>22.777</td>      <td>24.52325</td>      <td>24.9825</td>      <td>25.49525</td>      <td>27.807</td>    </tr><tr>      <th>AverageTemperatureUncertainty</th>      <td>2086.0</td>      <td>0.586000</td>      <td>0.398460</td>      <td>0.084</td>      <td>0.31000</td>      <td>0.4540</td>      <td>0.76000</td>      <td>4.120</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html">Se tiene 2086 datos, los cuales la temperatura promedio es 25.025 grados, y la incertidumbre es de 0.586, la desviaci&#243;n de la temperatura promedio es de 0.703, y de la incertidumbre es de 0.398, la m&#237;nima temperatura fue de 22.77, la m&#225;xima de 27.807.</div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[7]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">data_vzla</span><span class="o">.</span><span class="n">corr</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[7]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>AverageTemperature</th>      <th>AverageTemperatureUncertainty</th>    </tr></thead>  <tbody><tr>      <th>AverageTemperature</th>      <td>1.000000</td>      <td>-0.319882</td>    </tr><tr>      <th>AverageTemperatureUncertainty</th>      <td>-0.319882</td>      <td>1.000000</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html">Las dos variables tienen una correlaci&#243;n contraria en cierta manera.</div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Argentina">Argentina<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Argentina">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[8]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">data_arg</span><span class="o">.</span><span class="n">head</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[8]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>dt</th>      <th>AverageTemperature</th>      <th>AverageTemperatureUncertainty</th>      <th>Country</th>    </tr></thead>  <tbody><tr>      <th>25466</th>      <td>1855-05-01</td>      <td>10.745</td>      <td>1.499</td>      <td>Argentina</td>    </tr><tr>      <th>25467</th>      <td>1855-06-01</td>      <td>6.995</td>      <td>2.073</td>      <td>Argentina</td>    </tr><tr>      <th>25468</th>      <td>1855-07-01</td>      <td>6.901</td>      <td>1.568</td>      <td>Argentina</td>    </tr><tr>      <th>25469</th>      <td>1855-08-01</td>      <td>9.097</td>      <td>1.412</td>      <td>Argentina</td>    </tr><tr>      <th>25470</th>      <td>1855-09-01</td>      <td>11.316</td>      <td>1.384</td>      <td>Argentina</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[9]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">data_arg</span><span class="o">.</span><span class="n">describe</span><span class="p">()</span><span class="o">.</span><span class="n">T</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[9]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>count</th>      <th>mean</th>      <th>std</th>      <th>min</th>      <th>25%</th>      <th>50%</th>      <th>75%</th>      <th>max</th>    </tr></thead>  <tbody><tr>      <th>AverageTemperature</th>      <td>1900.0</td>      <td>14.621194</td>      <td>4.846885</td>      <td>4.796</td>      <td>10.13225</td>      <td>14.6305</td>      <td>19.27875</td>      <td>23.290</td>    </tr><tr>      <th>AverageTemperatureUncertainty</th>      <td>1900.0</td>      <td>0.527338</td>      <td>0.465652</td>      <td>0.083</td>      <td>0.20900</td>      <td>0.3035</td>      <td>0.74525</td>      <td>2.974</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Brasil">Brasil<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Brasil">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[10]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">data_brasil</span><span class="o">.</span><span class="n">head</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[10]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>dt</th>      <th>AverageTemperature</th>      <th>AverageTemperatureUncertainty</th>      <th>Country</th>    </tr></thead>  <tbody><tr>      <th>77110</th>      <td>1832-01-01</td>      <td>24.935</td>      <td>1.372</td>      <td>Brazil</td>    </tr><tr>      <th>77111</th>      <td>1832-02-01</td>      <td>24.505</td>      <td>1.953</td>      <td>Brazil</td>    </tr><tr>      <th>77112</th>      <td>1832-03-01</td>      <td>24.617</td>      <td>1.359</td>      <td>Brazil</td>    </tr><tr>      <th>77113</th>      <td>1832-04-01</td>      <td>23.990</td>      <td>2.013</td>      <td>Brazil</td>    </tr><tr>      <th>77114</th>      <td>1832-05-01</td>      <td>23.124</td>      <td>1.592</td>      <td>Brazil</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[11]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">data_brasil</span><span class="o">.</span><span class="n">describe</span><span class="p">()</span><span class="o">.</span><span class="n">T</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[11]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>count</th>      <th>mean</th>      <th>std</th>      <th>min</th>      <th>25%</th>      <th>50%</th>      <th>75%</th>      <th>max</th>    </tr></thead>  <tbody><tr>      <th>AverageTemperature</th>      <td>2164.0</td>      <td>24.699256</td>      <td>0.978787</td>      <td>21.797</td>      <td>24.02250</td>      <td>24.8295</td>      <td>25.44975</td>      <td>27.151</td>    </tr><tr>      <th>AverageTemperatureUncertainty</th>      <td>2164.0</td>      <td>0.572940</td>      <td>0.411794</td>      <td>0.060</td>      <td>0.24375</td>      <td>0.4160</td>      <td>0.84000</td>      <td>3.353</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Chile">Chile<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Chile">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[12]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">data_chile</span><span class="o">.</span><span class="n">head</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[12]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>dt</th>      <th>AverageTemperature</th>      <th>AverageTemperatureUncertainty</th>      <th>Country</th>    </tr></thead>  <tbody><tr>      <th>108248</th>      <td>1855-05-01</td>      <td>7.152</td>      <td>1.296</td>      <td>Chile</td>    </tr><tr>      <th>108249</th>      <td>1855-06-01</td>      <td>4.257</td>      <td>1.641</td>      <td>Chile</td>    </tr><tr>      <th>108250</th>      <td>1855-07-01</td>      <td>4.113</td>      <td>1.313</td>      <td>Chile</td>    </tr><tr>      <th>108251</th>      <td>1855-08-01</td>      <td>5.508</td>      <td>1.168</td>      <td>Chile</td>    </tr><tr>      <th>108252</th>      <td>1855-09-01</td>      <td>6.684</td>      <td>1.153</td>      <td>Chile</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[13]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">data_chile</span><span class="o">.</span><span class="n">describe</span><span class="p">()</span><span class="o">.</span><span class="n">T</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[13]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>count</th>      <th>mean</th>      <th>std</th>      <th>min</th>      <th>25%</th>      <th>50%</th>      <th>75%</th>      <th>max</th>    </tr></thead>  <tbody><tr>      <th>AverageTemperature</th>      <td>1900.0</td>      <td>9.383474</td>      <td>3.179081</td>      <td>3.206</td>      <td>6.502</td>      <td>9.3815</td>      <td>12.37775</td>      <td>15.493</td>    </tr><tr>      <th>AverageTemperatureUncertainty</th>      <td>1900.0</td>      <td>0.572654</td>      <td>0.418011</td>      <td>0.114</td>      <td>0.281</td>      <td>0.3825</td>      <td>0.80300</td>      <td>2.408</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Mexico">Mexico<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Mexico">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[14]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">data_mexico</span><span class="o">.</span><span class="n">head</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[14]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>dt</th>      <th>AverageTemperature</th>      <th>AverageTemperatureUncertainty</th>      <th>Country</th>    </tr></thead>  <tbody><tr>      <th>338438</th>      <td>1835-01-01</td>      <td>15.810</td>      <td>1.484</td>      <td>Mexico</td>    </tr><tr>      <th>338439</th>      <td>1835-02-01</td>      <td>14.911</td>      <td>1.579</td>      <td>Mexico</td>    </tr><tr>      <th>338440</th>      <td>1835-03-01</td>      <td>16.826</td>      <td>1.858</td>      <td>Mexico</td>    </tr><tr>      <th>338441</th>      <td>1835-04-01</td>      <td>19.925</td>      <td>1.966</td>      <td>Mexico</td>    </tr><tr>      <th>338442</th>      <td>1835-05-01</td>      <td>22.037</td>      <td>1.609</td>      <td>Mexico</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[15]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">data_mexico</span><span class="o">.</span><span class="n">describe</span><span class="p">()</span><span class="o">.</span><span class="n">T</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[15]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>count</th>      <th>mean</th>      <th>std</th>      <th>min</th>      <th>25%</th>      <th>50%</th>      <th>75%</th>      <th>max</th>    </tr></thead>  <tbody><tr>      <th>AverageTemperature</th>      <td>2145.0</td>      <td>20.567558</td>      <td>3.753343</td>      <td>12.064</td>      <td>17.109</td>      <td>21.050</td>      <td>24.164</td>      <td>26.926</td>    </tr><tr>      <th>AverageTemperatureUncertainty</th>      <td>2145.0</td>      <td>0.638233</td>      <td>0.547605</td>      <td>0.091</td>      <td>0.226</td>      <td>0.398</td>      <td>0.970</td>      <td>3.699</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Canad&#225;">Canad&#225;<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Canad%C3%A1">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[16]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">data_canada</span><span class="o">.</span><span class="n">head</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[16]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>dt</th>      <th>AverageTemperature</th>      <th>AverageTemperatureUncertainty</th>      <th>Country</th>    </tr></thead>  <tbody><tr>      <th>97255</th>      <td>1768-09-01</td>      <td>5.257</td>      <td>3.107</td>      <td>Canada</td>    </tr><tr>      <th>97256</th>      <td>1768-10-01</td>      <td>-3.393</td>      <td>2.981</td>      <td>Canada</td>    </tr><tr>      <th>97257</th>      <td>1768-11-01</td>      <td>-12.829</td>      <td>3.967</td>      <td>Canada</td>    </tr><tr>      <th>97258</th>      <td>1768-12-01</td>      <td>-20.582</td>      <td>4.622</td>      <td>Canada</td>    </tr><tr>      <th>97259</th>      <td>1769-01-01</td>      <td>-24.756</td>      <td>4.722</td>      <td>Canada</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[17]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">data_canada</span><span class="o">.</span><span class="n">describe</span><span class="p">()</span><span class="o">.</span><span class="n">T</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[17]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>count</th>      <th>mean</th>      <th>std</th>      <th>min</th>      <th>25%</th>      <th>50%</th>      <th>75%</th>      <th>max</th>    </tr></thead>  <tbody><tr>      <th>AverageTemperature</th>      <td>2504.0</td>      <td>-5.216659</td>      <td>12.878074</td>      <td>-28.736</td>      <td>-17.7025</td>      <td>-4.7285</td>      <td>7.41275</td>      <td>14.796</td>    </tr><tr>      <th>AverageTemperatureUncertainty</th>      <td>2504.0</td>      <td>1.256211</td>      <td>1.046127</td>      <td>0.123</td>      <td>0.2870</td>      <td>0.8980</td>      <td>2.12025</td>      <td>5.275</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html">Se nota que las variaciones de la temperatura promedio de incertidumbre es mayor en Brasil, Venezuela, Mexico y Canad&#225; en ese orden, con respecto a Chile y Argentina.</div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Incremento-anual-de-la-temperatura-promedio-global">Incremento anual de la temperatura promedio global<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Incremento-anual-de-la-temperatura-promedio-global">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[18]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">annual_mean_global</span> <span class="o">=</span> <span class="n">data_global</span><span class="o">.</span><span class="n">groupby</span><span class="p">(</span><span class="n">data_global</span><span class="p">[</span><span class="s2">"dt"</span><span class="p">]</span><span class="o">.</span><span class="n">dt</span><span class="o">.</span><span class="n">year</span><span class="p">)</span><span class="o">.</span><span class="n">mean</span><span class="p">()</span><br /><span class="n">reference_temperature_global</span> <span class="o">=</span> <span class="n">annual_mean_global</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="mi">1951</span><span class="p">:</span><span class="mi">1980</span><span class="p">]</span><span class="o">.</span><span class="n">mean</span><span class="p">()[</span><span class="s2">"LandAndOceanAverageTemperature"</span><span class="p">]</span><br /><span class="n">annual_mean_global</span><span class="p">[</span><span class="s2">"Anomaly"</span><span class="p">]</span> <span class="o">=</span> <span class="n">annual_mean_global</span><span class="p">[</span><span class="s2">"LandAndOceanAverageTemperature"</span><span class="p">]</span> <span class="o">-</span> <span class="n">reference_temperature_global</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[19]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">style</span><span class="o">.</span><span class="n">use</span><span class="p">(</span><span class="s2">"fivethirtyeight"</span><span class="p">)</span><br /><span class="n">annual_mean_global</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="mi">1960</span><span class="p">:</span><span class="mi">2015</span><span class="p">][</span><span class="s2">"Anomaly"</span><span class="p">]</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">figsize</span> <span class="o">=</span> <span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="mi">5</span><span class="p">),</span> <span class="n">grid</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">legend</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s2">"Anomalia anual de la temperatura promedio global"</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s1">''</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s1">'Anomalia de la temperatura'</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span><br /></pre><pre><span class="p"><br /></span></pre><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-u_QZqAGNI0Q/W8PMTPx2EOI/AAAAAAAATcE/egGlkwv-TacfR1kM2TTpTvNyja_HAKjBQCLcBGAs/s1600/Captura%2Bde%2Bpantalla%2Bde%2B2018-10-14%2B19-07-33.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="156" src="https://4.bp.blogspot.com/-u_QZqAGNI0Q/W8PMTPx2EOI/AAAAAAAATcE/egGlkwv-TacfR1kM2TTpTvNyja_HAKjBQCLcBGAs/s320/Captura%2Bde%2Bpantalla%2Bde%2B2018-10-14%2B19-07-33.png" width="320" /></a></div><pre><span class="p"><br /></span></pre><pre><span class="p"><br /></span></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_png output_subarea "></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html">Se nota que anualmente el incremento de la temperatura tiene una tendencia ascendente que ha aumentado en los &#250;ltimos a&#241;os,  este incremento en el a&#241;o 2015 fue de 0.75 grados que es conscistente con el cambio clim&#225;tico.</div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Venezuela.">Venezuela.<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Venezuela.">&#182;</a></h3>Se hace el mismo c&#225;lculo para el caso de Venezuela.</div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[20]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">annual_mean_vzla</span> <span class="o">=</span> <span class="n">data_vzla</span><span class="o">.</span><span class="n">groupby</span><span class="p">(</span><span class="n">data_vzla</span><span class="p">[</span><span class="s2">"dt"</span><span class="p">]</span><span class="o">.</span><span class="n">dt</span><span class="o">.</span><span class="n">year</span><span class="p">)</span><span class="o">.</span><span class="n">mean</span><span class="p">()</span><br /><span class="n">reference_temperature_vzla</span> <span class="o">=</span> <span class="n">annual_mean_vzla</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="mi">1951</span><span class="p">:</span><span class="mi">1980</span><span class="p">]</span><span class="o">.</span><span class="n">mean</span><span class="p">()[</span><span class="s2">"AverageTemperature"</span><span class="p">]</span><br /><span class="n">annual_mean_vzla</span><span class="p">[</span><span class="s2">"Anomaly"</span><span class="p">]</span> <span class="o">=</span> <span class="n">annual_mean_vzla</span><span class="p">[</span><span class="s2">"AverageTemperature"</span><span class="p">]</span> <span class="o">-</span> <span class="n">reference_temperature_vzla</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[21]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">annual_mean_vzla</span><span class="o">.</span><span class="n">head</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[21]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>AverageTemperature</th>      <th>AverageTemperatureUncertainty</th>      <th>Anomaly</th>    </tr><tr>      <th>dt</th>      <th></th>      <th></th>      <th></th>    </tr></thead>  <tbody><tr>      <th>1824</th>      <td>24.896545</td>      <td>1.516091</td>      <td>-0.420966</td>    </tr><tr>      <th>1825</th>      <td>25.071583</td>      <td>1.552083</td>      <td>-0.245928</td>    </tr><tr>      <th>1826</th>      <td>24.871900</td>      <td>1.440800</td>      <td>-0.445611</td>    </tr><tr>      <th>1827</th>      <td>25.156273</td>      <td>1.474182</td>      <td>-0.161238</td>    </tr><tr>      <th>1828</th>      <td>24.751818</td>      <td>1.516727</td>      <td>-0.565693</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[22]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">annual_mean_vzla</span><span class="o">.</span><span class="n">tail</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[22]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>AverageTemperature</th>      <th>AverageTemperatureUncertainty</th>      <th>Anomaly</th>    </tr><tr>      <th>dt</th>      <th></th>      <th></th>      <th></th>    </tr></thead>  <tbody><tr>      <th>2009</th>      <td>26.084917</td>      <td>0.353917</td>      <td>0.767406</td>    </tr><tr>      <th>2010</th>      <td>26.150250</td>      <td>0.341333</td>      <td>0.832739</td>    </tr><tr>      <th>2011</th>      <td>25.677333</td>      <td>0.336750</td>      <td>0.359822</td>    </tr><tr>      <th>2012</th>      <td>25.688583</td>      <td>0.401417</td>      <td>0.371072</td>    </tr><tr>      <th>2013</th>      <td>25.912875</td>      <td>0.484500</td>      <td>0.595364</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html">El &#250;ltimo registro es del a&#241;o 2013, el cual el incremento fue de 0.595 grados, hubo un pico en el a&#241;o 2010 de 0.8332 grados.</div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[23]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">style</span><span class="o">.</span><span class="n">use</span><span class="p">(</span><span class="s2">"fivethirtyeight"</span><span class="p">)</span><br /><span class="n">annual_mean_vzla</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="mi">1960</span><span class="p">:</span><span class="mi">2012</span><span class="p">][</span><span class="s2">"Anomaly"</span><span class="p">]</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">figsize</span> <span class="o">=</span> <span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="mi">5</span><span class="p">),</span> <span class="n">grid</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">legend</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s2">"Variaci&#243;n promedio anual de la temperatura de Venezuela"</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s1">''</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s1">'Incremento de la temperatura'</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span><br /></pre><pre><span class="p"><br /></span></pre><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-v--fV_38t_I/W8PMDWebbhI/AAAAAAAATb8/pflAUloVuoE_ChvRt-0HpIlhvJNvZpWtgCLcBGAs/s1600/Captura%2Bde%2Bpantalla%2Bde%2B2018-10-14%2B19-06-24.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="157" src="https://4.bp.blogspot.com/-v--fV_38t_I/W8PMDWebbhI/AAAAAAAATb8/pflAUloVuoE_ChvRt-0HpIlhvJNvZpWtgCLcBGAs/s320/Captura%2Bde%2Bpantalla%2Bde%2B2018-10-14%2B19-06-24.png" width="320" /></a></div><pre><span class="p"><br /></span></pre><pre><span class="p"><br /></span></pre><pre><span class="p"><br /></span></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_png output_subarea "></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Argentina">Argentina<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Argentina">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[24]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">annual_mean_arg</span> <span class="o">=</span> <span class="n">data_arg</span><span class="o">.</span><span class="n">groupby</span><span class="p">(</span><span class="n">data_arg</span><span class="p">[</span><span class="s2">"dt"</span><span class="p">]</span><span class="o">.</span><span class="n">dt</span><span class="o">.</span><span class="n">year</span><span class="p">)</span><span class="o">.</span><span class="n">mean</span><span class="p">()</span><br /><span class="n">reference_temperature_arg</span> <span class="o">=</span> <span class="n">annual_mean_arg</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="mi">1951</span><span class="p">:</span><span class="mi">1980</span><span class="p">]</span><span class="o">.</span><span class="n">mean</span><span class="p">()[</span><span class="s2">"AverageTemperature"</span><span class="p">]</span><br /><span class="n">annual_mean_arg</span><span class="p">[</span><span class="s2">"Anomaly"</span><span class="p">]</span> <span class="o">=</span> <span class="n">annual_mean_arg</span><span class="p">[</span><span class="s2">"AverageTemperature"</span><span class="p">]</span> <span class="o">-</span> <span class="n">reference_temperature_arg</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[25]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">annual_mean_arg</span><span class="o">.</span><span class="n">head</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[25]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>AverageTemperature</th>      <th>AverageTemperatureUncertainty</th>      <th>Anomaly</th>    </tr><tr>      <th>dt</th>      <th></th>      <th></th>      <th></th>    </tr></thead>  <tbody><tr>      <th>1855</th>      <td>11.729250</td>      <td>1.711875</td>      <td>-3.090742</td>    </tr><tr>      <th>1856</th>      <td>13.998750</td>      <td>1.553167</td>      <td>-0.821242</td>    </tr><tr>      <th>1857</th>      <td>14.221083</td>      <td>1.993417</td>      <td>-0.598908</td>    </tr><tr>      <th>1858</th>      <td>14.015667</td>      <td>1.770750</td>      <td>-0.804325</td>    </tr><tr>      <th>1859</th>      <td>14.414583</td>      <td>1.635583</td>      <td>-0.405408</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[26]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">annual_mean_arg</span><span class="o">.</span><span class="n">tail</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[26]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>AverageTemperature</th>      <th>AverageTemperatureUncertainty</th>      <th>Anomaly</th>    </tr><tr>      <th>dt</th>      <th></th>      <th></th>      <th></th>    </tr></thead>  <tbody><tr>      <th>2009</th>      <td>15.534417</td>      <td>0.215750</td>      <td>0.714425</td>    </tr><tr>      <th>2010</th>      <td>15.078833</td>      <td>0.218917</td>      <td>0.258842</td>    </tr><tr>      <th>2011</th>      <td>15.339667</td>      <td>0.219833</td>      <td>0.519675</td>    </tr><tr>      <th>2012</th>      <td>15.689000</td>      <td>0.265750</td>      <td>0.869008</td>    </tr><tr>      <th>2013</th>      <td>14.457125</td>      <td>0.276500</td>      <td>-0.362867</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[27]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">style</span><span class="o">.</span><span class="n">use</span><span class="p">(</span><span class="s2">"fivethirtyeight"</span><span class="p">)</span><br /><span class="n">annual_mean_arg</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="mi">1960</span><span class="p">:</span><span class="mi">2012</span><span class="p">][</span><span class="s2">"Anomaly"</span><span class="p">]</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">figsize</span> <span class="o">=</span> <span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="mi">5</span><span class="p">),</span> <span class="n">grid</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">legend</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s2">"Variaci&#243;n promedio anual de la temperatura de Argentina"</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s1">''</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s1">'Incremento de la temperatura'</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span><br /></pre><pre><span class="p"><br /></span></pre><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-dNLnOTmlvk4/W8PL1C_YRrI/AAAAAAAATb0/T-kaJavMvQEFnfa1Sydil0KIlnWN7mKYwCLcBGAs/s1600/Captura%2Bde%2Bpantalla%2Bde%2B2018-10-14%2B19-05-29.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="154" src="https://4.bp.blogspot.com/-dNLnOTmlvk4/W8PL1C_YRrI/AAAAAAAATb0/T-kaJavMvQEFnfa1Sydil0KIlnWN7mKYwCLcBGAs/s320/Captura%2Bde%2Bpantalla%2Bde%2B2018-10-14%2B19-05-29.png" width="320" /></a></div><pre><span class="p"><br /></span></pre><pre><span class="p"><br /></span></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_png output_subarea "></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html">Para el caso de Argentina la pendiente de la tendencia de incremento de la temperatura es menos pronunciada.</div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Brasil">Brasil<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Brasil">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[28]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">annual_mean_brasil</span> <span class="o">=</span> <span class="n">data_brasil</span><span class="o">.</span><span class="n">groupby</span><span class="p">(</span><span class="n">data_brasil</span><span class="p">[</span><span class="s2">"dt"</span><span class="p">]</span><span class="o">.</span><span class="n">dt</span><span class="o">.</span><span class="n">year</span><span class="p">)</span><span class="o">.</span><span class="n">mean</span><span class="p">()</span><br /><span class="n">reference_temperature_brasil</span> <span class="o">=</span> <span class="n">annual_mean_brasil</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="mi">1951</span><span class="p">:</span><span class="mi">1980</span><span class="p">]</span><span class="o">.</span><span class="n">mean</span><span class="p">()[</span><span class="s2">"AverageTemperature"</span><span class="p">]</span><br /><span class="n">annual_mean_brasil</span><span class="p">[</span><span class="s2">"Anomaly"</span><span class="p">]</span> <span class="o">=</span> <span class="n">annual_mean_brasil</span><span class="p">[</span><span class="s2">"AverageTemperature"</span><span class="p">]</span> <span class="o">-</span> <span class="n">reference_temperature_brasil</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[29]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">annual_mean_brasil</span><span class="o">.</span><span class="n">head</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[29]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>AverageTemperature</th>      <th>AverageTemperatureUncertainty</th>      <th>Anomaly</th>    </tr><tr>      <th>dt</th>      <th></th>      <th></th>      <th></th>    </tr></thead>  <tbody><tr>      <th>1832</th>      <td>23.858583</td>      <td>1.734500</td>      <td>-1.072247</td>    </tr><tr>      <th>1833</th>      <td>24.517833</td>      <td>1.450083</td>      <td>-0.412997</td>    </tr><tr>      <th>1834</th>      <td>24.346750</td>      <td>1.498083</td>      <td>-0.584081</td>    </tr><tr>      <th>1835</th>      <td>23.537500</td>      <td>1.298583</td>      <td>-1.393331</td>    </tr><tr>      <th>1836</th>      <td>23.921167</td>      <td>1.426083</td>      <td>-1.009664</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[30]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">annual_mean_brasil</span><span class="o">.</span><span class="n">tail</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[30]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>AverageTemperature</th>      <th>AverageTemperatureUncertainty</th>      <th>Anomaly</th>    </tr><tr>      <th>dt</th>      <th></th>      <th></th>      <th></th>    </tr></thead>  <tbody><tr>      <th>2009</th>      <td>25.600583</td>      <td>0.185667</td>      <td>0.669753</td>    </tr><tr>      <th>2010</th>      <td>25.812417</td>      <td>0.158000</td>      <td>0.881586</td>    </tr><tr>      <th>2011</th>      <td>25.428917</td>      <td>0.204833</td>      <td>0.498086</td>    </tr><tr>      <th>2012</th>      <td>25.717083</td>      <td>0.231000</td>      <td>0.786253</td>    </tr><tr>      <th>2013</th>      <td>25.348125</td>      <td>0.262250</td>      <td>0.417294</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[31]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">style</span><span class="o">.</span><span class="n">use</span><span class="p">(</span><span class="s2">"fivethirtyeight"</span><span class="p">)</span><br /><span class="n">annual_mean_brasil</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="mi">1960</span><span class="p">:</span><span class="mi">2012</span><span class="p">][</span><span class="s2">"Anomaly"</span><span class="p">]</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">figsize</span> <span class="o">=</span> <span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="mi">5</span><span class="p">),</span> <span class="n">grid</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">legend</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s2">"Variaci&#243;n promedio anual de la temperatura de Brasil"</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s1">''</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s1">'Incremento de la temperatura'</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span><br /></pre><pre><span class="p"><br /></span></pre><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-Jraqul8973w/W8PLoGzHG9I/AAAAAAAATbw/hoqZ6B1FQwQSY8zV8QdTnjtcc_JqlJLMQCLcBGAs/s1600/Captura%2Bde%2Bpantalla%2Bde%2B2018-10-14%2B19-04-46.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="157" src="https://2.bp.blogspot.com/-Jraqul8973w/W8PLoGzHG9I/AAAAAAAATbw/hoqZ6B1FQwQSY8zV8QdTnjtcc_JqlJLMQCLcBGAs/s320/Captura%2Bde%2Bpantalla%2Bde%2B2018-10-14%2B19-04-46.png" width="320" /></a></div><pre><span class="p"><br /></span></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_png output_subarea "></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html">En el caso de Brasil se nota un fuerte incremento en la decada de los 90s con un pico de m&#225;s de 1 grado, luego  la tendencia se ha estabilizado en 0.79 grados.</div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Chile">Chile<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Chile">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[32]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">annual_mean_chile</span> <span class="o">=</span> <span class="n">data_chile</span><span class="o">.</span><span class="n">groupby</span><span class="p">(</span><span class="n">data_chile</span><span class="p">[</span><span class="s2">"dt"</span><span class="p">]</span><span class="o">.</span><span class="n">dt</span><span class="o">.</span><span class="n">year</span><span class="p">)</span><span class="o">.</span><span class="n">mean</span><span class="p">()</span><br /><span class="n">reference_temperature_chile</span> <span class="o">=</span> <span class="n">annual_mean_chile</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="mi">1951</span><span class="p">:</span><span class="mi">1980</span><span class="p">]</span><span class="o">.</span><span class="n">mean</span><span class="p">()[</span><span class="s2">"AverageTemperature"</span><span class="p">]</span><br /><span class="n">annual_mean_chile</span><span class="p">[</span><span class="s2">"Anomaly"</span><span class="p">]</span> <span class="o">=</span> <span class="n">annual_mean_chile</span><span class="p">[</span><span class="s2">"AverageTemperature"</span><span class="p">]</span> <span class="o">-</span> <span class="n">reference_temperature_chile</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[33]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">annual_mean_chile</span><span class="o">.</span><span class="n">head</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[33]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>AverageTemperature</th>      <th>AverageTemperatureUncertainty</th>      <th>Anomaly</th>    </tr><tr>      <th>dt</th>      <th></th>      <th></th>      <th></th>    </tr></thead>  <tbody><tr>      <th>1855</th>      <td>7.070125</td>      <td>1.424125</td>      <td>-2.510742</td>    </tr><tr>      <th>1856</th>      <td>8.664083</td>      <td>1.319250</td>      <td>-0.916783</td>    </tr><tr>      <th>1857</th>      <td>8.645917</td>      <td>1.439250</td>      <td>-0.934950</td>    </tr><tr>      <th>1858</th>      <td>8.810250</td>      <td>1.428333</td>      <td>-0.770617</td>    </tr><tr>      <th>1859</th>      <td>9.245583</td>      <td>1.376917</td>      <td>-0.335283</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[34]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">annual_mean_chile</span><span class="o">.</span><span class="n">tail</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[34]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>AverageTemperature</th>      <th>AverageTemperatureUncertainty</th>      <th>Anomaly</th>    </tr><tr>      <th>dt</th>      <th></th>      <th></th>      <th></th>    </tr></thead>  <tbody><tr>      <th>2009</th>      <td>9.994417</td>      <td>0.281917</td>      <td>0.413550</td>    </tr><tr>      <th>2010</th>      <td>9.712833</td>      <td>0.340000</td>      <td>0.131967</td>    </tr><tr>      <th>2011</th>      <td>10.032250</td>      <td>0.322250</td>      <td>0.451383</td>    </tr><tr>      <th>2012</th>      <td>10.272583</td>      <td>0.384583</td>      <td>0.691717</td>    </tr><tr>      <th>2013</th>      <td>9.877375</td>      <td>0.393875</td>      <td>0.296508</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[35]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">style</span><span class="o">.</span><span class="n">use</span><span class="p">(</span><span class="s2">"fivethirtyeight"</span><span class="p">)</span><br /><span class="n">annual_mean_chile</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="mi">1960</span><span class="p">:</span><span class="mi">2012</span><span class="p">][</span><span class="s2">"Anomaly"</span><span class="p">]</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">figsize</span> <span class="o">=</span> <span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="mi">5</span><span class="p">),</span> <span class="n">grid</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">legend</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s2">"Variaci&#243;n promedio anual de la temperatura de Chile"</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s1">''</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s1">'Incremento de la temperatura'</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span><br /></pre><pre><span class="p"><br /></span></pre><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-9xM-uHr86Z8/W8PJ4HT1UqI/AAAAAAAATbg/SU_7WsA6IJQHW9c3HTX_jvZyfjaD2SUvgCLcBGAs/s1600/Captura%2Bde%2Bpantalla%2Bde%2B2018-10-14%2B18-57-14.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="156" src="https://2.bp.blogspot.com/-9xM-uHr86Z8/W8PJ4HT1UqI/AAAAAAAATbg/SU_7WsA6IJQHW9c3HTX_jvZyfjaD2SUvgCLcBGAs/s320/Captura%2Bde%2Bpantalla%2Bde%2B2018-10-14%2B18-57-14.png" width="320" /></a></div><pre><span class="p"><br /></span></pre><pre><span class="p"><br /></span></pre><pre><span class="p"><br /></span></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_png output_subarea "></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html">La variaci&#243;n  no supera el 0.8 grados de temperatura, con un aumento fuerte entre los 70s y 80s y luego un pico en los 90s.</div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Mexico">Mexico<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Mexico">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[36]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">annual_mean_mexico</span> <span class="o">=</span> <span class="n">data_mexico</span><span class="o">.</span><span class="n">groupby</span><span class="p">(</span><span class="n">data_mexico</span><span class="p">[</span><span class="s2">"dt"</span><span class="p">]</span><span class="o">.</span><span class="n">dt</span><span class="o">.</span><span class="n">year</span><span class="p">)</span><span class="o">.</span><span class="n">mean</span><span class="p">()</span><br /><span class="n">reference_temperature_mexico</span> <span class="o">=</span> <span class="n">annual_mean_mexico</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="mi">1951</span><span class="p">:</span><span class="mi">1980</span><span class="p">]</span><span class="o">.</span><span class="n">mean</span><span class="p">()[</span><span class="s2">"AverageTemperature"</span><span class="p">]</span><br /><span class="n">annual_mean_mexico</span><span class="p">[</span><span class="s2">"Anomaly"</span><span class="p">]</span> <span class="o">=</span> <span class="n">annual_mean_mexico</span><span class="p">[</span><span class="s2">"AverageTemperature"</span><span class="p">]</span> <span class="o">-</span> <span class="n">reference_temperature_mexico</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[37]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">annual_mean_mexico</span><span class="o">.</span><span class="n">head</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[37]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>AverageTemperature</th>      <th>AverageTemperatureUncertainty</th>      <th>Anomaly</th>    </tr><tr>      <th>dt</th>      <th></th>      <th></th>      <th></th>    </tr></thead>  <tbody><tr>      <th>1835</th>      <td>18.993250</td>      <td>1.684083</td>      <td>-1.745911</td>    </tr><tr>      <th>1836</th>      <td>19.587167</td>      <td>1.695333</td>      <td>-1.151994</td>    </tr><tr>      <th>1837</th>      <td>19.671083</td>      <td>1.647667</td>      <td>-1.068078</td>    </tr><tr>      <th>1838</th>      <td>19.337000</td>      <td>1.862417</td>      <td>-1.402161</td>    </tr><tr>      <th>1839</th>      <td>19.785833</td>      <td>1.603000</td>      <td>-0.953328</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[38]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">annual_mean_mexico</span><span class="o">.</span><span class="n">tail</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[38]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>AverageTemperature</th>      <th>AverageTemperatureUncertainty</th>      <th>Anomaly</th>    </tr><tr>      <th>dt</th>      <th></th>      <th></th>      <th></th>    </tr></thead>  <tbody><tr>      <th>2009</th>      <td>21.546083</td>      <td>0.205917</td>      <td>0.806922</td>    </tr><tr>      <th>2010</th>      <td>20.852917</td>      <td>0.217750</td>      <td>0.113756</td>    </tr><tr>      <th>2011</th>      <td>21.599333</td>      <td>0.245333</td>      <td>0.860172</td>    </tr><tr>      <th>2012</th>      <td>21.652417</td>      <td>0.324500</td>      <td>0.913256</td>    </tr><tr>      <th>2013</th>      <td>22.219222</td>      <td>0.365111</td>      <td>1.480061</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[39]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">style</span><span class="o">.</span><span class="n">use</span><span class="p">(</span><span class="s2">"fivethirtyeight"</span><span class="p">)</span><br /><span class="n">annual_mean_mexico</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="mi">1960</span><span class="p">:</span><span class="mi">2012</span><span class="p">][</span><span class="s2">"Anomaly"</span><span class="p">]</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">figsize</span> <span class="o">=</span> <span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="mi">5</span><span class="p">),</span> <span class="n">grid</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">legend</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s2">"Variaci&#243;n promedio anual de la temperatura de Mexico"</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s1">''</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s1">'Incremento de la temperatura'</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span><br /></pre><pre><span class="p"><br /></span></pre><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-bMsda0OCl_E/W8PJrcnM8YI/AAAAAAAATbc/Cl_IMqcH4X0W0htHDos0ecZ8JgX3pPuzQCLcBGAs/s1600/Captura%2Bde%2Bpantalla%2Bde%2B2018-10-14%2B18-56-01.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="157" src="https://2.bp.blogspot.com/-bMsda0OCl_E/W8PJrcnM8YI/AAAAAAAATbc/Cl_IMqcH4X0W0htHDos0ecZ8JgX3pPuzQCLcBGAs/s320/Captura%2Bde%2Bpantalla%2Bde%2B2018-10-14%2B18-56-01.png" width="320" /></a></div><pre><span class="p"><br /></span></pre><pre><span class="p"><br /></span></pre><pre><span class="p"><br /></span></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_png output_subarea "></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html">Se nota la tendencia al alsa de la temperatura en Mexico pasando el a&#241;o 2013 a estar por 1.48 grados por encima del promedio.</div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Canad&#225;">Canad&#225;<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Canad%C3%A1">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[40]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">annual_mean_canada</span> <span class="o">=</span> <span class="n">data_canada</span><span class="o">.</span><span class="n">groupby</span><span class="p">(</span><span class="n">data_canada</span><span class="p">[</span><span class="s2">"dt"</span><span class="p">]</span><span class="o">.</span><span class="n">dt</span><span class="o">.</span><span class="n">year</span><span class="p">)</span><span class="o">.</span><span class="n">mean</span><span class="p">()</span><br /><span class="n">reference_temperature_canada</span> <span class="o">=</span> <span class="n">annual_mean_canada</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="mi">1951</span><span class="p">:</span><span class="mi">1980</span><span class="p">]</span><span class="o">.</span><span class="n">mean</span><span class="p">()[</span><span class="s2">"AverageTemperature"</span><span class="p">]</span><br /><span class="n">annual_mean_canada</span><span class="p">[</span><span class="s2">"Anomaly"</span><span class="p">]</span> <span class="o">=</span> <span class="n">annual_mean_canada</span><span class="p">[</span><span class="s2">"AverageTemperature"</span><span class="p">]</span> <span class="o">-</span> <span class="n">reference_temperature_canada</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[41]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">annual_mean_canada</span><span class="o">.</span><span class="n">head</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[41]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>AverageTemperature</th>      <th>AverageTemperatureUncertainty</th>      <th>Anomaly</th>    </tr><tr>      <th>dt</th>      <th></th>      <th></th>      <th></th>    </tr></thead>  <tbody><tr>      <th>1768</th>      <td>-7.886750</td>      <td>3.66925</td>      <td>-2.969253</td>    </tr><tr>      <th>1769</th>      <td>-3.427875</td>      <td>3.50550</td>      <td>1.489622</td>    </tr><tr>      <th>1770</th>      <td>NaN</td>      <td>NaN</td>      <td>NaN</td>    </tr><tr>      <th>1771</th>      <td>NaN</td>      <td>NaN</td>      <td>NaN</td>    </tr><tr>      <th>1772</th>      <td>NaN</td>      <td>NaN</td>      <td>NaN</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[42]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">annual_mean_canada</span><span class="o">.</span><span class="n">tail</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[42]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>AverageTemperature</th>      <th>AverageTemperatureUncertainty</th>      <th>Anomaly</th>    </tr><tr>      <th>dt</th>      <th></th>      <th></th>      <th></th>    </tr></thead>  <tbody><tr>      <th>2009</th>      <td>-4.135083</td>      <td>0.231833</td>      <td>0.782414</td>    </tr><tr>      <th>2010</th>      <td>-1.887917</td>      <td>0.218583</td>      <td>3.029581</td>    </tr><tr>      <th>2011</th>      <td>-3.557083</td>      <td>0.232583</td>      <td>1.360414</td>    </tr><tr>      <th>2012</th>      <td>-3.176833</td>      <td>0.300083</td>      <td>1.740664</td>    </tr><tr>      <th>2013</th>      <td>-1.640667</td>      <td>0.533667</td>      <td>3.276831</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[43]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">style</span><span class="o">.</span><span class="n">use</span><span class="p">(</span><span class="s2">"fivethirtyeight"</span><span class="p">)</span><br /><span class="n">annual_mean_canada</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="mi">1960</span><span class="p">:</span><span class="mi">2012</span><span class="p">][</span><span class="s2">"Anomaly"</span><span class="p">]</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">figsize</span> <span class="o">=</span> <span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="mi">5</span><span class="p">),</span> <span class="n">grid</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">legend</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s2">"Variaci&#243;n promedio anual de la temperatura de Canad&#225;"</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s1">''</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s1">'Incremento de la temperatura'</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span><br /></pre><pre><span class="p"><br /></span></pre><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-fy53BVDkTWw/W8PJZIf55CI/AAAAAAAATbU/pXns9IIOKig9ZzZadtPeEqShAgnlZacVgCLcBGAs/s1600/Captura%2Bde%2Bpantalla%2Bde%2B2018-10-14%2B18-54-53.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="160" src="https://1.bp.blogspot.com/-fy53BVDkTWw/W8PJZIf55CI/AAAAAAAATbU/pXns9IIOKig9ZzZadtPeEqShAgnlZacVgCLcBGAs/s320/Captura%2Bde%2Bpantalla%2Bde%2B2018-10-14%2B18-54-53.png" width="320" /></a></div><pre><span class="p"><br /></span></pre><pre><span class="p"><br /></span></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_png output_subarea "></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html">Se nota la tendencia al alsa de la temperatura en Canad&#225; y lo preocupante es que la variaci&#243;n pase los 3 grados de temperatura en el a&#241;o 2013.</div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Niveles-anuales-de-CO2-en-la-Atmosfera">Niveles anuales de CO2 en la Atmosfera<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Niveles-anuales-de-CO2-en-la-Atmosfera">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[44]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">()</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">style</span><span class="o">.</span><span class="n">use</span><span class="p">(</span><span class="s2">"fivethirtyeight"</span><span class="p">)</span><br /><span class="n">annual_co2_ppm</span> <span class="o">=</span> <span class="n">co2_ppm</span><span class="o">.</span><span class="n">groupby</span><span class="p">(</span><span class="n">co2_ppm</span><span class="p">[</span><span class="s2">"Year"</span><span class="p">])</span><span class="o">.</span><span class="n">mean</span><span class="p">()</span><br /><span class="n">annual_co2_ppm</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="mi">1960</span><span class="p">:</span><span class="mi">2015</span><span class="p">][</span><span class="s2">"Carbon Dioxide (ppm)"</span><span class="p">]</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">figsize</span> <span class="o">=</span> <span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="mi">5</span><span class="p">),</span> <span class="n">grid</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">legend</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s2">"Nivel anual global de CO2 en la Atmosfera"</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s2">"CO2 partes por mill&#243;n"</span><span class="p">)</span><br /><span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span><br /></pre><pre><span class="p"><br /></span></pre><pre><span class="p"><br /></span></pre><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-bI1co5fPcTU/W8PJIh4-eWI/AAAAAAAATbM/MQ4nqdbSOgU6c-cCoAHkpqUn6K_7J82OQCLcBGAs/s1600/Captura%2Bde%2Bpantalla%2Bde%2B2018-10-14%2B18-54-07.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="170" src="https://3.bp.blogspot.com/-bI1co5fPcTU/W8PJIh4-eWI/AAAAAAAATbM/MQ4nqdbSOgU6c-cCoAHkpqUn6K_7J82OQCLcBGAs/s320/Captura%2Bde%2Bpantalla%2Bde%2B2018-10-14%2B18-54-07.png" width="320" /></a></div><pre><span class="p"><br /></span></pre><pre><span class="p"><br /></span></pre><pre><span class="p"><br /></span></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_png output_subarea "></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html">Se nota el incremento anual con tendencia al alza.</div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Se-c&#225;lcula-la-relaci&#243;n-del-CO2-con-la-temperatura.">Se c&#225;lcula la relaci&#243;n del CO2 con la temperatura.<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Se-c%C3%A1lcula-la-relaci%C3%B3n-del-CO2-con-la-temperatura.">&#182;</a></h3></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[45]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">annual_co2_temp</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">merge</span><span class="p">(</span><span class="n">annual_mean_global</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="mi">1960</span><span class="p">:</span><span class="mi">2015</span><span class="p">],</span> <span class="n">annual_co2_ppm</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="mi">1960</span><span class="p">:</span><span class="mi">2015</span><span class="p">],</span> <span class="n">left_index</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">right_index</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span><br /><span class="n">annual_co2_temp</span> <span class="o">=</span> <span class="n">annual_co2_temp</span><span class="p">[[</span><span class="s2">"LandAndOceanAverageTemperature"</span><span class="p">,</span> <span class="s2">"Anomaly"</span><span class="p">,</span> <span class="s2">"Carbon Dioxide (ppm)"</span><span class="p">]]</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span><br /><span class="n">annual_co2_temp</span><span class="o">.</span><span class="n">corr</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[45]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>LandAndOceanAverageTemperature</th>      <th>Anomaly</th>      <th>Carbon Dioxide (ppm)</th>    </tr></thead>  <tbody><tr>      <th>LandAndOceanAverageTemperature</th>      <td>1.000000</td>      <td>1.000000</td>      <td>0.923603</td>    </tr><tr>      <th>Anomaly</th>      <td>1.000000</td>      <td>1.000000</td>      <td>0.923603</td>    </tr><tr>      <th>Carbon Dioxide (ppm)</th>      <td>0.923603</td>      <td>0.923603</td>      <td>1.000000</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[46]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">sns</span><span class="o">.</span><span class="n">heatmap</span><span class="p">(</span><span class="n">annual_co2_temp</span><span class="o">.</span><span class="n">corr</span><span class="p">())</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[46]:</div><div class="output_text output_subarea output_execute_result"><pre>&lt;matplotlib.axes._subplots.AxesSubplot at 0x7fcacea9cdd8&gt;</pre><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-XRta6ytdle8/W8PIz3HeSfI/AAAAAAAATbE/KK1iZbnlEb4HRq9PEiLeOKRipIz32twGwCLcBGAs/s1600/Captura%2Bde%2Bpantalla%2Bde%2B2018-10-14%2B18-52-39.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="252" src="https://1.bp.blogspot.com/-XRta6ytdle8/W8PIz3HeSfI/AAAAAAAATbE/KK1iZbnlEb4HRq9PEiLeOKRipIz32twGwCLcBGAs/s320/Captura%2Bde%2Bpantalla%2Bde%2B2018-10-14%2B18-52-39.png" width="320" /></a></div><pre></pre><pre></pre><pre></pre></div></div><div class="output_area"><div class="prompt"></div><div class="output_png output_subarea "></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[47]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="mi">8</span><span class="p">))</span><br /><span class="n">sns</span><span class="o">.</span><span class="n">scatterplot</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="s2">"Anomaly"</span><span class="p">,</span><span class="n">y</span><span class="o">=</span><span class="s2">"Carbon Dioxide (ppm)"</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="n">annual_co2_temp</span><span class="p">)</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[47]:</div><div class="output_text output_subarea output_execute_result"><pre>&lt;matplotlib.axes._subplots.AxesSubplot at 0x7fcace8d6c50&gt;</pre><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-Cz0R_S7kRw4/W8PIidDAoRI/AAAAAAAATa8/LHcmqrNrLhcUz3Nib9r6sIQLhvIU5t-1wCLcBGAs/s1600/Captura%2Brealizada%2Bel%2B2018-10-14%2B18.51.02.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="233" src="https://2.bp.blogspot.com/-Cz0R_S7kRw4/W8PIidDAoRI/AAAAAAAATa8/LHcmqrNrLhcUz3Nib9r6sIQLhvIU5t-1wCLcBGAs/s320/Captura%2Brealizada%2Bel%2B2018-10-14%2B18.51.02.png" width="320" /></a></div><pre></pre><pre></pre><pre></pre></div></div><div class="output_area"><div class="prompt"></div><div class="output_png output_subarea ">" /&gt; </div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html">Con la gr&#225;fica de calor y la scatter, se nota la relaci&#243;n practicamente lineal del incremento de la temperatura y del  Dioxido de Carbono.  Ambas est&#225;n relacionadas en el Cambio clim&#225;tico.</div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[&nbsp;]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre> <br /></pre></div></div></div></div></div></div></div><br />En el sitio donde se almacenan los datos hay m&#225;s archivos, temperatura por ciudad por ejemplo para ir m&#225;s a detalle de la situaci&#243;n por ciudad. Tambi&#233;n pueden seguir buscando info de otros pa&#237;ses, en el art&#237;culo original se hizo el de Grecia, y ac&#225; prob&#233; con Argentina, Brasil, Chile, Canad&#225;, M&#233;xico y Venezuela.<br /><br />
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/108-architecture.png" alt="Architecture">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Architecture</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">10 10 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/108-architecture.png" alt="Architecture" title="Architecture" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="Government websites">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Government websites</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">09 10 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        If you are not the product, you're the taxpayer
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-LotY5s6UYto/W7lXJoceREI/AAAAAAAATVk/PvtqIbfAEU83VmxhnbWzYaapGkjOvrcGwCLcBGAs/s320/Gapminder_step2007.png" alt="La libertad de desarrollar...: Generar gr&amp;#225;ficos animados de burbuja a lo Gapminer con Python">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">La libertad de desarrollar...: Generar gr&amp;#225;ficos animados de burbuja a lo Gapminer con Python</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">07 10 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>En febrero de 2013 cre&#233; un art&#237;culo sobre <a href="https://blog.crespo.org.ve/2013/02/creacion-de-grafico-de-burbujas-con.html">c&#243;mo hacer gr&#225;ficos de burbujas con matplotlib</a>, la idea era ver como se generaba una gr&#225;fica al estilo de la presentaci&#243;n de <a href="https://es.wikipedia.org/wiki/Hans_Rosling">Hans Rosling</a>&nbsp;(por cierto, muri&#243; en Febrero de 2017).<br /><br /><br />A continuaci&#243;n el v&#237;deo que explica la historia de 200 pa&#237;ses en 200 a&#241;os, la experanza de vida y calida de vida.<br /><div class="separator" style="clear: both; text-align: center;"></div><br /><br />O su charla TED sobre&nbsp; sobre las mejores estad&#237;sticas que nunca haz visto:<br /><div class="separator" style="clear: both; text-align: center;"></div><br /><br />En el art&#237;culo que menciono se uso el conjunto de datos de la rata de criminalidad por estado de Estados Unidos del a&#241;o 2005. Pero s&#243;lo mostraba la informaci&#243;n y no la variaci&#243;n en el tiempo.<br /><br /><br />Este art&#237;culo se basa en el siguiente tutorial <a href="https://python-graph-gallery.com/341-python-gapminder-animation/">Python Gapminer Animation</a>.<br /><br />A continuaci&#243;n se muestra el c&#243;digo del script v&#237;a notebook de jupyter:<br /><br /><br /><div class="border-box-sizing" id="notebook" tabindex="-1"><div class="container" id="notebook-container"><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><a href="https://python-graph-gallery.com/341-python-gapminder-animation/">https://python-graph-gallery.com/341-python-gapminder-animation/</a></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[1]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Se importa las librerias matplitlib, numpy, pandas, seaborn</span><br /><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span><br /><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span><br /><span class="kn">import</span> <span class="nn">seaborn</span> <span class="k">as</span> <span class="nn">sns</span><br /><span class="n">sns</span><span class="o">.</span><span class="n">set_style</span><span class="p">(</span><span class="s2">"white"</span><span class="p">)</span><br /><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span><br /><span class="n">my_dpi</span><span class="o">=</span><span class="mi">96</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[2]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1"># Se obtiene los datos en formato csv  y se convierte en un dataframe</span><br /><span class="n">url</span> <span class="o">=</span> <span class="s1">'https://python-graph-gallery.com/wp-content/uploads/gapminderData.csv'</span><br /><span class="n">data</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">read_csv</span><span class="p">(</span><span class="n">url</span><span class="p">)</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[3]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Se muestra el data frame</span><br /><span class="n">data</span><span class="o">.</span><span class="n">head</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[3]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>country</th>      <th>year</th>      <th>pop</th>      <th>continent</th>      <th>lifeExp</th>      <th>gdpPercap</th>    </tr></thead>  <tbody><tr>      <th>0</th>      <td>Afghanistan</td>      <td>1952</td>      <td>8425333.0</td>      <td>Asia</td>      <td>28.801</td>      <td>779.445314</td>    </tr><tr>      <th>1</th>      <td>Afghanistan</td>      <td>1957</td>      <td>9240934.0</td>      <td>Asia</td>      <td>30.332</td>      <td>820.853030</td>    </tr><tr>      <th>2</th>      <td>Afghanistan</td>      <td>1962</td>      <td>10267083.0</td>      <td>Asia</td>      <td>31.997</td>      <td>853.100710</td>    </tr><tr>      <th>3</th>      <td>Afghanistan</td>      <td>1967</td>      <td>11537966.0</td>      <td>Asia</td>      <td>34.020</td>      <td>836.197138</td>    </tr><tr>      <th>4</th>      <td>Afghanistan</td>      <td>1972</td>      <td>13079460.0</td>      <td>Asia</td>      <td>36.088</td>      <td>739.981106</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html">Tiene las columnas pa&#237;ses, a&#241;o, poblaci&#243;n, contienen, experanza de vida y pib percapita</div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[4]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Se revisa los tipos de datos de las columnas</span><br /><span class="n">data</span><span class="o">.</span><span class="n">info</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_subarea output_stream output_stdout output_text"><pre>&lt;class 'pandas.core.frame.DataFrame'&gt;<br />RangeIndex: 1704 entries, 0 to 1703<br />Data columns (total 6 columns):<br />country      1704 non-null object<br />year         1704 non-null int64<br />pop          1704 non-null float64<br />continent    1704 non-null object<br />lifeExp      1704 non-null float64<br />gdpPercap    1704 non-null float64<br />dtypes: float64(3), int64(1), object(2)<br />memory usage: 80.0+ KB<br /></pre></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html">Se observa que la columna continente es del tipo objeto. Se necesita convertir en un tipo categoria.</div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[5]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1"># Transformar los datos de la columna continente a categoria.</span><br /><span class="n">data</span><span class="p">[</span><span class="s1">'continent'</span><span class="p">]</span><span class="o">=</span><span class="n">pd</span><span class="o">.</span><span class="n">Categorical</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s1">'continent'</span><span class="p">])</span><br /><span class="n">data</span><span class="o">.</span><span class="n">head</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[5]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>country</th>      <th>year</th>      <th>pop</th>      <th>continent</th>      <th>lifeExp</th>      <th>gdpPercap</th>    </tr></thead>  <tbody><tr>      <th>0</th>      <td>Afghanistan</td>      <td>1952</td>      <td>8425333.0</td>      <td>Asia</td>      <td>28.801</td>      <td>779.445314</td>    </tr><tr>      <th>1</th>      <td>Afghanistan</td>      <td>1957</td>      <td>9240934.0</td>      <td>Asia</td>      <td>30.332</td>      <td>820.853030</td>    </tr><tr>      <th>2</th>      <td>Afghanistan</td>      <td>1962</td>      <td>10267083.0</td>      <td>Asia</td>      <td>31.997</td>      <td>853.100710</td>    </tr><tr>      <th>3</th>      <td>Afghanistan</td>      <td>1967</td>      <td>11537966.0</td>      <td>Asia</td>      <td>34.020</td>      <td>836.197138</td>    </tr><tr>      <th>4</th>      <td>Afghanistan</td>      <td>1972</td>      <td>13079460.0</td>      <td>Asia</td>      <td>36.088</td>      <td>739.981106</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[6]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Se vuelve a revisar los tipos de las columnas y ahora se tiene que contienen es categoria</span><br /><span class="n">data</span><span class="o">.</span><span class="n">info</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_subarea output_stream output_stdout output_text"><pre>&lt;class 'pandas.core.frame.DataFrame'&gt;<br />RangeIndex: 1704 entries, 0 to 1703<br />Data columns (total 6 columns):<br />country      1704 non-null object<br />year         1704 non-null int64<br />pop          1704 non-null float64<br />continent    1704 non-null category<br />lifeExp      1704 non-null float64<br />gdpPercap    1704 non-null float64<br />dtypes: category(1), float64(3), int64(1), object(1)<br />memory usage: 68.5+ KB<br /></pre></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html">Ahora se generar&#225; las gr&#225;ficas por a&#241;o de experanza de vida y  PIB  por a&#241;o, cada gr&#225;fica se almacena con su nombre y a&#241;o a fin de que luego con Image Magick se convierta en un gif animado</div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[7]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1"># Por cada a&#241;o</span><br /><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">data</span><span class="o">.</span><span class="n">year</span><span class="o">.</span><span class="n">unique</span><span class="p">():</span><br />    <span class="c1"># inicializa la figura</span><br />    <span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">680</span><span class="o">/</span><span class="n">my_dpi</span><span class="p">,</span> <span class="mi">480</span><span class="o">/</span><span class="n">my_dpi</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="n">my_dpi</span><span class="p">)</span><br />    <span class="c1"># se cambia de color con c y alpha, se mapea el color del eje X.</span><br />    <span class="n">tmp</span><span class="o">=</span><span class="n">data</span><span class="p">[</span> <span class="n">data</span><span class="o">.</span><span class="n">year</span> <span class="o">==</span> <span class="n">i</span> <span class="p">]</span><br />    <span class="n">plt</span><span class="o">.</span><span class="n">scatter</span><span class="p">(</span><span class="n">tmp</span><span class="p">[</span><span class="s1">'lifeExp'</span><span class="p">],</span> <span class="n">tmp</span><span class="p">[</span><span class="s1">'gdpPercap'</span><span class="p">]</span> <span class="p">,</span> <span class="n">s</span><span class="o">=</span><span class="n">tmp</span><span class="p">[</span><span class="s1">'pop'</span><span class="p">]</span><span class="o">/</span><span class="mi">200000</span> <span class="p">,</span> <span class="n">c</span><span class="o">=</span><span class="n">tmp</span><span class="p">[</span><span class="s1">'continent'</span><span class="p">]</span><span class="o">.</span><span class="n">cat</span><span class="o">.</span><span class="n">codes</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s2">"Accent"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.6</span><span class="p">,</span> <span class="n">edgecolors</span><span class="o">=</span><span class="s2">"white"</span><span class="p">,</span> <span class="n">linewidth</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span><br />    <span class="c1"># Se agrega el t&#237;tulo, y los ejes.</span><br />    <span class="n">plt</span><span class="o">.</span><span class="n">yscale</span><span class="p">(</span><span class="s1">'log'</span><span class="p">)</span><br />    <span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s2">"Experanza de vida"</span><span class="p">)</span><br />    <span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s2">"PIB per capita"</span><span class="p">)</span><br />    <span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s2">"A&#241;o: "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="p">)</span><br />    <span class="n">plt</span><span class="o">.</span><span class="n">ylim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">100000</span><span class="p">)</span><br />    <span class="n">plt</span><span class="o">.</span><span class="n">xlim</span><span class="p">(</span><span class="mi">30</span><span class="p">,</span> <span class="mi">90</span><span class="p">)</span><br />    <br />    <span class="c1"># Se salva el archivo como png, cada archivo por a&#241;o.</span><br />    <span class="n">filename</span><span class="o">=</span><span class="s1">'Gapminder_step'</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="o">+</span><span class="s1">'.png'</span><br />    <span class="n">plt</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">96</span><span class="p">)</span><br />    <span class="n">plt</span><span class="o">.</span><span class="n">gca</span><span class="p">()</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_subarea output_stream output_stderr output_text"></div></div><div class="output_area"><div class="prompt"></div></div><br /><br /><br />Se muestra una imagen de las generadas:<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-LotY5s6UYto/W7lXJoceREI/AAAAAAAATVk/PvtqIbfAEU83VmxhnbWzYaapGkjOvrcGwCLcBGAs/s1600/Gapminder_step2007.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="225" src="https://1.bp.blogspot.com/-LotY5s6UYto/W7lXJoceREI/AAAAAAAATVk/PvtqIbfAEU83VmxhnbWzYaapGkjOvrcGwCLcBGAs/s320/Gapminder_step2007.png" width="320" /></a></div><br /><br />Para convertir las im&#225;genes generadas en gif se ejecuta el siguiente comando de image magick:<br /><br />&nbsp;convert -delay 80 Gapminder*.png animated_gapminder.gif<br /><br /><br /><br />El gif resultante se muestra a continuaci&#243;n:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-WWVn0zjctlo/W7lXXPEPYGI/AAAAAAAATVo/Ys9iPMJriHMYISwDeXyaWQtaskCZowBPACLcBGAs/s1600/animated_gapminder.gif" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="225" src="https://2.bp.blogspot.com/-WWVn0zjctlo/W7lXXPEPYGI/AAAAAAAATVo/Ys9iPMJriHMYISwDeXyaWQtaskCZowBPACLcBGAs/s320/animated_gapminder.gif" width="320" /></a></div><br /><br />En pr&#243;ximo art&#237;culo espero encontrar el conjunto de datos del art&#237;culo mencionado al inicio para hacerle una animaci&#243;n como el realizado en este art&#237;culo.<br /><br /></div></div></div></div></div>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">These Months in Common Lisp: Q3 2018</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">06 10 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<ul>
<li><a href="https://lisp-journey.gitlab.io/blog/these-months-in-common-lisp-q1-2018/">Q1 2018</a></li>
<li><a href="https://lisp-journey.gitlab.io/blog/these-months-in-common-lisp-q2-2018/">Q2 2018</a></li>
</ul>

<h1 id="documentation">Documentation</h1>

<ul>
<li><a href="https://lispcookbook.github.io/cl-cookbook/clos.html">CLOS – the Common Lisp Cookbook (extensive rewrite)</a></li>
<li><a href="http://cybertiggyr.com/fmt/fmt.pdf">Advanced Use of Lisp’s FORMAT Function (2004)</a></li>
<li><a href="https://www.cs.fsu.edu/~cap5605/Luger_Supplementary_Text.pdf">Book: Luger/Stubblefield, 2009; AI Algorithms, Data Structures, and Idioms in Prolog, Lisp, and Java (PDF)</a></li>
<li><a href="https://github.com/DalekBaldwin/on-lisp">GitHub - DalekBaldwin/on-lisp: A modernized and annotated code companion to Paul Graham&rsquo;s &ldquo;On Lisp&rdquo;</a></li>
<li><a href="https://joaotavora.github.io/sly/">SLY User Manual, version 1.0.0-beta-2</a></li>
</ul>

<h1 id="announcements">Announcements</h1>

<ul>
<li><a href="https://common-lisp.net/">A new version of Common-Lisp.net has been launched!</a></li>
<li><a href="https://old.reddit.com/r/Common_Lisp/comments/9as489/a_new_quickdist_distribution_ultralisporg/">A new quickdist distribution – Ultralisp.org</a></li>
<li><a href="https://events.tymoon.eu/4">Autumn Lisp Game Jam</a></li>
<li><a href="http://www.sbcl.org/all-news.html?1.4.12#1.4.12">SBCL 1.4.12 Released</a></li>
<li><a href="https://www.reddit.com/r/emacs/comments/9j1ubb/next_browser_linux_port_campaign/">Next Browser Linux Port Campaign</a></li>
<li><a href="https://awesome-cl.com/">awesome-cl.com (the website)</a></li>
</ul>

<h1 id="jobs">Jobs</h1>

<ul>
<li><a href="https://www.reddit.com/r/lisp/comments/9gs1ew/we_are_still_looking_for_lispers_who_want_to_work/">We are still looking for Lispers who want to work in AI (Toronto and around the world)</a></li>
</ul>

<h1 id="projects">Projects</h1>

<ul>
<li><a href="https://vimeo.com/237947324">Introducing Seed: An Interactive Software Environment in Common Lisp</a></li>
<li><a href="https://github.com/knobo/live-reload">Live reload prototype for clack</a></li>
<li><a href="https://gkbrk.com/2018/08/mastodon-bot-in-common-lisp/">Mastodon Bot in Common Lisp</a></li>
<li><a href="https://github.com/kkazuo/slack-client">slack-client: Slack Real Time Messaging API Client</a></li>
<li><a href="https://github.com/sirherrbatka/cl-progress-bar/">cl-progress-bar: Progress bars, just like in quicklisp!</a></li>
<li><a href="https://github.com/Shinmera/oxenfurt">Shinmera/oxenfurt: A Common Lisp client library for the Oxford dictionary API</a></li>
<li><a href="https://lisp-univ-etc.blogspot.com/2018/09/ann-flight-recorder-robust-repl-logging.html">flight-recorder - a robust REPL logging facility</a></li>
<li><a href="https://github.com/MegaLoler/Music">Music: Music framework for musical expression in Common Lisp with a focus on music theory (built from scratch, on development)</a></li>
<li><a href="https://common-lisp.net/project/tovero/">Tovero is a 3D modeling system for Common Lisp</a></li>
<li><a href="https://gitlab.com/jgkamat/rmsbolt">RMSBolt: See what your compiler is going inside of Emacs (has minimal support for Common Lisp)</a></li>
<li><a href="https://github.com/fjames86/ftw">ftw: Common Lisp Win32 GUI library</a></li>
<li><a href="https://www.michaelfiano.com/projects/pngload/">pngload: A PNG (Portable Network Graphics) image format decoder</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9g2ook/melbase_forked_and_actively_updated_versatile/">mel-base - forked and actively updated versatile mail library for common lisp</a></li>
<li><a href="https://github.com/phoe/wordnet">wordnet: Common Lisp interface to WordNet</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9brkej/clvep_a_video_effects_processor/">cl-vep: a video effects processor</a></li>
<li><a href="https://wayback.archive.org/web/20180611080125/https://www.informatik.uni-kiel.de/%7Ewg/clicc.html">CLiCC - The Common Lisp to C Compiler</a></li>
<li><a href="https://github.com/phoe/list-named-class">LIST-NAMED-CLASS - name your CLOS classes with lists, not just symbols</a></li>
<li><a href="https://www.guerra-espacial.rufina.link/">GUERRA-ESPACIAL: an implementation of the spacewar computer game in Common Lisp</a></li>
<li><a href="https://common-lisp.net/project/clive/">Clive is a Common Lisp binding to Open Inventor with extensions</a></li>
<li><a href="https://github.com/phoe/lorem-ipsum/">Lorem ipsum generator in portable Common Lisp</a></li>
<li><a href="https://github.com/tlikonen/cl-decimals">tlikonen/cl-decimals: Decimal number parser and formatter package</a></li>
<li><a href="https://github.com/tlikonen/cl-enchant">tlikonen/cl-enchant: Common Lisp bindings for the Enchant spell-checker library</a></li>
<li><a href="https://github.com/tlikonen/cl-general-accumulator">tlikonen/cl-general-accumulator: General-purpose, extensible value accumulator library</a></li>
<li><a href="https://github.com/cuichaox/dml">Drawing UML diagram with Common Lisp</a></li>
<li><a href="https://gitlab.com/m3tti/slurm-cl">slurm-cl - a web application framework for Common Lisp and single page applications.</a></li>
</ul>

<p>new releases:</p>

<ul>
<li><a href="https://github.com/cxxxr/lem/releases/tag/v1.4">Lem v1.4 has been released with paredit-mode</a></li>
<li><a href="https://github.com/froggey/Mezzano/releases/tag/demo4">Common Lisp OS Mezzano – Demo 4</a></li>
<li><a href="https://github.com/fukamachi/mito/pull/38">Mito ORM: new deftable shortcut to create default initargs, accessors and metaclass</a></li>
<li><a href="http://www.didierverna.net/blog/index.php?post/2018/08/07/Quickref-open-sourced">Quickref open-sourced - Didier Verna&rsquo;s Sci-Blog</a></li>
</ul>

<p>(re)discoveries:</p>

<ul>
<li><a href="https://lisp-journey.gitlab.io/blog/shuffletron-lisp-music-player-for-the-terminal/">Shuffletron, a Common Lisp Music Player for the terminal</a></li>
<li><a href="https://github.com/sellout/quid-pro-quo">quid-pro-quo: a contract programming library in the style of Eiffel’s Design by Contract</a></li>
<li><a href="https://successful-lisp.blogspot.com/p/httpsdrive.html">Successful Lisp: How to Understand and Use Common Lisp (Book download from Author&rsquo;s site)</a></li>
<li><a href="http://cram-system.org/doc/ide">Cognitive Robot Abstract Machine = Common Lisp + ROS</a></li>
<li><a href="https://github.com/mabragor/cl-yaclyaml">cl-yaclyaml - a YaML processor (loader, not dumper)</a></li>
<li><a href="https://scymtym.github.io/esrap/">Esrap - a packrat parser for Common Lisp</a></li>
<li><a href="https://gitlab.common-lisp.net/gendl/gendl">gendl - Generative Programming and Knowledge-based Engineering (KBE) system embedded in Common Lisp</a></li>
<li><a href="https://github.com/pcostanza/filtered-functions">pcostanza/filtered-functions: an extension of CLOS generic function invocation that enables the use of arbitrary predicates for selecting and applying methods.</a></li>
</ul>

<h1 id="articles">Articles</h1>

<ul>
<li><a href="http://stevelosh.com/blog/2018/08/a-road-to-common-lisp/">A Road to Common Lisp / Steve Losh</a></li>
<li><a href="http://www.newresalhaider.com/post/common-treasure/">Excavating a Common Treasure: Common Lisp</a></li>
<li><a href="http://christophe.rhodes.io/notes/blog/posts/2018/first_riscy_steps/">First RISCy Steps &ndash; Porting SBCL to the RISC-V</a></li>
<li><a href="https://medium.com/@mhkoji/my-pattern-to-write-a-web-application-in-common-lisp-3-86e79c5c3551">My pattern to write a web application in Common Lisp (3)</a></li>
<li><a href="A new way of blogging about Common Lisp">A new way of blogging about Common Lisp</a></li>
<li><a href="https://medium.com/@glikson/going-serverless-from-common-lisp-and-cgi-to-aws-lambda-and-api-gateway-9fba46c84fb8">Going Serverless: From Common LISP and CGI to AWS Lambda and API Gateway</a></li>
<li><a href="http://stevelosh.com/blog/2018/07/fun-with-macros-if-let/">Fun with Macros: If-Let and When-Let / Steve Losh</a></li>
<li><a href="https://old.reddit.com/r/Common_Lisp/comments/99q37t/how_to_enable_reader_macros_throughout_a_project/">How to enable reader macros throughout a project with ASDF&rsquo;s package-inferred-system (E. Fukamachi)</a></li>
<li><a href="https://openresearch-repository.anu.edu.au/bitstream/1885/144603/1/Sorensen%20Thesis%202018.pdf">Extempore - The design, implementation and application of a cyber-physical programming language, Andrew Sorensen, Thesis, 2018 (PDF)</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9gjd0m/lisping_copyleft_a_close_reading_of_the_lisp_lgpl/">https://www.ifosslr.org/ojs/ifosslr/article/view/75</a></li>
<li><a href="https://m00natic.github.io/lisp/manual-jit.html">Uniform Structured Syntax, Metaprogramming and Run-time Compilation</a></li>
<li><a href="https://z0ltan.wordpress.com/2018/08/04/simple-expression-evaluator-comparison-between-haskell-rust-and-common-lisp/">Simple expression evaluator comparison between Haskell, Rust, and Common Lisp</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/98s5zp/lisping_at_jpl/">Lisping at JPL</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/93v9cv/a_clon_guide/">A Clon guide</a></li>
<li><a href="https://www.radioeng.cz/fulltexts/2011/11_04_880_889.pdf">Common LISP as Simulation Program (CLASP) of Electronic Circuits (2011) (pdf)</a></li>
<li><a href="https://gitlab.com/criesbeck/cs325/">Lisp code for Christopher Riesbeck&rsquo;s cs325 AI course.</a></li>
<li><a href="https://old.reddit.com/r/Common_Lisp/comments/93g3p2/a_story_of_defun_games/">A Story of (defun games ())</a></li>
</ul>

<h1 id="discussion">Discussion</h1>

<ul>
<li><a href="https://www.reddit.com/r/lisp/comments/9c94lu/what_applicationstasks_are_you_working_on_this/">What are you working on this week ?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/8zvirn/cl_bad_for_native_guis_and_other_thoughts_on/">CL bad for native GUIs? And other thoughts on first CL project</a></li>
</ul>

<p>Learning Lisp:</p>

<ul>
<li><a href="https://www.reddit.com/r/lisp/comments/9er4mo/i_want_to_try_lisp_how_should_i_begin/">I want to try Lisp, how should I begin?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9b7v56/what_lisp_dialect_for_real_world_applications/">What lisp dialect for &ldquo;real world&rdquo; applications?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/8w8cr1/what_do_commercial_lisps_offer_that_frees_dont/">What do commercial Lisps offer that frees don&rsquo;t?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9kiji7/which_nonclojure_lisp_to_learn_first/">Which (non-Clojure) Lisp to learn first?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9k2vmi/can_cl_implement_clojures_keyword_as_function/">Can CL implement Clojure&rsquo;s keyword as function syntax?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9j7uld/why_cons_cells/">Why cons cells?</a></li>
</ul>

<h1 id="screencasts">Screencasts</h1>

<ul>
<li><a href="https://youtu.be/BL9MiiCcETM">Little bits of Lisp - cl-autowrap</a></li>
<li><a href="https://youtu.be/BL9MiiCcETM">Lots of bits of Lisp - Generating Bindings to C Libraries </a></li>
<li><a href="https://www.youtube.com/watch?v=ygKXeLKhiTI">Lots of bits of Lisp - Macros (2 hr episode)</a></li>
<li><a href="https://youtu.be/WEFLi-u7qyE">Pushing Pixels with Lisp - Episode 59 - Basic Disolve Shaders</a> (and more episodes !)</li>
<li><a href="https://www.youtube.com/watch?v=z7V5BL6W3CA">Common Lisp Study Group - Introduction to Screamer</a></li>
<li><a href="https://www.youtube.com/watch?v=uRLgZCV4bOM">Common Lisp Study Group: An Intro to SERIES</a></li>
<li><a href="https://www.youtube.com/watch?v=1zS46_HWRMo">Daniel G Bobrow: Common LISP Object Standard 1987 (video 53min)</a></li>
</ul>

<h1 id="common-lisp-vs">Common Lisp VS &hellip;</h1>

<ul>
<li><a href="https://www.reddit.com/r/lisp/comments/8wdw2r/is_there_a_lisp_that_is_considered_excellent/">Is there a Lisp that is considered &ldquo;excellent&rdquo; about error handling ?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9lhbnx/lisp_dialect_survey/">Lisp Dialect survey</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9i5mmp/the_julia_challenge/">the Julia challenge</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9g07to/python_pitfalls/">Python pitfalls ?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/9lpssp/how_a_common_lisp_programmer_views_users_of_other/">How a Common Lisp programmer views users of other languages (humor)</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">CLOS Tutorial</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">05 10 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p><em>We just updated the <a href="https://lispcookbook.github.io/cl-cookbook/clos.html">CLOS page on the Common Lisp Cookbook</a>. You should refer to it for updates.</em></p>

<p>CLOS is the &ldquo;Common Lisp Object System&rdquo;, arguably one of the most
powerful object systems available in any language.</p>

<p>Some of its features include:</p>

<ul>
<li>it is <strong>dynamic</strong>, making it a joy to work with in a Lisp REPL. For
example, changing a class definition will update the existing
objects, given certain rules which we have control upon.</li>
<li>it supports <strong>multiple dispatch</strong> and <strong>multiple inheritance</strong>,</li>
<li>it is different from most object systems in that class and method
definitions are not tied together,</li>
<li>it has excellent <strong>introspection</strong> capabilities,</li>
<li>it is provided by a <strong>meta-object protocol</strong>, which provides a
standard interface to the CLOS, and can be used to create new object
systems.</li>
</ul>

<p>The functionality belonging to this name was added to the Common Lisp
language between the publication of Steele&rsquo;s first edition of &ldquo;Common
Lisp, the Language&rdquo; in 1984 and the formalization of the language as
an ANSI standard ten years later.</p>

<p>This page aims to give a good understanding of how to use CLOS, but
only a brief introduction to the MOP.</p>

<p>To learn the subjects in depth, you will need two books:</p>

<ul>
<li><a href="http://www.communitypicks.com/r/lisp/s/17592186046723-object-oriented-programming-in-common-lisp-a-programmer">Object-Oriented Programming in Common Lisp: a Programmer&rsquo;s Guide to CLOS</a>, by Sonya Keene,</li>
<li><a href="http://www.communitypicks.com/r/lisp/s/17592186045709-the-art-of-the-metaobject-protocol">the Art of the Metaobject Protocol</a>, by Gregor Kiczales, Jim des Rivières et al.</li>
</ul>

<p>But see also</p>

<ul>
<li>the introduction in <a href="http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html">Practical Common Lisp</a> (online), by Peter Seibel.</li>
<li><a href="https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node260.html#SECTION003200000000000000000">Common Lisp, the Language</a></li>
<li>and for reference, the complete <a href="https://clos-mop.hexstreamsoft.com/">CLOS-MOP specifications</a>.</li>
</ul>

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-generate-toc again -->

<p><strong>Table of Contents</strong></p>

<ul>
<li><a href="#classes-and-instances">Classes and instances</a>

<ul>
<li><a href="#diving-in">Diving in</a></li>
<li><a href="#creating-objects-make-instance">Creating objects (make-instance)</a></li>
<li><a href="#slots">Slots</a>

<ul>
<li><a href="#a-function-that-always-works-slot-value">A function that always works (slot-value)</a></li>
<li><a href="#initial-and-default-values-initarg-initform">Initial and default values (initarg, initform)</a></li>
<li><a href="#getters-and-setters-accessor-reader-writer">Getters and setters (accessor, reader, writer)</a></li>
<li><a href="#class-vs-instance-slots">Class VS instance slots</a></li>
<li><a href="#slot-documentation">Slot documentation</a></li>
<li><a href="#slot-type">Slot type</a></li>
</ul></li>
<li><a href="#find-class-class-name-class-of">find-class, class-name, class-of</a></li>
<li><a href="#subclasses-and-inheritance">Subclasses and inheritance</a></li>
<li><a href="#multiple-inheritance">Multiple inheritance</a></li>
<li><a href="#redefining-and-changing-a-class">Redefining and changing a class</a></li>
<li><a href="#pretty-printing">Pretty printing</a></li>
<li><a href="#classes-of-traditional-lisp-types">Classes of traditional lisp types</a></li>
<li><a href="#introspection">Introspection</a></li>
<li><a href="#see-also">See also</a>

<ul>
<li><a href="#defclassstd-write-shorter-classes">defclass/std: write shorter classes</a></li>
</ul></li>
</ul></li>
<li><a href="#methods">Methods</a>

<ul>
<li><a href="#diving-in">Diving in</a></li>
<li><a href="#generic-functions-defgeneric-defmethod">Generic functions (defgeneric, defmethod)</a></li>
<li><a href="#multimethods">Multimethods</a></li>
<li><a href="#controlling-setters-setf-ing-methods">Controlling setters (setf-ing methods)</a></li>
<li><a href="#dispatch-mechanism-and-next-methods">Dispatch mechanism and next methods</a></li>
<li><a href="#method-qualifiers-before-after-around">Method qualifiers (before, after, around)</a></li>
<li><a href="#other-method-combinations">Other method combinations</a></li>
<li><a href="#debugging-tracing-method-combination">Debugging: tracing method combination</a></li>
</ul></li>
<li><a href="#mop">MOP</a>

<ul>
<li><a href="#metaclasses">Metaclasses</a></li>
<li><a href="#controlling-the-initialization-of-instances-initialize-instance">Controlling the initialization of instances (initialize-instance)</a></li>
</ul></li>
</ul>

<!-- markdown-toc end -->

<h1 id="classes-and-instances">Classes and instances</h1>

<h2 id="diving-in">Diving in</h2>

<p>Let&rsquo;s dive in with an example showing class definition, creation of
objects, slot access, methods specialized for a given class, and
inheritance.</p>

<pre><code class="language-lisp">(defclass person ()
  ((name
    :initarg :name
    :accessor name)
   (lisper
    :initform nil
    :accessor lisper)))

;; =&gt; #&lt;STANDARD-CLASS PERSON&gt;

(defvar p1 (make-instance 'person :name &quot;me&quot; ))
;;                                 ^^^^ initarg
;; =&gt; #&lt;PERSON {1006234593}&gt;

(name p1)
;;^^^ accessor
;; =&gt; &quot;me&quot;

(lisper p1)
;; =&gt; nil
;;    ^^ initform (slot unbound by default)

(setf (lisper p1) t)


(defclass child (person)
  ())

(defclass child (person)
  ((can-walk-p
     :accessor can-walk-p
     :initform t)))
;; #&lt;STANDARD-CLASS CHILD&gt;

(can-walk-p (make-instance 'child))
;; T
</code></pre>

<h2 id="defining-classes-defclass">Defining classes (defclass)</h2>

<p>The macro used for defining new data types in CLOS is <code>defclass</code>.</p>

<p>We used it like this:</p>

<pre><code class="language-lisp">(defclass person ()
  ((name
    :initarg :name
    :accessor name)
   (lisper
    :initform nil
    :accessor lisper)))
</code></pre>

<p>This gives us a CLOS type (or class) called <code>person</code> and two slots,
named <code>name</code> and <code>lisper</code>.</p>

<pre><code class="language-lisp">(class-of p1)
#&lt;STANDARD-CLASS PERSON&gt;

(type-of p1)
PERSON
</code></pre>

<p>The general form of <code>defclass</code> is:</p>

<pre><code>(defclass &lt;class-name&gt; (list of super classes)
  ((slot-1
     :slot-option slot-argument)
   (slot-2, etc))
  (:optional-class-option
   :another-optional-class-option))
</code></pre>

<p>So, our <code>person</code> class doesn&rsquo;t explicitely inherit from another class
(it gets the empty parentheses <code>()</code>). However it still inherits by default from
the class <code>t</code> and from <code>standard-object</code>. See below under
&ldquo;inheritance&rdquo;.</p>

<p>We could write a minimal class definition without slots options like this:</p>

<pre><code class="language-lisp">(defclass point ()
  (x y z))
</code></pre>

<p>or even without slots specificiers: <code>(defclass point () ())</code>.</p>

<h2 id="creating-objects-make-instance">Creating objects (make-instance)</h2>

<p>We create instances of a class with <code>make-instance</code>:</p>

<pre><code class="language-lisp">(defvar p1 (make-instance 'person :name &quot;me&quot; ))
</code></pre>

<p>It is generally good practice to define a constructor:</p>

<pre><code class="language-lisp">(defun make-person (name &amp;key lisper)
  (make-instance 'person :name name :lisper lisper))
</code></pre>

<p>This has the direct advantage that you can control the required
arguments. You should now export the constructor from your package and
not the class itself.</p>

<h2 id="slots">Slots</h2>

<h3 id="a-function-that-always-works-slot-value">A function that always works (slot-value)</h3>

<p>The function to access any slot anytime is <code>(slot-value &lt;object&gt; &lt;slot-name&gt;)</code>.</p>

<p>Given our <code>point</code> class above, which didn&rsquo;t define any slot accessors:</p>

<pre><code class="language-lisp">(defvar pt (make-instance 'point))

(inspect pt)
The object is a STANDARD-OBJECT of type POINT.
0. X: &quot;unbound&quot;
1. Y: &quot;unbound&quot;
2. Z: &quot;unbound&quot;
</code></pre>

<p>We got an object of type <code>POINT</code>, but <strong>slots are unbound by
default</strong>: trying to access them will raise an <code>UNBOUND-SLOT</code>
condition:</p>

<pre><code class="language-lisp">(slot-value pt 'x) ;; =&gt; condition: the slot is unbound
</code></pre>

<p><code>slot-value</code> is <code>setf</code>-able:</p>

<pre><code class="language-lisp">(setf (slot-value pt 'x) 1)
(slot-value pt 'x) ;; =&gt; 1
</code></pre>

<h3 id="initial-and-default-values-initarg-initform">Initial and default values (initarg, initform)</h3>

<ul>
<li><code>:initarg :foo</code> is the keyword we can pass to <code>make-instance</code> to
give a value to this slot:</li>
</ul>

<pre><code class="language-lisp">(make-instance 'person :name &quot;me&quot;)
</code></pre>

<p>(again: slots are unbound by default)</p>

<ul>
<li><code>:initform &lt;val&gt;</code> is the <em>default value</em> in case we didn&rsquo;t specify
an initarg.  This form is evaluated each time it&rsquo;s needed, in the
lexical environment of the <code>defclass</code>.</li>
</ul>

<p>Sometimes we see the following trick to clearly require a slot:</p>

<pre><code class="language-lisp">(defclass foo ()
    ((a
      :initarg :a
      :initform (error &quot;you didn't supply an initial value for slot a&quot;))))
;; #&lt;STANDARD-CLASS FOO&gt;

(make-instance 'foo) ;; =&gt; enters the debugger.
</code></pre>

<h3 id="getters-and-setters-accessor-reader-writer">Getters and setters (accessor, reader, writer)</h3>

<ul>
<li><code>:accessor foo</code>: an accessor is both a <strong>getter</strong> and a
<strong>setter</strong>. Its argument is a name that will become a <strong>generic
function</strong>.</li>
</ul>

<pre><code class="language-lisp">(name p1) ;; =&gt; &quot;me&quot;

(type-of #'name)
STANDARD-GENERIC-FUNCTION
</code></pre>

<ul>
<li><code>:reader</code> and <code>:writer</code> do what you expect. Only the <code>:writer</code> is <code>setf</code>-able.</li>
</ul>

<p>If you don&rsquo;t specify any of these, you can still use <code>slot-value</code>.</p>

<p>You can give a slot more than one <code>:accessor</code>, <code>:reader</code> or <code>:initarg</code>.</p>

<p>We introduce two macros to make the access to slots shorter in some situations:</p>

<p>1- <code>with-slots</code> allows to abbreviate several calls to slot-value. The
first argument is a list of slot names. The second argument evaluates
to a CLOS instance. This is followed by optional declarations and an
implicit <code>progn</code>. Lexically during the evaluation of the body, an
access to any of these names as a variable is equivalent to accessing
the corresponding slot of the instance with <code>slot-value</code>.</p>

<pre><code class="language-lisp">(with-slots (name lisper)
    c1
  (format t &quot;got ~a, ~a~&amp;&quot; name lisper))
</code></pre>

<p>or</p>

<pre><code class="language-lisp">(with-slots ((n name)
             (l lisper))
    c1
  (format t &quot;got ~a, ~a~&amp;&quot; n l))
</code></pre>

<p>2- <code>with-accessors</code> is equivalent, but instead of a list of slots it
takes a list of accessor functions. Any reference to the variable
inside the macro is equivalent to a call to the accessor function.</p>

<pre><code class="language-lisp">(with-accessors ((name        name)
                  ^^variable  ^^accessor
                 (lisper lisper))
            p1
          (format t &quot;name: ~a, lisper: ~a&quot; name lisper))
</code></pre>

<h3 id="class-vs-instance-slots">Class VS instance slots</h3>

<p><code>:allocation</code> specifies whether this slot is <em>local</em> or <em>shared</em>.</p>

<ul>
<li><p>a slot is <em>local</em> by default, that means it can be different for each instance of the class. In that case <code>:allocation</code> equals <code>:instance</code>.</p></li>

<li><p>a <em>shared</em> slot will always be equal for all instances of the
class. We set it with <code>:allocation :class</code>.</p></li>
</ul>

<p>In the following example, note how changing the value of the class
slot <code>species</code> of <code>p2</code> affects all instances of the
class (whether or not those instances exist yet).</p>

<pre><code class="language-lisp">(defclass person ()
  ((name :initarg :name :accessor name)
   (species
      :initform 'homo-sapiens
      :accessor species
      :allocation :class)))

;; Note that the slot &quot;lisper&quot; was removed in existing instances.
(inspect p1)
;; The object is a STANDARD-OBJECT of type PERSON.
;; 0. NAME: &quot;me&quot;
;; 1. SPECIES: HOMO-SAPIENS
;; &gt; q

(defvar p2 (make-instance 'person))

(species p1)
(species p2)
;; HOMO-SAPIENS

(setf (species p2) 'homo-numericus)
;; HOMO-NUMERICUS

(species p1)
;; HOMO-NUMERICUS

(species (make-instance 'person))
;; HOMO-NUMERICUS

(let ((temp (make-instance 'person)))
    (setf (species temp) 'homo-lisper))
;; HOMO-LISPER
(species (make-instance 'person))
;; HOMO-LISPER
</code></pre>

<h3 id="slot-documentation">Slot documentation</h3>

<p>Each slot accepts one <code>:documentation</code> option.</p>

<h3 id="slot-type">Slot type</h3>

<p>The <code>:type</code> slot option may not do the job you expect it does. If you
are new to the CLOS, we suggest you skip this section and use your own
constructors to manually check slot types.</p>

<p>Indeed, whether slot types are being checked or not is undefined. See the <a href="http://www.lispworks.com/documentation/HyperSpec/Body/m_defcla.htm#defclass">Hyperspec</a>.</p>

<p>Few implementations will do it. Clozure CL does it, SBCL does it when
safety is high (<code>(declaim (optimize safety))</code>).</p>

<p>To do it otherwise, see <a href="https://stackoverflow.com/questions/51723992/how-to-force-slots-type-to-be-checked-during-make-instance">this Stack-Overflow answer</a>, and see also <a href="https://github.com/sellout/quid-pro-quo">quid-pro-quo</a>, a contract programming library.</p>

<h2 id="find-class-class-name-class-of">find-class, class-name, class-of</h2>

<pre><code class="language-lisp">(find-class 'point)
;; #&lt;STANDARD-CLASS POINT 275B78DC&gt;

(class-name (find-class 'point))
;; POINT

(class-of my-point)
;; #&lt;STANDARD-CLASS POINT 275B78DC&gt;

(typep my-point (class-of my-point))
;; T
</code></pre>

<p>CLOS classes are also instances of a CLOS class, and we can find out
what that class is, as in the example below:</p>

<pre><code class="language-lisp">(class-of (class-of my-point))
;; #&lt;STANDARD-CLASS STANDARD-CLASS 20306534&gt;
</code></pre>

<p><u>Note</u>: this is your first introduction to the MOP. You don&rsquo;t need that to get started !</p>

<p>The object <code>my-point</code> is an instance of the class named <code>point</code>, and the
class named <code>point</code> is itself an instance of the class named
<code>standard-class</code>. We say that the class named <code>standard-class</code> is
the <em>metaclass</em> (i.e. the class of the class) of
<code>my-point</code>. We can make good uses of metaclasses, as we&rsquo;ll see later.</p>

<h2 id="subclasses-and-inheritance">Subclasses and inheritance</h2>

<p>As illustrated above, <code>child</code> is a subclass of <code>person</code>.</p>

<p>All objects inherit from the class <code>standard-object</code> and <code>t</code>.</p>

<p>Every child instance is also an instance of <code>person</code>.</p>

<pre><code class="language-lisp">(type-of c1)
;; CHILD

(subtypep (type-of c1) 'person)
;; T

(ql:quickload &quot;closer-mop&quot;)
;; ...

(closer-mop:subclassp (class-of c1) 'person)
;; T
</code></pre>

<p>The <a href="https://github.com/pcostanza/closer-mop">closer-mop</a> library is <em>the</em>
portable way to do CLOS/MOP operations.</p>

<p>A subclass inherits all of its parents slots, and it can override any
of their slot options. Common Lisp makes this process dynamic, great
for REPL session, and we can even control parts of it (like, do
something when a given slot is removed/updated/added, etc).</p>

<p>The <strong>class precedence list</strong> of a <code>child</code> is thus:</p>

<pre><code>child &lt;- person &lt;-- standard-object &lt;- t
</code></pre>

<p>Which we can get with:</p>

<pre><code class="language-lisp">(closer-mop:class-precedence-list (class-of c1))
;; (#&lt;standard-class child&gt;
;;  #&lt;standard-class person&gt;
;;  #&lt;standard-class standard-object&gt;
;;  #&lt;sb-pcl::slot-class sb-pcl::slot-object&gt;
;;  #&lt;sb-pcl:system-class t&gt;)
</code></pre>

<p>However, the <strong>direct superclass</strong> of a <code>child</code> is only:</p>

<pre><code class="language-lisp">(closer-mop:class-direct-superclasses (class-of c1))
;; (#&lt;standard-class person&gt;)
</code></pre>

<p>We can further inspect our classes with
<code>class-direct-[subclasses, slots, default-initargs]</code> and many more functions.</p>

<p>How slots are combined follows some rules:</p>

<ul>
<li><p><code>:accessor</code> and <code>:reader</code> are combined by the <strong>union</strong> of accessors
and readers from all the inherited slots.</p></li>

<li><p><code>:initarg</code>: the <strong>union</strong> of initialization arguments from all the
inherited slots.</p></li>

<li><p><code>:initform</code>: we get <strong>the most specific</strong> default initial value
form, i.e. the first <code>:initform</code> for that slot in the precedence
list.</p></li>

<li><p><code>:allocation</code> is not inherited. It is controlled solely by the class
being defined and defaults to <code>:instance</code>.</p></li>
</ul>

<p>Last but not least, be warned that inheritance is fairly easy to
misuse, and multiple inheritance is multiply so, so please take a
little care. Ask yourself whether <code>foo</code> really wants to inherit from
<code>bar</code>, or whether instances of <code>foo</code> want a slot containing a <code>bar</code>. A
good general guide is that if <code>foo</code> and <code>bar</code> are &ldquo;same sort of thing&rdquo;
then it&rsquo;s correct to mix them together by inheritance, but if they&rsquo;re
really separate concepts then you should use slots to keep them apart.</p>

<h2 id="multiple-inheritance">Multiple inheritance</h2>

<p>CLOS supports multiple inheritance.</p>

<pre><code class="language-lisp">(defun baby (child person)
  ())
</code></pre>

<p>The first class on the list of parent classes is the most specific
one, <code>child</code>&rsquo;s slots will take precedence over the <code>person</code>&rsquo;s</p>

<p>TODO (but
remember how slots are merged).</p>

<h2 id="redefining-and-changing-a-class">Redefining and changing a class</h2>

<p>This section briefly covers two topics:</p>

<ul>
<li>redefinition of an existing class, which you might already have done
by following our code snippets, and what we do naturally during
development, and</li>
<li>changing an instance of one class into an instance of another,
a powerful feature of CLOS that you&rsquo;ll probably won&rsquo;t use very often.</li>
</ul>

<p>We&rsquo;ll gloss over the details. Suffice it to say that everything&rsquo;s
configurable by implementing methods exposed by the MOP.</p>

<p>To redefine a class, simply evaluate a new <code>defclass</code> form. This then
takes the place of the old definition, the existing class object is
updated, and <strong>all instances of the class</strong> (and, recursively, its
subclasses) <strong>are lazily updated to reflect the new definition</strong>. You don&rsquo;t
have to recompile anything other than the new <code>defclass</code>, nor to
invalidate any of your objects. Think about it for a second: this is awesome !</p>

<p>For example, with our <code>person</code> class:</p>

<pre><code class="language-lisp">(defclass person ()
  ((name
    :initarg :name
    :accessor name)
   (lisper
    :initform nil
    :accessor lisper)))

(setf p1 (make-instance 'person :name &quot;me&quot; ))
</code></pre>

<p>Changing, adding, removing slots,&hellip;</p>

<pre><code class="language-lisp">(lisper p1)
;; NIL

(defclass person ()
  ((name
    :initarg :name
    :accessor name)
   (lisper
    :initform t        ;; &lt;-- from nil to t
    :accessor lisper)))

(lisper p1)
;; NIL (of course!)

(lisper (make-instance 'person :name &quot;You&quot;))
;; T

(defclass person ()
  ((name
    :initarg :name
    :accessor name)
   (lisper
    :initform nil
    :accessor lisper)
   (age
    :initarg :arg
    :initform 18
    :accessor age)))

(age p1)
;; =&gt; slot unbound error. This is different from &quot;slot missing&quot;:

(slot-value p1 'bwarf)
;; =&gt; &quot;the slot bwarf is missing from the object #&lt;person…&gt;&quot;

(setf (age p1) 30)
(age p1) ;; =&gt; 30

(defclass person ()
  ((name
    :initarg :name
    :accessor name)))

(slot-value p1 'lisper) ;; =&gt; slot lisper is missing.
(lisper p1) ;; =&gt; there is no applicable method for the generic function lisper when called with arguments #(lisper).
</code></pre>

<p>To change the class of an instance, use <code>change-class</code>:</p>

<pre><code class="language-lisp">(change-class p1 'child)
;; we can also set slots of the new class:
(change-class p1 'child :can-walk-p nil)

(class-of p1)
;; #&lt;STANDARD-CLASS CHILD&gt;

(can-walk-p p1)
;; T
</code></pre>

<p>In the above example, I became a <code>child</code>, and I inherited the <code>can-walk-p</code> slot, which is true by default.</p>

<h2 id="pretty-printing">Pretty printing</h2>

<p>Everytime we printed an object so far we got an output like</p>

<pre><code>#&lt;PERSON {1006234593}&gt;
</code></pre>

<p>which doesn&rsquo;t say much.</p>

<p>What if we want to show more information ? Something like</p>

<pre><code>#&lt;PERSON me lisper: t&gt;
</code></pre>

<p>Pretty printing is done by specializing the generic <code>print-object</code> method for this class:</p>

<pre><code class="language-lisp">(defmethod print-object ((obj person) stream)
      (print-unreadable-object (obj stream :type t)
        (with-accessors ((name name)
                         (lisper lisper))
            obj
          (format stream &quot;~a, lisper: ~a&quot; name lisper))))
</code></pre>

<p>It gives:</p>

<pre><code class="language-lisp">p1
;; #&lt;PERSON me, lisper: T&gt;
</code></pre>

<p><code>print-unreadable-object</code> prints the <code>#&lt;...&gt;</code>, that says to the reader
that this object can not be read back in. Its <code>:type t</code> argument asks
to print the object-type prefix, that is, <code>PERSON</code>. Without it, we get
<code>#&lt;me, lisper: T&gt;</code>.</p>

<p>We used the <code>with-accessors</code> macro, but of course for simple cases this is enough:</p>

<pre><code class="language-lisp">(defmethod print-object ((obj person) stream)
  (print-unreadable-object (obj stream :type t)
    (format stream &quot;~a, lisper: ~a&quot; (name obj) (lisper obj))))
</code></pre>

<p>Caution: trying to access a slot that is not bound by default will
lead to an error. Use <code>slot-boundp</code>.</p>

<p>For reference, the following reproduces the default behaviour:</p>

<pre><code class="language-lisp">(defmethod print-object ((obj person) stream)
  (print-unreadable-object (obj stream :type t :identity t)))
</code></pre>

<p>Here, <code>:identity</code> to <code>t</code> prints the <code>{1006234593}</code> address.</p>

<h2 id="classes-of-traditional-lisp-types">Classes of traditional lisp types</h2>

<p>Where we approach that we don&rsquo;t need CLOS objects to use CLOS.</p>

<p>Generously, the functions introduced in the last section also work on
lisp objects which are <u>not</u> CLOS instances:</p>

<pre><code class="language-lisp">(find-class 'symbol)
;; #&lt;BUILT-IN-CLASS SYMBOL&gt;
(class-name *)
;; SYMBOL
(eq ** (class-of 'symbol))
;; T
(class-of ***)
;; #&lt;STANDARD-CLASS BUILT-IN-CLASS&gt;
</code></pre>

<p>We see here that symbols are instances of the system class
<code>symbol</code>. This is one of 75 cases in which the language requires a
class to exist with the same name as the corresponding lisp
type. Many of these cases are concerned with CLOS itself (for
example, the correspondence between the type <code>standard-class</code> and
the CLOS class of that name) or with the condition system (which
might or might not be built using CLOS classes in any given
implementation). However, 33 correspondences remain relating to
&ldquo;traditional&rdquo; lisp types:</p>

<p>|<code>array</code>|<code>hash-table</code>|<code>readtable</code>|
|<code>bit-vector</code>|<code>integer</code>|<code>real</code>|
|<code>broadcast-stream</code>|<code>list</code>|<code>sequence</code>|
|<code>character</code>|<code>logical-pathname</code>|<code>stream</code>|
|<code>complex</code>|<code>null</code>|<code>string</code>|
|<code>concatenated-stream</code>|<code>number</code>|<code>string-stream</code>|
|<code>cons</code>|<code>package</code>|<code>symbol</code>|
|<code>echo-stream</code>|<code>pathname</code>|<code>synonym-stream</code>|
|<code>file-stream</code>|<code>random-state</code>|<code>t</code>|
|<code>float</code>|<code>ratio</code>|<code>two-way-stream</code>|
|<code>function</code>|<code>rational</code>|<code>vector</code>|</p>

<p>Note that not all &ldquo;traditional&rdquo; lisp types are included in this
list. (Consider: <code>atom</code>, <code>fixnum</code>, <code>short-float</code>, and any type not
denoted by a symbol.)</p>

<p>The presence of <code>t</code> is interesting. Just as every lisp
object is of type <code>t</code>, every lisp object is also a member
of the class named <code>t</code>. This is a simple example of
membership of more then one class at a time, and it brings into
question the issue of <em>inheritance</em>, which we will consider
in some detail later.</p>

<pre><code class="language-lisp">(find-class t)
;; #&lt;BUILT-IN-CLASS T 20305AEC&gt;
</code></pre>

<p>In addition to classes corresponding to lisp types, there is also a
    CLOS class for every structure type you define:</p>

<pre><code class="language-lisp">(defstruct foo)
FOO

(class-of (make-foo))
;; #&lt;STRUCTURE-CLASS FOO 21DE8714&gt;
</code></pre>

<p>The metaclass of a <code>structure-object</code> is the class
    <code>structure-class</code>. It is implementation-dependent whether
    the metaclass of a &ldquo;traditional&rdquo; lisp object is
    <code>standard-class</code>, <code>structure-class</code>, or
    <code>built-in-class</code>. Restrictions:</p>

<p>|<code>built-in-class</code>| May not use <code>make-instance</code>, may not use <code>slot-value</code>, may not use <code>defclass</code> to modify, may not create subclasses.|
|<code>structure-class</code>| May not use <code>make-instance</code>, might work with <code>slot-value</code> (implementation-dependent). Use <code>defstruct</code> to subclass application structure types. Consequences of modifying an existing <code>structure-class</code> are undefined: full recompilation may be necessary.|
|<code>standard-class</code>|None of these restrictions.|</p>

<h2 id="introspection">Introspection</h2>

<p>we already saw some introspection functions.</p>

<p>Your best option is to discover the
<a href="https://github.com/pcostanza/closer-mop">closer-mop</a> libray and to
keep the <a href="https://clos-mop.hexstreamsoft.com/">CLOS &amp; MOP specifications</a> at
hand.</p>

<p>More functions:</p>

<pre><code>closer-mop:class-default-initargs
closer-mop:class-direct-default-initargs
closer-mop:class-direct-slots
closer-mop:class-direct-subclasses
closer-mop:class-direct-superclasses
closer-mop:class-precedence-list
closer-mop:class-slots
closer-mop:classp
closer-mop:extract-lambda-list
closer-mop:extract-specializer-names
closer-mop:generic-function-argument-precedence-order
closer-mop:generic-function-declarations
closer-mop:generic-function-lambda-list
closer-mop:generic-function-method-class
closer-mop:generic-function-method-combination
closer-mop:generic-function-methods
closer-mop:generic-function-name
closer-mop:method-combination
closer-mop:method-function
closer-mop:method-generic-function
closer-mop:method-lambda-list
closer-mop:method-specializers
closer-mop:slot-definition
closer-mop:slot-definition-allocation
closer-mop:slot-definition-initargs
closer-mop:slot-definition-initform
closer-mop:slot-definition-initfunction
closer-mop:slot-definition-location
closer-mop:slot-definition-name
closer-mop:slot-definition-readers
closer-mop:slot-definition-type
closer-mop:slot-definition-writers
closer-mop:specializer-direct-generic-functions
closer-mop:specializer-direct-methods
closer-mop:standard-accessor-method
</code></pre>

<h2 id="see-also">See also</h2>

<h3 id="defclass-std-write-shorter-classes">defclass/std: write shorter classes</h3>

<p>The library <a href="https://github.com/EuAndreh/defclass-std">defclass/std</a>
provides a macro to write shorter <code>defclass</code> forms.</p>

<p>By default, it adds an accessor, an initarg and an initform to <code>nil</code> to your slots definition:</p>

<p>This:</p>

<pre><code class="language-lisp">(defclass/std example ()
  ((slot1 slot2 slot3)))
</code></pre>

<p>expands to:</p>

<pre><code class="language-lisp">(defclass example ()
  ((slot1
    :accessor slot1
    :initarg :slot1
    :initform nil)
   (slot2
     :accessor slot2
     :initarg :slot2
     :initform nil)
   (slot3
     :accessor slot3
     :initarg :slot3
     :initform nil)))
</code></pre>

<p>It does much more and it is very flexible, however it is seldom used
by the Common Lisp community: use at your own risks©.</p>

<h1 id="methods">Methods</h1>

<h2 id="diving-in-1">Diving in</h2>

<p>Recalling our <code>person</code> and <code>child</code> classes from the beginning:</p>

<pre><code class="language-lisp">(defclass person ()
  ((name
    :initarg :name
    :accessor name)))
;; =&gt; #&lt;STANDARD-CLASS PERSON&gt;

(defclass child (person)
  ())
;; #&lt;STANDARD-CLASS CHILD&gt;

(setf p1 (make-instance 'person :name &quot;me&quot;))
(setf c1 (make-instance 'child :name &quot;Alice&quot;))
</code></pre>

<p>Below we create methods, we specialize them, we use method combination
(before, after, around), and qualifiers.</p>

<pre><code class="language-lisp">(defmethod greet (obj)
  (format t &quot;Are you a person ? You are a ~a.~&amp;&quot; (type-of obj)))
;; style-warning: Implicitly creating new generic function common-lisp-user::greet.
;; #&lt;STANDARD-METHOD GREET (t) {1008EE4603}&gt;

(greet :anything)
;; Are you a person ? You are a KEYWORD.
;; NIL
(greet p1)
;; Are you a person ? You are a PERSON.

(defgeneric greet (obj)
  (:documentation &quot;say hello&quot;))
;; STYLE-WARNING: redefining COMMON-LISP-USER::GREET in DEFGENERIC
;; #&lt;STANDARD-GENERIC-FUNCTION GREET (2)&gt;

(defmethod greet ((obj person))
  (format t &quot;Hello ~a !~&amp;&quot; (name obj)))
;; #&lt;STANDARD-METHOD GREET (PERSON) {1007C26743}&gt;

(greet p1) ;; =&gt; &quot;Hello me !&quot;
(greet c1) ;; =&gt; &quot;Hello Alice !&quot;

(defmethod greet ((obj child))
  (format t &quot;ur so cute~&amp;&quot;))
;; #&lt;STANDARD-METHOD GREET (CHILD) {1008F3C1C3}&gt;

(greet p1) ;; =&gt; &quot;Hello me !&quot;
(greet c1) ;; =&gt; &quot;ur so cute&quot;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Method combination: before, after, around.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defmethod greet :before ((obj person))
  (format t &quot;-- before person~&amp;&quot;))
#&lt;STANDARD-METHOD GREET :BEFORE (PERSON) {100C94A013}&gt;

(greet p1)
;; -- before person
;; Hello me

(defmethod greet :before ((obj child))
  (format t &quot;-- before child~&amp;&quot;))
;; #&lt;STANDARD-METHOD GREET :BEFORE (CHILD) {100AD32A43}&gt;
(greet c1)
;; -- before child
;; -- before person
;; ur so cute

(defmethod greet :after ((obj person))
  (format t &quot;-- after person~&amp;&quot;))
;; #&lt;STANDARD-METHOD GREET :AFTER (PERSON) {100CA2E1A3}&gt;
(greet p1)
;; -- before person
;; Hello me
;; -- after person

(defmethod greet :after ((obj child))
  (format t &quot;-- after child~&amp;&quot;))
;; #&lt;STANDARD-METHOD GREET :AFTER (CHILD) {10075B71F3}&gt;
(greet c1)
;; -- before child
;; -- before person
;; ur so cute
;; -- after person
;; -- after child

(defmethod greet :around ((obj child))
  (format t &quot;Hello my dear~&amp;&quot;))
;; #&lt;STANDARD-METHOD GREET :AROUND (CHILD) {10076658E3}&gt;
(greet c1) ;; Hello my dear


;; call-next-method

(defmethod greet :around ((obj child))
  (format t &quot;Hello my dear~&amp;&quot;)
  (when (next-method-p)
    (call-next-method)))
;; #&lt;standard-method greet :around (child) {100AF76863}&gt;

(greet c1)
;; Hello my dear
;; -- before child
;; -- before person
;; ur so cute
;; -- after person
;; -- after child

;;;;;;;;;;;;;;;;;
;; Adding in &amp;key
;;;;;;;;;;;;;;;;;

;; In order to add &quot;&amp;key&quot; to our generic method, we need to remove its definition first.
(fmakunbound 'greet)  ;; with Slime: C-c C-u (slime-undefine-function)
(defmethod greet ((obj person) &amp;key talkative)
  (format t &quot;Hello ~a~&amp;&quot; (name obj))
  (when talkative
    (format t &quot;blah&quot;)))

(defgeneric greet (obj &amp;key &amp;allow-other-keys)
  (:documentation &quot;say hi&quot;))

(defmethod greet (obj &amp;key &amp;allow-other-keys)
  (format t &quot;Are you a person ? You are a ~a.~&amp;&quot; (type-of obj)))

(defmethod greet ((obj person) &amp;key talkative &amp;allow-other-keys)
  (format t &quot;Hello ~a !~&amp;&quot; (name obj))
  (when talkative
    (format t &quot;blah&quot;)))

(greet p1 :talkative t) ;; ok
(greet p1 :foo t) ;; still ok


;;;;;;;;;;;;;;;;;;;;;;;

(defgeneric greet (obj)
  (:documentation &quot;say hello&quot;)
  (:method (obj)
    (format t &quot;Are you a person ? You are a ~a~&amp;.&quot; (type-of obj)))
  (:method ((obj person))
    (format t &quot;Hello ~a !~&amp;&quot; (name obj)))
  (:method ((obj child))
    (format t &quot;ur so cute~&amp;&quot;)))

;;;;;;;;;;;;;;;;
;;; Specializers
;;;;;;;;;;;;;;;;

(defgeneric feed (obj meal-type)
  (:method (obj meal-type)
    (declare (ignorable meal-type))
    (format t &quot;eating~&amp;&quot;)))

(defmethod feed (obj (meal-type (eql :dessert)))
    (declare (ignorable meal-type))
    (format t &quot;mmh, dessert !~&amp;&quot;))

(feed c1 :dessert)
;; mmh, dessert !

(defmethod feed ((obj child) (meal-type (eql :soup)))
    (declare (ignorable meal-type))
    (format t &quot;bwark~&amp;&quot;))

(feed p1 :soup)
;; eating
(feed c1 :soup)
;; bwark
</code></pre>

<h2 id="generic-functions-defgeneric-defmethod">Generic functions (defgeneric, defmethod)</h2>

<p>A <code>generic function</code> is a lisp function which is associated
with a set of methods and dispatches them when it&rsquo;s invoked. All
the methods with the same function name belong to the same generic
function.</p>

<p>The <code>defmethod</code> form is similar to a <code>defun</code>. It associates a body of
code with a function name, but that body may only be executed if the
types of the arguments match the pattern declared by the lambda list.</p>

<p>They can have optional, keyword and <code>&amp;rest</code> arguments.</p>

<p>The <code>defgeneric</code> form defines the generic function. If we write a
<code>defmethod</code> without a corresponding <code>defgeneric</code>, a generic function
is automatically created (see examples).</p>

<p>It is generally a good idea to write the <code>defgeneric</code>s. We can add a
default implementation and even some documentation.</p>

<pre><code class="language-lisp">(defgeneric greet (obj)
  (:documentation &quot;says hi&quot;)
  (:method (obj)
    (format t &quot;Hi&quot;)))
</code></pre>

<p>The required parameters in the method&rsquo;s lambda list may take one of
the following three forms:</p>

<p>1- a simple variable:</p>

<pre><code class="language-lisp">(defmethod greet (foo)
  ...)
</code></pre>

<p>This method can take any argument, it is always applicable.</p>

<p>The variable <code>foo</code> is bound to the corresponding argument value, as
usual.</p>

<p>2- a variable and a <strong>specializer</strong>, as in:</p>

<pre><code class="language-lisp">(defmethod greet ((foo person))
  ...)
</code></pre>

<p>In this case, the variable <code>foo</code> is bound to the corresponding
argument only if that argument is of specializer class <code>person</code> <em>or a subclass</em>,
like <code>child</code> (indeed, a &ldquo;child&rdquo; is also a &ldquo;person&rdquo;).</p>

<p>If any argument fails to match its
specializer then the method is not <em>applicable</em> and it cannot be
executed with those arguments.We&rsquo;ll get an error message like
&ldquo;there is no applicable method for the generic function xxx when
called with arguments yyy&rdquo;.</p>

<p><strong>Only required parameters can be specialized</strong>. We can&rsquo;t specialize on optional <code>&amp;key</code> arguments.</p>

<p>3- a variable and an <strong>eql specializer</strong></p>

<pre><code class="language-lisp">(defmethod feed ((obj child) (meal-type (eql :soup)))
    (declare (ignorable meal-type))
    (format t &quot;bwark~&amp;&quot;))

(feed c1 :soup)
;; &quot;bwark&quot;
</code></pre>

<p>In place of a simple symbol (<code>:soup</code>), the eql specializer can be any
lisp form. It is evaluated at the same time of the defmethod.</p>

<p>You can define any number of methods with the same function name but
with different specializers, as long as the form of the lambda list is
<em>congruent</em> with the shape of the generic function. The system chooses
the most <em>specific</em> applicable method and executes its body. The most
specific method is the one whose specializers are nearest to the head
of the <code>class-precedence-list</code> of the argument (classes on the left of
the lambda list are more specific). A method with specializers is more
specific to one without any.</p>

<p><strong>Notes:</strong></p>

<ul>
<li><p>It is an error to define a method with the same function name as
an ordinary function. If you really want to do that, use the
shadowing mechanism.</p></li>

<li><p>To add or remove <code>keys</code> or <code>rest</code> arguments to an existing generic
method&rsquo;s lambda list, you will need to delete its declaration with
<code>fmakunbound</code> (or <code>C-c C-u</code> (slime-undefine-function) with the
cursor on the function in Slime) and start again. Otherwise,
you&rsquo;ll see:</p></li>
</ul>

<pre><code>attempt to add the method
  #&lt;STANDARD-METHOD NIL (#&lt;STANDARD-CLASS CHILD&gt;) {1009504233}&gt;
to the generic function
  #&lt;STANDARD-GENERIC-FUNCTION GREET (2)&gt;;
but the method and generic function differ in whether they accept
&amp;REST or &amp;KEY arguments.
</code></pre>

<ul>
<li><p>Methods can be redefined (exactly as for ordinary functions).</p></li>

<li><p>The order in which methods are defined is irrelevant, although
any classes on which they specialize must already exist.</p></li>

<li><p>An unspecialized argument is more or less equivalent to being
specialized on the class <code>t</code>. The only difference is that
all specialized arguments are implicitly taken to be &ldquo;referred to&rdquo; (in
the sense of <code>declare ignore</code>.)</p></li>

<li><p>Each <code>defmethod</code> form generates (and returns) a CLOS
instance, of class <code>standard-method</code>.</p></li>

<li><p>An <code>eql</code> specializer won&rsquo;t work as is with strings. Indeed, strings
need <code>equal</code> or <code>equalp</code> to be compared. But, we can assign our string
to a variable and use the variable both in the <code>eql</code> specializer and
for the function call.</p></li>

<li><p>All the methods with the same function name belong to the same generic function.</p></li>

<li><p>All slot accessors and readers defined by <code>defclass</code> are methods. They can override or be overridden by other methods on the same generic function.</p></li>
</ul>

<p>See more about <a href="http://www.lispworks.com/documentation/lw70/CLHS/Body/m_defmet.htm">defmethod on the CLHS</a>.</p>

<h2 id="multimethods">Multimethods</h2>

<p>Multimethods explicitly specialize more than one of the generic
function&rsquo;s required parameters.</p>

<p>They don&rsquo;t belong to a particular class. Meaning, we don&rsquo;t have to
decide on the class that would be best to host this method, as we might
have to in other languages.</p>

<pre><code class="language-lisp">(defgeneric hug (a b)
   (:documentation &quot;Hug between two persons.&quot;))
;; #&lt;STANDARD-GENERIC-FUNCTION HUG (0)&gt;

(defmethod hug ((a person) (b person))
  :person-person-hug)

(defmethod hug ((a person) (b child))
  :person-child-hug)
</code></pre>

<p>Read more on <a href="http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html#multimethods">Practical Common Lisp</a>.</p>

<h2 id="controlling-setters-setf-ing-methods">Controlling setters (setf-ing methods)</h2>

<p>In Lisp, we can define <code>setf</code> counterparts of functions or methods. We
might want this to have more control on how to update an object.</p>

<pre><code class="language-lisp">(defmethod (setf name) (new-val (obj person))
  (if (equalp new-val &quot;james bond&quot;)
    (format t &quot;Dude that's not possible.~&amp;&quot;)
    (setf (slot-value obj 'name) new-val)))

(setf (name p1) &quot;james bond&quot;) ;; -&gt; no rename
</code></pre>

<p>If you know Python, this behaviour is provided by the <code>@property</code> decorator.</p>

<h2 id="dispatch-mechanism-and-next-methods">Dispatch mechanism and next methods</h2>

<p>When a generic function is invoked, the application cannot directly invoke a method. The dispatch mechanism proceeds as follows:</p>

<ol>
<li>compute the list of applicable methods</li>
<li>if no method is applicable then signal an error</li>
<li>sort the applicable methods in order of specificity</li>
<li>invoke the most specific method.</li>
</ol>

<p>Our <code>greet</code> generic function has three applicable methods:</p>

<pre><code class="language-lisp">(closer-mop:generic-function-methods #'greet)
(#&lt;STANDARD-METHOD GREET (CHILD) {10098406A3}&gt;
 #&lt;STANDARD-METHOD GREET (PERSON) {1009008EC3}&gt;
 #&lt;STANDARD-METHOD GREET (T) {1008E6EBB3}&gt;)
</code></pre>

<p>During the execution of a method, the remaining applicable methods
are still accessible, via the <em>local function</em>
<code>call-next-method</code>. This function has lexical scope within
the body of a method but indefinite extent. It invokes the next most
specific method, and returns whatever value that method returned. It
can be called with either:</p>

<ul>
<li><p>no arguments, in which case the <em>next method</em> will
receive exactly the same arguments as this method did, or</p></li>

<li><p>explicit arguments, in which case it is required that the
sorted set of methods applicable to the new arguments must be the same
as that computed when the generic function was first called.</p></li>
</ul>

<p>For example:</p>

<pre><code class="language-lisp">(defmethod greet ((obj child))
  (format t &quot;ur so cute~&amp;&quot;)
  (when (next-method-p)
    (call-next-method)))
;; STYLE-WARNING: REDEFINING GREET (#&lt;STANDARD-CLASS CHILD&gt;) in DEFMETHOD
;; #&lt;STANDARD-METHOD GREET (child) {1003D3DB43}&gt;

(greet c1)
;; ur so cute
;; Hello Alice !
</code></pre>

<p>Calling <code>call-next-method</code> when there is no next method
signals an error. You can find out whether a next method exists by
calling the local function <code>next-method-p</code> (which also has
has lexical scope and indefinite extent).</p>

<p>Note finally that the body of every method establishes a block with the same name as the method’s generic function. If you <code>return-from</code> that name you are exiting the current method, not the call to the enclosing generic function.</p>

<h2 id="method-qualifiers-before-after-around">Method qualifiers (before, after, around)</h2>

<p>In our &ldquo;Diving in&rdquo; examples, we saw some use of the <code>:before</code>, <code>:after</code> and <code>:around</code> <em>qualifiers</em>:</p>

<ul>
<li><code>(defmethod foo :before (obj) (...))</code></li>
<li><code>(defmethod foo :after (obj) (...))</code></li>
<li><code>(defmethod foo :around (obj) (...))</code></li>
</ul>

<p>By default, in the <em>standard method combination</em> framework provided by
CLOS, we can only use one of those three qualifiers, and the flow of control is as follows:</p>

<ul>
<li>a <strong>before-method</strong> is called, well, before the applicable primary
method. If they are many before-methods, <strong>all</strong> are called. The
most specific before-method is called first (child before person).</li>
<li>the most specific applicable <strong>primary method</strong> (a method without
qualifiers) is called (only one).</li>
<li>all applicable <strong>after-methods</strong> are called. The most specific one is
called <em>last</em> (after-method of person, then after-method of child).</li>
</ul>

<p><strong>The generic function returns the value of the primary method</strong>. Any
values of the before or after methods are ignored. They are used for
their side effects.</p>

<p>And then we have <strong>around-methods</strong>. They are wrappers around the core
mechanism we just described. They can be useful to catch return values
or to set up an environment around the primary method (set up a catch,
a lock, timing an execution,…).</p>

<p>If the dispatch mechanism finds an around-method, it calls it and
returns its result. If the around-method has a <code>call-next-method</code>, it
calls the next most applicable around-method. It is only when we reach
the primary method that we start calling the before and after-methods.</p>

<p>Thus, the full dispatch mechanism for generic functions is as follows:</p>

<ol>
<li>compute the applicable methods, and partition them into
separate lists according to their qualifier;</li>
<li>if there is no applicable primary method then signal an
error;</li>
<li>sort each of the lists into order of specificity;</li>
<li>execute the most specific <code>:around</code> method and
return whatever that returns;</li>
<li>if an <code>:around</code> method invokes
<code>call-next-method</code>, execute the next most specific
<code>:around</code> method;</li>

<li><p>if there were no <code>:around</code> methods in the first
place, or if an <code>:around</code> method invokes
<code>call-next-method</code> but there are no further
<code>:around</code> methods to call, then proceed as follows:</p>

<p>a.  run all the <code>:before</code> methods, in order,
        ignoring any return values and not permitting calls to
        <code>call-next-method</code> or
        <code>next-method-p</code>;</p>

<p>b.  execute the most specific primary method and return
        whatever that returns;</p>

<p>c.  if a primary method invokes <code>call-next-method</code>,
        execute the next most specific primary method;</p>

<p>d.  if a primary method invokes <code>call-next-method</code>
        but there are no further primary methods to call then signal an
        error;</p>

<p>e.  after the primary method(s) have completed, run all the
        <code>:after</code> methods, in <strong><u>reverse</u></strong>
        order, ignoring any return values and not permitting calls to
        <code>call-next-method</code> or
        <code>next-method-p</code>.</p></li>
</ol>

<p>Think of it as an onion, with all the <code>:around</code>
    methods in the outermost layer, <code>:before</code> and
    <code>:after</code> methods in the middle layer, and primary methods
    on the inside.</p>

<h2 id="other-method-combinations">Other method combinations</h2>

<p>The default method combination type we just saw is named <code>standard</code>,
but other method combination types are available, and no need to say
that you can define your own.</p>

<p>The built-in types are:</p>

<pre><code>progn + list nconc and max or append min
</code></pre>

<p>You notice that these types are named after a lisp operator. Indeed,
what they do is they define a framework that combines the applicable
primary methods inside a call to the lisp operator of that name. For
example, using the <code>progn</code> combination type is equivalent to calling <strong>all</strong>
the primary methods one after the other:</p>

<pre><code class="language-lisp">(progn
  (method-1 args)
  (method-2 args)
  (method-3 args))
</code></pre>

<p>Here, unlike the standard mechanism, all the primary methods
applicable for a given object are called, the most specific
first.</p>

<p>To change the combination type, we set the <code>:method-combination</code>
option of <code>defgeneric</code> and we use it as the methods&rsquo; qualifier:</p>

<pre><code class="language-lisp">(defgeneric foo (obj)
  (:method-combination progn))

(defmethod foo progn ((obj obj))
   (...))
</code></pre>

<p>An example with <strong>progn</strong>:</p>

<pre><code class="language-lisp">(defgeneric dishes (obj)
   (:method-combination progn)
   (:method progn (obj)
     (format t &quot;- clean and dry.~&amp;&quot;))
   (:method progn ((obj person))
     (format t &quot;- bring a person's dishes~&amp;&quot;))
   (:method progn ((obj child))
     (format t &quot;- bring the baby dishes~&amp;&quot;)))
;; #&lt;STANDARD-GENERIC-FUNCTION DISHES (3)&gt;

(dishes c1)
;; - bring the baby dishes
;; - bring a person's dishes
;; - clean and dry.

(greet c1)
;; ur so cute  --&gt; only the most applicable method was called.
</code></pre>

<p>Similarly, using the <code>list</code> type is equivalent to returning the list
of the values of the methods.</p>

<pre><code class="language-lisp">(list
  (method-1 args)
  (method-2 args)
  (method-3 args))
</code></pre>

<pre><code class="language-lisp">(defgeneric tidy (obj)
  (:method-combination list)
  (:method list (obj)
    :foo)
  (:method list ((obj person))
    :books)
  (:method list ((obj child))
    :toys))
;; #&lt;STANDARD-GENERIC-FUNCTION TIDY (3)&gt;

(tidy c1)
;; (:toys :books :foo)
</code></pre>

<p><strong>Around methods</strong> are accepted:</p>

<pre><code class="language-lisp">(defmethod tidy :around (obj)
   (let ((res (call-next-method)))
     (format t &quot;I'm going to clean up ~a~&amp;&quot; res)
     (when (&gt; (length res)
              1)
       (format t &quot;that's too much !~&amp;&quot;))))

(tidy c1)
;; I'm going to clean up (toys book foo)
;; that's too much !
</code></pre>

<p>Note that these operators don&rsquo;t support <code>before</code>, <code>after</code> and <code>around</code>
methods (indeed, there is no room for them anymore). They do support
around methods, where <code>call-next-method</code> is allowed, but they don&rsquo;t
support calling <code>call-next-method</code> in the primary methods (it would
indeed be redundant since all primary methods are called, or clunky to
<em>not</em> call one).</p>

<p>CLOS allows us to define a new operator as a method combination type, be
it a lisp function, macro or special form. We&rsquo;ll let you refer to the
books if you feel the need.</p>

<h2 id="debugging-tracing-method-combination">Debugging: tracing method combination</h2>

<p>It is possible to <a href="http://www.xach.com/clhs?q=trace">trace</a> the method
combination, but this is implementation dependent.</p>

<p>In SBCL, we can use <code>(trace foo :methods t)</code>. See <a href="http://christophe.rhodes.io/notes/blog/posts/2018/sbcl_method_tracing/">this post by an SBCL core developer</a>.</p>

<p>For example, given a generic:</p>

<pre><code class="language-lisp">(defgeneric foo (x)
  (:method (x) 3))
(defmethod foo :around ((x fixnum))
  (1+ (call-next-method)))
(defmethod foo ((x integer))
  (* 2 (call-next-method)))
(defmethod foo ((x float))
  (* 3 (call-next-method)))
(defmethod foo :before ((x single-float))
  'single)
(defmethod foo :after ((x double-float))
 'double)
</code></pre>

<p>Let&rsquo;s trace it:</p>

<pre><code class="language-lisp">(trace foo :methods t)

(foo 2.0d0)
  0: (FOO 2.0d0)
    1: ((SB-PCL::COMBINED-METHOD FOO) 2.0d0)
      2: ((METHOD FOO (FLOAT)) 2.0d0)
        3: ((METHOD FOO (T)) 2.0d0)
        3: (METHOD FOO (T)) returned 3
      2: (METHOD FOO (FLOAT)) returned 9
      2: ((METHOD FOO :AFTER (DOUBLE-FLOAT)) 2.0d0)
      2: (METHOD FOO :AFTER (DOUBLE-FLOAT)) returned DOUBLE
    1: (SB-PCL::COMBINED-METHOD FOO) returned 9
  0: FOO returned 9
9
</code></pre>

<h1 id="mop">MOP</h1>

<p>We gather here some examples that make use of the framework provided
by the meta-object protocol, the configurable object system that rules
Lisp&rsquo;s object system. We touch advanced concepts so, new reader, don&rsquo;t
worry: you don&rsquo;t need to understand this section to start using the
Common Lisp Object System.</p>

<p>We won&rsquo;t explain much about the MOP here, but hopefully sufficiently
to make you see its possibilities or to help you understand how some
CL libraries are built. We invite you to read the books referenced in
the introduction.</p>

<h2 id="metaclasses">Metaclasses</h2>

<p>Metaclasses are needed to control the behaviour of other classes.</p>

<p><em>As announced, we won&rsquo;t talk much. See also Wikipedia for <a href="https://en.wikipedia.org/wiki/Metaclass">metaclasses</a> or <a href="https://en.wikipedia.org/wiki/Common_Lisp_Object_System">CLOS</a></em>.</p>

<p>The standard metaclass is <code>standard-class</code>:</p>

<pre><code class="language-lisp">(class-of p1) ;; #&lt;STANDARD-CLASS PERSON&gt;
</code></pre>

<p>But we&rsquo;ll change it to one of our own, so that we&rsquo;ll be able to
<strong>count the creation of instances</strong>. This same mechanism could be used
to auto increment the primary key of a database system (this is
how the Postmodern or Mito libraries do), to log the creation of objects,
etc.</p>

<p>Our metaclass inherits from <code>standard-class</code>:</p>

<pre><code class="language-lisp">(defclass counted-class (standard-class)
  ((counter :initform 0)))
#&lt;STANDARD-CLASS COUNTED-CLASS&gt;

(unintern 'person)
;; this is necessary to change the metaclass of person.
;; or (setf (find-class 'person) nil)
;; https://stackoverflow.com/questions/38811931/how-to-change-classs-metaclass#38812140

(defclass person ()
  ((name
    :initarg :name
    :accessor name)
  (:metaclass counted-class))) ;; &lt;- metaclass
;; #&lt;COUNTED-CLASS PERSON&gt;
;;   ^^^ not standard-class anymore.
</code></pre>

<p>The <code>:metaclass</code> class option can appear only once.</p>

<p>Actually you should have gotten a message asking to implement
<code>validate-superclass</code>. So, still with the <code>closer-mop</code> library:</p>

<pre><code class="language-lisp">(defmethod closer-mop:validate-superclass ((class counted-class)
                                           (superclass standard-class))
  t)
</code></pre>

<p>Now we can control the creation of new <code>person</code> instances:</p>

<pre><code class="language-lisp">(defmethod make-instance :after ((class counted-class) &amp;key)
  (incf (slot-value class 'counter)))
;; #&lt;STANDARD-METHOD MAKE-INSTANCE :AFTER (COUNTED-CLASS) {1007718473}&gt;
</code></pre>

<p>See that an <code>:after</code> qualifier is the safest choice, we let the
standard method run as usual and return a new instance.</p>

<p>The <code>&amp;key</code> is necessary, remember that <code>make-instance</code> is given initargs.</p>

<p>Now testing:</p>

<pre><code class="language-lisp">(defvar p3 (make-instance 'person :name &quot;adam&quot;))
#&lt;PERSON {1007A8F5B3}&gt;

(slot-value p3 'counter)
;; =&gt; error. No, our new slot isn't on the person class.
(slot-value (find-class 'person) 'counter)
;; 1

(make-instance 'person :name &quot;eve&quot;)
;; #&lt;PERSON {1007AD5773}&gt;
(slot-value (find-class 'person) 'counter)
;; 2
</code></pre>

<p>It&rsquo;s working.</p>

<h2 id="controlling-the-initialization-of-instances-initialize-instance">Controlling the initialization of instances (initialize-instance)</h2>

<p>To further customize the creation of instances by specializing
<code>initialize-instance</code>, which is called by <code>make-instance</code>, just after
it has created a new instance but didn&rsquo;t initialize it yet with the
default initargs and initforms.</p>

<p>It is recommended (Keene) to create an after method, since creating a
primary method would prevent slots&rsquo; initialization.</p>

<pre><code class="language-lisp">(defmethod initialize-instance :after ((obj person) &amp;key)
  (do something with obj))
</code></pre>

<p>Another rational. The CLOS implementation of
    <code>make-instance</code> is in two stages: allocate the new object,
    and then pass it along with all the <code>make-instance</code> keyword
    arguments, to the generic function
    <code>initialize-instance</code>. Implementors and application writers
    define <code>:after</code> methods on
    <code>initialize-instance</code>, to initialize the slots of the
    instance. The system-supplied primary method does this with regard to
    (a) <code>:initform</code> and <code>:initarg</code> values supplied
    with the class was defined and (b) the keywords passed through from
    <code>make-instance</code>. Other methods can extend this behaviour as
    they see fit. For example, they might accept an additional keyword
    which invokes a database access to fill certain slots. The lambda list
    for <code>initialize-instance</code> is:</p>

<pre><code>initialize-instance instance &amp;rest initargs &amp;key &amp;allow-other-keys
</code></pre>

<p>See more in the books !</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">September 2018 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">04 10 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together news September was a successful month. We have new project updates and results from our quarterly survey. Don&rsquo;t forget, CT is currently accepting applications for our 4th Quarter Call for Proposals.
Check out this great video presentation from Martin Klepsch on Documenting the Clojure/Script Ecosystem.
Thanks to all of our members who support Clojurists Together. It&rsquo;s thanks to your generous support that we can do this.
cljdoc updates Hey dear ClojuristsTogether crew!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/107-applied-tdd.png" alt="Applied TDD">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Applied TDD</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">02 10 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/107-applied-tdd.png" alt="Applied TDD" title="Applied TDD" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">¿Dejadez? ¿Desfachatez? ¿Desconocimiento? ¿Desinterés? Vertidos en Canarias.</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">01 10 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q4 2018 Survey Results and Call For Proposals</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">30 09 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        We&rsquo;ve recently finished our fourth round of surveys on our members to better understand the community&rsquo;s needs. We&rsquo;re posting this feedback so that they can see the aggregate results, and to give open source projects more information when applying for the Q4 2018 Clojurists Together funding round (closing on the 9th of October).
Survey Responses There were 56 respondents to the survey, up from 49 in the last survey. The highlights are presented below.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Volvemos! Wangari Muta Maathai.</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">26 09 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/106-tech-debt.png" alt="Tech Debt">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Tech Debt</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">25 09 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/106-tech-debt.png" alt="Tech Debt" title="Tech Debt" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Setting Up Hugo on Netlify</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">24 09 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Hugo is a static site generator that just like another alternatives(Nicola, Jekyll, etc) allows to write in plain text and generate html, js, css files. Hugo is so much simpler to use because it&#39;s a simple binary file that allows to develop and prepare the site to be published.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://erick.navarro.io/images/setting-up-hugo-on-netlify/01.png" alt="Setting Up Hugo on Netlify">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Setting Up Hugo on Netlify</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">24 09 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
<p>
<a href="http://gohugo.io">Hugo</a> is a static site generator that just like another alternatives(Nicola, Jekyll, etc) allows to write in plain text and generate html, js, css files.</p>
<p>
Hugo is so much simpler to use because it&#39;s a simple binary file, called <code class="verbatim">hugo</code>, that allows to develop and prepare the site to be published. Some of its features are:</p>
<ul>
<li>
<p>Generate a new site</p>
</li>
<li>
<p>Run a development server</p>
</li>
<li>
<p>Generate static files</p>
</li>
<li>
<p>Generate new pages for the site</p>
</li>
</ul>
<p>So let&#39;s start to build a site from scratch and publish it automatically using <a href="https://www.netlify.com">Netlify</a></p>
<div id="outline-container-headline-1" class="outline-3">
<h3 id="headline-1">
Creating the new site
</h3>
<div id="outline-text-headline-1" class="outline-text-3">
<p>
First we&#39;ll need to install hugo. You need to install the single binary using the package manager you prefer. In mac OS you can install it using Homebrew with the following command:</p>
<p>
<code class="verbatim">brew install hugo</code></p>
<p>
You can check the version with <code class="verbatim">hugo version</code>, at the time I&#39;m writing this post the latest version available is <code class="verbatim">0.48</code>.</p>
<p>
Now we need to generate an new empty site so we&#39;ll use the command <code class="verbatim">hugo new site myblog</code>. Once the command finished you&#39;ll have a new folder called <code class="verbatim">myblog</code></p>
<p>
The structure of the new folder should be:</p>
<div class="src src-bash">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">├── archetypes
│   └── default.md
├── config.toml
├── content
├── data
├── layouts
├── static
└── themes</code></pre></div>
</div>
<p>
For now we have to pay attention to only one file <code class="verbatim">config.toml</code> this file contains the configuration of the new site. We can define stuff like the title of the blog, menus structure, theme parameters, etc.</p>
<p>
The contents of <code class="verbatim">config.toml</code> should be like this:</p>
<div class="src src-toml">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-toml" data-lang="toml"><span style="color:#a6e22e">baseURL</span> = <span style="color:#e6db74">&#34;http://example.org/&#34;</span>
<span style="color:#a6e22e">languageCode</span> = <span style="color:#e6db74">&#34;en-us&#34;</span>
<span style="color:#a6e22e">title</span> = <span style="color:#e6db74">&#34;My New Hugo Site&#34;</span></code></pre></div>
</div>
<p>
We have to change <code class="verbatim">baseURL</code> to <code class="verbatim">/</code> to avoid error with broken links(we&#39;ll see these possible errors later). So the result <code class="verbatim">config.toml</code> will be:</p>
<div class="src src-toml">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-toml" data-lang="toml"><span style="color:#a6e22e">baseURL</span> = <span style="color:#e6db74">&#34;/&#34;</span>
<span style="color:#a6e22e">languageCode</span> = <span style="color:#e6db74">&#34;en-us&#34;</span>
<span style="color:#a6e22e">title</span> = <span style="color:#e6db74">&#34;My New Hugo Site&#34;</span></code></pre></div>
</div>
</div>
</div>
<div id="outline-container-headline-2" class="outline-3">
<h3 id="headline-2">
Adding a theme
</h3>
<div id="outline-text-headline-2" class="outline-text-3">
<p>
Now we have to install a theme. There are many awesome themes available for Hugo. You can check and pick one in <a href="https://themes.gohugo.io">Hugo themes</a>.</p>
<p>
For this example we&#39;ll use <a href="https://themes.gohugo.io/beautifulhugo/">Beautiful Hugo</a></p>
<p>
We have 2 options to include the theme in the new site:</p>
<ul>
<li>
<p>Clone the theme repository and add it to our folder. This will copy all the files inside our folder.</p>
</li>
<li>
<p>Use git sub modules to create a reference to the theme repository. This way we don&#39;t need to copy all the files.</p>
</li>
</ul>
<p>We&#39;ll use the second option this time.</p>
<p>
First we need to initialize a git repository inside our <code class="verbatim">myblog</code> folder using the following command <code class="verbatim">git init</code>. Now we have a git repository created.</p>
<p>
Now we have to run the following commands to add the theme:</p>
<div class="src src-sh">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-sh" data-lang="sh">cd themes
git submodule add https://github.com/halogenica/beautifulhugo.git
cd ..</code></pre></div>
</div>
<p>
This will clone the theme repository and add it to our repository as a submodule. We can see that now we have a <code class="verbatim">beautifulhugo</code> folder inside <code class="verbatim">themes</code> folder and also there is a new file in the root of <code class="verbatim">myblog</code> called <code class="verbatim">.gitmodules</code> with the following content:</p>
<div class="src src-ini">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ini" data-lang="ini"><span style="color:#66d9ef">[submodule &#34;themes/beautifulhugo&#34;]</span>
	<span style="color:#a6e22e">path</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">themes/beautifulhugo
</span><span style="color:#e6db74">	url = https://github.com/halogenica/beautifulhugo.git</span></code></pre></div>
</div>
<p>
Now we have to tell hugo we want to use this theme in the new site, we&#39;ll do this adding the following lines to the <code class="verbatim">config.toml</code> file:</p>
<div class="src src-toml">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-toml" data-lang="toml"><span style="color:#a6e22e">theme</span> = <span style="color:#e6db74">&#34;beautifulhugo&#34;</span></code></pre></div>
</div>
</div>
</div>
<div id="outline-container-headline-3" class="outline-3">
<h3 id="headline-3">
Running the development server
</h3>
<div id="outline-text-headline-3" class="outline-text-3">
<p>
To see the new site running before publish it we&#39;ll use the embedded development server. We run it with <code class="verbatim">hugo server -D -p 9000</code>.</p>
<p>
After that we&#39;ll an output similar to this:</p>
<div class="src src-text">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">                   | EN
+------------------+----+
  Pages            |  7
  Paginator pages  |  0
  Non-page files   |  0
  Static files     | 33
  Processed images |  0
  Aliases          |  1
  Sitemaps         |  1
  Cleaned          |  0

Total in 46 ms
Watching for changes in /Users/erick/Code/hugo/myblog/{content,data,layouts,static,themes}
Watching for config changes in /Users/erick/Code/hugo/myblog/config.toml
Serving pages from memory
Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender
Web Server is available at http://localhost:9000/ (bind address 127.0.0.1)
Press Ctrl+C to stop</code></pre></div>
</div>
<p>
Now we can open the browser and enter <a href="http://localhost:9000">http://localhost:9000</a> and we&#39;ll see the new site with the chosen theme.</p>
<p>
The server is watching for changes to be compiled so we leave it running.</p>
</div>
</div>
<div id="outline-container-headline-4" class="outline-3">
<h3 id="headline-4">
Writing content
</h3>
<div id="outline-text-headline-4" class="outline-text-3">
<p>
At this point we don&#39;t have any content to show up so let&#39;s create some.</p>
<p>
Hugo by default can render Markdown and Org-mode files. For this example we&#39;ll create a new post using markdown format.</p>
<p>
Run <code class="verbatim">hugo new post/hello-world.md</code> to create a new file called <code class="verbatim">hello-world.md</code> in <code class="verbatim">content/post/</code>, Hugo will create a new file with the following content:</p>
<div class="src src-markdown">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-markdown" data-lang="markdown">---
title: &#34;Hello World&#34;
date: 2018-09-22T15:05:47-05:00
draft: true
---</code></pre></div>
</div>
<p>
These lines are used by Hugo to show details about the content in the result file.</p>
<p>
Let&#39;s add the lines below to <code class="verbatim">hello-world.md</code></p>
<div class="src src-markdown">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-markdown" data-lang="markdown"># This is a heading with level 1

<span style="color:#75715e">## This is a heading with level 2
</span><span style="color:#75715e"></span>
This is a paragraph

This is some python code

This is a list:

<span style="color:#66d9ef">-</span> item 1
- item 2</code></pre></div>
</div>
<p>
Now if we go to the browser we&#39;ll see the home page with a summary of the content of <code class="verbatim">hello-world.md</code></p>
<p>
By default Hugo show a list of the posts created in <code class="verbatim">content/post</code> in the homepage. Now we can enter to the post to see the full content.</p>
<p>
Once we finished with the post it&#39;s necessary remove <code class="verbatim">draft: true</code> from <code class="verbatim">hello-world.md</code> file otherwise the file won&#39;t show up when we publish the site.</p>
</div>
</div>
<div id="outline-container-headline-5" class="outline-3">
<h3 id="headline-5">
Publishing the site
</h3>
<div id="outline-text-headline-5" class="outline-text-3">
<div id="outline-container-headline-6" class="outline-4">
<h4 id="headline-6">
Uploading the site to a remote repository
</h4>
<div id="outline-text-headline-6" class="outline-text-4">
<p>
We can use Github, Gitlab or Bitbucket to do this. These are the services supported by Netlify. For this example I&#39;ve uploaded the repository to Github and it&#39;s available in <a href="https://github.com/erickgnavar/hugo-demo-site">https://github.com/erickgnavar/hugo-demo-site</a>.</p>
</div>
</div>
<div id="outline-container-headline-7" class="outline-4">
<h4 id="headline-7">
Creating an account in Netlify
</h4>
<div id="outline-text-headline-7" class="outline-text-4">
<p>
Now we have to create an account in <a href="https://www.netlify.com">Netlify</a>, there is a free plan that we can use to host the new site.</p>
</div>
</div>
<div id="outline-container-headline-8" class="outline-4">
<h4 id="headline-8">
Deploying site
</h4>
<div id="outline-text-headline-8" class="outline-text-4">
<p>
Once we have the Netlify account and the site uploaded in a external repository we can proceed with the deploy.</p>
<p>
Now we can log in and start the process clicking in &#34;New site from Git&#34;.</p>
<p><img src="https://erick.navarro.io/images/setting-up-hugo-on-netlify/01.png" alt="/images/setting-up-hugo-on-netlify/01.png" title="/images/setting-up-hugo-on-netlify/01.png" /></p>
<p>
Then there are 3 steps to follow:</p>
<div id="outline-container-headline-9" class="outline-5">
<h5 id="headline-9">
Connect to git provider
</h5>
<div id="outline-text-headline-9" class="outline-text-5">
<p>
We have to log in using the service where we uploaded the site.</p>
<p><img src="https://erick.navarro.io/images/setting-up-hugo-on-netlify/02.png" alt="/images/setting-up-hugo-on-netlify/02.png" title="/images/setting-up-hugo-on-netlify/02.png" /></p>
</div>
</div>
<div id="outline-container-headline-10" class="outline-5">
<h5 id="headline-10">
Pick a repository
</h5>
<div id="outline-text-headline-10" class="outline-text-5">
<p>
Now we have access an a list of our repositories. We can search for the one where the site is in.</p>
<p><img src="https://erick.navarro.io/images/setting-up-hugo-on-netlify/03.png" alt="/images/setting-up-hugo-on-netlify/03.png" title="/images/setting-up-hugo-on-netlify/03.png" /></p>
</div>
</div>
<div id="outline-container-headline-11" class="outline-5">
<h5 id="headline-11">
Build options
</h5>
<div id="outline-text-headline-11" class="outline-text-5">
<p>
Once we chosen the repository we can specify the build options. Netlify recognize that the site is made with Hugo so these options are already configured.</p>
<p>
To proceed we click in &#34;Deploy site&#34;.</p>
<p><img src="https://erick.navarro.io/images/setting-up-hugo-on-netlify/04.png" alt="/images/setting-up-hugo-on-netlify/04.png" title="/images/setting-up-hugo-on-netlify/04.png" /></p>
</div>
</div>
<div id="outline-container-headline-12" class="outline-5">
<h5 id="headline-12">
Deploy result
</h5>
<div id="outline-text-headline-12" class="outline-text-5">
<p>
Netlify will pull the repository and compile the site with the given build options and then it will generate a url to access the deployed site.</p>
<p><img src="https://erick.navarro.io/images/setting-up-hugo-on-netlify/05.png" alt="/images/setting-up-hugo-on-netlify/05.png" title="/images/setting-up-hugo-on-netlify/05.png" /></p>
<p>
Now we can go to the url that Netlify generated for the site and we&#39;ll see the resulting site.</p>
</div>
</div>
<div id="outline-container-headline-13" class="outline-5">
<h5 id="headline-13">
Useful Netlify configuration
</h5>
<div id="outline-text-headline-13" class="outline-text-5">
<p>
By default Netlify only will build the site when we push changes to master. We can change this going to &#34;Deploy settings&#34; and changing &#34;Branch deploys&#34; options to &#34;All&#34; like the following image:</p>
<p><img src="https://erick.navarro.io/images/setting-up-hugo-on-netlify/06.png" alt="/images/setting-up-hugo-on-netlify/06.png" title="/images/setting-up-hugo-on-netlify/06.png" /></p>
<p>
With this configuration we can push changes to a different branch than <code class="verbatim">master</code> and Netlify will generate a new url to see the changes. This is useful to test changes before publish them to production site.</p>
<p>
It&#39;s also possible configure different kind of notifications(Slack, email, etc) to receive the result of the deploy.</p>
</div>
</div>
</div>
</div>
</div>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">About me</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(ノ°Д°)ノ︵ ┻━┻</a> <span class="article__date">22 09 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Hi there 👋, I&#39;m Erick Navarro, software developer.
 I&#39;ve worked mostly doing web development using Python and Javascript but now I work using Elixir also doing web. I&#39;m very interesting in functional programming and that&#39;s why I spend time learning cool tech like Haskell and Clojure.
 I&#39;m a emacs lover and that made me spend many hours tuning my emacs conf (I regret nothing).
 You can follow me on twitter or github
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/105-compromise.png" alt="Compromise">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Compromise</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">18 09 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/105-compromise.png" alt="Compromise" title="Compromise" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Be Careful With CTE in PostgreSQL</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">16 09 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Common table expressions, also known as the WITH clause, are a very useful feature. They help break down big queries into smaller pieces which makes it easier to read and understand. But, when used incorrectly they can cause a significant performance hit.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Adding click-to-copy buttons to a Hugo powered blog</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">14 09 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        In a previous post I described the process of adding nicely highlighted code snippets to a Hugo-powered blog.
Some of the code snippets added to my own blog are fairly long, and selecting the code manually to copy and paste it into a text editor was proving annoying and error-prone. Inspired by other sites, I wanted to add a &lsquo;Copy&rsquo; button to every snippet - when clicked, the button would take the code and copy it to the user&rsquo;s clipboard.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Adding click-to-copy buttons to a Hugo powered blog</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">14 09 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        In a previous post I described the process of adding nicely highlighted code snippets to a Hugo-powered blog.
Some of the code snippets added to my own blog are fairly long, and selecting the code manually to copy and paste it into a text editor was proving annoying and error-prone. Inspired by other sites, I wanted to add a &lsquo;Copy&rsquo; button to every snippet - when clicked, the button would take the code and copy it to the user&rsquo;s clipboard.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://github.com/ahefner/shuffletron/raw/master/img-search.png" alt="Shuffletron, a Common Lisp Music Player for the terminal">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Shuffletron, a Common Lisp Music Player for the terminal</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">11 09 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p><a href="https://github.com/ahefner/shuffletron/">Shuffletron</a> is a nice music
player for the terminal written in Common Lisp, &ldquo;based on search and
tagging&rdquo;, that seduced me with its attention to details. Moreover, its
author was very responsive to fix a couple issues.</p>

<p>The first time you launch it, it will ask for a music repository and
will propose to scan it for id3 tags with the <code>scanid3</code> command. It
is optional, but it allows to print colored information:</p>

<p><img src="https://github.com/ahefner/shuffletron/raw/master/img-search.png" alt="" /></p>

<p>The basic commands to know are the following:</p>

<ul>
<li><p>search with <code>/</code> followed by your search terms. You&rsquo;ll notice that
your prompt changed from <code>library</code> to <code>xy matches</code>. You can <strong>refine
the results</strong> by searching again. To enter a new query we have to go
back to the library, with as many successive &ldquo;enters&rdquo; as needed.</p></li>

<li><p>to play songs: <code>play</code>. We can select which songs to play, using their index:</p>

<ul>
<li>comma-separated indexes of songs: <code>1,3,10</code></li>
<li>a selection with a dash and an optional end: <code>1-10</code>, <code>0-</code></li>
<li>a combination of the two: <code>1,3-10</code>.</li>
</ul></li>

<li><p>there are the obvious <code>pause</code>, <code>shuffle</code>, <code>skip</code>, <code>next</code>, <code>seek</code>, <code>repeat</code>,…</p></li>

<li><p><code>now</code> to show the currently playing song.</p></li>
</ul>

<p>There is also a <strong>queue</strong>, <strong>id3 tags management</strong>, <strong>profiles</strong> to
use an alternate library (<code>./shuffletron --help</code>), and even an <strong>alarm
clock</strong> feature which allows to program music with something like:</p>

<pre><code>  alarm at 7:45 am      # \&quot;at\&quot; is optional and doesn't change the meaning
  alarm 7:45 am
  alarm 9 pm
  alarm 7               # If AM/PM not specified, assumes AM
  alarm in 5 minutes    # Relative alarm times, in minutes or hours
  alarm in 10m          # minutes, minute, mins, min, , m are synonyms
  alarm in 7 hours      # hours, hour, hr, h are synonyms
  alarm in 8h
  alarm in 7:29         # h:mm format - seven hours, twenty-nine minutes
  alarm reset           # off/never/delete/disable/cancel/clear/reset
</code></pre>

<p>I can see a use for a pomodoro-like technic :)</p>

<p>I&rsquo;ll list the complete set of commands below (available
<a href="https://github.com/ahefner/shuffletron/blob/master/src/help.lisp">on the sources</a>),
but first a note on installation.</p>

<h2 id="installation">Installation</h2>

<p>Shuffletron doesn&rsquo;t provide executables
(<a href="https://github.com/ahefner/shuffletron/issues/6">yet ?</a>). The
procedure is now documented in the readme so you just have to</p>

<pre><code>make shuffletron-bin  # sbcl
sudo make install
./shuffletron
</code></pre>

<p>This last line calls a script and it is actually important to use it,
to link dependencies and to use <code>rlwrap</code>. There is room for
improvement here.</p>

<p>To read Flac and Ogg files, you need those system dependencies:</p>

<pre><code>apt install libflac-dev
apt install libvorbis-dev
</code></pre>

<p>Finally, scanning my library failed for the first time, because of
badly manually encoded ogg files coming from youtube. The mixalot
library prefered to fail instead of showing error messages. If you
encounter a similar problem, see
<a href="https://github.com/ahefner/mixalot/pull/7">this PR</a>.</p>

<h2 id="all-commands">All commands</h2>

<p>In the application, type <code>help</code>, and <code>help commands</code> to get this list:</p>

<pre><code>Command list:

  /[query]       Search library for [query].
  show           Print search matches, highlighting songs in queue.
  back           Undo last search.
  [songs]        Play list of songs.
  all            Play all songs in selection (equivalent to \&quot;0-\&quot;)
  +[songs]       Append list of songs to queue.
  pre[songs]     Prepend list of songs to queue.
  random         Play a random song from the current selection.
  random QUERY   Play a random song matching QUERY
  shuffle SONGS  Play songs in random order.

  queue          Print queue contents and current song playing.
  shuffle        Randomize order of songs in queue.
  clear          Clear the queue (current song continues playing)
  loop           Toggle loop mode (loop through songs in queue)
  qdrop          Remove last song from queue
  qdrop RANGES   Remove songs from queue
  qtag TAGS      Apply tags to all songs in queue
  fromqueue      Transfer queue to selection
  toqueue        Replace queue with selection

  now            Print name of song currently playing.
  play           Resume playing
  stop           Stop playing (current song pushed to head of queue)
  pause          Toggle paused/unpaused.
  skip           Skip currently playing song. If looping is enabled, this
                 song won't played again.
  next           Advance to next song. If looping is enabled, the current
                 song will be enqueued.
  repeat N       Add N repetitions of currently playing song to head of queue.
  seek TIME      Seek to time (in [h:]m:ss format, or a number in seconds)
  seek +TIME     Seek forward
  seek -TIME     Seek backward
  startat TIME   Always start playback at a given time (to skip long intros)

  tag            List tags of currently playing song.
  tag TAGS       Add one or more textual tags to the current song.
  untag TAGS     Remove the given tags from the currently playing song.
  tagged TAGS    Search for files having any of specified tags.
  tags           List all tags (and # occurrences) within current query.
  killtag TAGS   Remove all occurances of the given tags
  tagall TAGS    Apply tags to all selected songs
  untagall TAGS  Remove given tags from all selected songs

  time           Print current time
  alarm          Set alarm (see \&quot;help alarms\&quot;)

  scanid3        Scan new files for ID3 tags
  prescan        Toggle file prescanning (useful if file IO is slow)
  exit           Exit the program.

  help [topic]   Help
</code></pre>

<h2 id="see-also">See also</h2>

<ul>
<li><a href="https://github.com/stassats/mpd">mpd</a>, an interface to Music Player
Daemon in CL.</li>
</ul>

<p>other music players:</p>

<ul>
<li><a href="https://cmus.github.io/">cmus</a></li>
<li>Emacs&rsquo; media players <a href="http://wikemacs.org/wiki/Media_player">http://wikemacs.org/wiki/Media_player</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/104-final-patch.png" alt="Final Patch">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Final Patch</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">11 09 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/104-final-patch.png" alt="Final Patch" title="Final Patch" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">August 2018 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">06 09 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together news August was the first month of funding for the quarter, so today we present the initial round of updates on new projects, cljdoc and Shadow CLJS.
This month we have hired Rachel Magruder part-time to help out with the day-to-day running of Clojurists Together. If you send us an email you may get a response from her. She is also helping out with the backend processing of contracts, grant reports, payments, e.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Freak Spot: Subprocesos en Python</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">04 09 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Los subprocesos o <a href="https://es.wikipedia.org/wiki/Hilo_de_ejecuci%C3%B3n">hilos de
ejecuci&#243;n</a> nos
permiten realizar tareas concurrentemente. En Python podemos utilizar el
m&#243;dulo <a href="https://docs.python.org/3.5/library/threading.html">threading</a>,
aunque hay muchos otros.</p>
<p>Vamos a crear varios subprocesos (<em>threads</em>) sencillos.</p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/usr/bin/env python</span>
<span class="c1"># -*- coding: utf-8 -*-</span>
<span class="kn">import</span> <span class="nn">threading</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="kn">import</span> <span class="nn">random</span>

<span class="k">def</span> <span class="nf">sleeper</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">s_time</span><span class="p">):</span>
    <span class="nb">print</span><span class="p">(</span><span class="s1">'</span><span class="si">{}</span><span class="s1"> iniciado a las </span><span class="si">{}</span><span class="s1">.'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
        <span class="n">name</span><span class="p">,</span> <span class="n">time</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s1">'%H:%M:%S'</span><span class="p">,</span> <span class="n">time</span><span class="o">.</span><span class="n">gmtime</span><span class="p">())))</span>

    <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="n">s_time</span><span class="p">)</span>

    <span class="nb">print</span><span class="p">(</span><span class="s1">'</span><span class="si">{}</span><span class="s1"> finalizado a las </span><span class="si">{}</span><span class="s1">.'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
        <span class="n">name</span><span class="p">,</span> <span class="n">time</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s1">'%H:%M:%S'</span><span class="p">,</span> <span class="n">time</span><span class="o">.</span><span class="n">gmtime</span><span class="p">())))</span>


<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
    <span class="n">thread</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">sleeper</span><span class="p">,</span> <span class="n">args</span><span class="o">=</span><span class="p">(</span>
        <span class="s1">'Proceso '</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">),</span> <span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">9</span><span class="p">)))</span>

    <span class="n">thread</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>

<span class="nb">print</span><span class="p">(</span><span class="s1">'Yo he terminado, pero los otros subprocesos no.'</span><span class="p">)</span>
</code></pre></div>

<p>Primero, hemos importado los modulos necesarios: <code>time</code>, <code>random</code> y
<code>threading</code>. Para crear <em>threads</em> solo necesitamos el &#250;ltimo. <code>time</code> lo
hemos utilizado para simular una tarea y obtener su tiempo de inicio y
fin; <code>random</code>, para hacer que nuestro proceso tenga una duraci&#243;n
aleatoria.</p>
<p>La funci&#243;n <em>sleeper</em> &#171;duerme&#187; (no hace nada) durante el tiempo que le
especifiquemos, nos dice cu&#225;ndo ha empezado a &#171;dormir&#187; y cuando ha
terminado de &#171;dormir&#187;. Como par&#225;metros le pasamos el nombre que le
queremos dar al subproceso y el tiempo que va a &#171;dormir&#187; la funci&#243;n.</p>
<p>Luego, creamos un bucle for que crea 5 subprocesos que ejecutan la
funci&#243;n <code>sleeper</code>. En el constructor (<code>threading.Thread</code>), debemos
indicar la funci&#243;n a ejecutar (<code>target=sleeper</code>) y los par&#225;metros que
queremos pasarle
(<code>args=('Proceso ' + str(i + 1), random.randint(1, 9)</code>).</p>
<div class="highlight"><pre><span></span><code><span class="k">Proc</span><span class="nb">es</span><span class="nv">o</span> <span class="mi">1</span> <span class="nv">iniciado</span> <span class="nv">a</span> <span class="nv">las</span> <span class="mi">21</span><span class="p">:</span><span class="mi">19</span><span class="p">:</span><span class="mi">23</span><span class="nv">.</span>
<span class="k">Proc</span><span class="nb">es</span><span class="nv">o</span> <span class="mi">2</span> <span class="nv">iniciado</span> <span class="nv">a</span> <span class="nv">las</span> <span class="mi">21</span><span class="p">:</span><span class="mi">19</span><span class="p">:</span><span class="mi">23</span><span class="nv">.</span>
<span class="k">Proc</span><span class="nb">es</span><span class="nv">o</span> <span class="mi">3</span> <span class="nv">iniciado</span> <span class="nv">a</span> <span class="nv">las</span> <span class="mi">21</span><span class="p">:</span><span class="mi">19</span><span class="p">:</span><span class="mi">23</span><span class="nv">.</span>
<span class="k">Proc</span><span class="nb">es</span><span class="nv">o</span> <span class="mi">4</span> <span class="nv">iniciado</span> <span class="nv">a</span> <span class="nv">las</span> <span class="mi">21</span><span class="p">:</span><span class="mi">19</span><span class="p">:</span><span class="mi">23</span><span class="nv">.</span>
<span class="k">Proc</span><span class="nb">es</span><span class="nv">o</span> <span class="mi">5</span> <span class="nv">iniciado</span> <span class="nv">a</span> <span class="nv">las</span> <span class="mi">21</span><span class="p">:</span><span class="mi">19</span><span class="p">:</span><span class="mi">23</span><span class="nv">.</span>
<span class="nf">Yo</span> <span class="nv">he</span> <span class="nv">terminado</span><span class="p">,</span> <span class="nv">pero</span> <span class="nv">los</span> <span class="nv">otros</span> <span class="nv">subprocesos</span> <span class="nv">no.</span>
<span class="k">Proc</span><span class="nb">es</span><span class="nv">o</span> <span class="mi">1</span> <span class="nv">finalizado</span> <span class="nv">a</span> <span class="nv">las</span> <span class="mi">21</span><span class="p">:</span><span class="mi">19</span><span class="p">:</span><span class="mi">25</span><span class="nv">.</span>
<span class="k">Proc</span><span class="nb">es</span><span class="nv">o</span> <span class="mi">5</span> <span class="nv">finalizado</span> <span class="nv">a</span> <span class="nv">las</span> <span class="mi">21</span><span class="p">:</span><span class="mi">19</span><span class="p">:</span><span class="mi">26</span><span class="nv">.</span>
<span class="k">Proc</span><span class="nb">es</span><span class="nv">o</span> <span class="mi">4</span> <span class="nv">finalizado</span> <span class="nv">a</span> <span class="nv">las</span> <span class="mi">21</span><span class="p">:</span><span class="mi">19</span><span class="p">:</span><span class="mi">27</span><span class="nv">.</span>
<span class="k">Proc</span><span class="nb">es</span><span class="nv">o</span> <span class="mi">2</span> <span class="nv">finalizado</span> <span class="nv">a</span> <span class="nv">las</span> <span class="mi">21</span><span class="p">:</span><span class="mi">19</span><span class="p">:</span><span class="mi">32</span><span class="nv">.</span>
<span class="k">Proc</span><span class="nb">es</span><span class="nv">o</span> <span class="mi">3</span> <span class="nv">finalizado</span> <span class="nv">a</span> <span class="nv">las</span> <span class="mi">21</span><span class="p">:</span><span class="mi">19</span><span class="p">:</span><span class="mi">32</span><span class="nv">.</span>
</code></pre></div>

<p>El resultado de la ejecuci&#243;n es aleatorio: no sabemos cu&#225;l proceso
finalizar&#225; primero.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="GDPR - What happened?">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">GDPR - What happened?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">02 09 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The tracking landscape post GDPR, adverse effects on competition and a market for compliance technologies
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/103-building-a-raft.png" alt="Building a raft">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Building a raft</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">28 08 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/103-building-a-raft.png" alt="Building a raft" title="Building a raft" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="Third-party cookies - the guests who won&#39;t leave">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Third-party cookies - the guests who won&#39;t leave</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">26 08 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        How the web ecosystem is preventing us from reverting the third-party cookie mistake.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/102-implementation.png" alt="Implementation">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Implementation</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">21 08 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/102-implementation.png" alt="Implementation" title="Implementation" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">July 2018 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">14 08 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together news This was the final month for CIDER and ClojureScript. Our next two projects that we are funding are cljdoc and Shadow CLJS. Thanks to all of our members who support Clojurists Together. It&rsquo;s thanks to your generous support that we can do this.
CIDER updates This months updates were all around getting nREPL 0.4 into the hands of everyone.
 I&rsquo;ve also opened PRs for lein and boot for the new nREPL.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/101-macro.png" alt="Macro">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Macro</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">14 08 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/101-macro.png" alt="Macro" title="Macro" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/media/2018/mastodon.png" alt="Join me on Mastodon">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Join me on Mastodon</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Danny van Kooten</a> <span class="article__date">13 08 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <blockquote>
  <p><strong>Summary:</strong> <a href="https://joinmastodon.org/">Join me on Mastodon</a>. It’s like Twitter, but less angry and more decentralized.</p>
</blockquote>

<p>I’ve been a happy Twitter user for years and got a lot of value out of it over the last decade. Even so, I find myself using the service very little these days.</p>

<p>While I can’t say for certain what is the cause of that, the non-chronological timeline and algorithms that seem to excel at showing me rage-inducing tweets come to mind. An extensive mute list helped for a little while, but even that is falling short nowadays.</p>

<p>That’s part of why I was happily surprised when revisiting Mastodon a few weeks ago.</p>

<p>A lot had improved since I last checked in early 2017. I connected to a few people that seemed to be sharing interesting content, found some I already knew and had a really good time exploring the “fediverse” since then.</p>

<h2 id="why-mastodon">Why Mastodon?</h2>

<p>Here’s a few things that make Mastodon great for me:</p>

<ul>
  <li>It’s open-source and you can host it yourself, while still participating in the global network and following users on other instances.</li>
  <li>Your feed is chronological, ad-free and there are no algorithms deciding what you actually end up seeing.</li>
  <li>You get 500 characters per “toot” and can hide things behind spoiler warnings.</li>
</ul>

<p><strong>A sample of what it could look like (although there are many different clients)</strong></p>

<p><a href="https://joinmastodon.org/"><img src="/media/2018/mastodon.png" alt="The Mastodon web app" /></a></p>

<p>I’m enthusiastic about the direction that Mastodon is heading in and am really enjoying myself on there already. If you’re looking for a place that feels a bit like Twitter in the early days, give Mastodon a proper try.</p>

<p>To further promote decentralization, I decided to run my own instance: <a href="https://mastodon.dvk.co/">mastodon.dvk.co</a> (which was super easy to set up, by the way).</p>

<h3 id="useful-mastodon-tools">Useful Mastodon tools</h3>

<p>If you’re new to Mastodon, you’ll have to put in some effort to turn it into something useful. It’s not much fun logging in to an empty feed after all.</p>

<p>Here are some of the tools that helped me:</p>

<ul>
  <li><a href="https://bridge.joinmastodon.org/">Find your Twitter friends on Mastodon</a></li>
  <li><a href="https://instances.social/">Find an instance that suits your needs and interests</a></li>
  <li><a href="https://docs.joinmastodon.org/admin/prerequisites/">Self-hosting Mastodon</a></li>
  <li>iOS apps: <a href="https://itunes.apple.com/us/app/tootdon-for-mastodon/id1282283934">Tootdon</a> and <a href="https://itunes.apple.com/us/app/amaroq-for-mastodon/id1214116200">Amaroq</a></li>
</ul>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The next ten years of Instapaper</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Instapaper</a> <span class="article__date">07 08 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>This year Instapaper celebrated its tenth birthday and, now that we are an <a target="_blank" href="http://blog.instapaper.com/post/175953870856">independent company</a>, we’ve been thinking a lot about the next ten years of Instapaper and beyond.</p><p><b></b></p><p>To ensure Instapaper can continue for the foreseeable future, it’s essential that the product generates enough revenue to cover its costs. In order to do so, we’re relaunching <a target="_blank" href="https://instapaper.com/premium">Instapaper Premium</a> today.</p><p><b></b></p><p>As a reminder, Instapaper Premium is a subscription for $2.99/month or $29.99/year that offers the following features:</p><p><b></b></p><ul><li>Full-text search for all articles in your account</li><li>Unlimited Notes</li><li>Text-to-Speech playlists on mobile</li><li>Speed reading to get through all of your articles up to 3x faster</li><li>An ad-free Instapaper website</li><li>“Send to Kindle” using a bookmarklet or our mobile apps</li></ul><p>In addition to getting access to Premium features, your Instapaper Premium subscription will help ensure that we can continue developing and operating Instapaper. Our goal is to build a long-term sustainable product and business, without venture capital, and we need your help to achieve that goal.<br/></p><p><b></b></p><p>If you decide to not subscribe to Instapaper Premium, you will continue with a standard free account without access to Premium features.</p><p><b></b></p><p>Additionally, today we are bringing back Instapaper to European Union users. Over the past two months we have taken a number of actions to address the General Data Protection Regulation, and we are happy to announce our return to the European Union. </p><p><b></b></p><p>We are very sorry for the extended downtime and, as a token of our apology, we are giving six months of Instapaper Premium to all EU users affected by the outage.</p><p><b></b></p><p>We’ve updated our <a target="_blank" href="https://instapaper.com/privacy">privacy policy</a> to include the rights afforded to EU users under the General Data Protection Regulation (GDPR). Additionally, in the interest of transparency, we are posting our privacy policy to GitHub where you can view a <a target="_blank" href="https://github.com/Instapaper/privacy/commits/master">versioned history of all the changes to our privacy policy</a>.</p><p><b></b></p><p>Thanks again for your support. If you have any questions, comments or concerns please let us know by sending an email to <a href="mailto:support@instapaper.com">support@help.instapaper.com</a>.</p><p>– Brian Donohue &amp; Rodion Gusev</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to deal with dirty side effects in your pure functional JavaScript</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">07 08 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        If you start learning about functional programming, it won't be long before you come across the idea of pure functions. And as you go on, you will discover functional programmers appear to be obsessed with them. “Pure functions let you reason about your code,” they say. “Pure functions are less likely to start a thermonuclear war.” “Pure functions give you referential transparency”. On and on it goes. And they have a point. Pure functions are a good thing. But what do you do with the impure bits of your code?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to deal with dirty side effects in your pure functional JavaScript</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">07 08 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        If you start learning about functional programming, it won't be long before you come across the idea of pure functions. And as you go on, you will discover functional programmers appear to be obsessed with them. “Pure functions let you reason about your code,” they say. “Pure functions are less likely to start a thermonuclear war.” “Pure functions give you referential transparency”. On and on it goes. And they have a point. Pure functions are a good thing. But what do you do with the impure bits of your code?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/100-blame.png" alt="Blame">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Blame</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">07 08 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/100-blame.png" alt="Blame" title="Blame" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Deploying a Hugo-powered site to Netlify with source code syntax highlighting</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">03 08 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        My hugo blog is based on the awesome Goa theme, but the default syntax highlighting (powered by HighlightJS) was not working very well with JSX code. Since much of my work is with React these days, code snippets on this blog are likely to use JSX, and so this was becoming a bit of an issue. Added to this is the general overhead of the site requesting extra CSS and JavaScript files to support this feature.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Deploying a Hugo-powered site to Netlify with source code syntax highlighting</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">03 08 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        My hugo blog is based on the awesome Goa theme, but the default syntax highlighting (powered by HighlightJS) was not working very well with JSX code. Since much of my work is with React these days, code snippets on this blog are likely to use JSX, and so this was becoming a bit of an issue. Added to this is the general overhead of the site requesting extra CSS and JavaScript files to support this feature.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q4 2018 Funding Announcement</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">03 08 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together is happy to announce that for Q4 of 2018/19 (November-January) we are funding two projects: Datascript and Kaocha.
Recap For those who are new to Clojurists Together, our goal is simple: Fund critical Clojure open-source projects to keep them healthy and sustainable. Clojure companies and individual developers sign up for a monthly contribution, and we pick projects to fund each quarter. This funding cycle is our fourth. Previously we have supported cljdoc, Shadow CLJS, clj-http, Figwheel, ClojureScript, and CIDER.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q3 2018 Funding Announcement</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">03 08 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together is happy to announce that for Q3 of 2018 (August-October) we are funding two projects: cljdoc and Shadow CLJS.
Recap For those who are new to Clojurists Together, our goal is simple: Fund critical Clojure open-source projects to keep them healthy and sustainable. Clojure companies and individual developers sign up for a monthly contribution, and we pick projects to fund each quarter. This funding cycle is our third. Previously we have supported clj-http, Figwheel, ClojureScript, and CIDER.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/99-pull-request.png" alt="Pull Request">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Pull Request</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">31 07 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/99-pull-request.png" alt="Pull Request" title="Pull Request" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/98-define-madness.png" alt="Define Madness">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Define Madness</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">25 07 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/98-define-madness.png" alt="Define Madness" title="Define Madness" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hyperreals *R: Borrado de un descriptor (correcci&amp;#243;n de&amp;#160;errores)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">24 07 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Tengo que hacer algunas correcciones a la serie de art&#237;culos sobre <em>descriptores</em>, en concreto sobre el m&#233;todo <code>__delete__</code> del protocolo <em>descriptor</em>.</p>
<p>Primero, aclaremos c&#243;mo funciona el m&#233;todo <code>__delete__</code> y en qu&#233; se diferencia de <code>__del__</code>. No se trata de m&#233;todos <em>destructores</em> tal y como se entiende en otros lenguajes de programaci&#243;n orientados a objeto. En python, <strong>todo objeto est&#225; vivo mientras est&#233; referenciado</strong>. S&#243;lo cuando se pierda la &#250;ltima referencia se proceder&#225; a la destrucci&#243;n y borrado del objeto en memoria por parte del <em>recolector de basura</em>.</p>
<p>Por ejemplo, veamos el siguiente&nbsp;c&#243;digo:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">Miclase</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>

    <span class="k">def</span> <span class="fm">__del__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="nb">print</span> <span class="s2">&quot;instance deleted&quot;</span>

<span class="n">a</span> <span class="o">=</span> <span class="n">Miclase</span><span class="p">()</span>
<span class="n">b</span> <span class="o">=</span> <span class="n">a</span>
<span class="k">del</span> <span class="n">a</span>

<span class="nb">print</span> <span class="n">b</span>
<span class="nb">print</span> <span class="s2">&quot;Come on&quot;</span>
<span class="n">b</span> <span class="o">=</span> <span class="mi">1</span>
<span class="nb">print</span> <span class="s2">&quot;END&quot;</span>
</code></pre></div>

<p>De su ejecuci&#243;n, podemos comprobar que el m&#233;todo <code>__del__</code> no se invoca justo en el momento de hacer <code>del a</code>, si no cuando se pierde la &#250;ltima referencia al asignar otro valor a la variable <code>b</code>. La sentencia <code>del a</code> no <em>destruye</em> el objeto, tan s&#243;lo desliga el objeto de la etiqueta <code>a</code> que lo referenciaba. Por ese motivo, es inexacto hablar en python de &#8220;variable de memoria&#8221;, como se entiende en otro lenguajes. Tan s&#243;lo cambiamos de una referencia de un objeto a otro, sin destruir su valor&nbsp;anterior.</p>
<h2>Revisi&#243;n del protocolo&nbsp;descriptor</h2>
<p>En un <a href="https://blog.ch3m4.org/2011/06/19/descriptores-parte-1/">anterior art&#237;culo</a> distingu&#237;a entre descriptores de datos y de no-datos. Hay que aclarar que un descriptor de datos &#8220;es tambi&#233;n el que s&#243;lo tiene definido un m&#233;todo <code>__delete__</code>, aunque no tenga m&#233;todo <code>__set__</code><span class="dquo">&#8220;</span>. &#191;Para qu&#233; puede sernos &#250;til tener uno sin el&nbsp;otro?</p>
<p>Un descriptor de datos sin m&#233;todo <code>__set__</code> no tiene forma de impedir que el atributo/m&#233;todo que implementa sea sustitu&#237;do por otro objeto (por ejemplo, por otro descriptor). El m&#233;todo <code>__delete__</code> nos dar&#237;a la &#250;ltima opci&#243;n de liberar recursos que ya no vayamos a usar antes de desaparecer el descriptor. Pero, independiemente de lo que haga, el m&#233;todo <code>__delete__</code> indicar&#237;a que el descriptor puede ser sustituido. En definitiva, se comportar&#237;a como un <em>descriptor de no-datos</em>, pero con las diferencias en la invocaci&#243;n entre estos dos tipos de descriptor<sup id="fnref:1"><a class="footnote-ref" href="https://blog.ch3m4.org/feeds/python.atom.xml#fn:1">1</a></sup>.</p>
<p>Para aclarar las cosas, veamos qu&#233; estaba mal en el <a href="https://blog.ch3m4.org/2011/06/19/descriptores-parte-1/">ejemplo</a> que puse en su momento  sobre el uso de <code>__delete__</code> (he cambiado algunos nombres para que se vea m&#225;s&nbsp;claro):</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">Desc</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">mul</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">mul</span> <span class="o">=</span> <span class="n">mul</span>

    <span class="k">def</span> <span class="fm">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="bp">cls</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">obj</span><span class="o">.</span><span class="n">value</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">mul</span>

    <span class="k">def</span> <span class="fm">__set__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
        <span class="k">raise</span> <span class="ne">AttributeError</span>

    <span class="k">def</span> <span class="fm">__delete__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
        <span class="k">del</span> <span class="bp">self</span>

<span class="k">class</span> <span class="nc">Miclase</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>

    <span class="n">a12</span> <span class="o">=</span> <span class="n">Desc</span><span class="p">(</span><span class="mi">12</span><span class="p">)</span>
    <span class="n">a200</span> <span class="o">=</span> <span class="n">Desc</span><span class="p">(</span><span class="mi">200</span><span class="p">)</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="n">value</span>


<span class="n">c</span> <span class="o">=</span> <span class="n">Miclase</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>

<span class="nb">print</span> <span class="n">c</span><span class="o">.</span><span class="n">a12</span> <span class="c1">#--&gt; 24</span>

<span class="n">c</span><span class="o">.</span><span class="n">a12</span> <span class="o">=</span> <span class="mi">100</span>  <span class="c1"># ERROR: AttributeError</span>

<span class="k">del</span> <span class="n">Miclase</span><span class="o">.</span><span class="n">a12</span>
<span class="n">c</span><span class="o">.</span><span class="n">a12</span><span class="o">=</span><span class="mi">100</span>

<span class="nb">print</span> <span class="n">c</span><span class="o">.</span><span class="n">a12</span>  <span class="c1">#--&gt; 100 (no descriptor)</span>
</code></pre></div>

<p>La idea era que se pudiera borrar el descriptor de datos para sustuirlo por otro valor. Tal como se&#241;alaba Cristian en un comentario al respecto, este ejemplo parece funcionar con o sin el m&#233;todo <code>__delete__</code> en el&nbsp;descriptor.</p>
<p>Funciona siempre debido a que con <code>'del Miclase.a12'</code> estamos borrando la referencia al descriptor que tiene la clase, sin pasar por el protocolo descriptor. La particularidad de los descriptores es que <em>viven</em> en la clase, pero se invocan desde la instancia. Con <code>'del Miclase.a12'</code> estamos salt&#225;ndonos el protocolo descriptor para acceder directamente al atributo de la clase<sup id="fnref:2"><a class="footnote-ref" href="https://blog.ch3m4.org/feeds/python.atom.xml#fn:2">2</a></sup>.</p>
<p>Adem&#225;s, este c&#243;digo no funcionar&#237;a&nbsp;nunca:</p>
<div class="highlight"><pre><span></span><code>    <span class="k">def</span> <span class="fm">__delete__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
        <span class="k">del</span> <span class="bp">self</span>
</code></pre></div>

<p>Si la idea era borrar el objeto <code>self</code>, referencia al descriptor, podemos quitarnos esa idea ya que el comando <code>del</code> borra la referencia del <em>scope</em> local donde se encuentra. <strong>&#161;No es un destructor!</strong> En realidad, todas las variables locales son borradas al finalizar el m&#233;todo. En este caso en concreto, tambi&#233;n la variable local <code>obj</code> ser&#225; borrada aunque no se indique&nbsp;expl&#237;citamente.</p>
<p>Otra cuesti&#243;n a tener en cuenta es que los atributos de clase son compartidos por todas sus instancias. Si en alg&#250;n momento alteramos un descriptor (por ejemplo, borr&#225;ndolo), entonces todas las instancias sufririan el mismo cambio. No parece que sea el efecto&nbsp;buscado.</p>
<p>La gran pregunta es <em>entonces, &#191;c&#243;mo podemos aprovecharnos del m&#233;todo <code>__delete__</code>?</em></p>
<p>Para sacarle alg&#250;n partido, el descriptor deber&#237;a comportarse de forma distinta seg&#250;n sea la instancia que lo invoca. Definido as&#237; el descriptoor, entonces podr&#237;amos usar el m&#233;todo <code>__delete__</code> para simular el borrado del atributo para esa instancia, sin que el descriptor pierda su&nbsp;funcionalidad.</p>
<p>Un ejemplo para ilustrar &#233;sto&nbsp;ser&#237;a:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">weakref</span> <span class="kn">import</span> <span class="n">WeakKeyDictionary</span>

<span class="k">class</span> <span class="nc">Desc</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="n">WeakKeyDictionary</span><span class="p">()</span>

    <span class="k">def</span> <span class="fm">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="bp">cls</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">obj</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">data</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">AttributeError</span>
        <span class="n">total</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span><span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
        <span class="k">return</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">obj</span><span class="p">),</span> <span class="n">total</span><span class="p">)</span>

    <span class="k">def</span> <span class="fm">__set__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">obj</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">data</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">AttributeError</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">data</span><span class="p">[</span><span class="n">obj</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>

    <span class="k">def</span> <span class="fm">__delete__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
        <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">data</span><span class="p">[</span><span class="n">obj</span><span class="p">]</span>

<span class="k">class</span> <span class="nc">Miclase</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>

    <span class="n">value</span> <span class="o">=</span> <span class="n">Desc</span><span class="p">()</span>


<span class="n">a</span> <span class="o">=</span> <span class="n">Miclase</span><span class="p">()</span>
<span class="n">b</span> <span class="o">=</span> <span class="n">Miclase</span><span class="p">()</span>

<span class="n">a</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="mi">2</span>
<span class="n">b</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="mi">5</span>

<span class="nb">print</span> <span class="n">a</span><span class="o">.</span><span class="n">value</span>  <span class="c1">#--&gt; (2, 7)</span>
<span class="nb">print</span> <span class="n">b</span><span class="o">.</span><span class="n">value</span>  <span class="c1">#--&gt; (5, 7)</span>

<span class="n">a</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="mi">100</span>  <span class="c1"># ERROR: AttributeError</span>

<span class="k">del</span> <span class="n">a</span><span class="o">.</span><span class="n">value</span>
<span class="n">a</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="mi">11</span>

<span class="nb">print</span> <span class="n">a</span><span class="o">.</span><span class="n">value</span>  <span class="c1">#--&gt; (11, 16)</span>
<span class="nb">print</span> <span class="n">b</span><span class="o">.</span><span class="n">value</span>  <span class="c1">#--&gt; (5, 16)</span>

<span class="k">del</span> <span class="n">b</span>

<span class="nb">print</span> <span class="n">a</span><span class="o">.</span><span class="n">value</span>  <span class="c1">#--&gt; (11, 11)</span>
</code></pre></div>

<p>El descriptor mantiene un diccionario <em>weak</em> con valores asignados para cada instancia de la clase. Usamos para ello un <em>WeakKeyDictionary</em> que tiene la particularidad de relajar la referencia al objeto, de modo que si todas las referencias al objeto son borradas en el programa, tambi&#233;n es borrada la referencia que conservaba el&nbsp;diccionario.</p>
<p>En este ejemplo, el m&#233;todo <code>__get__</code> devuelve el valor del atributo si el objeto est&#225; en el diccionario, si no da error. El m&#233;todo <code>__set__</code> asigna un valor al atributo s&#243;lo si el objeto no existe. Para ver mejor el funcionamiento, el m&#233;todo <code>__get__</code> devuelve una tupla con el valor del atributo y la suma de todos los&nbsp;atributos.</p>
<p>Ejecuntado el ejemplo, creamos dos instancias y les asignamos un valor al atributo controlado por el descriptor. Una vez asignado un valor, ya no podemos cambiarlo. La &#250;nica opci&#243;n ser&#225; borrar el atributo y volverlo a&nbsp;asignar.</p>
<p>Tambi&#233;n se puede comprobar que, cuando borramos el objeto <code>b</code>, la suma de todos los atributos se actualiza a las instancias que a&#250;n quedan <em>vivas</em>.</p>
<p>En el borrado del atributo se usa el m&#233;todo <code>__delete__</code> del descriptor; en el borrado de la instancia, el m&#233;todo <code>__del__</code> (si&nbsp;existiera).</p>
<h2>Referencia</h2>
<p>No quisiera acabar este art&#237;culo sin a&#241;adir una referencia sobre este tema que os recomiendo leer, con algunas recetas para aprovechar el uso de los&nbsp;descriptores:</p>
<p><a href="http://nbviewer.jupyter.org/gist/ChrisBeaumont/5758381/descriptor_writeup.ipynb"><span class="dquo">&#8220;</span>Python Descriptors Demystified&#8221;</a> by <a href="http://chrisbeaumont.org/">Chris&nbsp;Beaumont</a></p>
<div class="footnote">
<hr />
<ol>
<li id="fn:1">
<p>Comentado en los anteriores <a href="https://blog.ch3m4.org/tag/descriptor/">art&#237;culos sobre descriptores</a>.&#160;<a class="footnote-backref" href="https://blog.ch3m4.org/feeds/python.atom.xml#fnref:1" title="Jump back to footnote 1 in the text">&#8617;</a></p>
</li>
<li id="fn:2">
<p>Un modo de impedir el borrado de atributos de una clase ser&#237;a aplicando el protocolo descriptor con metaclases, pero pienso que estar&#237;amos complic&#225;ndolo todo demasiado para el beneficio que pudiera obtenerse a cambio.&#160;<a class="footnote-backref" href="https://blog.ch3m4.org/feeds/python.atom.xml#fnref:2" title="Jump back to footnote 2 in the text">&#8617;</a></p>
</li>
</ol>
</div>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hyperreals *R: Mutable o inmutable, he ah&amp;#237; el&amp;#160;dilema</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">24 07 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="admonition info">
<p class="admonition-title">Info</p>
<p>Disponible tambi&#233;n como <a href="http://nbviewer.jupyter.org/5224623">ipynb</a></p>
</div>
<p>Quien se enfrenta a la documentaci&#243;n de python por primera vez se pregunta porqu&#233; esa insistencia en mantener tipos de datos duplicados en versiones mutables e inmutables. Tenemos listas y tuplas que casi hacen lo mismo. En python3, tenemos el tipo inmutable <code>bytes</code> y el mutable <code>bytearray</code>. &#191;Qu&#233; sentido tiene tener <em>&#8220;duplicados&#8221;</em> algunos tipos en sus dos versiones? La &#250;nica explicaci&#243;n que se puede encontrar en la documentaci&#243;n es que los tipos inmutables son m&#225;s apropiados para usarlos como &#237;ndices en diccionarios. No parece mucha ventaja para la complejidad que&nbsp;aporta.</p>
<p>En este art&#237;culo veremos qu&#233; implica la <em>mutabilidad</em> de un tipo de dato y en qu&#233; puede sernos &#250;til usar un tipo mutable u otro&nbsp;inmutable.</p>
<h2>&#191;Qu&#233; es lo que&nbsp;cambia?</h2>
<p>Antes de explicar nada, veamos si somos capaces de saber qu&#233; est&#225; cambiando. Veamos dos c&#243;digos muy&nbsp;similares:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">a</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">a</span> <span class="o">+=</span> <span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">)</span>
</code></pre></div>

<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">a</span> <span class="o">+=</span> <span class="p">[</span><span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="nb">print</span><span class="p">(</span> <span class="n">a</span> <span class="p">)</span>
</code></pre></div>

<p>Parece que ambos c&#243;digos hagan lo mismo: a&#241;adir un fragmento, en sus versiones tupla y lista, respectivamente. Vamos a analizarlo mejor. Para saber qu&#233; pasa, usemos la funci&#243;n <code>id()</code>. Esta funci&#243;n devuelve un identificador de un objeto de tal modo que si dos objetos tienen el mismo identificador, entonces son el mismo&nbsp;objeto.</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">a</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="nb">print</span><span class="p">(</span><span class="nb">id</span><span class="p">(</span><span class="n">a</span><span class="p">))</span>
<span class="mi">192021604</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">a</span> <span class="o">+=</span> <span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="nb">print</span><span class="p">(</span><span class="nb">id</span><span class="p">(</span><span class="n">a</span><span class="p">))</span>
<span class="mi">189519828</span>
</code></pre></div>

<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="nb">print</span><span class="p">(</span><span class="nb">id</span><span class="p">(</span><span class="n">a</span><span class="p">))</span>
<span class="mi">189780876</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">a</span> <span class="o">+=</span> <span class="p">[</span><span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="nb">print</span><span class="p">(</span><span class="nb">id</span><span class="p">(</span><span class="n">a</span><span class="p">))</span>
<span class="mi">189780876</span>
</code></pre></div>

<p>En la versi&#243;n tupla, se ha creado una nueva tupla para realizar la operaci&#243;n, mientras que en la versi&#243;n lista se ha usado la misma lista, modific&#225;ndose con el resultado. Si cambiamos el operador <code>+=</code> por una versi&#243;n m&#225;s expl&#237;cita tal vez se vea&nbsp;mejor:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">a</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">a</span> <span class="o">=</span> <span class="n">a</span> <span class="o">+</span> <span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">)</span>
</code></pre></div>

<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">a</span><span class="o">.</span><span class="n">extend</span><span class="p">([</span><span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">])</span>
</code></pre></div>

<p>Al operar con tuplas, los operandos no cambian de valor, cre&#225;ndose una nueva tupla como resultado de la operaci&#243;n. Podr&#237;amos sustituir toda la operaci&#243;n por el resultado final y el c&#243;digo funcionar&#237;a igual. En el caso de las listas, la lista se modifica <em>&#8220;in situ&#8221;</em> durante la operaci&#243;n. En estos casos, cambiar la expresi&#243;n por el resultado final no garantiza que el programa funcione igual. Se necesita pasar por todos y cada uno de los estados intermedios para asegurar que todo funcione&nbsp;igual.</p>
<p>Esta propiedad de poder cambiar una expresi&#243;n por su resultado final es conocida por <a href="http://en.wikipedia.org/wiki/Referential_transparency_(computer_science)" title="Referential Transparency">Transparencia referencial</a> en programaci&#243;n funcional. Por lo general, los tipos inmutables se adec&#250;an mejor a operaciones de c&#225;lculo donde el resultado final depende &#250;nicamente de los argumentos de entrada. Por otro lado, los tipos mutables son &#250;tiles para salvaguardar estados intermedios necesarios para la toma de decisiones durante la ejecuci&#243;n de un&nbsp;programa.</p>
<p>Por lo general, se saber elegir un tipo mutable o su hom&#243;logo inmutable es todo un arte. Ante la duda, los tipos inmutables son m&#225;s f&#225;ciles de rastrear. As&#237; mismo, veremos en pr&#243;ximos art&#237;culos que los tipos inmutables ayudan bastante en programaci&#243;n concurrente, por si est&#225;s pensando en programaci&#243;n&nbsp;multiproceso.</p>
<h2>Ejemplos de tipos&nbsp;propios</h2>
<p>La mutabilidad e inmutabilidad va m&#225;s all&#225; de los tipos est&#225;ndar de python. Nosotros mismos podemos hacer nuestras propias clases mutables o inmutables, seg&#250;n nuestras&nbsp;necesidades.</p>
<p>Pongamos que creamos una clase <code>Point</code> para definir puntos, junto con unas sencillas operaciones para sumar, restar y desplazar. Nuestra idea es poder usar estos objetos en expresiones, por lo que es pr&#225;ctica com&#250;n que toda operaci&#243;n devuelva el resultado como un punto para seguir encadenando&nbsp;operaciones.</p>
<p>Una versi&#243;n <em>&#8220;mutable&#8221;</em> del objeto ser&#237;a&nbsp;as&#237;:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">PointMutable</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">x</span><span class="o">=</span><span class="n">x</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">y</span><span class="o">=</span><span class="n">y</span>

    <span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="s2">&quot;&lt;Point(</span><span class="si">%d</span><span class="s2">,</span><span class="si">%d</span><span class="s2">)&gt;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">y</span><span class="p">)</span>

    <span class="k">def</span> <span class="fm">__sub__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">-=</span> <span class="n">other</span><span class="o">.</span><span class="n">x</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">-=</span> <span class="n">other</span><span class="o">.</span><span class="n">y</span>
        <span class="k">return</span> <span class="bp">self</span>

    <span class="k">def</span> <span class="fm">__add__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">+=</span> <span class="n">other</span><span class="o">.</span><span class="n">x</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">+=</span> <span class="n">other</span><span class="o">.</span><span class="n">y</span>
        <span class="k">return</span> <span class="bp">self</span>

    <span class="k">def</span> <span class="nf">move</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dx</span><span class="p">,</span> <span class="n">dy</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">+=</span> <span class="n">dx</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">+=</span> <span class="n">dy</span>
        <span class="k">return</span> <span class="bp">self</span>
</code></pre></div>

<p>En todas las operaciones, operamos el objeto consigo mismo y lo retornamos como resultados. Si probamos, vemos que no funciona tal como se&nbsp;esperaba:</p>
<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">p1</span><span class="o">=</span><span class="n">PointMutable</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">p2</span><span class="o">=</span><span class="n">PointMutable</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="nb">print</span> <span class="n">p1</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="o">-</span> <span class="p">(</span><span class="n">p1</span> <span class="o">+</span> <span class="n">p2</span><span class="p">)</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="o">&lt;</span><span class="n">Point</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">)</span><span class="o">&gt;</span>
</code></pre></div>

<p>Devuelve <code>&lt;Point&lt;0,0&gt;</code> independientemente de los valores iniciales y de los desplazamientos que demos. Al ser nuestro objeto mutable, cada operaci&#243;n lo va cambiando. Al final, toda la expresi&#243;n se reduce a una simple resta <code>p1-p1</code>, que ser&#237;a la &#250;ltima operaci&#243;n y que da siempre <code>&lt;Point(0,0)&gt;</code>. No parece que sea el resultado&nbsp;esperado.</p>
<p>Debemos adoptar una t&#225;ctica m&#225;s defensiva: el objeto nunca debe cambiar durante el c&#225;lculo. Como resultado de cada operaci&#243;n deberemos devolver una nueva instancia y que el estado de &#233;sta, o sea, sus atributos, no se alteren a lo largo del&nbsp;c&#225;lculo:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">PointInmutable</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">x</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">y</span>

    <span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="s2">&quot;&lt;Point(</span><span class="si">%d</span><span class="s2">,</span><span class="si">%d</span><span class="s2">)&gt;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">y</span><span class="p">)</span>

    <span class="k">def</span> <span class="fm">__sub__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">PointInmutable</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">-</span> <span class="n">other</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">-</span> <span class="n">other</span><span class="o">.</span><span class="n">y</span><span class="p">)</span>

    <span class="k">def</span> <span class="fm">__add__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">PointInmutable</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">+</span> <span class="n">other</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">+</span> <span class="n">other</span><span class="o">.</span><span class="n">y</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">move</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dx</span><span class="p">,</span> <span class="n">dy</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">PointInmutable</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">+</span> <span class="n">dx</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">y</span> <span class="o">+</span> <span class="n">dy</span><span class="p">)</span>
</code></pre></div>

<div class="highlight"><pre><span></span><code><span class="o">&gt;&gt;&gt;</span> <span class="n">p1</span><span class="o">=</span><span class="n">PointInmutable</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">p2</span><span class="o">=</span><span class="n">PointInmutable</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="nb">print</span> <span class="n">p1</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="o">-</span> <span class="p">(</span><span class="n">p1</span> <span class="o">+</span> <span class="n">p2</span><span class="p">)</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="o">&lt;</span><span class="n">Point</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span><span class="o">&gt;</span>
</code></pre></div>

<p>Siendo perfeccionistas, deber&#237;amos blindar mejor los atributos de la clase para hacerlos de <em>s&#243;lo lectura</em> mediante <code>properties</code>.</p>
<p>En este ejemplo hemos podido ver los resultados imprevisibles que podemos tener si abusamos de la mutabilidad. Estos problemas se ven incrementados si hubiera varios hilos de ejecuci&#243;n y cada hilo estuviera modificando las mismas variables comunes. Lamentablemente, es un caso bastante com&#250;n debido a una mala previsi&#243;n a la hora de iniciar un proyecto de desarrollo. Pero &#233;sto lo veremos en un pr&#243;ximo&nbsp;art&#237;culo.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">June 2018 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">18 07 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together news This has been another productive month for CIDER and ClojureScript. There is one more month left in this funding cycle and then we&rsquo;re starting our next round.
We recently surveyed our members to see what they wanted us to fund. Error messages, documentation, developer experience, and IDE support featured highly. If you maintain a Clojure project that is important to some or all of the Clojure community, especially in one of these areas please apply for funding.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/97-production-ready.png" alt="Production Ready">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Production Ready</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">17 07 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/97-production-ready.png" alt="Production Ready" title="Production Ready" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Instapaper is going independent</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Instapaper</a> <span class="article__date">16 07 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Today, we’re announcing that Pinterest has entered into an agreement to transfer ownership of Instapaper to Instant Paper, Inc., a new company owned and operated by the same people who’ve been working on Instapaper since it was <a href="https://techcrunch.com/2013/04/25/betaworks-instapaper/">sold to betaworks by Marco Arment</a> in 2013. The ownership transfer will occur after a 21 day waiting period designed to give our users fair notice about the change of control with respect to their personal information.</p><p><b></b></p><p>We want to emphasize that not much is changing for the Instapaper product outside the new ownership. The product will continue to be built and maintained by the same people who’ve been working on Instapaper for the past five years. We plan to continue offering a robust service that focuses on readers and the reading experience for the foreseeable future.</p><p><b></b></p><p>Lastly, we want to express our deepest gratitude to Pinterest for being such great stewards of the product over the past two years. With their support, we rebuilt search, introduced an extension for Firefox, made a variety of optimizations for the latest mobile operating systems and more. Our focus is providing a great reading application to our users, we appreciated the opportunity to do that at Pinterest, and are excited to continue our work.</p><p><b></b></p><p>If you have any questions, comments or concerns please let us know by sending an email to <a href="mailto:support@help.instapaper.com">support@help.instapaper.com</a> or replying directly to this email. </p><p>– Instapaper Team</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://dqpzb8kjkmk2r.cloudfront.net/img/blog/2018/07/rw-podcast-69.jpg" alt="Programador Web Valencia: Charla sobre Python">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Programador Web Valencia: Charla sobre Python</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">14 07 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img alt="Grabando" class="medium" src="https://dqpzb8kjkmk2r.cloudfront.net/img/blog/2018/07/rw-podcast-69.jpg" /></p>

<p>En el episodio 69 de Rep&#250;blica Web, Podcast dirigido y escrito por <strong>Javier Archeni</strong> (@javierarcheni), he tenido el placer de ser invitado para mantener una <strong>tertulia animada sobre Python</strong>. Entre muchos temas se tocaron:</p>

<ul>
  <li>Libros interesantes.</li>
  <li>El origen del lenguaje.</li>
  <li>Virtudes.</li>
  <li>Consejos para novatos.</li>
  <li>Actualidad sobre el lenguaje.</li>
  <li>Frameworks como Django o Flask.</li>
  <li>Usos acad&#233;micos y empresariales.</li>
</ul>

<p>Si es un lenguaje que siempre te ha llamado la atenci&#243;n y sientes <strong>curiosidad por ver sus posibilidades</strong>, escucha el episodio con mucha atenci&#243;n. <strong>No te dejar&#225; indiferente</strong>. Y no olvides dejar un comentario.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q3 2018 Survey Results and Call For Proposals</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">12 07 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        We have recently run our third survey on our members to better understand them and their needs. We&rsquo;re publishing these results so that they can see the aggregate results, and to give open source projects more information when applying for the Q3 2018 Clojurists Together funding round (closing 20 July).
Survey Responses There were 49 respondents to the survey, down from 52 in the last survey. The highlights are presented below.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/96-zenos-progress.png" alt="Zeno&#39;s Progress">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Zeno&#39;s Progress</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">10 07 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/96-zenos-progress.png" alt="Zeno's Progress" title="Zeno's Progress" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Learning Rust 02: an ls clone</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">08 07 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I&rsquo;m learning Rust, and documenting the process. These posts are my notes - they&rsquo;re not guaranteed to be useful, interesting or correct!
In this post, I&rsquo;m building an ls clone. It&rsquo;s pretty similar to the last post&rsquo;s pwd clone. It&rsquo;s called rls.
Code use std::env; use std::fs; use std::process; fn main() { let args: Vec&lt;String&gt; = env::args().collect(); if args.len() != 2 { usage(); } let directory = &amp;args[1]; let paths = fs::read_dir(directory).
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://dqpzb8kjkmk2r.cloudfront.net/img/blog/2017/04/python-logo.jpg" alt="Programador Web Valencia: Qu&amp;#233; aporta Python para el desarrollo web">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Programador Web Valencia: Qu&amp;#233; aporta Python para el desarrollo web</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">04 07 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img alt="Python logo" src="https://dqpzb8kjkmk2r.cloudfront.net/img/blog/2017/04/python-logo.jpg" /></p>

<p><strong>Python es un lenguaje sencillo y r&#225;pido</strong> de aprender. Su sintaxis es parecida a <strong>escribir cualquier texto</strong> en ingl&#233;s, pero con la potencia de sus principales competidores en el BackEnd.</p>

<p>Es un <strong>placer de leer y redactar</strong>. Python predica que un c&#243;digo debe ser escrito por humanos para humanos. Despu&#233;s de todo lo que programas va a ser le&#237;do por ti y por el resto del equipo. <strong>Si escribes para m&#225;quinas, solo te entender&#225;n m&#225;quinas</strong>.</p>

<p>Adem&#225;s viene con <strong>&#8220;Pilas incluidas&#8221;</strong>. Eso quiere decir que posee su <strong>propio gestor de paquetes</strong>, sin necesidad de instalar aplicaciones externas. Simplificando tareas de instalaci&#243;n o actualizaci&#243;n.</p>

<p>Otro punto a su favor es que <strong>no necesita un ecosistema para ejecutarse</strong>, como puede ser Xampp, Vangrant, Docker&#8230;  <strong>Python solo requieres Python</strong>. Lanzando un comando en el terminal estar&#225; ejecut&#225;ndose su propio servidor Web, consiguiendo que su puesta en producci&#243;n sea sorprendentemente r&#225;pida.</p>

<p>Y por si fuera poco, es el <strong>segundo lenguajes que mejor esta pagado</strong> por las empresas. Por detr&#225;s de Ruby.</p>

<h2 id="donde-naci&#243;-python">&#191;Donde naci&#243; Python?</h2>

<p>En una navidad de <strong>1989</strong> un programador fue enviado a casa. Sus oficinas iban a estar cerradas durante unas semanas. Esta persona de <strong>33 a&#241;os</strong>, llamada <strong>Guido van Rossum</strong>, se encontr&#243; que solo ten&#237;a un solo aparato para entretenerse hasta que acabaran las navidades: un ordenador. Para <strong>matar el rato decidi&#243; distraerse programando un interprete</strong> para un nuevo lenguaje de programaci&#243;n de scripting que hab&#237;a estado teorizando en sus ratos libres. Un <strong>heredero de ABC</strong>. Sin mucho inter&#233;s, casi por formalidad, lo bautiz&#243; con un nombre sencillo. &#201;l <strong>era muy fan de los Monty Python</strong>, por lo que lo llam&#243;: Python.</p>

<p>Y aqu&#237; es donde naci&#243; uno de los lenguajes m&#225;s expresivos y <strong>buque insignia del C&#243;digo Abierto</strong>.</p>

<h2 id="frameworks-web">Frameworks Web</h2>

<p>Entre sus numerosos y fant&#225;sticos Frameworks, nos podemos encontrar unas bestias: <strong>Django</strong> y <strong>Flask</strong> (que no confundir que el zombie Adobe Flash).</p>

<p><strong>Django ser&#237;a lo m&#225;s cercano a Laravel en PHP o Ruby on Rails para Ruby</strong>. Un marco de trabajo completo y eficiente para desarrollar Aplicaciones Web de una gran complejidad con un m&#237;nimo esfuerzo. Casi cualquier cosa que necesites posiblemente estar&#225; integrado.</p>

<p>Para <strong>desarrollos altamente personalizados</strong> o con unos tiempos cortos, nos encontramos a <strong>Flask</strong>. Autodenominado microframework, pero con funcionalidades sencillas e inteligentes para construir cualquier sitio que se te pase por la cabeza.</p>

<p><strong>Uno no sustituye al otro</strong>. Merece la pena experimentarlos y ver sus diferentes enfoques.</p>

<h2 id="comunidad">Comunidad</h2>

<p>La comunidad de Python <strong>es una de las m&#225;s sanas y activas</strong> que te podr&#225;s encontrar. Los usuarios organizan espont&#225;neamente <strong>charlas mensuales</strong> y talleres gratuitos en torno al lenguaje. Anualmente se celebra diversos congresos. El m&#225;s popular se conoce como <strong>PyCon</strong> y este a&#241;o en Espa&#241;a se celebra la 6&#170; edici&#243;n en M&#225;laga entre el 5 y 7 de Octubre. Pero tambi&#233;n hay grupos especiales como las <strong>Django Girls</strong>, un <strong>grupo femenino para animar a que otras mujeres</strong> den el paso de aprender a programar.</p>

<p>Su gran apoyo por la comunidad se debe en parte por la <strong>gran variedad de profesiones</strong> que usan Python, como puede ser: el <strong>an&#225;lisis de datos</strong>, la <strong>inteligencia artificial</strong>, la creaci&#243;n de aplicaciones para <strong>escritorio</strong>, desarrollo de <strong>micro dispositivos</strong>, etc&#8230; Las librer&#237;as no dejan de crecer y suelen estar cuidadosamente documentadas, promoviendo un entorno agradable.</p>

<h2 id="competidores">Competidores</h2>

<p>En cuanto a la competencia, es amplia y con mucha experiencia. Hecho que no es malo de por s&#237;. Los m&#225;s destacables son: <strong>PHP, Ruby, Node.js, Java y Go</strong>. Aunque Ruby podr&#237;a considerarse un primo hermano por sus similitudes. Ambos se encuentras muy equilibrados, aunque Python no deja de subir a&#241;o tras a&#241;o entre los lenguajes m&#225;s utilizados.</p>

<h2 id="recomendaciones-para-el-primerizo">Recomendaciones para el primerizo</h2>

<p>Si quieres iniciarte en este lenguaje interpretado, y en concreto en el universo Web, te aconsejo que le des una <strong>oportunidad a Flask</strong>. Puedes crear peque&#241;os proyectos como una web sencilla, un REST API o un panel administrativo. Poco despu&#233;s ser&#237;a aconsejable dar el <strong>salto a Django</strong>, y vivir en tus propias carnes una de las experiencias m&#225;s completas de Python. Sum&#233;rgete en proyectos con una gran densidad de trabajo, como puede ser un blog, un e-commerce o una red social. Descubre cada uno de sus detalles, visita los ejemplos de la documentaci&#243;n, dise&#241;a bases de datos relacionales de gran solidez&#8230; no te decepcionar&#225; el ORM de Django (gestor para realizar consultas en la base de datos) ni su motor de plantillas.</p>

<h2 id="futuro">Futuro</h2>

<p><strong>Las previsiones son muy buenas</strong>. Las versiones son constantes y compatibles con todas las plataforma. Su creador, Guido van Rossum, es denominado como <strong>&#8220;Benevolente dictador vitalicio&#8221;</strong> por dejar que la comunidad tomen las decisiones. Tan solo dej&#243; <strong>4 directrices</strong>:</p>

<ul>
  <li>Python deber&#237;a ser <strong>f&#225;cil</strong>, intuitivo y tan potente como sus principales competidores.</li>
  <li>El proyecto ser&#237;a de <strong>C&#243;digo Abierto</strong> para que cualquiera pudiera colaborar.</li>
  <li>El c&#243;digo escrito en Python ser&#237;a tan <strong>comprensible como cualquier texto en ingl&#233;s</strong>.</li>
  <li>Python deber&#237;a ser <strong>apto para las actividades diarias</strong> permitiendo la construcci&#243;n de prototipos en poco tiempo.</li>
</ul>

<p>Y por ahora la comunidad <strong>lo cumple todo</strong>.</p>

<p>Ahora ya conoces los riesgos y beneficios, &#191;te atreves a cruzar la frontera?</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">La libertad de desarrollar...: Contar palabras de un texto usando Spark con  PySpark</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">03 07 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>En el art&#237;culo anterior se explic&#243; el <a href="https://blog.crespo.org.ve/2018/07/como-correr-apache-spark-desde-una.html">procedimiento de instalaci&#243;n de Spark usando Docker</a>.&nbsp; En este art&#237;culo se usar&#225; un texto tomado de la p&#225;gina de la ONU, de ah&#237; se extrae las l&#237;neas y se cuentan las palabras.<br /><br />A continuaci&#243;n el texto que se va a utilizar (lo pueden bajar desde el repositorio <a href="https://gitlab.com/mangoosta/articulos-cienciasdedatos/blob/master/datos/declaracion_onut.text">gitlab</a>):<br /><br /><b><i><span style="color: blue;">1942: La Declaraci&#243;n de las Naciones Unidas</span></i></b><br /><b><i><span style="color: blue;">Representantes de 26 Estados que lucharon contra las potencias del Eje Roma-Berl&#237;n-Tokio manifestaron su apoyo a la Carta del Atl&#225;ntico mediante su firma de la &#171; Declaraci&#243;n de las Naciones Unidas &#187;. En este trascendental documento, los signatarios se compromet&#237;an a poner su m&#225;ximo empe&#241;o en la guerra y a no firmar una paz por separado.&nbsp;</span></i></b><br /><br /><br /><b><i><span style="color: blue;">Declaraci&#243;n de las Naciones Unidas prometiendo "emplear todos sus recursos, militares o econ&#243;micos" en "la lucha por la victoria sobre el hitlerismo".</span></i></b><br /><b><i><span style="color: blue;">El d&#237;a de a&#241;o nuevo de 1942, el se&#241;or presidente Roosevelt y los se&#241;ores Winston Churchill, Maxim Litvinov, de la Uni&#243;n Sovi&#233;tica, y T. V. Soong, de China, firmaron un breve documento que luego se conocer&#237;a como la Declaraci&#243;n de las Naciones Unidas. Al d&#237;a siguiente se sumaron los representantes de otras 22 naciones m&#225;s. En este trascendental documento, los signatarios se compromet&#237;an a poner su m&#225;ximo empe&#241;o en la guerra y a no firmar una paz por separado.</span></i></b><br /><br /><b><span style="color: blue;"><i>La Declaraci&#243;n de las Naciones Unidas</i></span></b><br /><b><span style="color: blue;"><i>La alianza completa a que se lleg&#243; en esta forma concordaba con los principios enunciados en la Carta del Atl&#225;ntico, y la primera cl&#225;usula de la declaraci&#243;n de las Naciones Unidas reza que los pa&#237;ses signatarios&nbsp;</i></span></b><br /><b><span style="color: blue;"><i><br /></i></span></b><b><span style="color: blue;"><i>&#171; . . . han suscrito un programa com&#250;n de prop&#243;sitos y principios enunciados en la declaraci&#243;n conjunta del presidente de los Estados Unidos de Am&#233;rica y del primer ministro del Reino Unido de la Gran Breta&#241;a e Irlanda del Norte, fechada el 14 de agosto de 1941, y conocida como la Carta del Atl&#225;ntico. &#187;.</i></span></b><br /><b><span style="color: blue;"><i><br /></i></span></b><b><span style="color: blue;"><i>Cuando tres a&#241;os despu&#233;s se iniciaban los preparativos para la conferencia de San Francisco, &#250;nicamente se invit&#243; a participar a aquellos estados que, en marzo de 1945, hab&#237;an declarado la guerra a Alemania y al Jap&#243;n y que hab&#237;an firmado la Declaraci&#243;n de las Naciones Unidas.</i></span></b><br /><b><span style="color: blue;"><i><br /></i></span></b><b><span style="color: blue;"><i>Signatarios Originales de la Declaraci&#243;n de la ONU</i></span></b><br /><b><span style="color: blue;"><i>Los 26 signatarios originales fueron: Los Estados Unidos de Am&#233;rica, el Reino Unido de la Gran Breta&#241;a e Irlanda del Norte, la Uni&#243;n de Rep&#250;blicas Socialistas Sovi&#233;ticas, China, Australia, B&#233;lgica, Canad&#225;, Costa Rica, Checoeslovaquia, El Salvador, Grecia, Guatemala, Hait&#237;, Honduras, India, Luxemburgo, Nicaragua, Noruega, Nueva Zelandia, Pa&#237;ses Bajos, Panam&#225;, Polonia, Rep&#250;blica Dominicana, Uni&#243;n Sudafricana, Yugoeslavia .</i></span></b><br /><b><span style="color: blue;"><i><br /></i></span></b><b><span style="color: blue;"><i>Los firmantes posteriores</i></span></b><br /><b><span style="color: blue;"><i>M&#225;s tarde se adhirieron a la Declaraci&#243;n los siguientes pa&#237;ses (en el orden de las firmas): M&#233;xico, Colombia, Iraq, Ir&#225;n, Liberia, Paraguay, Chile, Uruguay, Egipto, Siria, Francia, Filipinas, Brasil, Bolivia, Etiop&#237;a, Ecuador, Per&#250;, Venezuela, Turqu&#237;a, Arabia Saudita, L&#237;bano.</i></span></b><br /><br /><br /><br />A continuaci&#243;n se muestra la ejecuci&#243;n del c&#243;digo (si quieren bajar el archivo jupyter notebook lo pueden descargar desde <a href="https://gitlab.com/mangoosta/articulos-cienciasdedatos/blob/master/spark1.ipynb">gitlab</a>):<br /><br />In&nbsp;[1]:<br /><div class="border-box-sizing" id="notebook" tabindex="-1"><div class="container" id="notebook-container"><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Se importa SparkContext y SparkConf</span><br /><span class="kn">from</span> <span class="nn">pyspark</span> <span class="k">import</span> <span class="n">SparkContext</span><span class="p">,</span> <span class="n">SparkConf</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[2]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Se crea la instancia de la configuraci&#243;n con el nombre de la aplicaci&#243;n contador</span><br /><span class="n">conf1</span> <span class="o">=</span> <span class="n">SparkConf</span><span class="p">()</span><span class="o">.</span><span class="n">setAppName</span><span class="p">(</span><span class="s2">"contador"</span><span class="p">)</span><span class="o">.</span><span class="n">setMaster</span><span class="p">(</span><span class="s2">"local[3]"</span><span class="p">)</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[3]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Se crea el contexto pasando la instancia de la configuraci&#243;n</span><br /><span class="n">sc</span> <span class="o">=</span> <span class="n">SparkContext</span><span class="p">(</span><span class="n">conf</span> <span class="o">=</span> <span class="n">conf1</span><span class="p">)</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[4]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Se extrae las l&#237;neas del texto </span><br /><span class="n">lineas</span> <span class="o">=</span> <span class="n">sc</span><span class="o">.</span><span class="n">textFile</span><span class="p">(</span><span class="s2">"data/declaracion_onut.text"</span><span class="p">)</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[6]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Se extrae las palabras del texto y se cuentan</span><br /><span class="n">contarPalabras</span> <span class="o">=</span> <span class="n">lineas</span><span class="o">.</span><span class="n">flatMap</span><span class="p">(</span><span class="k">lambda</span> <span class="n">linea</span><span class="p">:</span> <span class="n">linea</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">" "</span><span class="p">))</span><span class="o">.</span><span class="n">countByValue</span><span class="p">()</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[7]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Se muestra las palabras con la cantidad de veces que tiene su aparici&#243;n</span><br /><span class="k">for</span> <span class="n">palabra</span><span class="p">,</span> <span class="n">contador</span> <span class="ow">in</span> <span class="n">contarPalabras</span><span class="o">.</span><span class="n">items</span><span class="p">():</span><br />    <span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="si">{}</span><span class="s2"> : </span><span class="si">{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">palabra</span><span class="p">,</span> <span class="n">contador</span><span class="p">))</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_subarea output_stream output_stdout output_text"><pre>1942: : 1<br />La : 3<br />Declaraci&#243;n : 8<br />de : 29<br />las : 9<br />Naciones : 7<br />Unidas : 5<br />Representantes : 1<br />26 : 2<br />Estados : 3<br />que : 5<br />lucharon : 1<br />contra : 1<br />potencias : 1<br />del : 9<br />Eje : 1<br />Roma-Berl&#237;n-Tokio : 1<br />manifestaron : 1<br />su : 4<br />apoyo : 1<br />a : 10<br />la : 21<br />Carta : 3<br />Atl&#225;ntico : 1<br />mediante : 1<br />firma : 1<br />&#171; : 2<br />&#187;. : 2<br />En : 2<br />este : 2<br />trascendental : 2<br />documento, : 2<br />los : 9<br />signatarios : 4<br />se : 8<br />compromet&#237;an : 2<br />poner : 2<br />m&#225;ximo : 2<br />empe&#241;o : 2<br />en : 7<br />guerra : 3<br />y : 10<br />no : 2<br />firmar : 2<br />una : 2<br />paz : 2<br />por : 3<br />separado. : 2<br /> : 9<br />prometiendo : 1<br />"emplear : 1<br />todos : 1<br />sus : 1<br />recursos, : 1<br />militares : 1<br />o : 1<br />econ&#243;micos" : 1<br />"la : 1<br />lucha : 1<br />victoria : 1<br />sobre : 1<br />el : 5<br />hitlerismo". : 1<br />El : 2<br />d&#237;a : 2<br />a&#241;o : 1<br />nuevo : 1<br />1942, : 1<br />se&#241;or : 1<br />presidente : 2<br />Roosevelt : 1<br />se&#241;ores : 1<br />Winston : 1<br />Churchill, : 1<br />Maxim : 1<br />Litvinov, : 1<br />Uni&#243;n : 3<br />Sovi&#233;tica, : 1<br />T. : 1<br />V. : 1<br />Soong, : 1<br />China, : 2<br />firmaron : 1<br />un : 2<br />breve : 1<br />documento : 1<br />luego : 1<br />conocer&#237;a : 1<br />como : 2<br />Unidas. : 2<br />Al : 1<br />siguiente : 1<br />sumaron : 1<br />representantes : 1<br />otras : 1<br />22 : 1<br />naciones : 1<br />m&#225;s. : 1<br />alianza : 1<br />completa : 1<br />lleg&#243; : 1<br />esta : 1<br />forma : 1<br />concordaba : 1<br />con : 1<br />principios : 2<br />enunciados : 2<br />Atl&#225;ntico, : 1<br />primera : 1<br />cl&#225;usula : 1<br />declaraci&#243;n : 2<br />reza : 1<br />pa&#237;ses : 2<br />. : 4<br />han : 1<br />suscrito : 1<br />programa : 1<br />com&#250;n : 1<br />prop&#243;sitos : 1<br />conjunta : 1<br />Unidos : 2<br />Am&#233;rica : 1<br />primer : 1<br />ministro : 1<br />Reino : 2<br />Unido : 2<br />Gran : 2<br />Breta&#241;a : 2<br />e : 2<br />Irlanda : 2<br />Norte, : 2<br />fechada : 1<br />14 : 1<br />agosto : 1<br />1941, : 1<br />conocida : 1<br />Atl&#225;ntico. : 1<br />Cuando : 1<br />tres : 1<br />a&#241;os : 1<br />despu&#233;s : 1<br />iniciaban : 1<br />preparativos : 1<br />para : 1<br />conferencia : 1<br />San : 1<br />Francisco, : 1<br />&#250;nicamente : 1<br />invit&#243; : 1<br />participar : 1<br />aquellos : 1<br />estados : 1<br />que, : 1<br />marzo : 1<br />1945, : 1<br />hab&#237;an : 2<br />declarado : 1<br />Alemania : 1<br />al : 1<br />Jap&#243;n : 1<br />firmado : 1<br />Signatarios : 1<br />Originales : 1<br />ONU : 1<br />Los : 3<br />originales : 1<br />fueron: : 1<br />Am&#233;rica, : 1<br />Rep&#250;blicas : 1<br />Socialistas : 1<br />Sovi&#233;ticas, : 1<br />Australia, : 1<br />B&#233;lgica, : 1<br />Canad&#225;, : 1<br />Costa : 1<br />Rica, : 1<br />Checoeslovaquia, : 1<br />Salvador, : 1<br />Grecia, : 1<br />Guatemala, : 1<br />Hait&#237;, : 1<br />Honduras, : 1<br />India, : 1<br />Luxemburgo, : 1<br />Nicaragua, : 1<br />Noruega, : 1<br />Nueva : 1<br />Zelandia, : 1<br />Pa&#237;ses : 1<br />Bajos, : 1<br />Panam&#225;, : 1<br />Polonia, : 1<br />Rep&#250;blica : 1<br />Dominicana, : 1<br />Sudafricana, : 1<br />Yugoeslavia : 1<br />firmantes : 1<br />posteriores : 1<br />M&#225;s : 1<br />tarde : 1<br />adhirieron : 1<br />siguientes : 1<br />(en : 1<br />orden : 1<br />firmas): : 1<br />M&#233;xico, : 1<br />Colombia, : 1<br />Iraq, : 1<br />Ir&#225;n, : 1<br />Liberia, : 1<br />Paraguay, : 1<br />Chile, : 1<br />Uruguay, : 1<br />Egipto, : 1<br />Siria, : 1<br />Francia, : 1<br />Filipinas, : 1<br />Brasil, : 1<br />Bolivia, : 1<br />Etiop&#237;a, : 1<br />Ecuador, : 1<br />Per&#250;, : 1<br />Venezuela, : 1<br />Turqu&#237;a, : 1<br />Arabia : 1<br />Saudita, : 1<br />L&#237;bano. : 1<br /></pre></div></div></div></div></div></div></div><br /><br /><br /><br /><br /><br />Como se puede ver, se logra obtener la cantidad de veces que aparecen las palabras en el texto.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/95-unfinished-work.png" alt="Unfinished Work">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Unfinished Work</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">03 07 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/95-unfinished-work.png" alt="Unfinished Work" title="Unfinished Work" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">These Months in Common Lisp: Q2 2018</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">02 07 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p><a href="https://lisp-journey.gitlab.io/blog/these-months-in-common-lisp-q1-2018/">Q1 2018</a></p>

<h1 id="documentation">Documentation</h1>

<ul>
<li><a href="https://github.com/norvig/paip-lisp/blob/master/PAIP-safari.epub">Paradigms of Artificial Intelligence Programming epub</a></li>
<li><a href="https://lispcookbook.github.io/cl-cookbook/databases.html">Models and Databases, with Mito and SxQL - the Common Lisp Cookbook</a></li>
<li><a href="https://github.com/GustavBertram/awesome-common-lisp-learning-list">Awesome Common Lisp learning list</a></li>
</ul>

<h1 id="announcements">Announcements</h1>

<ul>
<li><a href="https://www.european-lisp-symposium.org/static/proceedings/2018.pdf">ELS2018 proceedings (PDF)</a></li>
<li><a href="http://sbcl.org/all-news.html?1.4.6#1.4.6">SBCL 1.4.6 released</a></li>
<li><a href="http://sbcl.org/all-news.html?1.4.7">SBCL 1.4.7 Released</a></li>
<li><a href="http://www.lispworks.com/downloads/patch-selection.html">LispWorks 7.1.1 - Patches</a></li>
<li><a href="http://christophe.rhodes.io/notes/blog/posts/2018/sbcl_method-combination_fixes/">SBCL method-combination fixes</a></li>
<li><a href="http://christophe.rhodes.io/notes/blog/posts/2018/sbcl_method_tracing/">SBCL method tracing</a></li>
<li><a href="https://www.bountysource.com/issues/47099106-use-microsoft-tools-to-build-lisp-kernel">$500 Bounty on Clozure/ccl</a></li>
</ul>

<h1 id="jobs">Jobs</h1>

<ul>
<li><a href="https://lispjobs.wordpress.com/2018/04/16/junior-lisp-developer-ravenpack-marbella-spain/">Junior Lisp Developer, RavenPack, Marbella, Spain</a></li>
<li><a href="http://3eeu.talentfinder.be/en/vacature/30101/lisp-developer">3E : Lisp Developer - development, maintenance, design and unit testing of SynaptiQ’s real-time aggregation and alerting engine that processes time-series and events. This data engine is Common Lisp based.</a></li>
<li><a href="https://www.indeed.com/viewjob?t=lisp+engineer+ai+natural+language+reasoning&amp;jk=d14c7726839e6b01&amp;_ga=2.203861651.2000107742.1525918694-1699101565.1509521844">Lisp Engineer - AI (Natural Language Reasoning)</a></li>
</ul>

<h1 id="projects">Projects</h1>

<p><a href="http://blog.quicklisp.org/2018/03/quicklisp-dist-update-for-march-2018.html">Quicklisp dist update, march 2018</a></p>

<ul>
<li><a href="https://github.com/bradleyjensen/shcl">SHCL: An Unholy Union of POSIX Shell and Common Lisp</a> (<a href="https://www.reddit.com/r/lisp/comments/8kpbcz/shcl_an_unholy_union_of_posix_shell_and_common/">reddit</a>)</li>
<li><a href="https://github.com/inaimathi/cl-notebook/">cl-notebook</a></li>
<li><a href="https://gitlab.com/duncan-bayne/heroku-buildpack-common-lisp">Heroku buildpack for Common Lisp</a></li>
<li><a href="https://github.com/xh4/cube">Kubernetes Client Library for Common Lisp</a></li>
<li><a href="http://blog.klipse.tech/lisp/2018/05/07/blog-common-lisp.html">Interactive Common Lisp code snippets in any web page</a></li>
<li><a href="https://github.com/fukamachi/rove/">rove</a> - small testing framework (Fukamachi&rsquo;s successor to Prove)</li>
<li><a href="http://blog.quicklisp.org/2018/03/quicklisp-dist-update-for-march-2018.html">can</a> - a role-based access right control library</li>
<li><a href="https://github.com/inaimathi/house/">house</a> - custom asynchronous HTTP server for the Deal project.</li>
<li><a href="https://github.com/Shinmera/oxenfurt">oxenfurt</a> - A Common Lisp client library for the Oxford dictionary API.</li>
<li><a href="https://github.com/tarballs-are-good/algebraic-data-library/">algebraic-data-library</a></li>
<li><a href="https://github.com/plkrueger/CommonLispFred">Lisp Interface to Federal Reserve Economic Data (FRED®)</a></li>
<li><a href="https://github.com/reddit-archive/reddit1.0">reddit1.0 source code</a> (<a href="https://www.reddit.com/r/Common_Lisp/comments/886yeu/reddit10/">comments</a>), then <a href="https://www.reddit.com/r/Common_Lisp/comments/8ata3c/reddit_code_runs_on_sbcl/">Reddit&rsquo;s code runs on SBCL</a>. See also <a href="https://www.reddit.com/r/programming/comments/883vzs/old_reddit_source_code/">reddit</a>.</li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/8f6wez/petalisp_elegant_high_performance_computing/">Petalisp</a>: Elegant High Performance Computing</li>
<li><a href="https://code-golf.io/">Code Golf Site with Common Lisp Support!</a></li>
<li><a href="https://github.com/vseloved/wiki-lang-detect">vseloved/wiki-lang-detect</a>: Text language identification using Wikipedia data</li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/8gzm4w/ppath_a_path_manipulation_library/">ppath, a path manipulation library</a></li>
<li><a href="http://cram-system.org/">CRAM</a>: Cognitive Robot Abstract Machine - a toolbox for designing, implementing and deploying software on autonomous robots</li>
<li><a href="http://compbio.ucdenver.edu/Hunter_lab/Hunter/cl-statistics.lisp">cl-statistics.lisp</a></li>
<li><a href="http://mumble.net/~jar/pseudoscheme/">Pseudoscheme - An implementation of Scheme embedded in Common Lisp</a> (&ldquo;with minor changes it runs in ABCL, CCL, ECL and LispWorks. But not in SBCL&hellip;&rdquo;)</li>
<li><a href="https://github.com/luksamuk/powerlisp">Powerlisp: A simple tool to automate your work with dmenu/rofi</a></li>
<li><a href="https://eschulte.github.io/curry-compose-reader-macros/">curry-compose-reader-macros</a> - concise function partial application and composition</li>
<li><a href="https://github.com/gschjetne/json-mop">json-mop</a>: A metaclass for bridging CLOS and JSON objects</li>
<li><a href="https://github.com/obicons/clsh">clsh</a>: a set of Lispy bindings for running and composing *nix processes</li>
<li><a href="https://github.com/BnMcGn/snakes">snakes</a> - Python style generators for Common Lisp. (Includes a port of itertools.)</li>
</ul>

<p>new releases:</p>

<ul>
<li><a href="https://github.com/portacle/portacle/releases/tag/1.2">Portacle: Release Linux Portability Fixes, Included SLY, Usability Improvements</a></li>
</ul>

<p>(re)discoveries:</p>

<ul>
<li><a href="https://github.com/plkrueger/CocoaInterface">Cocoa interface code written in Lisp for use with Clozure Common Lisp</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/882mz4/clbench_common_lisp_benchmarking_suite/">cl-bench - Common Lisp benchmarking suite</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/88xin6/eclipse_common_lisp_howard_stearns_elwood_corp/">Eclipse Common Lisp (Howard Stearns / Elwood Corp)</a></li>
<li><a href="https://github.com/Arboreta/arboreta-wasm/blob/master/wasm.cl">Arboreta/arboreta-wasm - Common Lisp tooling for WebAssembly</a></li>
<li><a href="http://faculty.hampshire.edu/lspector/qgame.html">QGAME: Quantum and Gate Measurement Emulator</a></li>
<li><a href="https://github.com/guicho271828/trivia">Trivia: Pattern Matching</a></li>
</ul>

<p>From the Lisp Game Jam 2018:</p>

<ul>
<li><a href="http://pages.cs.wisc.edu/~psilord/lisp-public/option-9.html">Option 9: A Shoot&rsquo;em Up Miniature Video Game in Common Lisp</a></li>
<li><a href="https://luksamuk.itch.io/cl-ods">Orbit Defense Strikeforce</a></li>
</ul>

<p>all <a href="https://www.indeed.com/viewjob?t=lisp+engineer+ai+natural+language+reasoning&amp;jk=d14c7726839e6b01&amp;_ga=2.203861651.2000107742.1525918694-1699101565.1509521844">results</a></p>

<h1 id="articles">Articles</h1>

<ul>
<li><a href="https://www.reddit.com/r/lisp/comments/8bshzw/lisp_jazz_aikido_three_expressions_of_a_single/">Lisp, Jazz, Aikido: Three Expressions of a Single Essence</a></li>
<li><a href="http://funlisp.blogspot.com/2018/03/creating-cl-rivescript-interpreter-part.html">Creating a CL-Rivescript Interpreter (Part 1)</a> and <a href="http://funlisp.blogspot.com/2018/04/creating-cl-rivescript-interpreter-part_14.html">part 10</a></li>
<li><a href="https://biolisp.github.io/#why-lisp">Why lisp - biolisp</a></li>
<li><a href="https://ebzzry.io/en/script-lisp/">Scripting in Common Lisp with buildapp&rsquo;s multi-call binaries and fare&rsquo;s cl-scripting</a></li>
<li><a href="http://stevelosh.com/blog/2018/05/fun-with-macros-gathering/">Fun with Macros: Gathering / Steve Losh</a></li>
<li><a href="http://www.rangakrish.com/index.php/2018/05/27/calling-go-functions-from-lisp/">Calling Go Functions from Lisp</a></li>
<li><a href="http://www.lispology.com/show?27LP">Lispology - Printing floating-point numbers</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/8pa6rg/prolog_to_lisp/">Prolog to Lisp</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/8svch2/how_do_you_design_with_prolog_in_lisp/">How do you design with Prolog in Lisp?</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/8qca4o/when_to_use_type_specifiers_in_cl_code/">When to use type specifiers in CL code?</a></li>
<li><a href="http://codeninja.blog/2018/lisp-code/">Jeff Massung: Common Lisp libraries that I made over the course of a few years and have consistenly returned to, always found useful, and kept up-to-date.</a></li>
<li><a href="http://can3p.github.io/blog/2018/06/19/client-writeup-intro/">Experience writing a full featured livejournal blog client in Common Lisp</a>. Part 2: <a href="http://can3p.github.io/blog/2018/06/22/client-writeup-logic/">client logic</a></li>
<li><a href="https://lthms.xyz/blog/lisp-journey-getting-started">My Lisp Journey #1: Getting Started With trivial-gamekit</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/8o2c1y/the_uncommon_lisp_approach_to_operations_research/">The (Un)common Lisp approach to Operations Research (2012)</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/8jq465/alien_return_of_alien_technology_to_classical/">Alien: Return of Alien Technology to Classical Planning </a></li>
</ul>

<h1 id="discussion">Discussion</h1>

<ul>
<li><a href="https://www.reddit.com/r/lisp/comments/8s5q7x/what_common_lisp_web_library_should_i_use/">What Common Lisp web library should I use?</a>, and <a href="https://www.reddit.com/r/lisp/comments/8k79iz/lisp_for_building_a_web_app_options/">Lisp for building a web app, options?</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/82wiyt/how_to_collect_all_asdf_dependencies_for/">How to collect all asdf dependencies for package-inferred-system?</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/85oo81/sbcl_on_raspberry_pi/">SBCL on Raspberry Pi</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/8665ga/please_join_the_cltelegrambot_refactoring_effort/">Please, join the cl-telegram-bot refactoring effort!</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/1jq5rk/common_lisp_gui_options/cbhh1y2/">GUI development done in Lisp (2013 comment)</a> (<a href="https://www.reddit.com/r/Common_Lisp/comments/86mbhc/gui_development_done_in_lisp_2013_comment/">reddit</a>)</li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/8ald5m/question_trying_to_generalize_posix_stat_functions/">Question: trying to generalize posix &lsquo;stat-&rsquo; functions</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/8azd8n/package_name_and_nickname_collisions_in_quicklisp/">Package Name and Nickname Collisions in Quicklisp</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/8bn7f9/common_lisp_and_machine_learning_these_days/">Common Lisp and Machine Learning these days</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/8bqava/is_clautowrap_the_preferred_way_to_generate_ffi/">Is cl-autowrap the preferred way to generate FFI bindings these days?</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/8oy69a/want_to_make_it_so_common_lisp_understands/">Want to make it so Common Lisp understands GeoJSON data</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/8szurv/how_to_send_and_receive_data_over_udp/">How to send and receive data over UDP asynchronously in common lisp?</a></li>
<li><a href="http://stevelosh.com/blog/2018/05/fun-with-macros-gathering/">Fun with Macros: Gathering / Steve Losh </a></li>
</ul>

<p>Learning Lisp:</p>

<ul>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/8r9jfc/one_package_per_or_file_project_somethingelse/">One package per (or file project something-else)?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/8nt95a/small_executables_in_lisp/">Small executables in LISP ?</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/8sgqfq/what_can_sly_do_outofthemetaphoricalbox_that/">What can Sly do out-of-the-metaphorical-box that slime+slime-company+<some-other-contribs> can&rsquo;t?</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/8a8sps/til_that_i_can_create_clos_constructors_for/">TIL that I can create CLOS constructors for conditions</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/8cwemh/macro_question_from_a_clojure_programmer/">Macro question from a Clojure programmer</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/8jzpzw/why_did_you_decide_to_learn_lisp/">Why did you decide to learn Lisp?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/8j9ing/how_do_you_go_about_starting_a_common_lisp/">How do you go about starting a Common Lisp Project? A beginner looking for pointers.</a></li>
</ul>

<h1 id="screencasts">Screencasts</h1>

<ul>
<li><a href="https://youtu.be/A5CnYlG7sc8">Lots of bits of lisp - CFFI </a></li>
<li><a href="https://www.youtube.com/watch?v=ygKXeLKhiTI">Lots of bits of Lisp - Macros (2 hr episode) </a></li>
<li><a href="https://www.youtube.com/watch?v=2Op3QLzMgSY&amp;t=106s">MIT OpenCourseWare</a></li>
<li><a href="https://www.youtube.com/watch?v=dw-y3vNDRWk">Lisp, The Quantum Programmer&rsquo;s Choice - Computerphile episode 2</a></li>
<li><a href="https://www.youtube.com/watch?v=9VIT_Ml2v-Q">McCLIM + Maxima: plot manipulation</a></li>
<li><a href="https://www.youtube.com/watch?v=AvC82EjoPYU">McCLIM + Maxima: vector demo</a></li>
<li><a href="https://www.youtube.com/watch?v=CbfHpLUPL7E">Comfy Lisp Programming - Project &ldquo;Wikify&rdquo; | Episode 2 @ 10am PST </a></li>
<li><a href="https://youtu.be/Zv_0U5kVIf8">Pushing Pixels with Lisp - Episode 45 - World space shenanigans &amp; Vignette</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/8ubnkn/common_lisp_and_c17_live_coding_stream_tinycdn/">Common lisp and C++17 Live coding stream | TinyCDN CFFI Interop | Episode 13</a></li>
<li><a href="https://www.youtube.com/watch?v=XT7JYPtWMd8">Growing a Lisp compiler - Amsterdam Lisp</a></li>
<li><a href="https://www.youtube.com/watch?v=bl8jQ2wRh6k">Web Development in Emacs, Common Lisp and Clojurescript - Potato (Slack-like)</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/8rsnec/any_news_on_the_els_videos/">Any news on the ELS videos?</a> (answer: no)</li>
</ul>

<h1 id="common-lisp-vs">Common Lisp VS &hellip;</h1>

<ul>
<li><a href="http://med.miami.edu/news/miller-school-researchers-help-push-the-limits-of-programming-languages-in-">Miller School Researchers Help Push the Limits of Programming Languages in Biology</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/8mcts3/lisp_vs_java_thought_you_guys_might_find_this/">Lisp vs Java (thought you guys might find this humorous)</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/8q6gaa/what_other_languages_besides_lisp_do_you_enjoy/">What other languages besides Lisp do you enjoy programming in?</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://40ants.com/weblocks/_images/quickstart-check-task.gif" alt="New Weblocks tutorial: widgets">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">New Weblocks tutorial: widgets</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">25 06 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>Weblocks is a web framework, created circa 2007, that allows to
<strong>write dynamic web applications in full Lisp, without a line of
Javascript</strong>. It is based on so called widgets, that are rendered
server-side and updated on the client, and it was also based on
continuations (they were removed in this fork, at least for now). It
was quietly being forgotten but it is being fixed, refactored,
documented and simplified by Alexander &ldquo;svetlyak40wt&rdquo; since a year or
so.</p>

<p>I rewrote the quickstart to show the use of widgets, the heart of
Weblocks, Alexander proof-read and here we are:</p>

<p><a href="http://40ants.com/weblocks/quickstart.html">http://40ants.com/weblocks/quickstart.html</a> (and <a href="https://www.reddit.com/r/lisp/comments/8tpkge/new_weblocks_web_framework_quickstart_widgets/">reddit comments</a>)</p>

<p>I copy it below, of course check the official website for updates.</p>

<p>The old Weblocks website is at <a href="https://common-lisp.net/project/cl-weblocks/">https://common-lisp.net/project/cl-weblocks/</a></p>

<hr />

<p>Btw, other isomorphic web frameworks I know are Haskell&rsquo;s
<a href="https://haste-lang.org/docs/">Haste</a>, Nim&rsquo;s
<a href="https://github.com/pragmagic/karax">Karax</a>, Ocaml&rsquo;s
<a href="http://ocsigen.org/eliom/">Heliom</a>, Python&rsquo;s
<a href="http://www.nagare.org/">Nagare</a>, of course Smalltalk&rsquo;s
<a href="http://seaside.st/">Seaside</a> and
<a href="https://github.com/vindarel/awesome-no-js-web-frameworks">a couple more</a>.</p>

<p>Weblocks is now the easiest to get started with, the one &ldquo;really
isomorphic&rdquo; (bluring the line between server and client code), the
most elegant (to me) and one of the two, with Seaside, that allow for
REPL-driven development.</p>

<p>For what I tested, Heliom is a hell to install, it seems a hell to
deploy, and it is bloated with specific Ocaml syntax that is always
upcoming in new compiler versions.</p>

<p>Karax seems promising, it was recently used to rewrite the
<a href="https://forum.nim-lang.org/">Nim forum</a>. It has currently zero docs
(not even a quickstart ;) ) and Nim&rsquo;s ecosystem isn&rsquo;t near as large as
CL&rsquo;s. (and, well, no REPL, no Lisp)</p>

<p>Nagare is actually based on Stackless Python. Looking at the code of
the successfull <a href="http://www.kansha.org/">Kansha</a> Trello clone, it
actually includes inline Javascript. And personnally, I&rsquo;m running away from Python so…</p>

<hr />

<h1 id="quickstart">Quickstart</h1>

<blockquote>
<p><strong>warning</strong></p>

<dl>
<dt>This version of Weblocks is not in Quicklisp yet. To</dt>
<dd>install it you need to clone the repository somewhere where ASDF
will find it, for example, to the <code>~/common-lisp/</code> directory.</dd>
</dl>

<p>Load weblocks and create a package for a sandbox:</p>
</blockquote>

<pre><code class="language-sourceCode common-lisp-repl">CL-USER&gt; (ql:quickload '(:weblocks :weblocks-ui :find-port))
CL-USER&gt; (defpackage todo
           (:use #:cl
                 #:weblocks-ui/form
                 #:weblocks/html)
           (:import-from #:weblocks/widget
                    #:render
                    #:update
                    #:defwidget)
           (:import-from #:weblocks/actions
                    #:make-js-action)
           (:import-from #:weblocks/app
                    #:defapp))
#&lt;PACKAGE &quot;TODO&quot;&gt;
CL-USER&gt; (in-package todo)
#&lt;PACKAGE &quot;TODO&quot;&gt;
</code></pre>

<p>Now, create an application:</p>

<pre><code class="language-sourceCode common-lisp-repl">TODO&gt; (defapp tasks)
TODO&gt; (weblocks/debug:on)
TODO&gt; (defvar *port* (find-port:find-port))
TODO&gt; (weblocks/server:start :port *port*)
 &lt;INFO&gt; [19:41:00] weblocks/server server.lisp (start) -
  Starting weblocks WEBLOCKS/SERVER::PORT: 40000
  WEBLOCKS/SERVER::SERVER-TYPE: :HUNCHENTOOT DEBUG: T
 &lt;INFO&gt; [19:41:00] weblocks/server server.lisp (start-server) -
  Starting webserver on WEBLOCKS/SERVER::INTERFACE: &quot;localhost&quot;
  WEBLOCKS/SERVER::PORT: 40000 DEBUG: T
 #&lt;SERVER port=40000 running&gt;
 (NIL)
</code></pre>

<p>Open <a href="http://localhost:40000/tasks/">http://localhost:40000/tasks/</a> in your browser (double check the
port) and you&rsquo;ll see a text like that:</p>

<pre><code>No weblocks/session:init method defined.
Please define a method weblocks.session:init to initialize a session.

It could be something simple, like this one:

(defmethod weblocks/session:init ((app tasks))
            &quot;Hello world!&quot;)

Read more in the documentaion.
</code></pre>

<p>It means that you didn&rsquo;t write any code for your application. Let&rsquo;s do
it now and make an application which outputs a list of tasks.</p>

<p>In the end, we&rsquo;ll build the mandatory TODO-list app:</p>

<p><img src="http://40ants.com/weblocks/_images/quickstart-check-task.gif" alt="the TODO-list app in Weblocks." /></p>

<h2 id="the-task-widget">The Task widget</h2>

<pre><code class="language-sourceCode common-lisp-repl">TODO&gt; (defwidget task ()
        ((title
          :initarg :title
          :accessor title)
         (done
          :initarg :done
          :initform nil
          :accessor done)))
</code></pre>

<p>This code defines a task widget, the building block of our application.
<code>defwidget</code> is similar to Common Lisp&rsquo;s <code>defclass</code>, in fact it is only a
wrapper around it. It takes a name, a list of super-classes (here <code>()</code>)
and a list of slot definitions.</p>

<p>We can create a task with <code>make-instance</code>:</p>

<pre><code class="language-sourceCode common-lisp-repl">TODO&gt; (defvar *task-1* (make-instance 'task :title &quot;Make my first Weblocks app&quot;))
TODO&gt; *task-1*
#&lt;TASK {1005406F33}&gt;
</code></pre>

<p>Above, <code>:title</code> is the initarg, and since we didn&rsquo;t give a <code>:done</code>
argument, it will be instanciated to its <code>:initform</code>, which is <code>nil</code>.</p>

<p>We defined accessors for both slots, so we can read and set them easily:</p>

<pre><code class="language-sourceCode common-lisp-repl">TODO&gt; (title *task-1*)
&quot;Make my first Weblocks app&quot;
TODO&gt; (done *TASK-1*)
NIL
TODO&gt; (setf (done *TASK-1*) t)
T
</code></pre>

<p>We define a constructor for our task:</p>

<pre><code class="language-sourceCode common-lisp-repl">TODO&gt; (defun make-task (&amp;key title done)
        (make-instance 'task :title title :done done))
</code></pre>

<p>It isn&rsquo;t mandatory, but it is good practice to do so.</p>

<p>If you are not familiar with the Common Lisp Object System (CLOS), you
can have a look at <a href="http://www.gigamonkeys.com/book/object-reorientation-classes.html">Practical Common
Lisp</a>
and the <a href="https://lispcookbook.github.io/cl-cookbook/clos.html">Common Lisp
Cookbook</a>.</p>

<p>Now let&rsquo;s carry on with our application.</p>

<h2 id="the-tasks-list-widget">The Tasks-list widget</h2>

<p>Below we define a more general widget that contains a list of tasks, and
we tell Weblocks how to display them by <em>specializing</em> the <code>render</code>
method for our newly defined classes:</p>

<pre><code class="language-sourceCode common-lisp-repl">TODO&gt; (defwidget task-list ()
        ((tasks
          :initarg :tasks
          :accessor tasks)))

TODO&gt; (defmethod render ((task task))
        &quot;Render a task.&quot;
        (with-html
              (:span (if (done task)
                         (with-html
                               (:s (title task)))
                       (title task)))))

TODO&gt; (defmethod render ((widget task-list))
        &quot;Render a list of tasks.&quot;
        (with-html
              (:h1 &quot;Tasks&quot;)
              (:ul
                (loop for task in (tasks widget) do
                      (:li (render task))))))
</code></pre>

<p>The <code>with-html</code> macro uses
<a href="https://github.com/ruricolist/spinneret/">Spinneret</a> under the hood,
but you can use anything that outputs html.</p>

<p>We can check how the generated html looks like by calling <code>render</code> in
the REPL:</p>

<pre><code class="language-sourceCode common-lisp-repl">TODO&gt; (render *task-1*)
&lt;div class=&quot;widget task&quot;&gt;&lt;span&gt;Make my first Weblocks app&lt;/span&gt;
&lt;/div&gt;
NIL
</code></pre>

<p>But we still don&rsquo;t get anything in the browser.</p>

<pre><code class="language-sourceCode common-lisp-repl">TODO&gt; (defun make-task-list (&amp;rest rest)
             &quot;Create some tasks from titles.&quot;
             (loop for title in rest collect
                   (make-task :title title)))

TODO&gt; (defmethod weblocks/session:init ((app tasks))
         (declare (ignorable app))
         (let ((tasks (make-task-list &quot;Make my first Weblocks app&quot;
                                      &quot;Deploy it somewhere&quot;
                                      &quot;Have a profit&quot;)))
           (make-instance 'task-list :tasks tasks)))
</code></pre>

<p>This defines a list of tasks (for simplicity, they are defined as a list
in memory) and returns what will be our session&rsquo;s root widget..</p>

<p>Restart the application:</p>

<pre><code class="language-sourceCode common-lisp-repl">TODO&gt; (weblocks/debug:reset-latest-session)
</code></pre>

<p>Right now it should look like this:</p>

<p><img src="_static/quickstart-list.png" alt="Our first list of tasks." /></p>

<h2 id="adding-tasks">Adding tasks</h2>

<p>Now, we&rsquo;ll add some ability to interact with a list – to add some tasks
into it, like so:</p>

<p><img src="_static/quickstart-add-task.gif" alt="Adding tasks in our TODO-list interactively." /></p>

<p>Import a new module, <code>weblocks-ui</code> to help in creating forms and other
UI elements:</p>

<pre><code class="language-sourceCode common-lisp-repl">TODO&gt; (ql:quickload &quot;weblocks-ui&quot;)
TODO&gt; (use-package :weblocks-ui/form)
</code></pre>

<p>Write a new <code>add-task</code> function and modify the <code>render</code> method of a
task-list:</p>

<pre><code class="language-sourceCode common-lisp-repl">TODO&gt; (defmethod render ((widget task-list))
          (flet ((add-task (&amp;key title &amp;allow-other-keys)
                   (push (make-task :title title)
                         (tasks (weblocks/widgets/root:get)))
                   (update (weblocks/widgets/root:get))))
            (with-html
              (:h1 &quot;Tasks&quot;)
              (loop for task in (tasks widget) do
                   (render task))
              (with-html-form (:POST #'add-task)
                (:input :type &quot;text&quot;
                        :name &quot;title&quot;
                        :placeholder &quot;Task's title&quot;)
                (:input :type &quot;submit&quot;
                        :value &quot;Add&quot;)))))

TODO&gt; (weblocks/debug:reset-latest-session)
</code></pre>

<p>The function <code>add-task</code> does only two simple things:</p>

<ul>
<li>it adds a task into a list;</li>
<li>it tells Weblocks that our root widget should be redrawn.</li>
</ul>

<p>This second point is really important because it allows Weblocks to
render necessary parts of the page on the server and to inject it into
the HTML DOM in the browser. Here it rerenders the root widget, but we
can as well <code>update</code> a specific task widget, as we&rsquo;ll do soon.</p>

<p>We also took care of defining <code>add-task</code> inline, as a closure, for it to
be thread safe.</p>

<p>Another block in our new version of <code>render</code> of a task-list is the form:</p>

<pre><code class="language-sourceCode common-lisp">(with-html-form (:POST #'add-task)
   (:input :type &quot;text&quot;
    :name &quot;task&quot;
    :placeholder &quot;Task's title&quot;)
   (:input :type &quot;submit&quot;
    :value &quot;Add&quot;))
</code></pre>

<p>It defines a text field, a submit button and an action to perform on
form submit. The <code>add-task</code> function will receive the text input as
argument.</p>

<blockquote>
<p><strong>note</strong></p>

<p>This is really amazing!</p>

<p>With Weblocks, you can handle all the business logic server-side,
because an action can be any lisp function, even an anonymous lambda,
closuring all necessary variables.</p>
</blockquote>

<p>Restart the application and reload the page. Test your form now and see
in a
<a href="https://developers.google.com/web/tools/chrome-devtools/inspect-styles/">Webinspector</a>
how Weblocks sends requests to the server and receives HTML code with
rendered HTML block.</p>

<p>Now we&rsquo;ll make our application really useful – we&rsquo;ll add code to toggle
the tasks&rsquo; status.</p>

<h2 id="toggle-tasks">Toggle tasks</h2>

<pre><code class="language-sourceCode common-lisp-repl">TODO&gt; (defmethod toggle ((task task))
        (setf (done task)
              (if (done task)
                  nil
                  t))
        (update task))

TODO&gt; (defmethod render ((task task))
        (with-html
          (:p (:input :type &quot;checkbox&quot;
            :checked (done task)
            :onclick (make-js-action
                      (lambda (&amp;rest rest)
                        (declare (ignore rest))
                      (toggle task))))
              (:span (if (done task)
                   (with-html
                         ;; strike
                         (:s (title task)))
                 (title task))))))
</code></pre>

<p>We defined a small helper to toggle the <code>done</code> attribute, and we&rsquo;ve
modified our task rendering function by adding a code to render a
checkbox with an anonymous lisp function, attached to its <code>onclick</code>
attribute.</p>

<p>The function <code>make-js-action</code> returns a Javascript code, which calls
back a lisp lambda function when evaluated in the browser. And because
<code>toggle</code> updates a Task widget, Weblocks returns on this callback a new
prerendered HTML for this one task only.</p>

<h2 id="what-is-next">What is next?</h2>

<p>As a homework:</p>

<ol>
<li>Play with lambdas and add a &ldquo;Delete&rdquo; button next after each task.</li>
<li>Add the ability to sort tasks by name or by completion flag.</li>
<li>Save tasks in a database (the
<a href="https://lispcookbook.github.io/cl-cookbook/databases.html">Cookbook</a>
might help).</li>
<li>Read the rest of the documentation and make a real application,
using the full power of Common Lisp.</li>
</ol>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Learning Rust 01: a pwd clone</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">23 06 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I&rsquo;m learning Rust, and documenting the process. These posts are my notes - they&rsquo;re not guaranteed to be useful, interesting or correct!
In this post, I&rsquo;m writing my first Rust program. It&rsquo;s a simplified clone of the Unix tool pwd, which prints out the current directory. I&rsquo;m calling it rpwd.
Creating a project I started a new executable application with:
$ cargo rpwd --bin Code The code is simple:
use std::env; fn main() { let path = env::current_dir().
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-A7Qeklr1elk/WybKN5GoxVI/AAAAAAAAS0g/CtDwRsgMvUI5mGVRyxd9SeehrXpWYcZNwCLcBGAs/s320/arboldecision-importarycrearinstancia.png" alt="La libertad de desarrollar...: Visualizaci&amp;#243;n de &amp;#193;rbol de decisi&amp;#243;n">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">La libertad de desarrollar...: Visualizaci&amp;#243;n de &amp;#193;rbol de decisi&amp;#243;n</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">19 06 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Como en Noviembre del a&#241;o pasado, escrib&#237; un art&#237;culo sobre <a href="http://blog.crespo.org.ve/search/label/Arbol%20de%20decisi%C3%B3n">&#225;rboles de decisi&#243;n con Python</a>, donde se ten&#237;a una serie de datos de entrada (altura, peso y talla)&nbsp; y de salida si era hombre o mujer.&nbsp; Para este art&#237;culo lo que se va a agregar es la visualizaci&#243;n del &#225;rbol de decisi&#243;n, para ello se usar&#225; dos librer&#237;as de Python pydot y&nbsp;graphviz .<br /><br />Se da por sentado que ya se tiene instalado scikit-learn, se instala entonces pydot y graphviz:<br /><br />#pip3 install pydot<br />#pip3 install graphviz<br /><br />Ahora se muestra el c&#243;digo:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-A7Qeklr1elk/WybKN5GoxVI/AAAAAAAAS0g/CtDwRsgMvUI5mGVRyxd9SeehrXpWYcZNwCLcBGAs/s1600/arboldecision-importarycrearinstancia.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="98" src="https://1.bp.blogspot.com/-A7Qeklr1elk/WybKN5GoxVI/AAAAAAAAS0g/CtDwRsgMvUI5mGVRyxd9SeehrXpWYcZNwCLcBGAs/s320/arboldecision-importarycrearinstancia.png" width="320" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-Dm9uXTRO1ZI/WybKg1IH6bI/AAAAAAAAS0o/_cCrWHVrcUknAs8S8rkzU0mKFmoEvhzlQCLcBGAs/s1600/arboldecision-datos.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="108" src="https://3.bp.blogspot.com/-Dm9uXTRO1ZI/WybKg1IH6bI/AAAAAAAAS0o/_cCrWHVrcUknAs8S8rkzU0mKFmoEvhzlQCLcBGAs/s320/arboldecision-datos.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-sFOV_REr3Zc/WybKzf8cx5I/AAAAAAAAS0w/HamC88FJdhULEhml5Ga5N8HDPfSWXomKwCLcBGAs/s1600/arboldecision-entrenamiento1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="191" src="https://1.bp.blogspot.com/-sFOV_REr3Zc/WybKzf8cx5I/AAAAAAAAS0w/HamC88FJdhULEhml5Ga5N8HDPfSWXomKwCLcBGAs/s320/arboldecision-entrenamiento1.png" width="320" /></a></div><br />Ahora toca la visualizaci&#243;n del &#225;rbol:<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-m25G03Qs6BI/WybLznYCzCI/AAAAAAAAS2s/-gPmHLZtuLUtDzHZ3Gj22tikV5CAn5kbwCLcBGAs/s1600/arboldecision-visualizacion-librerias.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="62" src="https://2.bp.blogspot.com/-m25G03Qs6BI/WybLznYCzCI/AAAAAAAAS2s/-gPmHLZtuLUtDzHZ3Gj22tikV5CAn5kbwCLcBGAs/s320/arboldecision-visualizacion-librerias.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-uLXLUYILItU/WybMD2zy1YI/AAAAAAAAS3U/QrE1zLu8LH4wySr3Fi_S73-2ivXYDp1JQCLcBGAs/s1600/arboldecision-visualizacion-grafo.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="97" src="https://2.bp.blogspot.com/-uLXLUYILItU/WybMD2zy1YI/AAAAAAAAS3U/QrE1zLu8LH4wySr3Fi_S73-2ivXYDp1JQCLcBGAs/s320/arboldecision-visualizacion-grafo.png" width="320" /></a></div><br />Para terminar se muestra el grafo del &#225;rbol:<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-cH3CmDL3iC8/WybMcZsBNBI/AAAAAAAAS3g/qC9ZPpHbfcMPU5lRiCZ97xnxMCGyXj-JgCLcBGAs/s1600/arboldecision-visualizacion.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="291" src="https://1.bp.blogspot.com/-cH3CmDL3iC8/WybMcZsBNBI/AAAAAAAAS3g/qC9ZPpHbfcMPU5lRiCZ97xnxMCGyXj-JgCLcBGAs/s320/arboldecision-visualizacion.png" width="320" /></a></div><br />Este grafo se genera a partir de la instancia de la clase que se usa para ingresar los datos, se entrena, y se usa para predecir con nuevos datos.<br />La informaci&#243;n que muestra cada nodo de decisi&#243;n:<br /><br /><ul><li>Samples: La cantidad de muestras que se maneja.</li><li>gini: Es un indice que indica el costo de la evaluaci&#243;n de separar los datos.</li><li>value: Es un valor que se est&#225; evaluando en ese momento.&nbsp;</li></ul>El c&#243;digo de este art&#237;culo lo pueden ver en el notebook que se encuentra en el <a href="https://gitlab.com/mangoosta/articulos-cienciasdedatos/blob/master/ArbolDecision.ipynb">repositorio de gitlab</a>.<br /><br />En pr&#243;ximo art&#237;culo se har&#225; otro ejemplo ya con un mayor conjunto de datos.<br /><br />S&#237; tienes algun pregunta u observaci&#243;n, puedes hacerlo en los comentarios del post.<br /><br /><div class="graf graf--p" name="91a6">&#161;Haz tu donativo!</div><div class="graf graf--p" name="af4b">Si te gust&#243; el art&#237;culo puedes realizar un donativo con Bitcoin (BTC) usando la billetera digital de tu preferencia a la siguiente direcci&#243;n: 17MtNybhdkA9GV3UNS6BTwPcuhjXoPrSzV</div><div class="graf graf--p" name="a993">O Escaneando el c&#243;digo QR desde billetera:<br /><br /><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-YLtwWShFQVA/WylZ7Fsvy5I/AAAAAAAAS7s/aeGvs39ZXooyKwIPvRwT7PAmx9T768WtwCLcBGAs/s1600/17MtNybhdkA9GV3UNS6BTwPcuhjXoPrSzV.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://4.bp.blogspot.com/-YLtwWShFQVA/WylZ7Fsvy5I/AAAAAAAAS7s/aeGvs39ZXooyKwIPvRwT7PAmx9T768WtwCLcBGAs/s1600/17MtNybhdkA9GV3UNS6BTwPcuhjXoPrSzV.png" /></a></div><br /></div>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/93-happy-flow.png" alt="Happy Flow">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Happy Flow</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">19 06 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/93-happy-flow.png" alt="Happy Flow" title="Happy Flow" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/94-tbd.png" alt="TBD">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">TBD</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">19 06 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/94-tbd.png" alt="TBD" title="TBD" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to use React (and Redux) with your crufty old CMS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">13 06 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Getting your JavaScript to run well on a CMS can be difficult at the best of times. But the difficulty grows exponentially when you add something like React and Redux. And this isn't the fault of the CMS. Unfortunately most React tutorials assume you're writing a Single Page web Application (SPA). And that's great if you are actually building an SPA. But what about when you're not? What about those of us who have a CMS imposed on us by our employer? What about those situations where a CMS is the best tool for the job?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to use React (and Redux) with your crufty old CMS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">13 06 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Getting your JavaScript to run well on a CMS can be difficult at the best of times. But the difficulty grows exponentially when you add something like React and Redux. And this isn't the fault of the CMS. Unfortunately most React tutorials assume you're writing a Single Page web Application (SPA). And that's great if you are actually building an SPA. But what about when you're not? What about those of us who have a CMS imposed on us by our employer? What about those situations where a CMS is the best tool for the job?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/92-root-cause.png" alt="Root Cause">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Root Cause</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">12 06 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/92-root-cause.png" alt="Root Cause" title="Root Cause" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://1.bp.blogspot.com/-EGnI53oyPaY/Wx2D-ODxX8I/AAAAAAAASzI/cBweD4nXz7UvqlMIz2v7oljOg941a8uUwCLcBGAs/s320/twitter-tendencias-valencia.png" alt="La libertad de desarrollar...: An&amp;#225;lisis de Sentimiento de tweets con Python, TextBlob y&amp;#160;tweepy">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">La libertad de desarrollar...: An&amp;#225;lisis de Sentimiento de tweets con Python, TextBlob y&amp;#160;tweepy</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">10 06 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Existe el &#225;rea de an&#225;lisis de redes sociales, puedes hacer gr&#225;ficos de tendencias, lograr cual fue el origen de un tweet. La idea es usar la librer&#237;a tweepy para conectase a Twitter y de all&#237; capturar los tweets para luego realizar un an&#225;lisis de sentimiento y graficar el resultado.<br /><br />El an&#225;lisis de sentimiento se refiere al uso de procesamiento de lenguaje natural, an&#225;lisis de texto y ling&#252;istica computacional para identificar y extraer informaci&#243;n subjetiva de los recursos (m&#225;s informaci&#243;n en <a href="https://es.wikipedia.org/wiki/An%C3%A1lisis_de_sentimiento">wikipedia</a>).<br /><br />Se puede realizar an&#225;lisis de sentimiento a cualquier texto, puede ser de correos, de p&#225;ginas web, de publicaciones en redes sociales como twitter, facebook, google+, entre otros.&nbsp; Con ello se puede lograr un aproximado de la evaluaci&#243;n emocional que tiene un tema o persona en alg&#250;n momento en las redes sociales o contenidos evaluados.<br /><br />La idea es obtener el tr&#225;fico de twitter sobre un tema o persona, aplicarle an&#225;lisis de sentimiento y graficar los resultados.<br /><br />Este art&#237;culo se basa en un art&#237;culo en ingl&#233;s publicado en freecodecamp con t&#237;tulo&nbsp;<a href="https://medium.freecodecamp.org/basic-data-analysis-on-twitter-with-python-251c2a85062e">Basic data analysis on Twitter with Python</a>&nbsp;. Este art&#237;culo se desarrolla una aplicaci&#243;n gr&#225;fica en TK para obtener la informaci&#243;n y luego realizar la captura, c&#225;lculos y gr&#225;ficos. El c&#243;digo fuente de la aplicaci&#243;n del art&#237;culo se encuentra en <a href="https://github.com/Fidel-Willis/Twitter-Data/blob/master/twitterData.py">github</a>.<br /><br />Para tener acceso al API de twitter se tiene que crear una cuenta en la <a href="https://apps.twitter.com/">p&#225;gina para las aplicaciones</a> que lo requieran.<br /><br />Para autenticarse se usar&#225; el siguiente c&#243;digo:<br /><pre class="graf graf--pre graf-after--p" id="4353" name="4353">consumer_key = 'consumer key'<br />consumer_secret = 'consumer secrets'<br />access_token = 'access token'<br />access_token_secret = 'access token secret'</pre><pre class="graf graf--pre graf-after--pre" id="da2d" name="da2d">auth = tweepy.OAuthHandler(consumer_key, consumer_secret)<br />auth.set_access_token(access_token, access_token_secret)<br />api = tweepy.API(auth)</pre><br />En este caso se usar&#225; jupyer lab para mostrar la aplicaci&#243;n con ajustes en el c&#243;digo para su reutilizaci&#243;n, por ejemplo, que realice el an&#225;lisis en Espa&#241;ol o Ingl&#233;s.<br /><br />La librer&#237;a a usar ser&#225; tweepy, la librer&#237;a para an&#225;lisis de texto TextBlob y matplotlib.<br /><br />Para instalar tweepy se usar&#225; pip3:<br /><br /><b><span style="color: red;">pip3 install tweepy textblob</span></b><br /><br /><br />Revisemos primero las tendencias en twitter para Valencia (Venezuela), a continuaci&#243;n una imagen de las tendencias.<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-EGnI53oyPaY/Wx2D-ODxX8I/AAAAAAAASzI/cBweD4nXz7UvqlMIz2v7oljOg941a8uUwCLcBGAs/s1600/twitter-tendencias-valencia.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://1.bp.blogspot.com/-EGnI53oyPaY/Wx2D-ODxX8I/AAAAAAAASzI/cBweD4nXz7UvqlMIz2v7oljOg941a8uUwCLcBGAs/s320/twitter-tendencias-valencia.png" width="196" /></a></div><div class="separator" style="clear: both; text-align: center;"></div><br /><br /><br />Se buscar&#225; el an&#225;lisis de sentimiento de la tendencia Rafael Nadal, se buscar&#225; en 200 tweets y en espa&#241;ol.<br /><br />A continuaci&#243;n el c&#243;digo fuente:<br /><br /><br />El c&#243;digo fuente en el repositorio de gitlab lo pueden ver en el&nbsp; <a href="https://gitlab.com/mangoosta/articulos-cienciasdedatos/blob/master/tweetanalitica.ipynb">enlace</a>.<br /><br /><pre><code><br /><i><span style="color: blue;"><br /></span></i><br /><i><span style="color: blue;">#!/usr/bin/env python3</span></i><br /><br /><i><span style="color: blue;"><br /></span></i><br /><i><span style="color: blue;">#Se importa la librer&#237;a tweepy</span></i><br /><br /><i><span style="color: blue;">import tweepy</span></i><br /><br /><i><span style="color: blue;">#Se importa sleep, datetime, TextBlob y matplotlib</span></i><br /><br /><i><span style="color: blue;">from time import sleep</span></i><br /><br /><i><span style="color: blue;">from datetime import datetime</span></i><br /><br /><i><span style="color: blue;">from textblob import TextBlob&nbsp;</span></i><br /><br /><i><span style="color: blue;">import matplotlib.pyplot as plt&nbsp;</span></i><br /><br /><i><span style="color: blue;"><br /></span></i><br /><i><span style="color: blue;">#Se define las variables para el acceso al API de twitter</span></i><br /><br /><i><span style="color: blue;">consumer_key = ''</span></i><br /><br /><i><span style="color: blue;">consumer_secret = ''</span></i><br /><br /><i><span style="color: blue;">access_token = ''</span></i><br /><br /><i><span style="color: blue;">access_token_secret = ''</span></i><br /><br /><i><span style="color: blue;"><br /></span></i><br /><i><span style="color: blue;">#Se autentica en twitter</span></i><br /><br /><i><span style="color: blue;">auth = tweepy.OAuthHandler(consumer_key, consumer_secret)</span></i><br /><br /><i><span style="color: blue;">auth.set_access_token(access_token, access_token_secret)</span></i><br /><br /><i><span style="color: blue;">api = tweepy.API(auth)</span></i><br /><br /><i><span style="color: blue;"><br /></span></i><br /><i><span style="color: blue;">#se verifica que el usuario conectado en twitter es de uno</span></i><br /><br /><i><span style="color: blue;">print(api.me().name)</span></i><br /><br /><i><span style="color: blue;"><br /></span></i><br /><i><span style="color: blue;">#Se pregunta por la palabra a preguntar</span></i><br /><br /><i><span style="color: blue;">palabra = input("Buscar: ")</span></i><br /><br /><i><span style="color: blue;"><br /></span></i><br /><i><span style="color: blue;">#Se define la cantida de tweets a capturar</span></i><br /><br /><i><span style="color: blue;">numero_de_Tweets = int(input(u"N&#250;mero de tweets a capturar: "))</span></i><br /><br /><i><span style="color: blue;"><br /></span></i><br /><i><span style="color: blue;">#Se define el idioma de los tweets a analizar</span></i><br /><br /><i><span style="color: blue;">lenguaje = input("Idioma [es/en]:")</span></i><br /><br /><i><span style="color: blue;"><br /></span></i><br /><i><span style="color: blue;"><br /></span></i><br /><i><span style="color: blue;">def ObtenerTweets(palabra="Trump",times=100,leguanje="en"):</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; #Se define las listas que capturan la popularidad</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; popularidad_list = []</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; numeros_list = []</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; numero = 1</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; for tweet in tweepy.Cursor(api.search, palabra, lang=lenguaje).items(numero_de_Tweets):</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; &nbsp; &nbsp; try:</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #Se toma el texto, se hace el analisis de sentimiento</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #y se agrega el resultado a las listas</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; analisis = TextBlob(tweet.text)</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; analisis = analisis.sentiment</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; popularidad = analisis.polarity</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; popularidad_list.append(popularidad)</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; numeros_list.append(numero)</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; numero = numero + 1</span></i><br /><br /><i><span style="color: blue;"><br /></span></i><br /><i><span style="color: blue;">&nbsp; &nbsp; &nbsp; &nbsp; except tweepy.TweepError as e:</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print(e.reason)</span></i><br /><br /><i><span style="color: blue;"><br /></span></i><br /><i><span style="color: blue;">&nbsp; &nbsp; &nbsp; &nbsp; except StopIteration:</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; return (numeros_list,popularidad_list,numero)</span></i><br /><br /><i><span style="color: blue;"><br /></span></i><br /><i><span style="color: blue;"><br /></span></i><br /><i><span style="color: blue;">def GraficarDatos(numeros_list,popularidad_list,numero):</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; axes = plt.gca()</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; axes.set_ylim([-1, 2])</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp;&nbsp;</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; plt.scatter(numeros_list, popularidad_list)</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; popularidadPromedio = (sum(popularidad_list))/(len(popularidad_list))</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; popularidadPromedio = "{0:.0f}%".format(popularidadPromedio * 100)</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; time&nbsp; = datetime.now().strftime("A : %H:%M\n El: %m-%d-%y")</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; plt.text(0, 1.25,&nbsp;</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;"Sentimiento promedio:&nbsp; " + str(popularidadPromedio) + "\n" + time,&nbsp;</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fontsize=12,&nbsp;</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;bbox = dict(facecolor='none',&nbsp;</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;edgecolor='black',&nbsp;</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;boxstyle='square, pad = 1'))</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp;&nbsp;</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; plt.title("Sentimientos sobre " + palabra + " en twitter")</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; plt.xlabel("Numero de tweets")</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; plt.ylabel("Sentimiento")</span></i><br /><br /><i><span style="color: blue;">&nbsp; &nbsp; plt.show()</span></i><br /><br /><i><span style="color: blue;"><br /></span></i><br /><i><span style="color: blue;"><br /></span></i><br /><i><span style="color: blue;">numeros_list,popularidad_list,numero = ObtenerTweets(palabra,numero_de_Tweets,lenguaje)</span></i><br /><br /><i><span style="color: blue;">GraficarDatos(numeros_list,popularidad_list,numero)</span></i><br /><br /><div><br /></div><br /></code><br /></pre><div>Al ejecutar el programa se tiene la siguiente gr&#225;fica.</div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-KV7Xav6vysc/Wx2LoLKDCmI/AAAAAAAASzU/cJA9oxR3uZYNKKU5RmJjCPW7hMCRoU_UwCLcBGAs/s1600/analisissentimiento.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="224" src="https://1.bp.blogspot.com/-KV7Xav6vysc/Wx2LoLKDCmI/AAAAAAAASzU/cJA9oxR3uZYNKKU5RmJjCPW7hMCRoU_UwCLcBGAs/s320/analisissentimiento.png" width="320" /></a></div><br />Para el caso de Nadal, tiene un valor promedio positivo, habr&#225; casos donde el sentimiento sea de un valor negativo, pero para este caso, lo mejor es ampliar la cantidad de tweets a capturar para tener una mejor aproximaci&#243;n del sentimiento de la gente de lo que habla en twitter de Nadal.<br /><br />S&#237; tienes algun pregunta u observaci&#243;n, puedes hacerlo en los comentarios del post.<br /><br /><div class="graf graf--p" name="91a6">&#161;Haz tu donativo!</div><div class="graf graf--p" name="af4b">Si te gust&#243; el art&#237;culo puedes realizar un donativo con Bitcoin (BTC) usando la billetera digital de tu preferencia a la siguiente direcci&#243;n: 197vyJ3KSCj287nLqhb7FSJpJUDayDoTMP&nbsp;</div><div class="graf graf--p" name="af4b"><br /></div><div class="graf graf--p" name="a993">O Escaneando el c&#243;digo QR desde billetera:</div><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-YOx8OXA-Vog/Wxg0Hh2zK9I/AAAAAAAASyA/lvV7QGFiAyYxijXA0UFA0w-B4nSF37HIwCLcBGAs/s1600/197vyJ3KSCj287nLqhb7FSJpJUDayDoTMP.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://2.bp.blogspot.com/-YOx8OXA-Vog/Wxg0Hh2zK9I/AAAAAAAASyA/lvV7QGFiAyYxijXA0UFA0w-B4nSF37HIwCLcBGAs/s1600/197vyJ3KSCj287nLqhb7FSJpJUDayDoTMP.png" /></a></div><div class="graf graf--p" name="a993">Para el caso de paypal, tienes el bot&#243;n del lado derecho de la p&#225;gina.</div></div>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://3.bp.blogspot.com/-_Hssjywird8/WxgvgExy9KI/AAAAAAAASxA/rcNLSRxNnk8i4WuSwCeIFg53QZiQ-pTXgCLcBGAs/s320/importandolibrerias.png" alt="La libertad de desarrollar...: Visualizando series de tiempo de precios del mercado con pandas y matplotlib">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">La libertad de desarrollar...: Visualizando series de tiempo de precios del mercado con pandas y matplotlib</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">10 06 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>En este art&#237;culo la fuente de datos&nbsp; se usar&#225; la librer&#237;a de Quandl directamente. La idea es obtener los precios de mercado de 3 Aerolineas (Delta con c&#243;digo DAL, Jet Blue con c&#243;digo JBLU y Southwest con c&#243;digo LUV).&nbsp; Se gr&#225;fica&nbsp; el historico de los precios de cierre, el volumen de ventas y movimientos promedios de estas tres aerolineas.<br /><br /><br />Continuando con los art&#237;culos sobre <a href="http://blog.crespo.org.ve/search/label/Pandas">Pandas</a> y <a href="http://blog.crespo.org.ve/search/label/Ciencia%20de%20datos">Ciencia de Datos</a>, en el art&#237;culo <a href="http://blog.crespo.org.ve/2018/05/como-obtener-datos-financieros-de.html">anterior</a> se mostr&#243; como trabajar con Series de tiempo obteniendo datos desde Quandl.<br /><br />Este art&#237;culo se basa en un art&#237;culo en ingl&#233;s que se t&#237;tula <a href="http://byteacademy.co/blog/time-series-python">Visualizing Time Series Data of Stock Prices</a>&nbsp;(en este art&#237;culo usan la librer&#237;a pandas_datareader, pero est&#225; dando errores, as&#237; que se usar&#225; la librer&#237;a Quandl).<br /><br /><br />El c&#243;digo del ejercicio se muestra a continuaci&#243;n:<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-_Hssjywird8/WxgvgExy9KI/AAAAAAAASxA/rcNLSRxNnk8i4WuSwCeIFg53QZiQ-pTXgCLcBGAs/s1600/importandolibrerias.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="176" src="https://3.bp.blogspot.com/-_Hssjywird8/WxgvgExy9KI/AAAAAAAASxA/rcNLSRxNnk8i4WuSwCeIFg53QZiQ-pTXgCLcBGAs/s320/importandolibrerias.png" width="320" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-qjOqNSt_YqM/WxgvtEQbzII/AAAAAAAASxE/ZvLqZdHRbBMVYJlVbzQMMqPErZpSyu4CwCLcBGAs/s1600/obteniendodatos.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="147" src="https://3.bp.blogspot.com/-qjOqNSt_YqM/WxgvtEQbzII/AAAAAAAASxE/ZvLqZdHRbBMVYJlVbzQMMqPErZpSyu4CwCLcBGAs/s320/obteniendodatos.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-Yz6Pd01Kqk4/WxgwHSA-yGI/AAAAAAAASxM/-3HKH7uUb5Y_Oz3xWVmK1sfDj6njzramgCLcBGAs/s1600/jb.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="101" src="https://1.bp.blogspot.com/-Yz6Pd01Kqk4/WxgwHSA-yGI/AAAAAAAASxM/-3HKH7uUb5Y_Oz3xWVmK1sfDj6njzramgCLcBGAs/s320/jb.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-v1GEUUeMGRI/WxgwLxi0X_I/AAAAAAAASxQ/t0kyQVyHxaM7mFzycLvY-aR_kW9TZgycACLcBGAs/s1600/sw.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="115" src="https://4.bp.blogspot.com/-v1GEUUeMGRI/WxgwLxi0X_I/AAAAAAAASxQ/t0kyQVyHxaM7mFzycLvY-aR_kW9TZgycACLcBGAs/s320/sw.png" width="320" /></a></div><br /><h2 id="Visualizando">Visualizando</h2><br /><div class="p-Widget jp-Cell jp-MarkdownCell jp-Notebook-cell jp-mod-rendered jp-mod-active jp-mod-selected"><div class="p-Widget p-Panel jp-Cell-inputWrapper"><div class="p-Widget jp-InputArea jp-Cell-inputArea"><div class="p-Widget jp-RenderedHTMLCommon jp-RenderedMarkdown jp-MarkdownOutput"><h3 id="Graficar-Ajuste-de-precio-de-cierre">Graficar Ajuste de precio de cierre<a class="jp-InternalAnchorLink" href="http://localhost:8888/lab#Graficar-Ajuste-de-precio-de-cierre" target="_self"></a></h3></div></div></div><div class="p-Widget jp-CellFooter jp-Cell-footer"></div></div><div class="p-Widget jp-Cell jp-MarkdownCell jp-Notebook-cell jp-mod-rendered"><div class="p-Widget jp-CellHeader jp-Cell-header"></div><div class="p-Widget p-Panel jp-Cell-inputWrapper"><div class="p-Widget jp-Collapser jp-InputCollapser jp-Cell-inputCollapser"><div class="jp-Collapser-child"></div></div><div class="p-Widget jp-InputArea jp-Cell-inputArea"></div></div></div><div class="p-Widget jp-RenderedHTMLCommon jp-RenderedMarkdown jp-MarkdownOutput">Se va a graficar el Ajuste de precio de cierre de las 3 aerolineas.<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-cONYlxYMnto/Wxgw21LRS8I/AAAAAAAASxc/6RT3CNqWVLInMT8J2iEDxEEb1nF0R6_xACLcBGAs/s1600/graficaajustecierre.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="175" src="https://2.bp.blogspot.com/-cONYlxYMnto/Wxgw21LRS8I/AAAAAAAASxc/6RT3CNqWVLInMT8J2iEDxEEb1nF0R6_xACLcBGAs/s320/graficaajustecierre.png" width="320" /></a></div><br /><h3 id="Graficar-el-Volumen-(Volume)">Graficar el Volumen (Volume)</h3><div class="separator" style="clear: both; text-align: center;"><a href="https://3.bp.blogspot.com/-ZVuBoELbBdw/WxgxI2bperI/AAAAAAAASxk/4OsxhZlIZ7EmN-jSsMJE7UbcKZmsb6n1ACLcBGAs/s1600/graficavolumen.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="164" src="https://3.bp.blogspot.com/-ZVuBoELbBdw/WxgxI2bperI/AAAAAAAASxk/4OsxhZlIZ7EmN-jSsMJE7UbcKZmsb6n1ACLcBGAs/s320/graficavolumen.png" width="320" /></a></div><div><div class="p-Widget jp-Cell jp-MarkdownCell jp-Notebook-cell jp-mod-rendered jp-mod-active jp-mod-selected"><div class="p-Widget p-Panel jp-Cell-inputWrapper"><div class="p-Widget jp-InputArea jp-Cell-inputArea"><div class="p-Widget jp-RenderedHTMLCommon jp-RenderedMarkdown jp-MarkdownOutput">Se puede notar que la aerolinea Delta tiene un pico muy alto en alg&#250;n momento del a&#241;o 2013.</div></div></div><div class="p-Widget jp-CellFooter jp-Cell-footer"></div></div><div class="p-Widget jp-Cell jp-MarkdownCell jp-Notebook-cell jp-mod-rendered"><div class="p-Widget jp-CellHeader jp-Cell-header"></div><div class="p-Widget p-Panel jp-Cell-inputWrapper"><div class="p-Widget jp-Collapser jp-InputCollapser jp-Cell-inputCollapser"><div class="jp-Collapser-child"></div></div><div class="p-Widget jp-InputArea jp-Cell-inputArea"></div></div></div><div class="p-Widget jp-RenderedHTMLCommon jp-RenderedMarkdown jp-MarkdownOutput">Para obtener la fecha se usa el m&#233;todo idxmax.<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-1zf_0uFk1r8/WxgxdbYHHDI/AAAAAAAASxs/bFRhRRGy7QQUf4ATgb8fer05L1Ud_mwlwCLcBGAs/s1600/idxmax.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="38" src="https://4.bp.blogspot.com/-1zf_0uFk1r8/WxgxdbYHHDI/AAAAAAAASxs/bFRhRRGy7QQUf4ATgb8fer05L1Ud_mwlwCLcBGAs/s320/idxmax.png" width="320" /></a></div><br /><div class="p-Widget jp-Cell jp-MarkdownCell jp-Notebook-cell jp-mod-rendered jp-mod-active jp-mod-selected"><div class="p-Widget p-Panel jp-Cell-inputWrapper"><div class="p-Widget jp-InputArea jp-Cell-inputArea"><div class="p-Widget jp-RenderedHTMLCommon jp-RenderedMarkdown jp-MarkdownOutput"><h3 id="Movimientos-promedios--MA">Movimientos promedios  MA<a class="jp-InternalAnchorLink" href="http://localhost:8888/lab#Movimientos-promedios--MA" target="_self"></a></h3></div></div></div><div class="p-Widget jp-CellFooter jp-Cell-footer"></div></div><div class="p-Widget jp-Cell jp-MarkdownCell jp-Notebook-cell jp-mod-rendered"><div class="p-Widget jp-CellHeader jp-Cell-header"></div><div class="p-Widget p-Panel jp-Cell-inputWrapper"><div class="p-Widget jp-Collapser jp-InputCollapser jp-Cell-inputCollapser"><div class="jp-Collapser-child"></div></div><div class="p-Widget jp-InputArea jp-Cell-inputArea"></div></div></div><div class="p-Widget jp-RenderedHTMLCommon jp-RenderedMarkdown jp-MarkdownOutput">Los movimientos promedios se usan para detectar oportunidades de trading. <br />Este c&#225;lculo se toma de la media o promedio de los pasados precios (se llama movimientos promedio por que los datos est&#225;n continuamente moviendose).<br />Dependiendo del tipo de inversor (alto riesgo vs bajo riesgo, corto t&#233;rmino vs largo t&#233;rmino), se pueden ajustar los movimientos promedio a 10 d&#237;as, 20 d&#237;as, 50 d&#237;as, 200 d&#237;as, 1 a&#241;o, 5 a&#241;os, etc. <br />Para este caso se calcular&#225; el movimiento promedio a 50 d&#237;as y a 200 d&#237;as.<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-or5GGar5aDE/Wxgxw24vNsI/AAAAAAAASx0/5LrxJTx6HiQdb2YdYC27-2H6Ra3k3mKOQCLcBGAs/s1600/ma50-200.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="171" src="https://2.bp.blogspot.com/-or5GGar5aDE/Wxgxw24vNsI/AAAAAAAASx0/5LrxJTx6HiQdb2YdYC27-2H6Ra3k3mKOQCLcBGAs/s320/ma50-200.png" width="320" /></a></div><br /></div></div></div></div><br /><br />El raw del notebook lo pueden bajar del repositorio <a href="https://gitlab.com/mangoosta/articulos-cienciasdedatos/raw/master/quandl/VisualizandoSeriesTiempo.ipynb">gitlab</a>.<br /><br /><div class="graf graf--p" name="cef8">Si tienes alguna sugerencia o idea de como se puede aplicar este art&#237;culo, lo puedes dejar en los comentarios.</div><div class="graf graf--p" name="cef8"><br /></div><div class="graf graf--p" name="91a6">&#161;Haz tu donativo!</div><div class="graf graf--p" name="af4b">Si te gust&#243; el art&#237;culo puedes realizar un donativo con Bitcoin (BTC)  usando la billetera digital de tu preferencia a la siguiente direcci&#243;n: 197vyJ3KSCj287nLqhb7FSJpJUDayDoTMP&nbsp;</div><div class="graf graf--p" name="af4b"><br /></div><div class="graf graf--p" name="a993">O Escaneando el c&#243;digo QR desde billetera:</div><div class="separator" style="clear: both; text-align: center;"><a href="https://2.bp.blogspot.com/-YOx8OXA-Vog/Wxg0Hh2zK9I/AAAAAAAASyA/lvV7QGFiAyYxijXA0UFA0w-B4nSF37HIwCLcBGAs/s1600/197vyJ3KSCj287nLqhb7FSJpJUDayDoTMP.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://2.bp.blogspot.com/-YOx8OXA-Vog/Wxg0Hh2zK9I/AAAAAAAASyA/lvV7QGFiAyYxijXA0UFA0w-B4nSF37HIwCLcBGAs/s1600/197vyJ3KSCj287nLqhb7FSJpJUDayDoTMP.png" /></a></div><div class="graf graf--p" name="a993">Para el caso de paypal, tienes el bot&#243;n del lado derecho de la p&#225;gina.</div>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="June Update - Do you consent?">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">June Update - Do you consent?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">06 06 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The rushed, rough and rogue UX of services getting you to opt-in.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/91-refactoring.png" alt="Refactoring">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Refactoring</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">05 06 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/91-refactoring.png" alt="Refactoring" title="Refactoring" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Automating the Boring Stuff in Django Using the Check Framework</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">04 06 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Every team has a unique development style. Some teams implement localization and require translations. Some teams are more sensitive to database issues and require more careful handling of indexes and constraints. In this article we describe how we enforce our own development style using the Django check framework, the inspect and the ast modules from the Python standard library.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Power of Recursive Macros in Vim</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Jovica Ilic</a> <span class="article__date">03 06 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>If for some crazy reason you&#8217;re not already a user of Vim, shutdown your computer and go think about your life choices. Joking aside, Vim is really a great editor. And if you didn&#8217;t know &#8211; Vim supports macros. Basics of macros in Vim Macros represent a simple concept which can be described as &#8220;record... <a class="more-link" href="https://jovicailic.org/2018/06/recursive-macros-in-vim/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a rel="nofollow" href="https://jovicailic.org/2018/06/recursive-macros-in-vim/">The Power of Recursive Macros in Vim</a> appeared first on <a rel="nofollow" href="https://jovicailic.org">Jovica Ilic</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Models and databases with the Mito ORM and SxQL</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">29 05 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>Following is a tutorial on how to use the Mito ORM.</p>

<p>As usual, this is best read on the <a href="https://lispcookbook.github.io/cl-cookbook/databases.html">Common Lisp Cookbook</a>. It will be updated there.</p>

<p>The
<a href="https://github.com/CodyReichert/awesome-cl#database">Database section on the Awesome-cl list</a>
is a resource listing popular libraries to work with different kind of
databases. We can group them roughly in four categories:</p>

<ul>
<li>wrappers to one database engine (cl-sqlite, postmodern, cl-redis,…),</li>
<li>interfaces to several DB engines (clsql, sxql,…),</li>
<li>persistent object databases (bknr.datastore (see chap. 21 of &ldquo;Common Lisp Recipes&rdquo;), ubiquitous,…),</li>
<li><a href="https://en.wikipedia.org/wiki/Object-relational_mapping">Object Relational Mappers</a> (Mito),</li>
</ul>

<p>and other DB-related tools (pgloader).</p>

<p>We&rsquo;ll begin with an overview of Mito. If you must work with an
existing DB, you might want to have a look at cl-dbi and clsql. If you
don&rsquo;t need a SQL database and want automatic persistence of Lisp
objects, you also have a choice of libraries.</p>

<h1 id="the-mito-orm-and-sxql">The Mito ORM and SxQL</h1>

<p>Mito is in Quicklisp:</p>

<pre><code class="language-lisp">(ql:quickload :mito)
</code></pre>

<h2 id="overview">Overview</h2>

<p><a href="https://github.com/fukamachi/mito">Mito</a> is &ldquo;an ORM for Common Lisp
with migrations, relationships and PostgreSQL support&rdquo;.</p>

<ul>
<li>it <strong>supports MySQL, PostgreSQL and SQLite3</strong>,</li>
<li>when defining a model, it adds an <code>id</code> (serial primary key),
<code>created_at</code> and <code>updated_at</code> fields by default like Ruby&rsquo;s
ActiveRecord or Django,</li>
<li>handles DB <strong>migrations</strong> for the supported backends,</li>
<li>permits DB <strong>schema versioning</strong>,</li>
<li>is tested under SBCL and CCL.</li>
</ul>

<p>As an ORM, it allows to write class definitions, to specify
relationships, and provides functions to query the database.  For
custom queries, it relies on
<a href="https://github.com/fukamachi/sxql">SxQL</a>, an SQL generator that
provides the same interface for several backends.</p>

<p>Working with Mito generally involves these steps:</p>

<ul>
<li>connecting to the DB</li>
<li>writing <a href="https://lispcookbook.github.io/cl-cookbook/clos.html">CLOS</a> classes to define models</li>
<li>running migrations to create or alter tables</li>
<li>creating objects, saving same in the DB,</li>
</ul>

<p>and iterating.</p>

<h2 id="connecting-to-a-db">Connecting to a DB</h2>

<p>Mito provides the function <code>connect-toplevel</code> to establish a
connection to RDBMs:</p>

<pre><code class="language-lisp">(mito:connect-toplevel :mysql :database-name &quot;myapp&quot; :username &quot;fukamachi&quot; :password &quot;c0mon-1isp&quot;)
</code></pre>

<p>The driver type can be of <code>:mysql</code>, <code>:sqlite3</code> and <code>:postgres</code>.</p>

<p>With sqlite you don&rsquo;t need the username and password:</p>

<pre><code class="language-lisp">(connect-toplevel :sqlite3 :database-name &quot;myapp&quot;)
</code></pre>

<p>As usual, you need to create the MySQL or Postgre database beforehand.
Refer to their documentation.</p>

<p>Connecting sets <code>mito:*connection*</code> to the new connection and returns it.</p>

<p>Disconnect with <code>disconnect-toplevel</code>.</p>

<p>=&gt; you might make good use of a wrapper function:</p>

<pre><code class="language-lisp">(defun connect ()
  &quot;Connect to the DB.&quot;
  (connect-toplevel :sqlite3 :database-name &quot;myapp&quot;))
</code></pre>

<h2 id="models">Models</h2>

<h3 id="defining-models">Defining models</h3>

<p>In Mito, you can define a class which corresponds to a database table
by specifying <code>(:metaclass mito:dao-table-class)</code>:</p>

<pre><code class="language-lisp">(defclass user ()
  ((name :col-type (:varchar 64)
         :initarg :name
         :accessor user-name)
   (email :col-type (or (:varchar 128) :null)
          :initarg :email
          :accessor user-email))
  (:metaclass mito:dao-table-class))
</code></pre>

<p>Note that the class automatically adds some slots: a primary key named <code>id</code>
if there&rsquo;s no primary keys, <code>created_at</code> and <code>updated_at</code> for
recording timestamps. To disable these behaviors, specify <code>:auto-pk
nil</code> or <code>:record-timestamps nil</code> to the defclass forms.</p>

<p>You can inspect the new class:</p>

<pre><code class="language-lisp">(mito.class:table-column-slots (find-class 'user))
;=&gt; (#&lt;MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS MITO.DAO.MIXIN::ID&gt;
;    #&lt;MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS COMMON-LISP-USER::NAME&gt;
;    #&lt;MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS COMMON-LISP-USER::EMAIL&gt;
;    #&lt;MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS MITO.DAO.MIXIN::CREATED-AT&gt;
;    #&lt;MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS MITO.DAO.MIXIN::UPDATED-AT&gt;)
</code></pre>

<p>The class inherits <code>mito:dao-class</code> implicitly.</p>

<pre><code class="language-lisp">(find-class 'user)
;=&gt; #&lt;MITO.DAO.TABLE:DAO-TABLE-CLASS COMMON-LISP-USER::USER&gt;

(c2mop:class-direct-superclasses *)
;=&gt; (#&lt;STANDARD-CLASS MITO.DAO.TABLE:DAO-CLASS&gt;)
</code></pre>

<p>This may be useful when you define methods which can be applied for
all table classes.</p>

<p>For more information on using the Common Lisp Object System, see the
<a href="clos.html">clos</a> page.</p>

<h3 id="creating-the-tables">Creating the tables</h3>

<p>After defining the models, you must create the tables:</p>

<pre><code class="language-lisp">(mito:ensure-table-exists 'user)
</code></pre>

<p>So a helper function:</p>

<pre><code class="language-lisp">(defun ensure-tables ()
  (mapcar #'mito:ensure-table-exists '(user foo bar)))
</code></pre>

<p>See
<a href="https://github.com/fukamachi/mito#generating-table-definitions">Mito&rsquo;s documentation</a>
for a couple more ways.</p>

<p>When you alter the model you&rsquo;ll need to run a DB migration, see the next section.</p>

<h3 id="fields">Fields</h3>

<h4 id="fields-types">Fields types</h4>

<p>Field types are:</p>

<p><code>(:varchar &lt;integer&gt;)</code> ,</p>

<p><code>:serial</code>, <code>:bigserial</code>, <code>:integer</code>, <code>:bigint</code>, <code>:unsigned</code>,</p>

<p><code>:timestamp</code>, <code>:timestamptz</code>,</p>

<p><code>:bytea</code>,</p>

<h4 id="optional-fields">Optional fields</h4>

<p>Use <code>(or &lt;real type&gt; :null)</code>:</p>

<pre><code class="language-lisp">   (email :col-type (or (:varchar 128) :null)
          :initarg :email
          :accessor user-email))
</code></pre>

<h4 id="field-constraints">Field constraints</h4>

<p><code>:unique-keys</code> can be used like so:</p>

<pre><code class="language-lisp">(defclass user ()
  ((name :col-type (:varchar 64)
         :initarg :name
         :accessor user-name)
   (email :col-type (:varchar 128)
          :initarg :email
          :accessor user-email))
  (:metaclass mito:dao-table-class)
  (:unique-keys email))
</code></pre>

<p>We already saw <code>:primary-key</code>.</p>

<p>You can change the table name with <code>:table-name</code>.</p>

<h3 id="relationships">Relationships</h3>

<p>You can define a relationship by specifying  a foreign class with <code>:col-type</code>:</p>

<pre><code class="language-lisp">(defclass tweet ()
  ((status :col-type :text
           :initarg :status
           :accessor tweet-status)
   ;; This slot refers to USER class
   (user :col-type user
         :initarg :user
         :accessor tweet-user))
  (:metaclass mito:dao-table-class))

(table-definition (find-class 'tweet))
;=&gt; (#&lt;SXQL-STATEMENT: CREATE TABLE tweet (
;        id BIGSERIAL NOT NULL PRIMARY KEY,
;        status TEXT NOT NULL,
;        user_id BIGINT NOT NULL,
;        created_at TIMESTAMP,
;        updated_at TIMESTAMP
;    )&gt;)
</code></pre>

<p>Now you can create or retrieve a <code>TWEET</code> by a <code>USER</code> object, not a <code>USER-ID</code>.</p>

<pre><code class="language-lisp">(defvar *user* (mito:create-dao 'user :name &quot;Eitaro Fukamachi&quot;))
(mito:create-dao 'tweet :user *user*)

(mito:find-dao 'tweet :user *user*)
</code></pre>

<p>Mito doesn&rsquo;t add foreign key constraints for refering tables.</p>

<h4 id="one-to-one">One-to-one</h4>

<p>A one-to-one relationship is simply represented with a simple foreign
key on a slot (as <code>:col-type user</code> in the <code>tweet</code> class). Besides, we
can add a unicity constraint, as with <code>(:unique-keys email)</code>.</p>

<h4 id="one-to-many-many-to-one">One-to-many, many-to-one</h4>

<p>The tweet example above shows a one-to-many relationship between a user and
his tweets: a user can write many tweets, and a tweet belongs to only
one user.</p>

<p>The relationship is defined with a foreign key on the &ldquo;many&rdquo; side
linking back to the &ldquo;one&rdquo; side. Here the <code>tweet</code> class defines a
<code>user</code> foreign key, so a tweet can only have one user. You didn&rsquo;t need
to edit the <code>user</code> class.</p>

<p>A many-to-one relationship is actually the contraty of a one-to-many.
You have to put the foreign key on the approriate side.</p>

<h4 id="many-to-many">Many-to-many</h4>

<p>A many-to-many relationship needs an intermediate table, which will be
the &ldquo;many&rdquo; side for the two tables it is the intermediary of.</p>

<p>And, thanks to the join table, we can store more information about the relationship.</p>

<p>Let&rsquo;s define a <code>book</code> class:</p>

<pre><code class="language-lisp">(defclass book ()
    ((title
       :col-type (:varchar 128)
       :initarg :title
       :accessor title)
     (ean
       :col-type (or (:varchar 128) :null)
       :initarg :ean
       :accessor ean))
    (:metaclass mito:dao-table-class))
</code></pre>

<p>A user can have many books, and a book (as the title, not the physical
copy) is likely to be in many people&rsquo;s library. Here&rsquo;s the
intermediate class:</p>

<pre><code class="language-lisp">(defclass user-books ()
    ((user
      :col-type user
      :initarg :user)
    (book
      :col-type book
      :initarg :book))
    (:metaclass mito:dao-table-class))
</code></pre>

<p>Each time we want to add a book to a user&rsquo;s collection (say in
a <code>add-book</code> function), we create a new <code>user-books</code> object.</p>

<p>But someone may very well own many copies of one book. This is an
information we can store in the join table:</p>

<pre><code class="language-lisp">(defclass user-books ()
    ((user
      :col-type user
      :initarg :user)
    (book
      :col-type book
      :initarg :book)
    ;; Set the quantity, 1 by default:
    (quantity
      :col-type :integer
      :initarg :quantity
      :initform 1
      :accessor quantity))
    (:metaclass mito:dao-table-class))
</code></pre>

<h3 id="inheritance-and-mixin">Inheritance and mixin</h3>

<p>A subclass of DAO-CLASS is allowed to be inherited. This may be useful
when you need classes which have similar columns:</p>

<pre><code class="language-lisp">(defclass user ()
  ((name :col-type (:varchar 64)
         :initarg :name
         :accessor user-name)
   (email :col-type (:varchar 128)
          :initarg :email
          :accessor user-email))
  (:metaclass mito:dao-table-class)
  (:unique-keys email))

(defclass temporary-user (user)
  ((registered-at :col-type :timestamp
                  :initarg :registered-at
                  :accessor temporary-user-registered-at))
  (:metaclass mito:dao-table-class))

(mito:table-definition 'temporary-user)
;=&gt; (#&lt;SXQL-STATEMENT: CREATE TABLE temporary_user (
;        id BIGSERIAL NOT NULL PRIMARY KEY,
;        name VARCHAR(64) NOT NULL,
;        email VARCHAR(128) NOT NULL,
;        registered_at TIMESTAMP NOT NULL,
;        created_at TIMESTAMP,
;        updated_at TIMESTAMP,
;        UNIQUE (email)
;    )&gt;)
</code></pre>

<p>If you need a &lsquo;template&rsquo; for tables which doesn&rsquo;t related to any
database tables, you can use <code>DAO-TABLE-MIXIN</code>. Below the <code>has-email</code>
class will not create a table.</p>

<pre><code class="language-lisp">(defclass has-email ()
  ((email :col-type (:varchar 128)
          :initarg :email
          :accessor object-email))
  (:metaclass mito:dao-table-mixin)
  (:unique-keys email))
;=&gt; #&lt;MITO.DAO.MIXIN:DAO-TABLE-MIXIN COMMON-LISP-USER::HAS-EMAIL&gt;

(defclass user (has-email)
  ((name :col-type (:varchar 64)
         :initarg :name
         :accessor user-name))
  (:metaclass mito:dao-table-class))
;=&gt; #&lt;MITO.DAO.TABLE:DAO-TABLE-CLASS COMMON-LISP-USER::USER&gt;

(mito:table-definition 'user)
;=&gt; (#&lt;SXQL-STATEMENT: CREATE TABLE user (
;       id BIGSERIAL NOT NULL PRIMARY KEY,
;       name VARCHAR(64) NOT NULL,
;       email VARCHAR(128) NOT NULL,
;       created_at TIMESTAMP,
;       updated_at TIMESTAMP,
;       UNIQUE (email)
;   )&gt;)
</code></pre>

<p>See more examples of use in <a href="https://github.com/fukamachi/mito-auth/">mito-auth</a>.</p>

<h3 id="troubleshooting">Troubleshooting</h3>

<h4 id="cannot-change-class-objects-into-class-metaobjects">&ldquo;Cannot CHANGE-CLASS objects into CLASS metaobjects.&rdquo;</h4>

<p>If you get the following error message:</p>

<pre><code>Cannot CHANGE-CLASS objects into CLASS metaobjects.
   [Condition of type SB-PCL::METAOBJECT-INITIALIZATION-VIOLATION]
See also:
  The Art of the Metaobject Protocol, CLASS [:initialization]
</code></pre>

<p>it is certainly because you first wrote a class definition and <em>then</em>
added the Mito metaclass and tried to evaluate the class definition
again.</p>

<p>If this happens, you must remove the class definition from the current package:</p>

<pre><code class="language-lisp">(setf (find-class 'foo) nil)
</code></pre>

<p>or, with the Slime inspector, click on the class and find the &ldquo;remove&rdquo; button.</p>

<p>More info <a href="https://stackoverflow.com/questions/38811931/how-to-change-classs-metaclass">here</a>.</p>

<h2 id="migrations">Migrations</h2>

<p>First create the tables if needed:</p>

<pre><code class="language-lisp">(ensure-table-exists 'user)
</code></pre>

<p>then alter the tables, if needed:</p>

<pre><code class="language-lisp">(mito:migrate-table 'user)
</code></pre>

<p>You can check the SQL generated code with <code>migration-expressions
'class</code>. For example, we create the <code>user</code> table:</p>

<pre><code class="language-lisp">(ensure-table-exists 'user)
;-&gt; ;; CREATE TABLE IF NOT EXISTS &quot;user&quot; (
;       &quot;id&quot; BIGSERIAL NOT NULL PRIMARY KEY,
;       &quot;name&quot; VARCHAR(64) NOT NULL,
;       &quot;email&quot; VARCHAR(128),
;       &quot;created_at&quot; TIMESTAMP,
;       &quot;updated_at&quot; TIMESTAMP
;   ) () [0 rows] | MITO.DAO:ENSURE-TABLE-EXISTS
</code></pre>

<p>There are no changes from the previous user definition:</p>

<pre><code class="language-lisp">(mito:migration-expressions 'user)
;=&gt; NIL
</code></pre>

<p>Now let&rsquo;s add a unique <code>email</code> field:</p>

<pre><code class="language-lisp">(defclass user ()
  ((name :col-type (:varchar 64)
         :initarg :name
         :accessor user-name)
   (email :col-type (:varchar 128)
          :initarg :email
          :accessor user-email))
  (:metaclass mito:dao-table-class)
  (:unique-keys email))
</code></pre>

<p>The migration will run the following code:</p>

<pre><code class="language-lisp">(mito:migration-expressions 'user)
;=&gt; (#&lt;SXQL-STATEMENT: ALTER TABLE user ALTER COLUMN email TYPE character varying(128), ALTER COLUMN email SET NOT NULL&gt;
;    #&lt;SXQL-STATEMENT: CREATE UNIQUE INDEX unique_user_email ON user (email)&gt;)
</code></pre>

<p>so let&rsquo;s apply it:</p>

<pre><code class="language-lisp">(mito:migrate-table 'user)
;-&gt; ;; ALTER TABLE &quot;user&quot; ALTER COLUMN &quot;email&quot; TYPE character varying(128), ALTER COLUMN &quot;email&quot; SET NOT NULL () [0 rows] | MITO.MIGRATION.TABLE:MIGRATE-TABLE
;   ;; CREATE UNIQUE INDEX &quot;unique_user_email&quot; ON &quot;user&quot; (&quot;email&quot;) () [0 rows] | MITO.MIGRATION.TABLE:MIGRATE-TABLE
;-&gt; (#&lt;SXQL-STATEMENT: ALTER TABLE user ALTER COLUMN email TYPE character varying(128), ALTER COLUMN email SET NOT NULL&gt;
;    #&lt;SXQL-STATEMENT: CREATE UNIQUE INDEX unique_user_email ON user (email)&gt;)
</code></pre>

<h2 id="queries">Queries</h2>

<h3 id="creating-objects">Creating objects</h3>

<p>We can create user objects with the regular <code>make-instance</code>:</p>

<pre><code class="language-lisp">(defvar me
  (make-instance 'user :name &quot;Eitaro Fukamachi&quot; :email &quot;e.arrows@gmail.com&quot;))
;=&gt; USER
</code></pre>

<p>To save it in DB, use <code>insert-dao</code>:</p>

<pre><code class="language-lisp">(mito:insert-dao me)
;-&gt; ;; INSERT INTO `user` (`name`, `email`, `created_at`, `updated_at`) VALUES (?, ?, ?, ?) (&quot;Eitaro Fukamachi&quot;, &quot;e.arrows@gmail.com&quot;, &quot;2016-02-04T19:55:16.365543Z&quot;, &quot;2016-02-04T19:55:16.365543Z&quot;) [0 rows] | MITO.DAO:INSERT-DAO
;=&gt; #&lt;USER {10053C4453}&gt;
</code></pre>

<p>Do the two steps above at once:</p>

<pre><code class="language-lisp">(mito:create-dao 'user :name &quot;Eitaro Fukamachi&quot; :email &quot;e.arrows@gmail.com&quot;)
</code></pre>

<p>You should not export the <code>user</code> class and create objects outside of
its package (it is good practice anyway to keep all database-related
operations in say a <code>models</code> package and file). You should instead use
a helper function:</p>

<pre><code class="language-lisp">(defun make-user (&amp;key name)
  (make-instance 'user :name name))
</code></pre>

<h3 id="updating-fields">Updating fields</h3>

<pre><code class="language-lisp">(setf (slot-value me 'name) &quot;nitro_idiot&quot;)
;=&gt; &quot;nitro_idiot&quot;
</code></pre>

<p>and save it:</p>

<pre><code class="language-lisp">(mito:save-dao me)
</code></pre>

<h3 id="deleting">Deleting</h3>

<pre><code class="language-lisp">(mito:delete-dao me)
;-&gt; ;; DELETE FROM `user` WHERE (`id` = ?) (1) [0 rows] | MITO.DAO:DELETE-DAO

;; or:
(mito:delete-by-values 'user :id 1)
;-&gt; ;; DELETE FROM `user` WHERE (`id` = ?) (1) [0 rows] | MITO.DAO:DELETE-DAO
</code></pre>

<h3 id="get-the-primary-key-value">Get the primary key value</h3>

<pre><code class="language-lisp">(mito:object-id me)
;=&gt; 1
</code></pre>

<h3 id="count">Count</h3>

<pre><code class="language-lisp">(mito:count-dao 'user)
;=&gt; 1
</code></pre>

<h3 id="find-one">Find one</h3>

<pre><code class="language-lisp">(mito:find-dao 'user :id 1)
;-&gt; ;; SELECT * FROM `user` WHERE (`id` = ?) LIMIT 1 (1) [1 row] | MITO.DB:RETRIEVE-BY-SQL
;=&gt; #&lt;USER {10077C6073}&gt;
</code></pre>

<p>So here&rsquo;s a possibility of generic helpers to find an object by a given key:</p>

<pre><code class="language-lisp">(defgeneric find-user (key-name key-value)
  (:documentation &quot;Retrieves an user from the data base by one of the unique
keys.&quot;))

(defmethod find-user ((key-name (eql :id)) (key-value integer))
  (mito:find-dao 'user key-value))

(defmethod find-user ((key-name (eql :name)) (key-value string))
  (first (mito:select-dao 'user
                          (sxql:where (:= :name key-value)))))
</code></pre>

<h3 id="find-all">Find all</h3>

<p>Use <code>select-dao</code>.</p>

<p>Get a list of all users:</p>

<pre><code class="language-lisp">(mito:select-dao 'user)
;=&gt; (#&lt;USER {10077C6073}&gt;)
</code></pre>

<h3 id="find-by-relationship">Find by relationship</h3>

<p>As seen above:</p>

<pre><code class="language-lisp">(mito:find-dao 'tweet :user *user*)
</code></pre>

<h3 id="custom-queries">Custom queries</h3>

<p>It is with <code>select-dao</code> that you can write more precise queries by
giving it <a href="https://github.com/fukamachi/sxql">SxQL</a> statements.</p>

<p>Example:</p>

<pre><code class="language-lisp">(select-dao 'tweet
    (where (:like :status &quot;%Japan%&quot;)))
</code></pre>

<h4 id="clauses">Clauses</h4>

<p>See the <a href="https://github.com/fukamachi/sxql#sql-clauses">SxQL documentation</a>.</p>

<p>Examples:</p>

<pre><code class="language-lisp">(select-dao 'foo
  (where (:and (:&gt; :age 20) (:&lt;= :age 65))))
</code></pre>

<pre><code class="language-lisp">(order-by :age (:desc :id))
</code></pre>

<pre><code class="language-lisp">(group-by :sex)
</code></pre>

<pre><code class="language-lisp">(having (:&gt;= (:sum :hoge) 88))
</code></pre>

<pre><code class="language-lisp">(limit 0 10)
</code></pre>

<p>and <code>join</code>s, etc.</p>

<h4 id="operators">Operators</h4>

<pre><code class="language-lisp">:not
:is-null, :not-null
:asc, :desc
:distinct
:=, :!=
:&lt;, :&gt;, :&lt;= :&gt;=
:a&lt;, :a&gt;
:as
:in, :not-in
:like
:and, :or
:+, :-, :* :/ :%
:raw
</code></pre>

<h2 id="triggers">Triggers</h2>

<p>Since <code>insert-dao</code>, <code>update-dao</code> and <code>delete-dao</code> are defined as generic
functions, you can define <code>:before</code>, <code>:after</code> or <code>:around</code> methods to those, like regular <a href="https://lispcookbook.github.io/cl-cookbook/clos.html#qualifiers-and-method-combination">method combination</a>.</p>

<pre><code class="language-lisp">(defmethod mito:insert-dao :before ((object user))
  (format t &quot;~&amp;Adding ~S...~%&quot; (user-name object)))

(mito:create-dao 'user :name &quot;Eitaro Fukamachi&quot; :email &quot;e.arrows@gmail.com&quot;)
;-&gt; Adding &quot;Eitaro Fukamachi&quot;...
;   ;; INSERT INTO &quot;user&quot; (&quot;name&quot;, &quot;email&quot;, &quot;created_at&quot;, &quot;updated_at&quot;) VALUES (?, ?, ?, ?) (&quot;Eitaro Fukamachi&quot;, &quot;e.arrows@gmail.com&quot;, &quot;2016-02-16 21:13:47&quot;, &quot;2016-02-16 21:13:47&quot;) [0 rows] | MITO.DAO:INSERT-DAO
;=&gt; #&lt;USER {100835FB33}&gt;
</code></pre>

<h2 id="inflation-deflation">Inflation/Deflation</h2>

<p>Inflation/Deflation is a function to convert values between Mito and RDBMS.</p>

<pre><code class="language-lisp">(defclass user-report ()
  ((title :col-type (:varchar 100)
          :initarg :title
          :accessor report-title)
   (body :col-type :text
         :initarg :body
         :initform &quot;&quot;
         :accessor report-body)
   (reported-at :col-type :timestamp
                :initarg :reported-at
                :initform (local-time:now)
                :accessor report-reported-at
                :inflate #'local-time:universal-to-timestamp
                :deflate #'local-time:timestamp-to-universal))
  (:metaclass mito:dao-table-class))
</code></pre>

<h2 id="eager-loading">Eager loading</h2>

<p>One of the pains in the neck to use ORMs is the &ldquo;N+1 query&rdquo; problem.</p>

<pre><code class="language-lisp">;; BAD EXAMPLE

(use-package '(:mito :sxql))

(defvar *tweets-contain-japan*
  (select-dao 'tweet
    (where (:like :status &quot;%Japan%&quot;))))

;; Getting names of tweeted users.
(mapcar (lambda (tweet)
          (user-name (tweet-user tweet)))
        *tweets-contain-japan*)
</code></pre>

<p>This example sends a query to retrieve a user like &ldquo;SELECT * FROM user
WHERE id = ?&rdquo; at each iteration.</p>

<p>To prevent this performance issue, add <code>includes</code> to the above query
which only sends a single WHERE IN query instead of N queries:</p>

<pre><code class="language-lisp">;; GOOD EXAMPLE with eager loading

(use-package '(:mito :sxql))

(defvar *tweets-contain-japan*
  (select-dao 'tweet
    (includes 'user)
    (where (:like :status &quot;%Japan%&quot;))))
;-&gt; ;; SELECT * FROM `tweet` WHERE (`status` LIKE ?) (&quot;%Japan%&quot;) [3 row] | MITO.DB:RETRIEVE-BY-SQL
;-&gt; ;; SELECT * FROM `user` WHERE (`id` IN (?, ?, ?)) (1, 3, 12) [3 row] | MITO.DB:RETRIEVE-BY-SQL
;=&gt; (#&lt;TWEET {1003513EC3}&gt; #&lt;TWEET {1007BABEF3}&gt; #&lt;TWEET {1007BB9D63}&gt;)

;; No additional SQLs will be executed.
(tweet-user (first *))
;=&gt; #&lt;USER {100361E813}&gt;
</code></pre>

<h2 id="schema-versioning">Schema versioning</h2>

<pre><code>$ ros install mito
$ mito
Usage: mito command [option...]

Commands:
    generate-migrations
    migrate

Options:
    -t, --type DRIVER-TYPE          DBI driver type (one of &quot;mysql&quot;, &quot;postgres&quot; or &quot;sqlite3&quot;)
    -d, --database DATABASE-NAME    Database name to use
    -u, --username USERNAME         Username for RDBMS
    -p, --password PASSWORD         Password for RDBMS
    -s, --system SYSTEM             ASDF system to load (several -s's allowed)
    -D, --directory DIRECTORY       Directory path to keep migration SQL files (default: &quot;/Users/nitro_idiot/Programs/lib/mito/db/&quot;)
    --dry-run                       List SQL expressions to migrate
</code></pre>

<h2 id="introspection">Introspection</h2>

<p>Mito provides some functions for introspection.</p>

<p>We can access the information of <strong>columns</strong> with the functions in
<code>(mito.class.column:...)</code>:</p>

<ul>
<li><code>table-column-[class, name, info, not-null-p,...]</code></li>
<li><code>primary-key-p</code></li>
</ul>

<p>and likewise for <strong>tables</strong> with <code>(mito.class.table:...)</code>.</p>

<p>Given we get a list of slots of our class:</p>

<pre><code class="language-lisp">(ql:quickload &quot;closer-mop&quot;)

(closer-mop:class-direct-slots (find-class 'user))
;; (#&lt;MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS NAME&gt;
;;  #&lt;MITO.DAO.COLUMN:DAO-TABLE-COLUMN-CLASS EMAIL&gt;)

(defparameter user-slots *)
</code></pre>

<p>We can answer the following questions:</p>

<h3 id="what-is-the-type-of-this-column">What is the type of this column ?</h3>

<pre><code class="language-lisp">(mito.class.column:table-column-type (first user-slots))
;; (:VARCHAR 64)
</code></pre>

<h3 id="is-this-column-nullable">Is this column nullable ?</h3>

<pre><code class="language-lisp">(mito.class.column:table-column-not-null-p
  (first user-slots))
;; T
(mito.class.column:table-column-not-null-p
  (second user-slots))
;; NIL
</code></pre>

<h2 id="testing">Testing</h2>

<p>We don&rsquo;t want to test DB operations against the production one. We
need to create a temporary DB before each test.</p>

<p>The macro below creates a temporary DB with a random name, creates the
tables, runs the code and connects back to the original DB connection.</p>

<pre><code class="language-lisp">(defun random-string (length)
  ;; thanks 40ants/hacrm.
  (let ((chars &quot;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789&quot;))
    (coerce (loop repeat length
                  collect (aref chars (random (length chars))))
            'string)))

(defmacro with-empty-db (&amp;body body)
  &quot;Run `body` with a new temporary DB.
  &quot;
  `(let* ((*random-state* (make-random-state t))
          (prefix (concatenate 'string
                               (random-string 8)
                               &quot;/&quot;))
          (connection mito:*connection*))
     (uiop:with-temporary-file (:pathname name :prefix prefix)
       (let* ((*db-name* name)
              (*db* (connect)))
         (ensure-tables-exist)
         (migrate-all)
         ,@body
         (setf mito:*connection* connection)
         (connect)))))
</code></pre>

<p>Use it like this:</p>

<pre><code class="language-lisp">(prove:subtest &quot;Creation in a temporary DB.&quot;
  (with-empty-db
    (let ((user (make-user :name &quot;Cookbook&quot;)))
      (save-user user)

      (prove:is (name user)
                &quot;Cookbook&quot;
                &quot;Test username in a temp DB.&quot;))))
;; Creation in a temporary DB
;;  CREATE TABLE &quot;user&quot; (
;;       id BIGSERIAL NOT NULL PRIMARY KEY,
;;       name VARCHAR(64) NOT NULL,
;;       email VARCHAR(128) NOT NULL,
;;       created_at TIMESTAMP,
;;       updated_at TIMESTAMP,
;;       UNIQUE (email)
;; ) () [0 rows] | MITO.DB:EXECUTE-SQL
;; ✓ Test username in a temp DB.
</code></pre>

<h2 id="see-also">See also</h2>

<ul>
<li><a href="https://github.com/fukamachi/mito-attachment">mito-attachment</a></li>
<li><a href="https://github.com/fukamachi/mito-auth">mito-auth</a></li>
<li><a href="https://github.com/fukamachi/can/">can</a> a role-based access right control library</li>
<li>an advanced <a href="https://lispcookbook.github.io/cl-cookbook/assets/defmodel.lisp">&ldquo;defmodel&rdquo; macro</a>.</li>
</ul>

<!-- # todo: Generating models for an existing DB -->

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/90-drive-test.png" alt="Drive Test">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Drive Test</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">29 05 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/90-drive-test.png" alt="Drive Test - QA" title="Drive Test - QA" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="Tracker Tax">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Tracker Tax</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">28 05 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The impact of third-party trackers on website speed in the United States.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Dynamic Bézier Curves</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">23 05 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A deep dive into Bézier curves in React. We'll look at how to build dynamic effects such as scroll-to-flatten using SVG path instructions, and how to architect our components for maximum readability and reusability.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/89-reopened.png" alt="Reopened">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Reopened</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">22 05 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/89-reopened.png" alt="Reopened" title="Reopened" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/88-workaround.png" alt="Workaround">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Workaround</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">15 05 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/88-workaround.png" alt="Workaround" title="Workaround" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://www.emezeta.com/img/logo.png" alt="10 comandos de terminal que quizás no conocías">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">10 comandos de terminal que quizás no conocías</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Emezeta blog</a> <span class="article__date">13 05 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ¿Buscas comandos para realizar tareas cómoda y rápidamente en una terminal? Has llegado al sitio adecuado. A continuación, una lista de comandos que quizás desconoces.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">May 2018 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">12 05 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together news Not much to report from Clojurists Together this month, things have been pretty quiet with lots of other things going on. This is the first month of work from the second round of funding. Bozhidar Batsov is working on CIDER + related projects and Mike Fikes is working on ClojureScript. If you like the work that they&rsquo;re doing and would like to support it further, consider joining yourself or your company as a member.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/media/2018/paul-fathom-tweet.jpg" alt="Reviving Ana as Fathom: simple &amp; transparent website analytics">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Reviving Ana as Fathom: simple &amp; transparent website analytics</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Danny van Kooten</a> <span class="article__date">11 05 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <blockquote>
  <p>Update (Mar 2019): I <a href="/stepping-down-fathom-maintainer/">left the Fathom project</a>.</p>
</blockquote>

<p>As I was browsing my Twitter feed a few weeks ago, I came across the following tweet.</p>

<p><a href="https://twitter.com/pjrvs/status/985874315563286528"><img src="/media/2018/paul-fathom-tweet.jpg" alt="Paul's tweet about Fathom" /></a></p>

<p>I had the same idea in late 2016 when I set out to built my own open-source website analytics alternative called Ana. It even got some traction back then.</p>

<p>Sadly, I got sidetracked and didn’t spend any more time on it. I still firmly believe in the idea though.</p>

<p>Knowing Paul as a super knowledgeable power-user of our <a href="https://www.mc4wp.com/">Mailchimp for WordPress plugin</a>, I tweeted him that I would love to help out, if at all possible. And it was!</p>

<p>Together, we are setting out to build <strong>website analytics that is simple, transparent and that respects your visitor’s privacy</strong>. We’re a few weeks in at this point and already running a beta version on our personal sites:</p>

<p><img src="/media/2018/fathom-preview.png" alt="Fathom dashboard for this site" /></p>

<p>We’re developing Fathom out in the open; here’s <a href="https://github.com/usefathom/fathom">Fathom on GitHub</a>.</p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="May Update - Countdown to GDPR">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">May Update - Countdown to GDPR</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">10 05 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Facebook's "Tough" month and Google's recommendation
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/87-code-reuse.png" alt="Code Reuse">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Code Reuse</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">08 05 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/87-code-reuse.png" alt="Code Reuse" title="Code Reuse" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://www.emezeta.com/img/logo.png" alt="Tutorial CSS: Cómo crear un objeto que baile">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Tutorial CSS: Cómo crear un objeto que baile</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Emezeta blog</a> <span class="article__date">04 05 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        En Codevember 2017 hice esta demo con un personaje moviéndose mientras sonaba de fondo Bonetrousle (Undertale). Veamos paso a paso, como hacer esto con CSS.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="Tracking visits without tracking people">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Tracking visits without tracking people</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">02 05 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A privacy-by-design approach.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/86-fixing-unit-tests.png" alt="Fixing Unit Tests">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Fixing Unit Tests</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">02 05 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/86-fixing-unit-tests.png" alt="Fixing Unit Tests" title="Fixing Unit Tests" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q2 2018 Funding Announcement</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">26 04 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together is happy to announce that for Q2 of 2018 (May-July) we are funding two projects: CIDER and ClojureScript.
Recap For those who are new to Clojurists Together, our goal is simple: Fund critical Clojure open-source projects to keep them healthy and sustainable. Clojure companies and individual developers sign up for a monthly contribution, and we pick projects to fund each quarter. This is our second funding cycle since launching.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/85-going-global.png" alt="Going Global">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Going Global</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">24 04 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/85-going-global.png" alt="Going Global" title="Going Global" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="The end of google.{your country}?">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">The end of google.{your country}?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">22 04 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Google's move to keep their cookies.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">La libertad de desarrollar...: Algoritmo de Clasificaci&amp;#243;n con scikit-learn</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">21 04 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Continuando con los art&#237;culos sobre Inteligencia Artificial con Python.<br /><br />La serie de art&#237;culos sobre Scikit-Learn han sido:<br /><br /><ol><li><a href="http://blog.crespo.org.ve/2017/11/arbol-de-decision-hecho-en-python.html">&#193;rbol de decisi&#243;n hecho con Python</a>&nbsp;(est&#233; tendr&#225; una segunda parte).</li><li><a href="http://blog.crespo.org.ve/2018/02/una-red-neuronal-para-aprendizaje.html">Una red neuronal para aprendizaje supervisado usando scikit-learn</a>.</li><li><a href="http://blog.crespo.org.ve/2018/02/funciones-de-activacion-para-un.html">Funciones de activaci&#243;n para un perceptron</a>.</li></ol>El ejercicio que se explicar&#225; ser&#225; el de algoritmo de clasificaci&#243;n usando scikit-learn por medio del ejemplo de la resoluci&#243;n de la tabla de la verdad de un Or exclusivo (XOR).<br /><br /><a href="http://scikit-learn.org/">Scikit-learn</a> es una librer&#237;a de Machine Learning para Python que soporta algoritmos de clasificaci&#243;n, regresi&#243;n y clustering (<a href="https://en.wikipedia.org/wiki/Scikit-learn">wikipedia</a>).<br /><br />A continuaci&#243;n el notebook de jupyter:<br /><br /><br /><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Se-crear&#225;-una-red-neuronal-para-clasificaci&#243;n">Se crear&#225; una red neuronal para clasificaci&#243;n<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Se-crear%C3%A1-una-red-neuronal-para-clasificaci%C3%B3n">&#182;</a></h3>Se usar&#225; la tabla de la verdad de XOR<br /><table><thead><tr><th>x</th><th>y</th><th>Salida</th></tr></thead><tbody><tr><td>0</td><td>0</td><td>0</td><td></td></tr><tr><td>0</td><td>1</td><td>1</td><td></td></tr><tr><td>1</td><td>0</td><td>1</td><td></td></tr><tr><td>1</td><td>1</td><td>0</td><td></td></tr></tbody></table><br />Para instalar scikit-learn se usa pip<br /> <code>pip3 install  scikit-learn</code></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[4]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">##Se importa Numpy, MLPCCLassifier y KNeighborsClassifier</span><br /><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span><br /><span class="kn">from</span> <span class="nn">sklearn.neural_network</span> <span class="k">import</span> <span class="n">MLPClassifier</span><br /><span class="kn">from</span> <span class="nn">sklearn.neighbors</span> <span class="k">import</span> <span class="n">KNeighborsClassifier</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[5]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#un Arreglo con la tabla de la verdad</span><br /><span class="c1"># 0 0</span><br /><span class="c1"># 0 1</span><br /><span class="c1"># 1 0</span><br /><span class="c1"># 1 1</span><br /><span class="n">xs</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><br />    <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span><br />    <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span><br />    <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span><br />    <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><br /><span class="p">])</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span><br /><span class="n">xs</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[5]:</div><div class="output_text output_subarea output_execute_result"><pre>array([[0, 0],<br />       [0, 1],<br />       [1, 0],<br />       [1, 1]])</pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[6]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Se muestra un arreglo con el resultado de hacer un XOR</span><br /><span class="n">ys</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="mi">4</span><span class="p">,)</span><br /><span class="n">ys</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[6]:</div><div class="output_text output_subarea output_execute_result"><pre>array([0, 1, 1, 0])</pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[7]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Se crea el clasificador con la funci&#243;n de activaci&#243;n relu,con 10k iteraciones y tiene capaz ocultas 4,2</span><br /><span class="n">model</span> <span class="o">=</span> <span class="n">MLPClassifier</span><span class="p">(</span><span class="n">activation</span><span class="o">=</span><span class="s1">'tanh'</span><span class="p">,</span> <span class="n">max_iter</span><span class="o">=</span><span class="mi">10000</span><span class="p">,</span> <span class="n">hidden_layer_sizes</span><span class="o">=</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span><span class="mi">2</span><span class="p">))</span><br /><span class="n">model</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[7]:</div><div class="output_text output_subarea output_execute_result"><pre>MLPClassifier(activation='tanh', alpha=0.0001, batch_size='auto', beta_1=0.9,<br />       beta_2=0.999, early_stopping=False, epsilon=1e-08,<br />       hidden_layer_sizes=(4, 2), learning_rate='constant',<br />       learning_rate_init=0.001, max_iter=10000, momentum=0.9,<br />       nesterovs_momentum=True, power_t=0.5, random_state=None,<br />       shuffle=True, solver='adam', tol=0.0001, validation_fraction=0.1,<br />       verbose=False, warm_start=False)</pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[8]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Se entrena la red neuronal pasando los arreglos de entrada y de salida</span><br /><span class="n">model</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">xs</span><span class="p">,</span> <span class="n">ys</span><span class="p">)</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[8]:</div><div class="output_text output_subarea output_execute_result"><pre>MLPClassifier(activation='tanh', alpha=0.0001, batch_size='auto', beta_1=0.9,<br />       beta_2=0.999, early_stopping=False, epsilon=1e-08,<br />       hidden_layer_sizes=(4, 2), learning_rate='constant',<br />       learning_rate_init=0.001, max_iter=10000, momentum=0.9,<br />       nesterovs_momentum=True, power_t=0.5, random_state=None,<br />       shuffle=True, solver='adam', tol=0.0001, validation_fraction=0.1,<br />       verbose=False, warm_start=False)</pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[9]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="nb">print</span><span class="p">(</span><span class="s1">'prediccion:'</span><span class="p">,</span> <span class="n">model</span><span class="o">.</span><span class="n">predict</span><span class="p">(</span><span class="n">xs</span><span class="p">))</span> <span class="c1"># salida 0110</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_subarea output_stream output_stdout output_text"><pre>prediccion: [0 1 1 0]<br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[10]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="nb">print</span><span class="p">(</span><span class="s1">'Se espera:'</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">]))</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_subarea output_stream output_stdout output_text"><pre>Se espera: [0 1 1 0]<br /></pre></div></div></div></div></div><div class="cell border-box-sizing text_cell rendered"><div class="prompt input_prompt"></div><div class="inner_cell"><div class="text_cell_render border-box-sizing rendered_html"><h3 id="Otro-ejercicio">Otro ejercicio<a class="anchor-link" href="https://www.blogger.com/blogger.g?blogID=882744969176160062#Otro-ejercicio">&#182;</a></h3><table><thead><tr><th>Entrada</th><th>Salida</th></tr></thead><tbody><tr><td>001</td><td>0</td><td></td></tr><tr><td>111</td><td>1</td><td></td></tr><tr><td>101</td><td>1</td><td></td></tr><tr><td>011</td><td>0</td><td></td></tr><tr><td>100</td><td>?</td><td></td></tr></tbody></table></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[11]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Se importa de numpy array</span><br /><span class="kn">from</span> <span class="nn">numpy</span> <span class="k">import</span> <span class="n">array</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[12]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Datos de entrada y de salida</span><br /><span class="n">datos_entrada</span> <span class="o">=</span> <span class="n">array</span><span class="p">([[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">]])</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span><br /><span class="n">datos_salida</span> <span class="o">=</span> <span class="n">array</span><span class="p">([[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">]])</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="p">)</span><br /><span class="nb">print</span><span class="p">(</span><span class="n">datos_entrada</span><span class="p">)</span><br /><span class="nb">print</span> <span class="p">(</span><span class="s2">"-"</span><span class="o">*</span><span class="mi">4</span><span class="p">)</span><br /><span class="nb">print</span><span class="p">(</span><span class="n">datos_salida</span><span class="p">)</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_subarea output_stream output_stdout output_text"><pre>[[0 0 1]<br /> [1 1 1]<br /> [1 0 1]<br /> [0 1 1]]<br />----<br />[0 1 1 0]<br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[13]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#En este caso se usa KNeighborsClassifier con 2 capaz</span><br /><span class="n">KNC</span> <span class="o">=</span> <span class="n">KNeighborsClassifier</span><span class="p">(</span><span class="n">n_neighbors</span><span class="o">=</span> <span class="mi">2</span><span class="p">)</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[14]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="n">KNC</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">datos_entrada</span><span class="p">,</span><span class="n">datos_salida</span><span class="p">)</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[14]:</div><div class="output_text output_subarea output_execute_result"><pre>KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',<br />           metric_params=None, n_jobs=1, n_neighbors=2, p=2,<br />           weights='uniform')</pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[15]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Se predice el valor de 1,0,0 que da como resultado el mismo del art&#237;culo anterior.</span><br /><span class="nb">print</span><span class="p">(</span><span class="n">KNC</span><span class="o">.</span><span class="n">predict</span><span class="p">([[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">]]))</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_subarea output_stream output_stdout output_text"><pre>[1]<br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[16]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Se crea la red de nuevo pero ahora con PLPCCLassifier.</span><br /><span class="c1">#Se crea el clasificador con la funci&#243;n de activaci&#243;n relu,con 10k iteraciones y tiene capaz ocultas 4,2</span><br /><span class="n">KNC</span> <span class="o">=</span> <span class="n">MLPClassifier</span><span class="p">(</span><span class="n">activation</span><span class="o">=</span><span class="s1">'tanh'</span><span class="p">,</span> <span class="n">max_iter</span><span class="o">=</span><span class="mi">10000</span><span class="p">,</span> <span class="n">hidden_layer_sizes</span><span class="o">=</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span><span class="mi">2</span><span class="p">))</span><br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[17]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Se entrena la red neuronal pasando los arreglos de entrada y de salida</span><br /><span class="n">KNC</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">datos_entrada</span><span class="p">,</span> <span class="n">datos_salida</span><span class="p">)</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[17]:</div><div class="output_text output_subarea output_execute_result"><pre>MLPClassifier(activation='tanh', alpha=0.0001, batch_size='auto', beta_1=0.9,<br />       beta_2=0.999, early_stopping=False, epsilon=1e-08,<br />       hidden_layer_sizes=(4, 2), learning_rate='constant',<br />       learning_rate_init=0.001, max_iter=10000, momentum=0.9,<br />       nesterovs_momentum=True, power_t=0.5, random_state=None,<br />       shuffle=True, solver='adam', tol=0.0001, validation_fraction=0.1,<br />       verbose=False, warm_start=False)</pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[18]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Se predice el valor de 1,0,0 que da como resultado el mismo del art&#237;culo anterior.</span><br /><span class="nb">print</span><span class="p">(</span><span class="n">KNC</span><span class="o">.</span><span class="n">predict</span><span class="p">([[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">]]))</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_subarea output_stream output_stdout output_text"><pre>[1]<br /></pre></div></div></div></div></div><br /><br />En el siguiente art&#237;culo se explicar&#225; otro ejemplo de &#193;rbol de decisi&#243;n usando scikit-learn.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://4.bp.blogspot.com/-EV-yj9hUFk0/Wti8u0uxxkI/AAAAAAAASnk/Kdr9BI5slV8iper3FdX4P_IHgJ1xN2LeQCLcBGAs/s320/estadosVenezuela-wikipedia.png" alt="La libertad de desarrollar...: WebScraping (extracci&amp;#243;n de datos) de wikipedia con Pandas">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">La libertad de desarrollar...: WebScraping (extracci&amp;#243;n de datos) de wikipedia con Pandas</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">19 04 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Continuando con la serie de art&#237;culos sobre <a href="http://blog.crespo.org.ve/search/label/Pandas">Pandas</a>, en este art&#237;culo se muestra un proceso de <a href="http://blog.crespo.org.ve/search/label/webscraping">extracci&#243;n de datos web</a> de la <a href="https://es.wikipedia.org/wiki/Estados_de_Venezuela">p&#225;gina que contiene informaci&#243;n sobre&nbsp; los Estados de Venezuela de Wikipedia</a>.<br /><br />En los procesos anteriores de WebScraping se trabajaba practicamente a mano para indentificar&nbsp; las secciones del c&#243;digo html donde se encuentra la informaci&#243;n &#250;til, para el caso con Pandas este abstrae ese proceso.<br /><br />A continuaci&#243;n se muestra una captura de pantalla de la p&#225;gina donde se quiere extraer la informaci&#243;n:<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://4.bp.blogspot.com/-EV-yj9hUFk0/Wti8u0uxxkI/AAAAAAAASnk/Kdr9BI5slV8iper3FdX4P_IHgJ1xN2LeQCLcBGAs/s1600/estadosVenezuela-wikipedia.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="167" src="https://4.bp.blogspot.com/-EV-yj9hUFk0/Wti8u0uxxkI/AAAAAAAASnk/Kdr9BI5slV8iper3FdX4P_IHgJ1xN2LeQCLcBGAs/s320/estadosVenezuela-wikipedia.png" width="320" /></a></div><br /><br />La informaci&#243;n que maneja la p&#225;gina son los estados con sus capitales, densidad poblacional, superficie, a&#241;o de admisi&#243;n, poblaci&#243;n, densidad, regi&#243;n y c&#243;digo ISO, la parte de la bandera ni del mapa no se muestra por que son im&#225;genes y no se obtiene informaci&#243;n &#250;til de ellas.<br /><br />A continuaci&#243;n todo el proceso de extracci&#243;n de informaci&#243;n de la p&#225;gina:<br /><br /><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[1]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Se importa pandas como pd</span><br /><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span><br /><span class="c1">#Se lee los datos de wikipedia de los estados de venezuela, este devuelve una lista</span><br /><span class="n">estados</span><span class="o">=</span>   <span class="n">pd</span><span class="o">.</span><span class="n">read_html</span><span class="p">(</span><span class="s1">'https://es.wikipedia.org/wiki/Estados_de_Venezuela'</span><span class="p">)</span> <br /><span class="n">estados</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[1]:</div><div class="output_text output_subarea output_execute_result"><pre>[    0                                                  1<br /> 0 NaN  Este art&#237;culo o secci&#243;n necesita referencias q...,<br />                                                    0<br /> 0                     Estados Federales de Venezuela<br /> 1  Bol&#237;var Amazonas Apure Zulia T&#225;chira Barinas M...,<br />           0                       1                       2           3  \<br /> 0   Bandera         Entidad federal                 Capital  C&#243;digo ISO   <br /> 1       NaN                Amazonas         Puerto Ayacucho        VE-Z   <br /> 2       NaN              Anzo&#225;tegui               Barcelona        VE-B   <br /> 3       NaN                   Apure   San Fernando de Apure        VE-C   <br /> 4       NaN                  Aragua                 Maracay        VE-D   <br /> 5       NaN                 Barinas                 Barinas        VE-E   <br /> 6       NaN                 Bol&#237;var          Ciudad Bol&#237;var        VE-F   <br /> 7       NaN                Carabobo                Valencia        VE-G   <br /> 8       NaN                 Cojedes              San Carlos        VE-H   <br /> 9       NaN           Delta Amacuro                Tucupita        VE-Y   <br /> 10      NaN        Distrito Capital                 Caracas        VE-A   <br /> 11      NaN                  Falc&#243;n                    Coro        VE-I   <br /> 12      NaN                 Gu&#225;rico  San Juan de Los Morros        VE-J   <br /> 13      NaN                    Lara            Barquisimeto        VE-K   <br /> 14      NaN                  M&#233;rida                  M&#233;rida        VE-L   <br /> 15      NaN                 Miranda              Los Teques        VE-M   <br /> 16      NaN                 Monagas                 Matur&#237;n        VE-N   <br /> 17      NaN           Nueva Esparta             La Asunci&#243;n        VE-O   <br /> 18      NaN              Portuguesa                 Guanare        VE-P   <br /> 19      NaN                   Sucre                  Cuman&#225;        VE-R   <br /> 20      NaN                 T&#225;chira           San Crist&#243;bal        VE-S   <br /> 21      NaN                Trujillo                Trujillo        VE-T   <br /> 22      NaN                  Vargas               La Guaira        VE-X   <br /> 23      NaN                 Yaracuy              San Felipe        VE-U   <br /> 24      NaN                   Zulia               Maracaibo        VE-V   <br /> 25      NaN  Dependencias Federales              Gran Roque        VE-W   <br /> <br />                   4                                 5  \<br /> 0   A&#241;o de admisi&#243;n              Poblaci&#243;n (2011)[2]&#8203;   <br /> 1              1992    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0161844.&amp;&amp;&amp;&amp;&amp;0161&nbsp;844   <br /> 2              1909  &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;02179838.&amp;&amp;&amp;&amp;&amp;02&nbsp;179&nbsp;838   <br /> 3              1864    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0501404.&amp;&amp;&amp;&amp;&amp;0501&nbsp;404   <br /> 4              1909  &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;01819630.&amp;&amp;&amp;&amp;&amp;01&nbsp;819&nbsp;630   <br /> 5              1937    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0853949.&amp;&amp;&amp;&amp;&amp;0853&nbsp;949   <br /> 6              1901  &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;02069064.&amp;&amp;&amp;&amp;&amp;02&nbsp;069&nbsp;064   <br /> 7              1865  &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;02342665.&amp;&amp;&amp;&amp;&amp;02&nbsp;342&nbsp;665   <br /> 8              1864    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0367020.&amp;&amp;&amp;&amp;&amp;0367&nbsp;020   <br /> 9              1992    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0180363.&amp;&amp;&amp;&amp;&amp;0180&nbsp;363   <br /> 10             1999  &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;04033186.&amp;&amp;&amp;&amp;&amp;04&nbsp;033&nbsp;186   <br /> 11             1872  &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;01064615.&amp;&amp;&amp;&amp;&amp;01&nbsp;064&nbsp;615   <br /> 12             1864    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0746174.&amp;&amp;&amp;&amp;&amp;0746&nbsp;174   <br /> 13             1909  &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;01892439.&amp;&amp;&amp;&amp;&amp;01&nbsp;892&nbsp;439   <br /> 14             1909    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0903955.&amp;&amp;&amp;&amp;&amp;0903&nbsp;955   <br /> 15             1909  &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;03112851.&amp;&amp;&amp;&amp;&amp;03&nbsp;112&nbsp;851   <br /> 16             1909    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0938185.&amp;&amp;&amp;&amp;&amp;0938&nbsp;185   <br /> 17             1909    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0525139.&amp;&amp;&amp;&amp;&amp;0525&nbsp;139   <br /> 18             1909    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0897104.&amp;&amp;&amp;&amp;&amp;0897&nbsp;104   <br /> 19             1909    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0892990.&amp;&amp;&amp;&amp;&amp;0892&nbsp;990   <br /> 20             1899  &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;01277241.&amp;&amp;&amp;&amp;&amp;01&nbsp;277&nbsp;241   <br /> 21             1864    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0901239.&amp;&amp;&amp;&amp;&amp;0901&nbsp;239   <br /> 22             1998    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0419928.&amp;&amp;&amp;&amp;&amp;0419&nbsp;928   <br /> 23             1899    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0645688.&amp;&amp;&amp;&amp;&amp;0645&nbsp;688   <br /> 24             1864  &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;04694856.&amp;&amp;&amp;&amp;&amp;04&nbsp;694&nbsp;856   <br /> 25             1938       &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;02155.&amp;&amp;&amp;&amp;&amp;02155   <br /> <br />                                  6                              7  \<br /> 0                 Superficie (km&#178;)             Densidad (hab/km&#178;)   <br /> 1   &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0177617.&amp;&amp;&amp;&amp;&amp;0177&nbsp;617    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;00.9900000,99   <br /> 2    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;043300.&amp;&amp;&amp;&amp;&amp;043&nbsp;300    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;033.90000033,9   <br /> 3    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;076500.&amp;&amp;&amp;&amp;&amp;076&nbsp;500     &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;06.&amp;&amp;&amp;&amp;&amp;06,0   <br /> 4      &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;07014.&amp;&amp;&amp;&amp;&amp;07014   &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0235.600000235,6   <br /> 5    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;035200.&amp;&amp;&amp;&amp;&amp;035&nbsp;200    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;023.20000023,2   <br /> 6   &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0240528.&amp;&amp;&amp;&amp;&amp;0240&nbsp;528    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;07.8700007,87   <br /> 7      &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;04650.&amp;&amp;&amp;&amp;&amp;04650  &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0713.&amp;10000713,01   <br /> 8    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;014800.&amp;&amp;&amp;&amp;&amp;014&nbsp;800    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;021.80000021,8   <br /> 9    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;040200.&amp;&amp;&amp;&amp;&amp;040&nbsp;200    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;04.6500004,65   <br /> 10      &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0433.&amp;&amp;&amp;&amp;&amp;0433  &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;07246.4000007246,4   <br /> 11   &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;024800.&amp;&amp;&amp;&amp;&amp;024&nbsp;800    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;036.40000036,4   <br /> 12   &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;064986.&amp;&amp;&amp;&amp;&amp;064&nbsp;986    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;011.50000011,5   <br /> 13   &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;019800.&amp;&amp;&amp;&amp;&amp;019&nbsp;800    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;089.60000089,6   <br /> 14   &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;011300.&amp;&amp;&amp;&amp;&amp;011&nbsp;300    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;092.80000092,8   <br /> 15     &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;07950.&amp;&amp;&amp;&amp;&amp;07950   &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0336.500000336,5   <br /> 16   &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;028900.&amp;&amp;&amp;&amp;&amp;028&nbsp;900    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;031.30000031,3   <br /> 17     &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;01150.&amp;&amp;&amp;&amp;&amp;01150  &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0480.&amp;10000480,01   <br /> 18   &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;015200.&amp;&amp;&amp;&amp;&amp;015&nbsp;200    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;057.70000057,7   <br /> 19   &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;011800.&amp;&amp;&amp;&amp;&amp;011&nbsp;800    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;076.&amp;&amp;&amp;&amp;&amp;076,0   <br /> 20   &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;011100.&amp;&amp;&amp;&amp;&amp;011&nbsp;100   &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0105.300000105,3   <br /> 21     &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;07400.&amp;&amp;&amp;&amp;&amp;07400    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;092.80000092,8   <br /> 22     &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;01497.&amp;&amp;&amp;&amp;&amp;01497   &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0235.800000235,8   <br /> 23     &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;07100.&amp;&amp;&amp;&amp;&amp;07100    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;084.60000084,6   <br /> 24   &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;063100.&amp;&amp;&amp;&amp;&amp;063&nbsp;100    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;073.70000073,7   <br /> 25      &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;0120.&amp;&amp;&amp;&amp;&amp;0120    &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;018.&amp;&amp;&amp;&amp;&amp;018,0   <br /> <br />                     8     9  <br /> 0              Regi&#243;n  Mapa  <br /> 1             Guayana   NaN  <br /> 2      Nor - Oriental   NaN  <br /> 3              Llanos   NaN  <br /> 4             Central   NaN  <br /> 5              Andina   NaN  <br /> 6             Guayana   NaN  <br /> 7             Central   NaN  <br /> 8             Central   NaN  <br /> 9             Guayana   NaN  <br /> 10            Capital   NaN  <br /> 11  Centro-Occidental   NaN  <br /> 12             Llanos   NaN  <br /> 13  Centro-Occidental   NaN  <br /> 14             Andina   NaN  <br /> 15            Capital   NaN  <br /> 16     Nor - Oriental   NaN  <br /> 17            Insular   NaN  <br /> 18  Centro-Occidental   NaN  <br /> 19     Nor - Oriental   NaN  <br /> 20             Andina   NaN  <br /> 21             Andina   NaN  <br /> 22            Capital   NaN  <br /> 23  Centro-Occidental   NaN  <br /> 24            Zuliana   NaN  <br /> 25            Insular   NaN  ]</pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[2]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Tipo de los estados</span><br /><span class="nb">type</span><span class="p">(</span><span class="n">estados</span><span class="p">)</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[2]:</div><div class="output_text output_subarea output_execute_result"><pre>list</pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[3]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Tipo del primer elemento es un dataframe</span><br /><span class="nb">type</span><span class="p">(</span><span class="n">estados</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[3]:</div><div class="output_text output_subarea output_execute_result"><pre>pandas.core.frame.DataFrame</pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[4]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Se listan del dataframe estados y capitales (elementos 1 y 2 del dataframe, y se recorre)</span><br /><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">26</span><span class="p">):</span><br />    <span class="nb">print</span><span class="p">(</span><span class="n">estados</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">1</span><span class="p">][</span><span class="n">i</span><span class="p">],</span><span class="n">estados</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">2</span><span class="p">][</span><span class="n">i</span><span class="p">])</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_subarea output_stream output_stdout output_text"><pre>Amazonas Puerto Ayacucho<br />Anzo&#225;tegui Barcelona<br />Apure San Fernando de Apure<br />Aragua Maracay<br />Barinas Barinas<br />Bol&#237;var Ciudad Bol&#237;var<br />Carabobo Valencia<br />Cojedes San Carlos<br />Delta Amacuro Tucupita<br />Distrito Capital Caracas<br />Falc&#243;n Coro<br />Gu&#225;rico San Juan de Los Morros<br />Lara Barquisimeto<br />M&#233;rida M&#233;rida<br />Miranda Los Teques<br />Monagas Matur&#237;n<br />Nueva Esparta La Asunci&#243;n<br />Portuguesa Guanare<br />Sucre Cuman&#225;<br />T&#225;chira San Crist&#243;bal<br />Trujillo Trujillo<br />Vargas La Guaira<br />Yaracuy San Felipe<br />Zulia Maracaibo<br />Dependencias Federales Gran Roque<br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[5]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Ahora se crea una lista de diccionarios donde estar&#225; la informaci&#243;n de cada estado</span><br /><span class="n">lista</span> <span class="o">=</span> <span class="p">[]</span><br /><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">26</span><span class="p">):</span><br />    <span class="n">lista</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">'Estado'</span><span class="p">:</span><span class="n">estados</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">1</span><span class="p">][</span><span class="n">i</span><span class="p">],</span><br />                  <span class="s1">'Capital'</span><span class="p">:</span> <span class="n">estados</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">2</span><span class="p">][</span><span class="n">i</span><span class="p">],</span><br />                  <span class="s1">'codigo_iso'</span><span class="p">:</span> <span class="n">estados</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">3</span><span class="p">][</span><span class="n">i</span><span class="p">],</span><br />                  <span class="sa">u</span><span class="s1">'a&#241;o_admision'</span><span class="p">:</span> <span class="n">estados</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">4</span><span class="p">][</span><span class="n">i</span><span class="p">],</span><br />                  <span class="s1">'Poblacion'</span><span class="p">:</span> <span class="nb">int</span><span class="p">(</span><span class="n">estados</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">5</span><span class="p">][</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"."</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"&amp;"</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]),</span><br />                  <span class="s1">'Superficie'</span><span class="p">:</span> <span class="nb">int</span><span class="p">(</span><span class="n">estados</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">6</span><span class="p">][</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"."</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"&amp;"</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]),</span><br />                  <span class="s1">'Densidad'</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">estados</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">7</span><span class="p">][</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">","</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"&amp;"</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]),</span><br />                  <span class="s1">'Region'</span><span class="p">:</span> <span class="n">estados</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">8</span><span class="p">][</span><span class="n">i</span><span class="p">]</span><br />                 <span class="p">})</span><br />    <br /><span class="nb">print</span><span class="p">(</span><span class="n">lista</span><span class="p">)</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt"></div><div class="output_subarea output_stream output_stdout output_text"><pre>[{'Region': 'Guayana', 'Densidad': 0.99, 'Superficie': 177617, 'Estado': 'Amazonas', 'codigo_iso': 'VE-Z', 'Poblacion': 161844, 'Capital': 'Puerto Ayacucho', 'a&#241;o_admision': '1992'}, {'Region': 'Nor - Oriental', 'Densidad': 33.90000033, 'Superficie': 43300, 'Estado': 'Anzo&#225;tegui', 'codigo_iso': 'VE-B', 'Poblacion': 2179838, 'Capital': 'Barcelona', 'a&#241;o_admision': '1909'}, {'Region': 'Llanos', 'Densidad': 6.0, 'Superficie': 76500, 'Estado': 'Apure', 'codigo_iso': 'VE-C', 'Poblacion': 501404, 'Capital': 'San Fernando de Apure', 'a&#241;o_admision': '1864'}, {'Region': 'Central', 'Densidad': 235.600000235, 'Superficie': 7014, 'Estado': 'Aragua', 'codigo_iso': 'VE-D', 'Poblacion': 1819630, 'Capital': 'Maracay', 'a&#241;o_admision': '1909'}, {'Region': 'Andina', 'Densidad': 23.20000023, 'Superficie': 35200, 'Estado': 'Barinas', 'codigo_iso': 'VE-E', 'Poblacion': 853949, 'Capital': 'Barinas', 'a&#241;o_admision': '1937'}, {'Region': 'Guayana', 'Densidad': 7.8700007, 'Superficie': 240528, 'Estado': 'Bol&#237;var', 'codigo_iso': 'VE-F', 'Poblacion': 2069064, 'Capital': 'Ciudad Bol&#237;var', 'a&#241;o_admision': '1901'}, {'Region': 'Central', 'Densidad': 10000713.0, 'Superficie': 4650, 'Estado': 'Carabobo', 'codigo_iso': 'VE-G', 'Poblacion': 2342665, 'Capital': 'Valencia', 'a&#241;o_admision': '1865'}, {'Region': 'Central', 'Densidad': 21.80000021, 'Superficie': 14800, 'Estado': 'Cojedes', 'codigo_iso': 'VE-H', 'Poblacion': 367020, 'Capital': 'San Carlos', 'a&#241;o_admision': '1864'}, {'Region': 'Guayana', 'Densidad': 4.6500004, 'Superficie': 40200, 'Estado': 'Delta Amacuro', 'codigo_iso': 'VE-Y', 'Poblacion': 180363, 'Capital': 'Tucupita', 'a&#241;o_admision': '1992'}, {'Region': 'Capital', 'Densidad': 7246.4000007246, 'Superficie': 433, 'Estado': 'Distrito Capital', 'codigo_iso': 'VE-A', 'Poblacion': 4033186, 'Capital': 'Caracas', 'a&#241;o_admision': '1999'}, {'Region': 'Centro-Occidental', 'Densidad': 36.40000036, 'Superficie': 24800, 'Estado': 'Falc&#243;n', 'codigo_iso': 'VE-I', 'Poblacion': 1064615, 'Capital': 'Coro', 'a&#241;o_admision': '1872'}, {'Region': 'Llanos', 'Densidad': 11.50000011, 'Superficie': 64986, 'Estado': 'Gu&#225;rico', 'codigo_iso': 'VE-J', 'Poblacion': 746174, 'Capital': 'San Juan de Los Morros', 'a&#241;o_admision': '1864'}, {'Region': 'Centro-Occidental', 'Densidad': 89.60000089, 'Superficie': 19800, 'Estado': 'Lara', 'codigo_iso': 'VE-K', 'Poblacion': 1892439, 'Capital': 'Barquisimeto', 'a&#241;o_admision': '1909'}, {'Region': 'Andina', 'Densidad': 92.80000092, 'Superficie': 11300, 'Estado': 'M&#233;rida', 'codigo_iso': 'VE-L', 'Poblacion': 903955, 'Capital': 'M&#233;rida', 'a&#241;o_admision': '1909'}, {'Region': 'Capital', 'Densidad': 336.500000336, 'Superficie': 7950, 'Estado': 'Miranda', 'codigo_iso': 'VE-M', 'Poblacion': 3112851, 'Capital': 'Los Teques', 'a&#241;o_admision': '1909'}, {'Region': 'Nor - Oriental', 'Densidad': 31.30000031, 'Superficie': 28900, 'Estado': 'Monagas', 'codigo_iso': 'VE-N', 'Poblacion': 938185, 'Capital': 'Matur&#237;n', 'a&#241;o_admision': '1909'}, {'Region': 'Insular', 'Densidad': 10000480.0, 'Superficie': 1150, 'Estado': 'Nueva Esparta', 'codigo_iso': 'VE-O', 'Poblacion': 525139, 'Capital': 'La Asunci&#243;n', 'a&#241;o_admision': '1909'}, {'Region': 'Centro-Occidental', 'Densidad': 57.70000057, 'Superficie': 15200, 'Estado': 'Portuguesa', 'codigo_iso': 'VE-P', 'Poblacion': 897104, 'Capital': 'Guanare', 'a&#241;o_admision': '1909'}, {'Region': 'Nor - Oriental', 'Densidad': 76.0, 'Superficie': 11800, 'Estado': 'Sucre', 'codigo_iso': 'VE-R', 'Poblacion': 892990, 'Capital': 'Cuman&#225;', 'a&#241;o_admision': '1909'}, {'Region': 'Andina', 'Densidad': 105.300000105, 'Superficie': 11100, 'Estado': 'T&#225;chira', 'codigo_iso': 'VE-S', 'Poblacion': 1277241, 'Capital': 'San Crist&#243;bal', 'a&#241;o_admision': '1899'}, {'Region': 'Andina', 'Densidad': 92.80000092, 'Superficie': 7400, 'Estado': 'Trujillo', 'codigo_iso': 'VE-T', 'Poblacion': 901239, 'Capital': 'Trujillo', 'a&#241;o_admision': '1864'}, {'Region': 'Capital', 'Densidad': 235.800000235, 'Superficie': 1497, 'Estado': 'Vargas', 'codigo_iso': 'VE-X', 'Poblacion': 419928, 'Capital': 'La Guaira', 'a&#241;o_admision': '1998'}, {'Region': 'Centro-Occidental', 'Densidad': 84.60000084, 'Superficie': 7100, 'Estado': 'Yaracuy', 'codigo_iso': 'VE-U', 'Poblacion': 645688, 'Capital': 'San Felipe', 'a&#241;o_admision': '1899'}, {'Region': 'Zuliana', 'Densidad': 73.70000073, 'Superficie': 63100, 'Estado': 'Zulia', 'codigo_iso': 'VE-V', 'Poblacion': 4694856, 'Capital': 'Maracaibo', 'a&#241;o_admision': '1864'}, {'Region': 'Insular', 'Densidad': 18.0, 'Superficie': 120, 'Estado': 'Dependencias Federales', 'codigo_iso': 'VE-W', 'Poblacion': 2155, 'Capital': 'Gran Roque', 'a&#241;o_admision': '1938'}]<br /></pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[6]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Luego se crea un dataframe de la lista de diccionarios</span><br /><span class="n">df</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">lista</span><span class="p">)</span><br /><span class="n">df</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[6]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>Capital</th>      <th>Densidad</th>      <th>Estado</th>      <th>Poblacion</th>      <th>Region</th>      <th>Superficie</th>      <th>a&#241;o_admision</th>      <th>codigo_iso</th>    </tr></thead>  <tbody><tr>      <th>0</th>      <td>Puerto Ayacucho</td>      <td>9.900000e-01</td>      <td>Amazonas</td>      <td>161844</td>      <td>Guayana</td>      <td>177617</td>      <td>1992</td>      <td>VE-Z</td>    </tr><tr>      <th>1</th>      <td>Barcelona</td>      <td>3.390000e+01</td>      <td>Anzo&#225;tegui</td>      <td>2179838</td>      <td>Nor - Oriental</td>      <td>43300</td>      <td>1909</td>      <td>VE-B</td>    </tr><tr>      <th>2</th>      <td>San Fernando de Apure</td>      <td>6.000000e+00</td>      <td>Apure</td>      <td>501404</td>      <td>Llanos</td>      <td>76500</td>      <td>1864</td>      <td>VE-C</td>    </tr><tr>      <th>3</th>      <td>Maracay</td>      <td>2.356000e+02</td>      <td>Aragua</td>      <td>1819630</td>      <td>Central</td>      <td>7014</td>      <td>1909</td>      <td>VE-D</td>    </tr><tr>      <th>4</th>      <td>Barinas</td>      <td>2.320000e+01</td>      <td>Barinas</td>      <td>853949</td>      <td>Andina</td>      <td>35200</td>      <td>1937</td>      <td>VE-E</td>    </tr><tr>      <th>5</th>      <td>Ciudad Bol&#237;var</td>      <td>7.870001e+00</td>      <td>Bol&#237;var</td>      <td>2069064</td>      <td>Guayana</td>      <td>240528</td>      <td>1901</td>      <td>VE-F</td>    </tr><tr>      <th>6</th>      <td>Valencia</td>      <td>1.000071e+07</td>      <td>Carabobo</td>      <td>2342665</td>      <td>Central</td>      <td>4650</td>      <td>1865</td>      <td>VE-G</td>    </tr><tr>      <th>7</th>      <td>San Carlos</td>      <td>2.180000e+01</td>      <td>Cojedes</td>      <td>367020</td>      <td>Central</td>      <td>14800</td>      <td>1864</td>      <td>VE-H</td>    </tr><tr>      <th>8</th>      <td>Tucupita</td>      <td>4.650000e+00</td>      <td>Delta Amacuro</td>      <td>180363</td>      <td>Guayana</td>      <td>40200</td>      <td>1992</td>      <td>VE-Y</td>    </tr><tr>      <th>9</th>      <td>Caracas</td>      <td>7.246400e+03</td>      <td>Distrito Capital</td>      <td>4033186</td>      <td>Capital</td>      <td>433</td>      <td>1999</td>      <td>VE-A</td>    </tr><tr>      <th>10</th>      <td>Coro</td>      <td>3.640000e+01</td>      <td>Falc&#243;n</td>      <td>1064615</td>      <td>Centro-Occidental</td>      <td>24800</td>      <td>1872</td>      <td>VE-I</td>    </tr><tr>      <th>11</th>      <td>San Juan de Los Morros</td>      <td>1.150000e+01</td>      <td>Gu&#225;rico</td>      <td>746174</td>      <td>Llanos</td>      <td>64986</td>      <td>1864</td>      <td>VE-J</td>    </tr><tr>      <th>12</th>      <td>Barquisimeto</td>      <td>8.960000e+01</td>      <td>Lara</td>      <td>1892439</td>      <td>Centro-Occidental</td>      <td>19800</td>      <td>1909</td>      <td>VE-K</td>    </tr><tr>      <th>13</th>      <td>M&#233;rida</td>      <td>9.280000e+01</td>      <td>M&#233;rida</td>      <td>903955</td>      <td>Andina</td>      <td>11300</td>      <td>1909</td>      <td>VE-L</td>    </tr><tr>      <th>14</th>      <td>Los Teques</td>      <td>3.365000e+02</td>      <td>Miranda</td>      <td>3112851</td>      <td>Capital</td>      <td>7950</td>      <td>1909</td>      <td>VE-M</td>    </tr><tr>      <th>15</th>      <td>Matur&#237;n</td>      <td>3.130000e+01</td>      <td>Monagas</td>      <td>938185</td>      <td>Nor - Oriental</td>      <td>28900</td>      <td>1909</td>      <td>VE-N</td>    </tr><tr>      <th>16</th>      <td>La Asunci&#243;n</td>      <td>1.000048e+07</td>      <td>Nueva Esparta</td>      <td>525139</td>      <td>Insular</td>      <td>1150</td>      <td>1909</td>      <td>VE-O</td>    </tr><tr>      <th>17</th>      <td>Guanare</td>      <td>5.770000e+01</td>      <td>Portuguesa</td>      <td>897104</td>      <td>Centro-Occidental</td>      <td>15200</td>      <td>1909</td>      <td>VE-P</td>    </tr><tr>      <th>18</th>      <td>Cuman&#225;</td>      <td>7.600000e+01</td>      <td>Sucre</td>      <td>892990</td>      <td>Nor - Oriental</td>      <td>11800</td>      <td>1909</td>      <td>VE-R</td>    </tr><tr>      <th>19</th>      <td>San Crist&#243;bal</td>      <td>1.053000e+02</td>      <td>T&#225;chira</td>      <td>1277241</td>      <td>Andina</td>      <td>11100</td>      <td>1899</td>      <td>VE-S</td>    </tr><tr>      <th>20</th>      <td>Trujillo</td>      <td>9.280000e+01</td>      <td>Trujillo</td>      <td>901239</td>      <td>Andina</td>      <td>7400</td>      <td>1864</td>      <td>VE-T</td>    </tr><tr>      <th>21</th>      <td>La Guaira</td>      <td>2.358000e+02</td>      <td>Vargas</td>      <td>419928</td>      <td>Capital</td>      <td>1497</td>      <td>1998</td>      <td>VE-X</td>    </tr><tr>      <th>22</th>      <td>San Felipe</td>      <td>8.460000e+01</td>      <td>Yaracuy</td>      <td>645688</td>      <td>Centro-Occidental</td>      <td>7100</td>      <td>1899</td>      <td>VE-U</td>    </tr><tr>      <th>23</th>      <td>Maracaibo</td>      <td>7.370000e+01</td>      <td>Zulia</td>      <td>4694856</td>      <td>Zuliana</td>      <td>63100</td>      <td>1864</td>      <td>VE-V</td>    </tr><tr>      <th>24</th>      <td>Gran Roque</td>      <td>1.800000e+01</td>      <td>Dependencias Federales</td>      <td>2155</td>      <td>Insular</td>      <td>120</td>      <td>1938</td>      <td>VE-W</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[7]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Si se quiere la informaci&#243;n de Carabobo</span><br /><span class="n">mascara</span> <span class="o">=</span> <span class="n">df</span><span class="p">[</span><span class="s2">"Estado"</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"Carabobo"</span><br /><span class="n">df</span><span class="p">[</span><span class="n">mascara</span><span class="p">]</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[7]:</div><div class="output_html rendered_html output_subarea output_execute_result"><div> <br /><table border="1" class="dataframe">  <thead><tr style="text-align: right;">      <th></th>      <th>Capital</th>      <th>Densidad</th>      <th>Estado</th>      <th>Poblacion</th>      <th>Region</th>      <th>Superficie</th>      <th>a&#241;o_admision</th>      <th>codigo_iso</th>    </tr></thead>  <tbody><tr>      <th>6</th>      <td>Valencia</td>      <td>10000713.0</td>      <td>Carabobo</td>      <td>2342665</td>      <td>Central</td>      <td>4650</td>      <td>1865</td>      <td>VE-G</td>    </tr></tbody></table></div></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[8]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Otra forma de traer la informaci&#243;n de Carabobo</span><br /><span class="n">df</span><span class="o">.</span><span class="n">iloc</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[8]:</div><div class="output_text output_subarea output_execute_result"><pre>Capital            Valencia<br />Densidad        1.00007e+07<br />Estado             Carabobo<br />Poblacion           2342665<br />Region              Central<br />Superficie             4650<br />a&#241;o_admision           1865<br />codigo_iso             VE-G<br />Name: 6, dtype: object</pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[9]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre><span class="c1">#Para obtener la capital del estado</span><br /><span class="n">df</span><span class="o">.</span><span class="n">iloc</span><span class="p">[</span><span class="mi">6</span><span class="p">][</span><span class="s2">"Capital"</span><span class="p">]</span><br /></pre></div></div></div></div><div class="output_wrapper"><div class="output"><div class="output_area"><div class="prompt output_prompt">Out[9]:</div><div class="output_text output_subarea output_execute_result"><pre>'Valencia'</pre></div></div></div></div></div><div class="cell border-box-sizing code_cell rendered"><div class="input"><div class="prompt input_prompt">In&nbsp;[&nbsp;]:</div><div class="inner_cell"><div class="input_area"><div class=" highlight hl-ipython3"><pre> <br /></pre></div></div></div></div></div>El proceso de eliminar la basura dentro del texto de algunos campos no se muestra, pero se usa en la construcci&#243;n del diccionario.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/84-everytime.png" alt="everytime">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">everytime</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">17 04 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/84-everytime.png" alt="#everytime" title="#everytime" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="April Update - Preparing for Internationalisation">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">April Update - Preparing for Internationalisation</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">11 04 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A new data format to ease access to tracker data.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q2 2018 Survey Results and Call For Proposals</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">10 04 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        We have recently run our second survey on our members to better understand them and their needs. We&rsquo;re publishing these results so that they can see the aggregate results, and to give open source projects more information when applying for the Q2 2018 Clojurists Together funding round (closing 22 April).
Survey Responses There were 52 respondents to the survey, up from 27 in the last survey. The highlights are presented below.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">March 2018 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">03 04 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Hi folks!
Welcome to the second monthly update for Clojurists Together.
Clojurists Together news This month we had around 45 members sign up (we still need to process any signups at the end of this month), and one company member join. We&rsquo;ve had a really strong response from individual contributors, but not so much from companies. If you work for a company that uses Clojure, please consider talking to your manager about supporting Clojurists Together.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">April 2018 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">03 04 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together news This is the third and final update from clj-http and Figwheel. Both projects finished their work at the end of April. Both projects have done great work, and we are really impressed with what they&rsquo;ve been able to achieve. We recently announced that we are funding CIDER and ClojureScript for our Q2 funding round. Those two projects have just started, we&rsquo;ll have more details on what they&rsquo;re working on next month.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/83-ico.png" alt="ICO">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">ICO</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">03 04 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/83-ico.png" alt="ICO" title="ICO" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">What’s the point of art?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">01 04 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        What is art for? What is the point of it? It’s not like food, clothing and shelter. We don’t die without art. At least, not straight away. Take away air, or water, or food, and we die. But we seem to be able to last much longer without art. Art doesn’t appear to be essential for life. In fact, it even seems frivolous at times. Its utility is not obvious. Yet, we humans keep making it. And the better our physical needs are met, the more art we seem to make.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">These months in Common Lisp: Q1 2018</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">01 04 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<h1 id="documentation">Documentation</h1>

<ul>
<li><a href="Multidimensional arrays – the Common Lisp Cookbook">Multidimensional arrays – the Common Lisp Cookbook</a></li>
<li><a href="https://lispcookbook.github.io/cl-cookbook/error_handling.html">Error and condition handling - the Common Lisp Cookbook</a></li>
<li><a href="https://lispcookbook.github.io/cl-cookbook/scripting.html">Scripting: parsing command line arguments, building self-contained executables - the Common Lisp Cookbook</a></li>
<li><a href="https://gitlab.common-lisp.net/asdf/asdf/blob/master/doc/best_practices.md">ASDF Best Practices for 2018</a></li>
<li><a href="http://blog.quicklisp.org/2018/01/the-quicklisp-local-projects-mechanism.html">The Quicklisp local-projects mechanism</a></li>
<li><a href="https://github.com/roswell/roswell/wiki/How-to-distribute-your-software,-not-library,-on-Quicklisp-ala-python-pip">How to distribute your software, not library, on Quicklisp ala python pip</a></li>
<li><a href="https://commonlispbr.github.io/">Common Lisp Brazil Community</a></li>
<li><a href="https://github.com/azzamsa/awesome-lisp-companies">Awesome Lisp companies</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/7jk0co/announcing_quickref_a_global_documentation/">Announcing Quickref: a global documentation project for Common Lisp</a></li>
</ul>

<h1 id="announcements">Announcements</h1>

<ul>
<li><a href="https://european-lisp-symposium.org/2018/index.html">European Lisp Symposium 2018</a></li>
<li><a href="https://itch.io/jam/lisp-game-jam-2018">Lisp Game Jam 2018</a></li>
</ul>

<h1 id="projects">Projects</h1>

<ul>
<li><a href="https://github.com/next-browser/next">Next web browser</a></li>
<li><a href="https://github.com/koji-kojiro/cl-repl">cl-repl, the Common Lisp ipython-like REPL</a></li>
<li><a href="https://github.com/emotiq/emotiq">Emotiq - blockchain in Common Lisp</a></li>
<li><a href="https://github.com/reddit-archive/reddit1.0">original reddit code</a> from 2005. <a href="https://www.reddit.com/r/lisp/comments/88513q/original_reddit_code_from_2005/">reddit</a>.</li>
<li><a href="https://sjl.bitbucket.io/temperance/">Temperance - logic programming (in development, reached v1.0.0)</a></li>
<li><a href="https://github.com/jnjcc/cl-qrencode">QR code 2005 encoder in Common Lisp</a></li>
<li><a href="https://github.com/vindarel/print-licenses">print-licences: print licenses used by the given project and its dependencies (from sjl and dk_jackdaniel&rsquo;s utils)</a></li>
<li><a href="https://github.com/privet-kitty/dufy">Dufy, color library</a></li>
<li><a href="https://github.com/borodust/cl-flow/">cl-flow</a> - Data-flowish computation tree library for non-blocking concurrent Common Lisp.</li>
<li><a href="https://hub.docker.com/r/eshamster/cl-devel2/">A docker container for CL development</a> (also <a href="https://hub.docker.com/r/daewok/lisp-devel/">lisp-devel</a>, <a href="https://lispcookbook.github.io/cl-cookbook/testing.html#gitlab-ci">CI on CL Cookbook</a>)</li>
<li><a href="https://github.com/svspire/quickfork">Quickfork - Quicklisp for teams</a></li>
<li><a href="https://github.com/apache/thrift/commits/master">Apache Thrift gains CL support</a></li>
<li><a href="https://github.com/t-cool/jscl-playground">JSCL playground</a></li>
<li><a href="https://github.com/rigetticomputing/magicl">MAGICL: Matrix Algebra proGrams In Common Lisp - Rigetti Computing</a></li>
<li><a href="https://github.com/BusFactor1Inc/eturia">Eturia has been open-sourced. An Open Computer for Education for teaching #Lisp written in #Javascript. </a></li>
</ul>

<p>New releases:</p>

<ul>
<li><a href="http://blog.quicklisp.org/2018/02/quicklisp-dist-update-for-february-2018.html">Quicklisp dist update for february 2018</a></li>
<li><a href="http://www.sbcl.org/all-news.html#1.4.5">SBCL 1.4.5</a></li>
<li><a href="https://github.com/portacle/portacle/releases/tag/1.1">Portacle 1.1 release: SBCL update, ASDF fixes </a></li>
<li><a href="https://common-lisp.net/project/mcclim/posts/McCLIM-097-Imbolc-release.html">McCLIM 0.9.7 &ldquo;Imbolc&rdquo; release</a></li>
<li><a href="https://github.com/norvig/paip-lisp">Peter Norvig&rsquo;s Paradigms of Artificial Intelligence Programming - book as pdf and lisp code on Github</a></li>
<li><a href="cl-torrents 0.9 - readline interface and 1337x.to scraper">cl-torrents 0.9 - readline interface and 1337x.to scraper</a></li>
</ul>

<p>Discoveries:</p>

<ul>
<li><a href="https://github.com/mikelevins/folio2">Folio2 - a collection of small libraries that provide support for functional idioms and data structures in Common Lisp; seamless integration of Series and FSet </a></li>
<li><a href="https://github.com/plkrueger/CommonLispFred">Lisp Interface to Federal Reserve Economic Data (FRED®)</a></li>
<li><a href="https://gitlab.common-lisp.net/ansi-test/cl-bench">cl-bench</a> benchmarking tool. <a href="https://www.reddit.com/r/Common_Lisp/comments/882mz4/clbench_common_lisp_benchmarking_suite/">reddit</a>.</li>
<li><a href="https://github.com/nikodemus/screamer">Screamer - nondeterministic programming. Augment Common Lisp with practically all of the functionality of both Prolog and constraint logic programming languages (10 yo, Nikodemus)</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/7oaum4/cmera_a_commonlisp_sourcetosource_compiler_to/">C-Mera, a Common Lisp source-to-source compiler to generate C/C++</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/7nf4an/regex_regular_expression_library_in_common_lisp/">Regex, regular expression library in Common Lisp</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/7mji50/cells_spreadsheetlike_expressiveness_for_clos/">Cells, spreadsheet-like expressiveness for CLOS</a></li>
</ul>

<h1 id="articles">Articles</h1>

<ul>
<li><a href="http://notes.eatonphil.com/starting-a-minimal-common-lisp-project.html">Starting a minimal Common Lisp project</a></li>
<li><a href="https://blog.teknik.io/phoe/p/1633">Emacs + ECL on Android</a></li>
<li><a href="https://lisp-journey.gitlab.io/blog/generice-consistent-access-of-data-structures-dotted-path/">Generic, consistent and dotted access of data structures with Access - lisp-journey</a> (<a href="https://www.reddit.com/r/Common_Lisp/comments/7pysmx/generic_consistent_and_dotted_access_of_data/">reddit</a>)</li>
<li><a href="http://blog.quicklisp.org/2018/01/build-failure-rss-feeds.html">Quicklisp&rsquo;s per-project build failures RSS feed</a></li>
<li><a href="http://blog.quicklisp.org/2018/02/quicklisp-implementation-stats-for-2017.html">Quicklisp implementation stats for 2017+</a></li>
<li><a href="http://turtleware.eu/posts/cl-charms-crash-course.html">cl-charms crash course</a></li>
<li><a href="https://medium.com/@MartinCracauer/llvms-garbage-collection-facilities-and-sbcl-s-generational-gc-a13eedfb1b31">LLVM’s garbage collection facilities and SBCL’s generational GC</a></li>
<li><a href="https://lisp-journey.gitlab.io/blog/snippets-functional-style-more/">A bunch of utilities from (again) sjl: higher order functions, sequences, debugging, profiling.</a></li>
<li><a href="https://common-lisp.net/project/mcclim/posts/Sheets-as-ideal-forms.html">Sheets as ideal forms</a></li>
<li><a href="http://langnostic.inaimathi.ca/posts/the-return-of-cl-notebook">The return of cl-notebook</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/7rsfyn/testing_the_series_common_lisp_package/">Testing the SERIES package</a></li>
</ul>

<h1 id="discussion">Discussion</h1>

<ul>
<li><a href="https://news.ycombinator.com/item?id=16591592">Portacle hits #1 on Hackernews</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/7n90l4/what_do_you_plan_to_work_on_in_2018/">What do you plan to work on in 2018?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/87gyhq/pros_and_cons_of_different_ways_to_declare_types/">Pros and cons of different ways to declare types in Common Lisp?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/7z7wuq/has_anyone_considered_or_started_a_project_to/">Has anyone considered or started a project to write a CL implementation in WebAssembly?</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/7s53qi/what_do_you_recommend_to_work_with_sql_databases/">What do you recommend to work with SQL databases ? What&rsquo;s your experience with Mito ?</a> and <a href="https://www.reddit.com/r/Common_Lisp/comments/7ozdcf/sqliteonly_interface_clsqlite_or_cldbi/">sqlite only interface: cl-sqlite or cl-dbi ?</a>
and <a href="https://www.reddit.com/r/lisp/comments/7iebty/ask_rlisp_is_there_any_lightweight_orm_that/">is there an ORM that generates classes from table definitions ?</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/82wiyt/how_to_collect_all_asdf_dependencies_for/">How to get asdf system dependencies</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/8665ga/please_join_the_cltelegrambot_refactoring_effort/">Join the cl-telegraph-bot refactoring effort !</a></li>
<li><a href="https://www.reddit.com/r/Common_Lisp/comments/86mbhc/gui_development_done_in_lisp_2013_comment/">GUI development done in Lisp (2013 comment)</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/88f9qs/strategies_for_dealing_with_large_amounts_of/">Strategies for Dealing with Large Amounts of Memory in Lisp? (SBCL)</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/7xizfr/gui_embedded_plots_in_lisp/">GUI embedded plots in Lisp ?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/7sp8mo/is_there_any_nonlisp_that_copies_common_lisps/">Is there any non-lisp that copies Common Lisp&rsquo;s condition system?</a></li>
</ul>

<h2 id="common-lisp-vs">Common Lisp VS &hellip;</h2>

<ul>
<li><a href="https://www.reddit.com/r/lisp/comments/86ze0t/as_a_newbie_what_i_will_miss_if_i_choose_racket/">As a newbie, what I will miss if I choose Racket over Common Lisp? Or if I happen to learn both at somepoint in future, choosing Racket/Common Lisp now would make sense?</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/7lf149/what_can_other_languages_do_that_lisp_cant/">What can other languages do that Lisp can&rsquo;t ?</a></li>
</ul>

<h1 id="screencasts">Screencasts</h1>

<ul>
<li><a href="https://youtu.be/unFYp6QFEiU?t=9m4s">Pushing Pixels with Lisp</a></li>
<li><a href="https://events.tymoon.eu/1?20180311">Lisp Treehouse</a></li>
<li><a href="https://www.youtube.com/watch?v=G2hgarXaEJI">Common Lisp study group 01-30-2018</a> (video)</li>
<li><a href="https://www.youtube.com/playlist?list=PL2VAYZE_4wRJi_vgpjsH75kMhN4KsuzR_">Little bits of Lisp</a></li>
</ul>

<h1 id="jobs">Jobs</h1>

<ul>
<li><a href="https://www.mail-archive.com/types-announce@lists.seas.upenn.edu/msg06942.html">Research Scientist Interactive Theorem Proving (using PVS, a Common Lisp application)</a></li>
<li><a href="https://lispjobs.wordpress.com/2017/11/22/lisp-engineer-mind-ai-seoul-korea-l-a-usa/">Lisp Engineer, Mind.ai</a></li>
<li><a href="https://angel.co/l/2717mK">lisp-based domain specific language, compiler design</a></li>
<li><a href="https://www.reddit.com/r/lisp/comments/7ik44o/seeking_cofounder_for_lisp_game_studio/">Seeking co-founder for Lisp game studio</a></li>
</ul>

<hr />

<p>If we missed anything: <a href="https://gitlab.com/lisp-journey/lisp-journey.gitlab.io">https://gitlab.com/lisp-journey/lisp-journey.gitlab.io</a></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">End of Year Review 2017-18</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">31 03 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        My services are provided through a limited company, Studio Zeffa. The company&rsquo;s financial year ends today, and so I thought I&rsquo;d take a moment to review the company&rsquo;s progress during this time.
Projects Over the past year I&rsquo;ve worked on the following projects:
Development and maintenance of Flow XO, a SaaS platform for building chatbots. Design and development of Blooms for Bees, a smartphone app for tracking bumblebee movements in the UK.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">End of Year Review 2017-18</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">31 03 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        My services are provided through a limited company, Studio Zeffa. The company&rsquo;s financial year ends today, and so I thought I&rsquo;d take a moment to review the company&rsquo;s progress during this time.
Projects Over the past year I&rsquo;ve worked on the following projects:
Development and maintenance of Flow XO, a SaaS platform for building chatbots. Design and development of Blooms for Bees, a smartphone app for tracking bumblebee movements in the UK.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/82-sprint-break.png" alt="Sprint Break">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Sprint Break</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">27 03 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/82-sprint-break.png" alt="Sprint Break" title="Sprint Break" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Migrating to Hugo</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">23 03 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Over the past 4 years, this site has been managed by Octopress - which has served me very well.
Unfortunately, I&rsquo;ve been unable to write any content for some time now. This is due to an upgrade to my laptop, moving from Ubuntu to Mac - as a result, I needed to reinstall a lot of things, and the (old) version of Octopress I was using no longer works with the latest Ruby.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Migrating to Hugo</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">23 03 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Over the past 4 years, this site has been managed by Octopress - which has served me very well.
Unfortunately, I&rsquo;ve been unable to write any content for some time now. This is due to an upgrade to my laptop, moving from Ubuntu to Mac - as a result, I needed to reinstall a lot of things, and the (old) version of Octopress I was using no longer works with the latest Ruby.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://www.emezeta.com/img/logo.png" alt="10 juegos de GameBoy que quizás no recordabas">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">10 juegos de GameBoy que quizás no recordabas</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Emezeta blog</a> <span class="article__date">21 03 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ¿Viviste la fiebre de las GameBoy durante los 90? ¿Tuviste una de primera generación? Entonces quizás recuerdes alguno de los siguientes juegos para GameBoy...
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/81-compiler.png" alt="Compiler">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Compiler</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">20 03 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/81-compiler.png" alt="Compiler" title="Compiler" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.freakspot.net/wp-content/uploads/2017/05/usando-pygettext.png" alt="Freak Spot: Internacionalizaci&amp;#243;n de programas Python">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Freak Spot: Internacionalizaci&amp;#243;n de programas Python</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">19 03 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>La
<a href="https://es.wikipedia.org/wiki/Internacionalizaci%C3%B3n_y_localizaci%C3%B3n">internacionalizaci&#243;n</a>
de programas permite que estos puedan ser entendidos por personas que
hablan idiomas diferentes.</p>
<p>En este art&#237;culo ense&#241;o c&#243;mo internacionalizar un programa escrito en
Python 3. Para este prop&#243;sito se suele utilizar el m&#243;dulo
<a href="https://docs.python.org/3/library/gettext.html">gettext</a>, que esta
incluido en Python.</p>
<span id="read_more_link"></span>

<p>Antes de nada, debemos tener un programa para poder traducirlo. Vamos a
traducir el siguiente programa llamado <code>saluda.py</code>:</p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/usr/bin/env python3</span>

<span class="n">nombre</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s1">'&#191;C&#243;mo te llamas? '</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'Hola, </span><span class="si">{}</span><span class="s1">.'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">nombre</span><span class="p">))</span>
</code></pre></div>

<p>El programa es muy sencillo. Pregunta al usuario su nombre y le saluda
por su nombre o, mejor dicho, le vuelve a repetir lo que el usuario ha
escrito.</p>
<p>Para internacionalizar el programa anterior vamos a importar el m&#243;dulo
gettext y a ejecutar la funci&#243;n <code>install</code> de gettext. Despu&#233;s, debemos
rodear el texto que queramos traducir con <code>_()</code>, es decir, si queremos
traducir <code>'texto'</code> escribiremos
<code>_('texto')</code>.</p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/usr/bin/env python3</span>

<span class="kn">import</span> <span class="nn">gettext</span>

<span class="n">gettext</span><span class="o">.</span><span class="n">install</span><span class="p">(</span><span class="s1">'saluda'</span><span class="p">,</span> <span class="s1">'locale'</span><span class="p">)</span>

<span class="n">nombre</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="n">_</span><span class="p">(</span><span class="s1">'&#191;C&#243;mo te llamas? '</span><span class="p">))</span>
<span class="nb">print</span><span class="p">(</span><span class="n">_</span><span class="p">(</span><span class="s1">'Hola, </span><span class="si">{}</span><span class="s1">.'</span><span class="p">)</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">nombre</span><span class="p">))</span>
</code></pre></div>

<p>Ahora creamos el directorio <code>locale</code>, donde guardaremos las traducciones:</p>
<div class="highlight"><pre><span></span><code><span class="err">mkdir locale</span>
</code></pre></div>

<p>Despu&#233;s debemos ejecutar pygettext, que viene instalado con Python.
Quiz&#225;s deb&#233;is ejecutar pygettext3 para indicar que quer&#233;is trabajar con
Python 3:</p>
<div class="highlight"><pre><span></span><code><span class="err">pygettext -d saluda -p locale saluda.py</span>
</code></pre></div>

<p>Yo lo hice as&#237; desde la terminal:</p>
<p><a href="https://www.freakspot.net/wp-content/uploads/2017/05/usando-pygettext.png">
<img alt="Ejecutando pygettext" src="https://www.freakspot.net/wp-content/uploads/2017/05/usando-pygettext.png" />
</a></p>
<p>Ahora tenemos el archivo <code>saluda.pot</code> en el directorio <code>locale</code>. Para
trabajar con archivos de traducci&#243;n es recomendable usar un editor
preparado para dicha tarea, porque hacerlo a mano es muy tedioso.
Podemos usar el editor Poedit o cualquier otro editor dise&#241;ado para
traducir.</p>
<p>Si vamos a utilizar Poedit, seleccionamos <strong>Archivo&gt;Nueva desde archivo
POT/PO</strong> y seleccionamos el archivo <code>saluda.pot</code>. A continuaci&#243;n,
debemos seleccionar el idioma al que queremos traducir, yo voy a elegir
el alem&#225;n.</p>
<p><a href="https://www.freakspot.net/wp-content/uploads/2017/05/Poedit-seleccionando-idioma.png">
<img alt="Seleccionando idioma para traducci&#243;n con Poedit" height="520" src="https://www.freakspot.net/wp-content/uploads/2017/05/Poedit-seleccionando-idioma.png" width="1018" />
</a></p>
<p>Cuando terminemos la traducci&#243;n, debemos guardarla:</p>
<p><a href="https://www.freakspot.net/wp-content/uploads/2017/05/Poedit-guardando-traducci&#243;n.png">
<img alt="Guardando traducci&#243;n con Poedit" height="932" src="https://www.freakspot.net/wp-content/uploads/2017/05/Poedit-guardando-traducci&#243;n.png" width="1439" />
</a></p>
<p>Se generar&#225;n dos archivos: <code>de.po</code> y
<code>de.mo</code>. El archivo <code>de.po</code> es legible por los humanos y el archivo
<code>de.mo</code> es legible por la m&#225;quina. El archivo <code>de.mo</code> debe guardarse
seg&#250;n la siguiente estructura de ficheros:
<code>locale/de/LC_MESSAGES/de.mo</code>. Para que no tengamos que acordarnos de la
anterior estructura cada vez que creemos o actualicemos una traducci&#243;n,
podemos ubicar el siguiente programa en el directorio <code>locale</code> y
ejecutarlo cada vez que actualicemos un archivo <code>.po</code>:</p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/usr/bin/env python3</span>
<span class="c1"># Copyright (C) 2016 Julie Marchant &lt;onpon4@riseup.net&gt;</span>
<span class="c1">#</span>
<span class="c1"># This program is free software: you can redistribute it and/or modify</span>
<span class="c1"># it under the terms of the GNU General Public License as published by</span>
<span class="c1"># the Free Software Foundation, either version 3 of the License, or</span>
<span class="c1"># (at your option) any later version.</span>
<span class="c1">#</span>
<span class="c1"># This program is distributed in the hope that it will be useful,</span>
<span class="c1"># but WITHOUT ANY WARRANTY; without even the implied warranty of</span>
<span class="c1"># MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span>
<span class="c1"># GNU General Public License for more details.</span>
<span class="c1">#</span>
<span class="c1"># You should have received a copy of the GNU General Public License</span>
<span class="c1"># along with this program.  If not, see &lt;http://www.gnu.org/licenses/&gt;.</span>

<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">subprocess</span>

<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&quot;__main__&quot;</span><span class="p">:</span>
    <span class="k">for</span> <span class="n">fname</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">():</span>
        <span class="n">root</span><span class="p">,</span> <span class="n">ext</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">splitext</span><span class="p">(</span><span class="n">fname</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">ext</span> <span class="o">==</span> <span class="s2">&quot;.po&quot;</span><span class="p">:</span>
            <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Generando </span><span class="si">{}</span><span class="s2">...&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">fname</span><span class="p">))</span>
            <span class="n">d</span><span class="p">,</span> <span class="n">root</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">root</span><span class="p">)</span>
            <span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="n">root</span><span class="p">,</span> <span class="s2">&quot;LC_MESSAGES&quot;</span><span class="p">),</span> <span class="n">exist_ok</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
            <span class="n">oname</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="n">root</span><span class="p">,</span> <span class="s2">&quot;LC_MESSAGES&quot;</span><span class="p">,</span> <span class="s2">&quot;saluda.mo&quot;</span><span class="p">)</span>
            <span class="n">subprocess</span><span class="o">.</span><span class="n">call</span><span class="p">([</span><span class="s2">&quot;msgfmt&quot;</span><span class="p">,</span> <span class="s2">&quot;-o&quot;</span><span class="p">,</span> <span class="n">oname</span><span class="p">,</span> <span class="n">fname</span><span class="p">])</span>

    <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Terminado.&quot;</span><span class="p">)</span>
</code></pre></div>

<p>Tras ejecutar el anterior programa, ya tendremos los archivos de
traducci&#243;n donde corresponden. Al ejecutar <code>saluda.py</code> se utilizar&#225; el
idioma por defecto del sistema operativo que lo ejecute. Es decir, si
estamos utilizando el alem&#225;n como el idioma predeterminado del sistema
operativo, el programa se ejecutar&#225; en alem&#225;n. Podemos comprobar si
funciona para este idioma cambiando la variable de entorno LANGUAGE en
el caso de que estemos trabajando con GNU/Linux. Se puede probar as&#237;:</p>
<p><a href="https://www.freakspot.net/wp-content/uploads/2017/05/programa-internacionalizado.png">
<img alt="Programa internacionalizado" src="https://www.freakspot.net/wp-content/uploads/2017/05/programa-internacionalizado.png" />
</a></p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/images/content/news/2018-03-19/clojure-use.png" alt="State of Clojure 2018 Results">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">State of Clojure 2018 Results</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">19 03 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Welcome to the annual State of Clojure 2018 survey results! Thanks so much for taking the time to check in and provide your feedback. We are very fortunate to have data for some of these questions going all the way back to 2010, giving us a long view on how the data is trending. This year, we had 2325 respondents, about the same as last year.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_rapid_uptake_of_clojure_1_9"><a class="anchor" href="#_rapid_uptake_of_clojure_1_9"></a>Rapid Uptake of Clojure 1.9</h2>
<div class="sectionbody">
<div class="paragraph">
<p>With the release of Clojure 1.9 in December, we expected to see a shift in version usage, and we did. 72% of developers are already using it with about 60% still using Clojure 1.8 as well. Only a small (6%) number of developers are still using versions 1.7 or older.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2018-03-19/clojure-use.png" alt="Clojure version use">
</div>
</div>
<div class="paragraph">
<p>We also keep an eye on JDK usage. Uptake of Java 1.9, released last year, has been a bit slower with only 29% adopting Java 1.9 so far and 88% of developers using Java 1.8. Only 6% of developers are using Java 1.7 and less than 1% are still using Java 1.6.</p>
</div>
<div class="paragraph">
<p>In the editor/IDE world we saw some consolidation this year with both Emacs (50%) and IntelliJ/Cursive (29%) making gains. All other editors saw decreases, although there is still a lot of interesting innovation happening around Atom and VS Code, which was not included but saw a lot of mentions in the comments (~5% of total respondents) - will definitely add next year!</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2018-03-19/editor.png" alt="Editor use">
</div>
</div>
<div class="paragraph">
<p>In the ClojureScript world, Figwheel continues to dominate as a critical part of most ClojureScript developer&#8217;s REPL workflow (76%). <a href="https://clojuriststogether.org/">Clojurists Together</a> is a new community effort to support open source projects in the community and they have been <a href="https://clojuriststogether.org/news/february-2018-monthly-update/">funding</a> work on Figwheel among other projects. Lumo was a new REPL option this year and made a strong showing of 12%.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2018-03-19/repl.png" alt="CLJS REPL use">
</div>
</div>
<div class="paragraph">
<p>In CLJS target environments, we saw an increase of +6% targeting Node (to 29%) and +4% targeting Lambda (to 13%) - both things to watch.</p>
</div>
<div class="paragraph">
<p>In the build tooling world, the entry of the <a href="https://clojure.org/guides/deps_and_cli">clj</a> tool is driving a lot of reevaluation and change right now. With so many things in flux, this area is sure to evolve significantly in 2018 and it will be interesting to see where we are in 2019. One important omission in the choices this year was shadow-cljs. There were a lot of mentions in the comments and it&#8217;s clearly an important tool for many to build and deploy - we&#8217;ll be sure to add it next year.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_interest_surging_from_javascript_programmers"><a class="anchor" href="#_interest_surging_from_javascript_programmers"></a>Interest Surging from JavaScript Programmers</h2>
<div class="sectionbody">
<div class="paragraph">
<p>When we look at which language communities people are coming from, those answers have been remarkably stable for years, but there was significant movement this year for JavaScript (which vaulted over both Python and Ruby). Clearly people are finding ClojureScript (and its strong resonance with React) as an interesting and viable alternative to JavaScript.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2018-03-19/prior-langs.png" alt="Prior language">
</div>
</div>
<div class="paragraph">
<p>As to where Clojurists hang out, we saw significant increases in use of Reddit (+5%) and Slack (+4%) and some decreases in use of the Clojure mailing lists, IRC, and attendance at both in-person and on-line conferences. One new choice added this year was the ClojureVerse Discourse server - it seems to be a useful midpoint between Slack (high volume live chat) and mailing lists (low volume asynchronous discussion). This was a new option yet 17% of respondents reported using it.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2018-03-19/community-forums.png" alt="Community forums">
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_clojure_and_clojurescript_used_in_many_domains_and_industries"><a class="anchor" href="#_clojure_and_clojurescript_used_in_many_domains_and_industries"></a>Clojure and ClojureScript Used in Many Domains and Industries</h2>
<div class="sectionbody">
<div class="paragraph">
<p>One of the things we are always watching is the trend of people using Clojure for their day-to-day work. This year, we continued to see about 2/3 of respondents using Clojure for work (compare that to the very first survey back in 2010 when less than 1/3 were doing so). Web development has always been the most dominant domain - in 2010, 53% were doing web dev and these days fully 82% of Clojure devs are involved in some kind of web development (not surprising given how many Clojure devs are using both Clojure and ClojureScript together).</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2018-03-19/domains.png" alt="Domains">
</div>
</div>
<div class="paragraph">
<p>When looking at the industries using Clojure, we added a few choices this year based on prominent results in last year&#8217;s "Other" category - entertainment (3%), energy/utility (2%), automotive/manufacturing (2%). We also saw a noticeable increase (+3%) in Financial services. Perhaps due to the new choices, we saw small decreases in the largest and most generic categories, enterprise software and consumer software.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2018-03-19/industries.png" alt="Industries">
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_interest_in_hiring_stays_strong"><a class="anchor" href="#_interest_in_hiring_stays_strong"></a>Interest in Hiring Stays Strong</h2>
<div class="sectionbody">
<div class="paragraph">
<p>There are several questions about how Clojure and ClojureScript should change or be prioritized for improvement. The results are largely similar to prior years, although the question format changed a little making it hard to directly compare every detail. The top result is clearly error messages though - while spec has started us down a road, that is still a work in progress which will continue this year. Many people have been using the Expound library for taking spec error output and making the data easier to read.</p>
</div>
<div class="paragraph">
<p>Hiring and staffing is always an interesting one to watch and that increased this year. We often see the seemingly contradictory dual complaints of companies that need more people and developers that have a hard time finding positions. To a large degree this is either a mismatch in the geographic distribution of jobs and people and/or a mismatch in needs and skill levels. It has been very encouraging to see so many large teams growing and hiring of late though.</p>
</div>
<div class="paragraph">
<p>The need for more docs and tutorials is also one that has gone up and down over the years and seems to be up again this year. While there are a wealth of resources for new Clojure developers now in every format, it is also sometimes difficult for people to find just the right resource for their experience level and need. There have been many good discussions lately about this and lots of active work in the community.</p>
</div>
<div class="paragraph">
<p>In general, there have been so many new tools, learning resources, companies, etc of late that it&#8217;s hard to keep up - 2018 is going to be a great year for Clojure!</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_check_out_the_data"><a class="anchor" href="#_check_out_the_data"></a>Check Out the Data</h2>
<div class="sectionbody">
<div class="paragraph">
<p>If you&#8217;d like to dig into the full results, you can find the complete set of data from this and former years here:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://www.surveymonkey.com/results/SM-9BC5FNJ68/">2018</a></p>
</li>
<li>
<p><a href="https://www.surveymonkey.com/results/SM-7K6NXJY3/">2016</a></p>
</li>
<li>
<p><a href="http://blog.cognitect.com/blog/2016/1/28/state-of-clojure-2015-survey-results">2015</a></p>
</li>
<li>
<p><a href="http://blog.cognitect.com/blog/2014/10/20/results-of-2014-state-of-clojure-and-clojurescript-survey">2014</a></p>
</li>
<li>
<p><a href="http://cemerick.com/2013/11/18/results-of-the-2013-state-of-clojure-clojurescript-survey/">2013</a></p>
</li>
<li>
<p><a href="http://cemerick.com/2012/08/06/results-of-the-2012-state-of-clojure-survey/">2012</a></p>
</li>
<li>
<p><a href="http://cemerick.com/2011/07/11/results-of-the-2011-state-of-clojure-survey/">2011</a></p>
</li>
<li>
<p><a href="http://cemerick.com/2010/06/07/results-from-the-state-of-clojure-summer-2010-survey/">2010</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p><em>Note that we are doing the survey about every 14 months so the last survey occurred in late 2016 rather than 2017.</em></p>
</div>
<div class="paragraph">
<p>Thanks again for being part of the community!</p>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://raw.githubusercontent.com/tanrax/workshop-flask-with-vuejs/master/flaskyvuejs.jpg" alt="Programador Web Valencia: Tutorial Flask para crear un API REST con VueJS">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Programador Web Valencia: Tutorial Flask para crear un API REST con VueJS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Python Hispano</a> <span class="article__date">18 03 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img alt="Flask y Vuejs" src="https://raw.githubusercontent.com/tanrax/workshop-flask-with-vuejs/master/flaskyvuejs.jpg" /></p>

<h2 id="introducci&#243;n">Introducci&#243;n</h2>

<p>En el siguiente <strong>tutorial con Flask</strong> vamos a construir un <strong>API REST</strong> completa paso a paso en <strong>18 sencillos temas</strong>. Aprenderemos a trabajar con Flask, a realizar un esquema sencillo, a conectar con una base de datos, realizar un CRUD, a conectar con una base de datos, crear una interfaz con VueJS, e integrarlo todo con comodidad. Todos temas son accesibles desde cada rama del repositorio.</p>

<p>El objetivo no es aburrirte con infinitas explicaciones, sino darte <strong>nociones reales para trabajar</strong>. De ese modo podr&#225;s experimentar revisando <strong>el c&#243;digo que te dejo en cada tema</strong>.</p>

<h2 id="indice">Indice</h2>

<ul>
  <li>Tema 1: Flask
    <ul>
      <li><a href="https://github.com/tanrax/workshop-flask-with-vuejs/tree/tema1-1">1-1 Hola Flask</a></li>
      <li><a href="https://github.com/tanrax/workshop-flask-with-vuejs/tree/tema1-2">1-2 Hola API Rest</a></li>
      <li><a href="https://github.com/tanrax/workshop-flask-with-vuejs/tree/tema1-3">1-3 Preparamos proyecto</a></li>
    </ul>
  </li>
  <li>Tema 2: API Rest
    <ul>
      <li><a href="https://github.com/tanrax/workshop-flask-with-vuejs/tree/tema2-1">2-1 Hola Flask-restplus</a></li>
      <li><a href="https://github.com/tanrax/workshop-flask-with-vuejs/tree/tema2-2">2-2 Primeras llamadas</a></li>
      <li><a href="https://github.com/tanrax/workshop-flask-with-vuejs/tree/tema2-3">2-3 Completamos las peticiones</a></li>
    </ul>
  </li>
  <li>Tema 3: Base de datos
    <ul>
      <li><a href="https://github.com/tanrax/workshop-flask-with-vuejs/tree/tema3-1">3-1 ORM con SQLAlchemy</a></li>
      <li><a href="https://github.com/tanrax/workshop-flask-with-vuejs/tree/tema3-2">3-2 Migraciones</a></li>
      <li><a href="https://github.com/tanrax/workshop-flask-with-vuejs/tree/tema3-3">3-3 Generando informaci&#243;n para desarrollo</a></li>
      <li><a href="https://github.com/tanrax/workshop-flask-with-vuejs/tree/tema3-4">3-4 Esquemas para crear JSONs</a></li>
      <li><a href="https://github.com/tanrax/workshop-flask-with-vuejs/tree/tema3-5">3-5 CRUD y definiciones finales</a></li>
    </ul>
  </li>
  <li>Tema 4: Vue-cli
    <ul>
      <li><a href="https://github.com/tanrax/workshop-flask-with-vuejs/tree/tema4-1">4-1 Hola Vue-cli</a></li>
      <li><a href="https://github.com/tanrax/workshop-flask-with-vuejs/tree/tema4-2">4-2 Plantilla HTML</a></li>
      <li><a href="https://github.com/tanrax/workshop-flask-with-vuejs/tree/tema4-3">4-3 Vue-resource: Peticiones desde VueJS</a></li>
      <li><a href="https://github.com/tanrax/workshop-flask-with-vuejs/tree/tema4-4">4-4 Guardamos un dato nuevo</a></li>
      <li><a href="https://github.com/tanrax/workshop-flask-with-vuejs/tree/tema4-5">4-5 Componente nuevo</a></li>
      <li><a href="https://github.com/tanrax/workshop-flask-with-vuejs/tree/tema4-6">4-6 Compilamos e integramos en Flask</a></li>
      <li><a href="https://github.com/tanrax/workshop-flask-with-vuejs/tree/tema4-7">4-7 Detalles est&#233;ticos</a></li>
    </ul>
  </li>
</ul>

<h2 id="objetivo-final">Objetivo final</h2>

<p><a href="http://flask-api-vuejs.programadorwebvalencia.com/#/">Prueba la DEMO</a></p>

<p><img alt="screenshot" src="https://raw.githubusercontent.com/tanrax/workshop-flask-with-vuejs/master/screenshot.png" /></p>

<h2 id="necesitaremos">Necesitaremos</h2>

<ul>
  <li>Port&#225;til, y tuyo.</li>
  <li>Python 3.5&gt;</li>
  <li>Internet superior a 56k</li>
  <li>Editor de texto enriquecido y con fundamento.</li>
  <li><a href="https://httpie.org/">httpie</a></li>
  <li><a href="https://docs.pipenv.org/">pipenv</a></li>
</ul>

<h2 id="bibliotecas">&#191;Bibliotecas?</h2>

<h3 id="microframework-web">Microframework Web</h3>

<ul>
  <li><strong>Flask</strong>.</li>
</ul>

<h3 id="base-de-datos">Base de datos</h3>

<ul>
  <li><strong>Flask-SQLAlchemy</strong>: ORM</li>
  <li><strong>Flask-Migrate</strong>: A&#241;ade herramientas para gestionar nuestra base de datos.</li>
  <li><strong>Flask-Script</strong>: Creaci&#243;n de comandos personalizados</li>
  <li><strong>Faker</strong>: Generador de informaci&#243;n falsa</li>
</ul>

<h3 id="api-rest">API Rest</h3>

<ul>
  <li><strong>Flask-restplus</strong>: Nos ayuda con las peticiones y autodocumentaci&#243;n</li>
  <li><strong>Flask-JWT</strong>: Identificaci&#243;n b&#225;sica.</li>
  <li><strong>Flask-marshmallow</strong>: Convertir&#225; los objetos ORM en JSON.</li>
  <li><strong>Flask-CORS</strong>: Nos permitir&#225; peticiones desde el exterior.</li>
</ul>

<h3 id="herramientas-de-desarrollo">Herramientas de desarrollo</h3>

<ul>
  <li><strong>httpie</strong>: Cliente de API Rest para pruebas.</li>
  <li><strong>python-dotenv</strong>: Implementaci&#243;n de un archivo de configuraci&#243;n.</li>
</ul>

<h3 id="instalaci&#243;n">Instalaci&#243;n</h3>

<p>Si estas en Debian/Ubuntu, antes necesitar&#225;s.</p>

<figure class="highlight"><pre><code class="language-bash"><span class="nb">sudo </span>apt-get <span class="nb">install </span>python3-venv</code></pre></figure>

<p>&#161;Ahora s&#237;!</p>

<figure class="highlight"><pre><code class="language-bash">git clone git@github.com:tanrax/workshop-flask-with-vuejs.git
<span class="nb">cd </span>workshop-flask-with-vuejs
python3 <span class="nt">-m</span> venv venv
<span class="nb">source </span>venv/bin/activate
pip3 <span class="nb">install</span> <span class="nt">-r</span> requirements.txt</code></pre></figure>

<h2 id="empezamos">&#191;Empezamos?</h2>

<p><a href="https://github.com/tanrax/workshop-flask-with-vuejs/tree/tema1-1">Tema 1 Paso 1</a></p>

<h2 id="pista-para-programadores">&#161;Pista para programadores!</h2>

<p>Para seguir el taller sin perderte puedes ir saltando a los &#127880;checkpoints&#127880; de la siguiente manera.</p>

<figure class="highlight"><pre><code class="language-bash">git checkout tema1-1</code></pre></figure>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/80-the-struggle.png" alt="The Struggle">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Struggle</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">13 03 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/80-the-struggle.png" alt="The Struggle" title="The Struggle" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Nine months with Vim</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">11 03 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Over summer, I attended the Recurse Center. I noticed that around half the people in my batch were using Vim, and figured it would be a good time to try it out. I ran into two difficulties:
 I knew the basics of using Vim but I was less efficient than with my previous editor, Visual Studio Code I didn&rsquo;t know how to configure Vim to use the syntax highlighting, indentation and linters I was used to.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Tip: capture standard and error output</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">06 03 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>What if we want to capture standard (and/or error) output in order to
ignore it or post-process it ? It&rsquo;s very simple, a
<a href="https://stackoverflow.com/questions/35333715/lisp-capture-stdout-and-stderr-store-it-in-separate-variables">little search</a>
and we&rsquo;re good:</p>

<pre><code class="language-lisp">(let ((*standard-output* (make-string-output-stream))
      (*error-output* (make-string-output-stream)))
  (apply function args) ;; anything
  (setf standard-output (get-output-stream-string *standard-output*)))
(print-results standard-output))
</code></pre>

<p>and now in <code>print-results</code> we can print to standard output without
being intercepted (and in our case, we&rsquo;ll highlight some user-defined
keywords).</p>

<p>Above, just don&rsquo;t forget to get the output content with
<code>(get-output-stream-string *standard-output*)</code>.</p>

<p>A thing to note is that if your app printed stuff on error output and
standard output consecutively, now it will print all standard output
as a single block.</p>

<p>(<strong>edit</strong>) Of course, <code>with-output-to-string</code> is simpler to capture one stream:</p>

<pre><code class="language-lisp">(setf standard-output (with-output-to-string (*standard-output*)
                        (apply function args)))
</code></pre>

<p><strong>edit 2</strong>, thanks to <a href="https://www.reddit.com/r/learnlisp/comments/837i0j/tip_capture_standard_and_error_output/">redditers</a>:</p>

<p>Don&rsquo;t bind <em><code>standard-output</code></em> directly; bind the string stream to a
lexical, then bind <code>*standard-output*</code> to that:</p>

<pre><code class="language-lisp">(with-output-to-string (s)
  (let ((*standard-output* s)) (write-string &quot;abc&quot;)))
-&gt; &quot;abc&quot;
</code></pre>

<p>Now, let&rsquo;s bind both <code>*standard-output*</code> and <code>*standard-error*</code> to s:</p>

<pre><code class="language-lisp">(with-output-to-string (s)
  (let ((*standard-output* s)
        (*standard-error* s))
    (write-string &quot;abc&quot;)
    (write-string &quot;def&quot; *standard-error*)))
-&gt; &quot;abcdef&quot;
</code></pre>

<p>Eliminate s and just bind <code>*standard-output*</code> and then tie
<code>*standard-error*</code> to the same stream:</p>

<pre><code class="language-lisp">(with-output-to-string (*standard-output*)
  (let ((*standard-error* *standard-output*))
    (write-string &quot;abc&quot;)
    (write-string &quot;def&quot; *standard-error*)))
--&gt; &quot;abcdef&quot;
</code></pre>

<p>The conclusion stays: it&rsquo;s handy and easy :)</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/79-focus.png" alt="Focus">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Focus</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">06 03 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/79-focus.png" alt="Focus" title="Focus" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The “dot” command in Vim</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Jovica Ilic</a> <span class="article__date">02 03 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I believe you have already heard of the principle Don&#8217;t Repeat Yourself. In software engineering, this is a principle of software development where your focus is on reducing repetition of all kinds. As you&#8217;ll see throughout the book, Vim has many ways and commands to automate different kinds of tasks, so you don&#8217;t have to... <a class="more-link" href="https://jovicailic.org/2018/03/vim-the-dot-command/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a rel="nofollow" href="https://jovicailic.org/2018/03/vim-the-dot-command/">The &#8220;dot&#8221; command in Vim</a> appeared first on <a rel="nofollow" href="https://jovicailic.org">Jovica Ilic</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">February 2018 Monthly Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">01 03 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Hi folks!
Welcome to the first monthly update for Clojurists Together. Now that things are a bit more settled, we are going to be issuing more regular updates keeping you up to date with what is going on with Clojurists Together.
Clojurists Together news In February we had three new company members, and 25 new developer members sign up. In total, we were supported by 14 companies, and 75 developers. We are really thrilled with how developers and companies are responding to Clojurists Together and the two projects that were selected for the first funding round: clj-http and Figwheel.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Pico-8 Game of life</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">25 02 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The Pico-8 is a &lsquo;fantasy console&rsquo; built by Lexaloffle. It&rsquo;s a program that runs on your computer that lets you write an play small games written in Lua. I recently implemented Conway&rsquo;s Game of Life for Pico-8 and it was a fun and rewarding experience. You can play with my implementation here.
This post contains some thoughts I had while making the game.
Lua This was my first time writing Lua and found it easy to pick up.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/78-demo.png" alt="Demo">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Demo</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">19 02 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/78-demo.png" alt="Demo" title="Demo" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Your First Vim Session</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Jovica Ilic</a> <span class="article__date">16 02 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The major barrier to any skill acquisition isn’t intellectual, but emotional. The same goes for learning Vim. That&#8217;s why, as one of the first chapters in my book Mastering Vim Quickly, I teach how to do something very cool. It&#8217;s very motivational, especially for someone who is new to the Vim world. You see you... <a class="more-link" href="https://jovicailic.org/2018/02/first-vim-session/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a rel="nofollow" href="https://jovicailic.org/2018/02/first-vim-session/">Your First Vim Session</a> appeared first on <a rel="nofollow" href="https://jovicailic.org">Jovica Ilic</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/77-testing-during-development.png" alt="Testing during development">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Testing during development</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">13 02 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/77-testing-during-development.png" alt="Testing during development" title="Testing during development" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Fixing a CL21 error message in an unrelated library after a quicklisp update (it&#39;s about cache)</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">12 02 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I just updated my Quicklisp dist and suddenly couldn&rsquo;t load some
libraries any more. I got an error related to cl21 looking like the one below
(I didn&rsquo;t note the exact message sorry), even though the library was
unrelate to cl21 (it was about osicat and cffi.grovel):</p>

<blockquote>
<p>couldn&rsquo;t find adjustable-vectors from CL21.core.arrays</p>
</blockquote>

<p>If you skip through the restarts you&rsquo;ll see mentions of a cache in
<code>~/.cache/common-lisp/sbclxx-xx/quicklisp/…</code>. It contains the compiled <code>.fasl</code> files.</p>

<p>I deleted this cache and I&rsquo;m good to go.</p>

<hr />

<p>related: <a href="https://github.com/cl21/cl21/issues/99">https://github.com/cl21/cl21/issues/99</a></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q1 2018 Funding Announcement</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">07 02 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Clojurists Together is excited to announce the two projects that are being funded in Q1 2018: clj-http and Figwheel!
Recap For those who are new to Clojurists Together, our goal is simple: Fund critical Clojure open-source projects to keep them healthy and sustainable. Clojure companies and individual developers sign up for a monthly contribution, and we pick projects to fund each quarter. This is our first funding cycle since launching.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/76-debugging.png" alt="Debugging">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Debugging</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">06 02 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/76-debugging.png" alt="When stackoverflow is missing the answer" title="When stackoverflow is missing the answer" /></p>

<div class="no-max" style="text-align: center; margin-top: 60px;">
  <div style="max-width: 350px; display: inline-block;">
  <div class="center">Created by <a href="https://twitter.com/spectrekelevra"><i class="ssk ssk-icon ssk-twitter"></i>@spectrekelevra</a></div>
  <img src="https://www.monkeyuser.com/assets/images/2018/76-debugging-suggestion1.png" alt="Community edit" title="Community edit" />
</div>
  <div style="max-width: 350px; display: inline-block;">
  <div class="center">Suggested by reddit community</div>
  <img src="https://www.monkeyuser.com/assets/images/2018/76-debugging-suggestion2.png" alt="Community edit" title="Community edit" />
</div>
  <div style="clear: both">
</div>
</div>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="February Update - The Tracking Shell Game">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">February Update - The Tracking Shell Game</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">05 02 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        How mergers and acquisitions are hiding who actually is tracking us.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Q1 2018 Update and Survey Results</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">31 01 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Welcome to the first Clojurists Together update for 2018! We have recently run a survey on our members to better understand them and their needs. We are currently working in the process of finalising the projects we will fund and will have an announcement soon. In the meantime, we wanted to share the results of the survey to help future applicants see what our areas of focus are.
New Members Since our announcement we have had 11 companies and 50 developers join up.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/75-perspectives.png" alt="Perspectives">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Perspectives</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">30 01 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/75-perspectives.png" alt="Perspectives" title="Perspectives" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">9 Django Tips for Working with Databases</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">28 01 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>ORMs offer great utility for developers but abstracting access to the database has its costs. Developers who are willing to poke around the database and change some defaults often find that great improvements can be made.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year1.png" alt="10 Years of Instapaper">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">10 Years of Instapaper</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Instapaper</a> <span class="article__date">28 01 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>On January 28, 2008, Marco Arment <a href="https://marco.org/2008/01/28/instapaper">announced</a> a new side project called Instapaper. Ten years and billions of articles later, we&rsquo;re thrilled to be helping our readers learn, research and experience the Internet removed from the typical distractions.</p><p>First, we want to thank all of our users. Whether you’ve been around since the Marco days, joined us when betaworks took over the development or signed up after our acquisition by Pinterest, thank you! We wouldn’t be anywhere without you, and we look forward to incorporating your requests into our 2018 updates.<br/></p><p>In Internet years a decade is a century. Instapaper predates the App Store, Google Chrome and the entire Android OS, so we wanted to take this opportunity to look back on some of our product and business milestones.<br/></p><p><b>2008</b></p><p>At launch, Instapaper was more of a bookmarking tool than the full-featured reading product it is today. Users could save items to their Instapaper list and then go view the original website at their convenience.</p><p><figure class="tmblr-full" data-orig-height="439" data-orig-width="531" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year1.png"><img src="https://64.media.tumblr.com/8d19f261d708b4c174bb209007060e12/tumblr_inline_p7gifaLhGo1rof3ra_540.png" alt="image" data-orig-height="439" data-orig-width="531" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year1.png"/></figure></p><p>In April, we introduced <a href="https://marco.org/2008/04/07/instapaper-updated">“Text mode”</a> to reduce load times for slower phone connections. The parser behind that feature remains one of the most foundational and innovative components of Instapaper today.</p><p>Apple launched its App Store in July, and we were one of the first apps available. Instapaper got over 2,000 downloads on its first day (and more than <a href="https://marco.org/2008/07/20/instapapers-iphone-app-passed-15-000-downloads">15,000 downloads before the end of the month</a>), and we got our first of many App Store features.</p><p><figure class="tmblr-full" data-orig-height="215" data-orig-width="500" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year2.png"><img src="https://64.media.tumblr.com/47e589514acb31f484d1f8bbae8ed2a4/tumblr_inline_p7gifbJSqu1rof3ra_540.png" alt="image" data-orig-height="215" data-orig-width="500" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year2.png"/></figure></p><p>By the end of the year, we also added the first proper offline mode, more fonts, the Archive section, “Give me something to read” (the precursor to the current Daily/Feature content), tilt-scroll and our first business model–a separate version of the app called <a href="http://blog.instapaper.com/post/53247960">Instapaper Pro</a> which cost $9.99.</p><p><b>2009</b></p><p>With the core function of processing content for offline reading in place, 2009 was all about adding more ways to get content into and out of Instapaper with the <a href="http://blog.instapaper.com/post/73123968/read-later-api">launch of our API</a> in January, <a href="http://blog.instapaper.com/post/84727433">Kindle</a> support and <a href="http://blog.instapaper.com/post/82648498">Likes</a> in March, <a href="http://blog.instapaper.com/post/129332224">folders and background updating</a> in June and <a href="http://blog.instapaper.com/post/245254098">ePub and Kindle exports</a> in November.</p><p><figure class="tmblr-full" data-orig-height="348" data-orig-width="497" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year3.png"><img src="https://64.media.tumblr.com/bfe1cc4e4f6fffe19062e069ed4661a1/tumblr_inline_p7gifcjYEY1rof3ra_540.png" alt="image" data-orig-height="348" data-orig-width="497" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year3.png"/></figure></p><p>Instapaper Pro went on sale, and $4.99 became the new price for the paid version of the app.<br/></p><p><figure class="tmblr-full" data-orig-height="550" data-orig-width="600" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year4.png"><img src="https://64.media.tumblr.com/bd37de563d9a9ac64dd433f1de5392f8/tumblr_inline_p7gife8EuV1rof3ra_540.png" alt="image" data-orig-height="550" data-orig-width="600" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year4.png"/></figure></p><p><b>2010</b></p><p>As more users saved more content, we introduced a <a href="http://blog.instapaper.com/post/326185394">bulk edit option</a> for easier content management and <a href="http://blog.instapaper.com/post/382873580">paywall/multi-page support</a> to improve saving overall. The app got a slight facelift for our <a href="http://blog.instapaper.com/post/469281634">iPad debut</a> as well as the addition of <a href="http://blog.instapaper.com/post/751563359">pagination mode</a>, themes, auto-dark mode, in-app dictionary, and <a href="http://blog.instapaper.com/post/1538890633">length indicators</a> for saves.</p><p><figure class="tmblr-full" data-orig-height="390" data-orig-width="500" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year5.png"><img src="https://64.media.tumblr.com/f11172975efb997071b54f86c47716ac/tumblr_inline_p7giffnHl81rof3ra_540.png" alt="image" data-orig-height="390" data-orig-width="500" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year5.png"/></figure></p><p>In October, <a href="https://techcrunch.com/2010/10/04/instapaper-subscriptions/">Instapaper launched an optional subscription</a> for $1 per-month to help support our operation and future feature development. Eventually, Instapaper’s full-text search feature would launch exclusively for subscribers.</p><p>To close out the year, Instapaper was added to <a href="http://blog.instapaper.com/post/1508729676">Apple’s Hall of Fame</a> and awarded a <a href="https://www.macworld.com/article/1155497/26thannual_eddies.html">Macworld editors’ choice award</a>.<br/></p><p><b>2011</b></p><p>This was the year we got even more connected, with a <a href="http://blog.instapaper.com/post/3208433429">full API launch</a>, <a href="http://blog.instapaper.com/post/3772087268">social sharing</a> in the Instapaper 3.0 release, a brand new <a href="http://blog.instapaper.com/post/4637427075">dictionary and zoomable images</a>. It also was the year the FBI may have <a href="http://blog.instapaper.com/post/6830514157">unintentionally confiscated</a>–and <a href="http://blog.instapaper.com/post/6854208028">later returned</a>–one of our servers during an unrelated raid.<br/></p><p><figure class="tmblr-full" data-orig-height="550" data-orig-width="600" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year6.png"><img src="https://64.media.tumblr.com/ae88b5c7632a5f7f37dcba7f6b06218e/tumblr_inline_p7gifgNSIK1rof3ra_540.png" alt="image" data-orig-height="550" data-orig-width="600" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year6.png"/></figure></p><p>Additionally, the free version of <a href="https://marco.org/2011/04/28/removed-instapaper-free">our app was removed from the App Store</a>, leaving only the $4.99 Instapaper Pro version.<br/></p><p><b>2012</b></p><p>In 2012, our <a href="http://blog.instapaper.com/post/18556429689">bookmarklet got a facelift</a>, with a more prominent overlay, and confirmation and automatic multi-page save capability. The iOS app also got iBooks-style pagination mode, the option to manually select twilight sepia at any time and swipe gestures in <a href="http://blog.instapaper.com/post/18556429689">Instapaper 4.2</a>. In June, we released the first version of <a href="http://blog.instapaper.com/post/24549960305">Instapaper for Android</a> for $2.99 and dropped the price of the iOS app to $3.99. Lastly, we added support for the <a href="http://blog.instapaper.com/post/31834532875">OpenDyslexie</a> and <a href="http://blog.instapaper.com/post/32233350372">FS Me</a> fonts to improve accessibility.<br/></p><p><figure class="tmblr-full" data-orig-height="274" data-orig-width="500" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year7.png"><img src="https://64.media.tumblr.com/4fbc83ee42b83a22aa9bb6725ed13472/tumblr_inline_p7gifh3Rbj1rof3ra_540.png" alt="image" data-orig-height="274" data-orig-width="500" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year7.png"/></figure></p><p><b>2013</b></p><p>Instapaper was <a href="https://marco.org/2013/04/25/instapaper-next-generation">acquired by betaworks</a> in 2013. With a new team in place, we worked on<a href="http://blog.instapaper.com/post/52725785436"> backend infrastructure improvements</a>, a <a href="http://blog.instapaper.com/post/59614190398">site redesign</a>, a <a href="http://blog.instapaper.com/post/64302977025">Chrome extension</a> launch and the development of <a href="http://blog.instapaper.com/post/61764950884">InstaRank</a>, which was our first attempt to gain insight into aggregate reading trends across the service. <br/></p><p><figure class="tmblr-full" data-orig-height="696" data-orig-width="345" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year8.gif"><img src="https://64.media.tumblr.com/b577760d9ea4d13f5ce62351d6aa5ccc/tumblr_inline_p7gifidzdD1rof3ra_540.gif" alt="image" style="height: 550px;" data-orig-height="696" data-orig-width="345" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year8.gif"/></figure></p><p>The apps also got major updates with <a href="http://blog.instapaper.com/post/61609255324">Instapaper 5.0</a> for iOS 7, including a modern user interface, video support, parsing improvements and localization for 13 languages in September; an <a href="http://blog.instapaper.com/post/64785196661">Android app redesign</a> in October; and an <a href="http://blog.instapaper.com/post/66190518154">iPad redesign</a> in November. </p><p>The year was rounded out with the launch of the InstaRank-based <a href="http://blog.instapaper.com/post/70924183086">Instapaper Daily</a>, a compilation of the most popular articles saved to Instapaper every day.<br/></p><p><b>2014</b></p><p>With steady Instapaper Daily engagement, the articles from that feed became part of Instapaper’s Browse section and we began sending out a compilation of Daily articles as an email digest called <a href="http://blog.instapaper.com/post/74088929566">Instapaper Weekly.</a><br/></p><p><figure class="tmblr-full" data-orig-height="98" data-orig-width="500" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year9.png"><img src="https://64.media.tumblr.com/ab72ff6d71b7af513785dba5f9ffbb81/tumblr_inline_p7gifjuTtK1rof3ra_540.png" alt="image" data-orig-height="98" data-orig-width="500" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year9.png"/></figure></p><p>In May, Instapaper.com was fully redesigned. <a href="http://blog.instapaper.com/post/85125160146">Highlights</a> was introduced and has since become one of our most-used features. Also, after years of using Georgia (a standard serif font), we got our first “real logo” from <a href="https://klim.co.nz/">Klim Type Foundry</a>:<br/></p><p><figure class="tmblr-full" data-orig-height="89" data-orig-width="493" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year10.png"><img src="https://64.media.tumblr.com/ccd69dac3ec98d15908308151a3fc5dc/tumblr_inline_p7gifkNMev1rof3ra_540.png" alt="image" data-orig-height="89" data-orig-width="493" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year10.png"/></figure></p><p>The App Store landscape had changed dramatically since 2008, and by September 2014 it made the most sense for us to <a href="https://medium.com/making-instapaper/making-instapaper-free-3844af1606ee">transition Instapaper into a freemium product</a>, marking the first time Instapaper was offered for free on the App Store since the removal of “Instapaper Free” in 2011.</p><p>In the <a href="http://blog.instapaper.com/post/97750859246">same release</a>, we added the iOS save extension, text-to-speech and public profiles. <a href="http://blog.instapaper.com/post/104333776481">In the subsequent 6.1 update</a>, Instapaper got its current slim save overlay, unread counts and handoff support for seamlessly picking up where you left off from your iPhone, iPad or the website.<br/></p><p><figure class="tmblr-full" data-orig-height="438" data-orig-width="500" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year11.gif"><img src="https://64.media.tumblr.com/c0333306f93812319c304a5149cfd304/tumblr_inline_p7giflTL5U1rof3ra_540.gif" alt="image" data-orig-height="438" data-orig-width="500" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year11.gif"/></figure></p><p><b>2015</b></p><p>Highlights were a great tool for pulling out key phrases in saves but a lot of users were asking to annotate what they were highlighting. That’s why we added <a href="http://blog.instapaper.com/post/120705386086">Notes</a>, the ability to add annotations to your Instapaper saves.<br/></p><iframe src="https://player.vimeo.com/video/129800846?title=0&amp;byline=0&amp;portrait=0" width="540" height="304" frameborder="0" title="Introducing Instapaper Notes!"></iframe><p>In addition to Notes, we implemented a speed reading feature and Instant Sync support in <a href="http://blog.instapaper.com/post/114681736471">Instapaper 6.2</a> as well as an <a href="http://blog.instapaper.com/post/117264393776">Apple Watch app</a> for triggering text-to-speech. <a href="http://blog.instapaper.com/post/129227268641">Instapaper 7</a> smoothed up all these developments and also included the addition of thumbnails, an iPad redesign, multi-task support and picture-in-picture for video playback.</p><p><b>2016</b></p><p>After adding so many new features, it was essential to bring legacy parts of Instapaper up to the same level. In January, we completely rewrote the parser and launched the first version of the current Instaparser. With <a href="http://blog.instapaper.com/post/137288701461">Instaparser 1.0</a>, we added enhanced video support, way better image handling, more aggressive stripping of non-article text and performance improvements that led to 10x faster saving.</p><p><figure class="tmblr-full" data-orig-height="720" data-orig-width="1200" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year13.png"><img src="https://64.media.tumblr.com/014f3fa5c8eddb5981246b07eb90d854/tumblr_inline_p7gifmTJDT1rof3ra_540.png" alt="image" data-orig-height="720" data-orig-width="1200" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year13.png"/></figure></p><p>Search was next on the update block. First, we overhauled <a href="http://blog.instapaper.com/post/143899635741">search infrastructure</a> entirely to improve speeds by 6x and allow us to add new features including sorting options, title searches, exact matches, site/author filtering, paged results and multi-language sort. With the new infrastructure in place, we then revamped mobile search to allow for local offline search, as well as searching for and opening items outside the device sync limit in Instapaper formatting.<br/></p><p><figure class="tmblr-full" data-orig-height="416" data-orig-width="600" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year12.png"><img src="https://64.media.tumblr.com/cda20f3a44fe76d731c59ee422aefb29/tumblr_inline_p7gifnbNOF1rof3ra_540.png" alt="image" data-orig-height="416" data-orig-width="600" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/10year12.png"/></figure></p><p>Instapaper opened a few new business models in 2016, including the <a href="http://blog.instapaper.com/post/142649520761">Instapaper Weekly Sponsorship</a> and the <a href="http://blog.instapaper.com/post/142296652536">Instaparser developer API</a>, which allowed third-party developers to use our article parser.</p><p>In August, <a href="http://blog.instapaper.com/post/149374303661">Instapaper joined Pinterest</a>, where we continue to operate as a separate, standalone product. With added resources under Pinterest, we were able to make <a href="http://blog.instapaper.com/post/152600596211">Instapaper Premium free for all users</a>.<br/></p><p><b>2017</b></p><p>Disaster struck in early 2017, as we experienced our first <a href="http://blog.instapaper.com/post/157027537441">major, extended outage</a>. While there was no data loss, Instapaper was offline for 20 hours, and it took almost five days to completely restore the service (quite the departure from our uptime of 99.93% the previous year). </p><p>On a more positive note, that year also included the launch of our <a href="http://blog.instapaper.com/post/156087271011">Firefox extension</a>, an iOS 11-optimized update with drag &amp; drop support and an iPhone X-specific update that was featured on launch at Apple’s new App Store.</p><iframe src="https://player.vimeo.com/video/234592989" width="540" height="304" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe><p><b>2018</b></p><p>This year, and beyond, we’ll continue the tradition of the past decade: offering a no-frills, high-quality service with total focus on the reader and the reading experience.<br/></p><p>Whether you use text-to-speech in the car, speed reading to read faster, highlights for your research or just read the good-old fashioned way. We look forward to helping you read and learn.<br/></p><p>We’d also like to reward anyone who made it all the way through this post, so if you send us an email to <a href="https://t.umblr.com/redirect?z=mailto%3Asupport%40help.instapaper.com&amp;t=NTNkYzQyMTdkMGRmZTUzMmY4YzBmNThlZDRhYWY0Y2QzNmEzZjI0OCxkUlk3V1dNeA%3D%3D&amp;b=t%3AOZjQZ-Pa6uMEdOyfetS5_g&amp;p=http%3A%2F%2Fblog.instapaper.com%2Fpost%2F165547951996&amp;m=1">support@help.instapaper.com</a> with your mailing address, we’ll send you some Instapaper stickers (U.S.-only, while stickers last). <br/></p><p>If you have any requests for what you’d like to see in Instapaper or just want to say hello, please let us know via <a href="https://t.umblr.com/redirect?z=mailto%3Asupport%40help.instapaper.com&amp;t=NTNkYzQyMTdkMGRmZTUzMmY4YzBmNThlZDRhYWY0Y2QzNmEzZjI0OCxkUlk3V1dNeA%3D%3D&amp;b=t%3AOZjQZ-Pa6uMEdOyfetS5_g&amp;p=http%3A%2F%2Fblog.instapaper.com%2Fpost%2F165547951996&amp;m=1">support@help.instapaper.com</a> or <a href="https://twitter.com/InstapaperHelp">@InstapaperHelp</a> on Twitter.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/media/2018/buy-and-hold-vs-trend-sma-365.png" alt="Backtesting 12-month SMA investing strategy with Pandas">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Backtesting 12-month SMA investing strategy with Pandas</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Danny van Kooten</a> <span class="article__date">24 01 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>In my quest to learn more about investing, I came across <a href="https://ofdollarsanddata.com/follow-the-money-eb1ae0c9a3bd">this post</a>.  The author writes <em>“How One Simple Rule Can Beat Buy and Hold Investing”</em> and then explains how following the trend is likely to beat a more traditional buy and hold investment approach.</p>

<p>Intrigued, I decided to dive into the data to see if I could replicate his results.</p>

<p>In this post I’ll walk you through the code and results for backtesting a 12-month simple moving average trend strategy on S&amp;P 500 stock market data.</p>

<p>We’ll compare entering the market when it is trending up and moving to cash when it is trending down to simply staying invested at all times. The latter approach is known as buy &amp; hold, or <a href="https://en.wikipedia.org/wiki/HODL">HODL</a> depending on what corner of the internet you’re from.</p>

<h3 id="obtaining-data-on-daily-closing-prices-for-the-sp-500">Obtaining data on daily closing prices for the S&amp;P 500</h3>

<p>First things first, we need data.</p>

<p>Yahoo Finance provides us with <a href="https://finance.yahoo.com/quote/%5EGSPC/history?p=%5EGSPC">historical data for the S&amp;P 500 as far back as 1960</a>. Let’s start out with parsing the CSV download into a DataFrame so we can get to work.</p>

<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">%</span><span class="n">matplotlib</span> <span class="n">inline</span>
<span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="n">pd</span>

<span class="n">sp500</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">read_csv</span><span class="p">(</span><span class="s">'data/SP500.csv'</span><span class="p">,</span> <span class="n">sep</span><span class="o">=</span><span class="s">','</span><span class="p">,</span> <span class="n">parse_dates</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">index_col</span><span class="o">=</span><span class="s">'Date'</span><span class="p">,</span> <span class="n">usecols</span><span class="o">=</span><span class="p">[</span><span class="s">'Adj Close'</span><span class="p">,</span> <span class="s">'Date'</span><span class="p">])</span>
<span class="n">sp500</span><span class="p">.</span><span class="n">head</span><span class="p">()</span>
</code></pre></div></div>

<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>Adj Close</th>
    </tr>
    <tr>
      <th>Date</th>
      <th></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>1960-01-04</th>
      <td>59.910000</td>
    </tr>
    <tr>
      <th>1960-01-05</th>
      <td>60.389999</td>
    </tr>
    <tr>
      <th>1960-01-06</th>
      <td>60.130001</td>
    </tr>
    <tr>
      <th>1960-01-07</th>
      <td>59.689999</td>
    </tr>
    <tr>
      <th>1960-01-08</th>
      <td>59.500000</td>
    </tr>
  </tbody>
</table>

<h3 id="calculating-the-12-month-simple-moving-average">Calculating the 12 month simple moving average</h3>

<p>To test our trend strategy later on, we need the daily change (in %) and the 12-month simple moving average.</p>

<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sp500</span><span class="p">[</span><span class="s">'Pct Change'</span><span class="p">]</span> <span class="o">=</span> <span class="n">sp500</span><span class="p">[</span><span class="s">'Adj Close'</span><span class="p">].</span><span class="n">pct_change</span><span class="p">()</span>
<span class="n">sp500</span><span class="p">[</span><span class="s">'SMA 365'</span><span class="p">]</span> <span class="o">=</span> <span class="n">sp500</span><span class="p">[</span><span class="s">'Adj Close'</span><span class="p">].</span><span class="n">rolling</span><span class="p">(</span><span class="n">window</span><span class="o">=</span><span class="mi">365</span><span class="p">).</span><span class="n">mean</span><span class="p">()</span>
<span class="n">sp500</span><span class="p">.</span><span class="n">dropna</span><span class="p">().</span><span class="n">head</span><span class="p">()</span>
</code></pre></div></div>

<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>Adj Close</th>
      <th>Pct Change</th>
      <th>SMA 365</th>
    </tr>
    <tr>
      <th>Date</th>
      <th></th>
      <th></th>
      <th></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>1961-06-14</th>
      <td>65.980003</td>
      <td>0.002736</td>
      <td>58.350521</td>
    </tr>
    <tr>
      <th>1961-06-15</th>
      <td>65.690002</td>
      <td>-0.004395</td>
      <td>58.366356</td>
    </tr>
    <tr>
      <th>1961-06-16</th>
      <td>65.180000</td>
      <td>-0.007764</td>
      <td>58.379479</td>
    </tr>
    <tr>
      <th>1961-06-19</th>
      <td>64.580002</td>
      <td>-0.009205</td>
      <td>58.391671</td>
    </tr>
    <tr>
      <th>1961-06-20</th>
      <td>65.150002</td>
      <td>0.008826</td>
      <td>58.406630</td>
    </tr>
  </tbody>
</table>

<p>This leaves us with all the data we need to compare our two investment strategies.</p>

<h3 id="defining-the-trend-strategy">Defining the trend strategy</h3>

<p>To recap, we want to invest when the trend is moving up, ie when the stock price is higher than the average price over the last 12 months. When the stock is traded at a price lower than the moving average, we move to cash.</p>

<p>Let’s add a column to our dataframe indicating whether the criteria for our trend strategy is met.</p>

<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sp500</span><span class="p">[</span><span class="s">'Criteria'</span><span class="p">]</span> <span class="o">=</span> <span class="n">sp500</span><span class="p">[</span><span class="s">'Adj Close'</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="n">sp500</span><span class="p">[</span><span class="s">'SMA 365'</span><span class="p">]</span> 
<span class="n">sp500</span><span class="p">[</span><span class="s">'Criteria'</span><span class="p">].</span><span class="n">value_counts</span><span class="p">()</span> 
</code></pre></div></div>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>True     10577
False     4032
Name: Criteria, dtype: int64
</code></pre></div></div>

<p>This tells us that on our entire dataset, our criteria was met on 10577 of the market’s trading days.</p>

<h3 id="calculating-our-investment-return">Calculating our investment return</h3>

<p>To calculate the return for our benchmark buy &amp; hold strategy, all we need to do is calculate the cumulative product of the daily change in prices.</p>

<p>Let’s assume an initial investment of $100 and calculate the return if we were to hold for the entire time period.</p>

<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sp500</span><span class="p">[</span><span class="s">'Buy &amp; Hold'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">100</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1</span> <span class="o">+</span> <span class="n">sp500</span><span class="p">[</span><span class="s">'Pct Change'</span><span class="p">]).</span><span class="n">cumprod</span><span class="p">()</span>
</code></pre></div></div>

<p>To calculate the return for our strategy, we should only add the compounded return for the days on which we are actually in the market.</p>

<p>On all other days the cash value of our investment remains unchanged.</p>

<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sp500</span><span class="p">[</span><span class="s">'Trend'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">100</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1</span> <span class="o">+</span> <span class="p">(</span> <span class="n">sp500</span><span class="p">[</span><span class="s">'Criteria'</span><span class="p">].</span><span class="n">shift</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="n">sp500</span><span class="p">[</span><span class="s">'Pct Change'</span><span class="p">]</span> <span class="p">)).</span><span class="n">cumprod</span><span class="p">()</span>
</code></pre></div></div>

<p>Let’s plot the values of both strategies in a single graph so that we can compare performances.</p>

<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ax</span> <span class="o">=</span> <span class="n">sp500</span><span class="p">[[</span><span class="s">'Trend'</span><span class="p">,</span> <span class="s">'Buy &amp; Hold'</span><span class="p">]].</span><span class="n">plot</span><span class="p">(</span><span class="n">grid</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">kind</span><span class="o">=</span><span class="s">'line'</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="s">"Trend (12 month SMA) vs. Buy &amp; Hold"</span><span class="p">,</span> <span class="n">logy</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</code></pre></div></div>

<p><img src="/media/2018/buy-and-hold-vs-trend-sma-365.png" alt="12-month SMA vs Buy &amp; Hold" /></p>

<p>This shows us that <strong>a simple buy &amp; hold investing approach actually outperformed our trend strategy when looking at the S&amp;P 500 market data for 1960 to early 2018</strong>.</p>

<h3 id="seeking-outperformance">Seeking outperformance</h3>

<p>Looking at the graph above, you can see that the trend did well during ongoing bear markets but sometimes failed to pick up on quick market recoveries.</p>

<p>Let’s cheat a little bit and look at “the lost decade”, which contains not just one but two relatively long bear markets!</p>

<p><img src="/media/2018/buy-and-hold-vs-sma-365-2000s.png" alt="" /></p>

<p>This shows us that our trend strategy resulted in considerable outperformance during the last 2 decades, but only because of the two bear markets.</p>

<h3 id="conclusion-trend-following-over-buy--hold">Conclusion: Trend following over Buy &amp; Hold?</h3>

<p>After playing with the data and looking at several time periods, I am still firmly in the “buy &amp; hold” camp and think it is the way to go for most individual investors.</p>

<p>With some curve fitting, we can make the trend model outperform over some specific time periods like the 2000’s. Increase the holding period and this outperformance does not last though.</p>

<p><em>You can <a href="https://github.com/dannyvankooten/dannyvankooten.com/blob/master/notebooks/12%20month%20SMA%20vs%20Buy%20and%20Hold.ipynb">find the complete Jupyter Notebook for this post here</a>.</em></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">snippets - functional style, sequences, debugging and more utilities</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">23 01 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>From
<a href="https://github.com/sjl/cl-losh/blob/master/losh.lisp">sjl&rsquo;s utilities</a>
(thanks so much for the nice docstrings). The goal here is to read
some code and learn about (hidden) gems.</p>

<p>The following snippets should be copy-pastable. They are the ones I
find most interesting, I left some behind.</p>

<p>To reduce the dependency load, Alexandria or Quickutil functions can
be imported one by one with <a href="http://quickutil.org/">Quickutil</a>.</p>

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-generate-toc again -->

<p><strong>Table of Contents</strong></p>

<ul>
<li><a href="#higher-order-functions">Higher order functions</a></li>
<li><a href="#sequences">Sequences</a></li>
<li><a href="#debugging-and-logging">Debugging and logging</a></li>
<li><a href="#profiling-with-sbcl">Profiling (with SBCL)</a></li>
</ul>

<!-- markdown-toc end -->

<h2 id="higher-order-functions">Higher order functions</h2>

<p>See also <a href="https://github.com/mikelevins/folio2">https://github.com/mikelevins/folio2</a> and <a href="/blog/functional-programming-in-common-lisp/">How to do functional programming in CL</a>.</p>

<pre><code class="language-lisp">(defun juxt (&amp;rest functions)
  &quot;Return a function that will juxtapose the results of `functions`.
  This is like Clojure's `juxt`.  Given functions `(f0 f1 ... fn)`, this will
  return a new function which, when called with some arguments, will return
  `(list (f0 ...args...) (f1 ...args...) ... (fn ...args...))`.
  Example:
    (funcall (juxt #'list #'+ #'- #'*) 1 2)
    =&gt; ((1 2) 3 -1 2)
  &quot;
  (lambda (&amp;rest args)
    (mapcar (alexandria:rcurry #'apply args) functions)))
</code></pre>

<pre><code class="language-lisp">(defun nullary (function &amp;optional result)
  &quot;Return a new function that acts as a nullary-patched version of `function`.
  The new function will return `result` when called with zero arguments, and
  delegate to `function` otherwise.
  Examples:
    (max 1 10 2) ; =&gt; 10
    (max)        ; =&gt; invalid number of arguments
    (funcall (nullary #'max))          ; =&gt; nil
    (funcall (nullary #'max 0))        ; =&gt; 0
    (funcall (nullary #'max 0) 1 10 2) ; =&gt; 10
    (reduce #'max nil)                  ; =&gt; invalid number of arguments
    (reduce (nullary #'max) nil)        ; =&gt; nil
    (reduce (nullary #'max :empty) nil) ; =&gt; :empty
    (reduce (nullary #'max) '(1 10 2))  ; =&gt; 10
  &quot;
  (lambda (&amp;rest args)
    (if (null args) result (apply function args))))
</code></pre>

<pre><code class="language-lisp">(defmacro gathering (&amp;body body)
  ;; https://github.com/sjl/cl-losh/blob/master/losh.lisp#L515
  &quot;Run `body` to gather some things and return a fresh list of them.
  `body` will be executed with the symbol `gather` bound to a function of one
  argument.  Once `body` has finished, a list of everything `gather` was called
  on will be returned.
  It's handy for pulling results out of code that executes procedurally and
  doesn't return anything, like `maphash` or Alexandria's `map-permutations`.
  The `gather` function can be passed to other functions, but should not be
  retained once the `gathering` form has returned (it would be useless to do so
  anyway).
  Examples:
    (gathering
      (dotimes (i 5)
        (gather i))
    =&gt;
    (0 1 2 3 4)
    (gathering
      (mapc #'gather '(1 2 3))
      (mapc #'gather '(a b)))
    =&gt;
    (1 2 3 a b)
  &quot;
  (with-gensyms (result)
    `(let ((,result (make-queue)))
      (flet ((gather (item)
               (enqueue item ,result)))
        (declare (dynamic-extent #'gather))
        ,@body)
      (queue-contents ,result))))
</code></pre>

<p>Here we need the <code>queue</code> struct.</p>

<pre><code class="language-lisp">(defstruct (queue (:constructor make-queue))
  (contents nil :type list)
  (last nil :type list)
  (size 0 :type fixnum))

;; real code is richer, with inline and inlinable function declarations.

(defun make-queue ()
  &quot;Allocate and return a fresh queue.&quot;
  (make-queue%))

(defun queue-empty-p (queue)
  &quot;Return whether `queue` is empty.&quot;
  (zerop (queue-size queue)))

(defun enqueue (item queue)
  &quot;Enqueue `item` in `queue`, returning the new size of the queue.&quot;
  (let ((cell (cons item nil)))
    (if (queue-empty-p queue)
      (setf (queue-contents queue) cell)
      (setf (cdr (queue-last queue)) cell))
    (setf (queue-last queue) cell))
  (incf (queue-size queue)))

(defun dequeue (queue)
  &quot;Dequeue an item from `queue` and return it.&quot;
  (when (zerop (decf (queue-size queue)))
    (setf (queue-last queue) nil))
  (pop (queue-contents queue)))

(defun queue-append (queue list)
  &quot;Enqueue each element of `list` in `queue` and return the queue's final size.&quot;
  (loop :for item :in list
        :for size = (enqueue item queue)
        :finally (return size)))
</code></pre>

<h2 id="sequences">Sequences</h2>

<pre><code class="language-lisp">(defun frequencies (sequence &amp;key (test 'eql))
  ;; https://github.com/sjl/cl-losh/blob/master/losh.lisp#L1910
  &quot;Return a hash table containing the frequencies of the items in `sequence`.
  Uses `test` for the `:test` of the hash table.
  Example:
    (frequencies '(foo foo bar))
    =&gt; {foo 2
        bar 1}
  &quot;
  (iterate
    (with result = (make-hash-table :test test))
    (for i :in-whatever sequence)
    (incf (gethash i result 0))
    (finally (return result))))
</code></pre>

<pre><code class="language-lisp">(defun proportions (sequence &amp;key (test 'eql) (float t))
  &quot;Return a hash table containing the proportions of the items in `sequence`.
  Uses `test` for the `:test` of the hash table.
  If `float` is `t` the hash table values will be coerced to floats, otherwise
  they will be left as rationals.
  Example:
    (proportions '(foo foo bar))
    =&gt; {foo 0.66666
        bar 0.33333}
    (proportions '(foo foo bar) :float nil)
    =&gt; {foo 2/3
        bar 1/3}
  &quot;
  (let* ((freqs (frequencies sequence :test test))
         (total (reduce #'+ (hash-table-values freqs)
                        :initial-value (if float 1.0 1))))
    (mutate-hash-values (lambda (v) (/ v total))
                        freqs)))
</code></pre>

<pre><code class="language-lisp">(defun group-by (function sequence &amp;key (test #'eql) (key #'identity))
  &quot;Return a hash table of the elements of `sequence` grouped by `function`.
  This function groups the elements of `sequence` into buckets.  The bucket for
  an element is determined by calling `function` on it.
  The result is a hash table (with test `test`) whose keys are the bucket
  identifiers and whose values are lists of the elements in each bucket.  The
  order of these lists is unspecified.
  If `key` is given it will be called on each element before passing it to
  `function` to produce the bucket identifier.  This does not effect what is
  stored in the lists.
  Examples:
    (defparameter *items* '((1 foo) (1 bar) (2 cats) (3 cats)))
    (group-by #'first *items*)
    ; =&gt; { 1 ((1 foo) (1 bar))
    ;      2 ((2 cats))
    ;      3 ((3 cats)) }
    (group-by #'second *items*)
    ; =&gt; { foo  ((1 foo))
    ;      bar  ((1 bar))
    ;      cats ((2 cats) (3 cats)) }
    (group-by #'evenp *items* :key #'first)
    ; =&gt; { t   ((2 cats))
    ;      nil ((1 foo) (1 bar) (3 cats)) }
  &quot;
  (iterate
    (with result = (make-hash-table :test test))
    (for i :in-whatever sequence)
    (push i (gethash (funcall function (funcall key i)) result))
    (finally (return result))))


(defun take-list (n list)
  (iterate (declare (iterate:declare-variables))
           (repeat n)
           (for item :in list)
           (collect item)))

(defun take-seq (n seq)
  (subseq seq 0 (min n (length seq))))
</code></pre>

<pre><code class="language-lisp">(defmacro do-repeat (n &amp;body body)
  &quot;Perform `body` `n` times.&quot;
  `(dotimes (,(gensym) ,n)
     ,@body))
</code></pre>

<pre><code class="language-lisp">(defmacro do-range (ranges &amp;body body)
  &quot;Perform `body` on the given `ranges`.

  Each range in `ranges` should be of the form `(variable from below)`.  During
  iteration `body` will be executed with `variable` bound to successive values
  in the range [`from`, `below`).

  If multiple ranges are given they will be iterated in a nested fashion.

  Example:

    (do-range ((x  0  3)
               (y 10 12))
      (pr x y))
    ; =&gt;
    ; 0 10
    ; 0 11
    ; 1 10
    ; 1 11
    ; 2 10
    ; 2 11

  &quot;
  (if (null ranges)
    `(progn ,@body)
    (destructuring-bind (var from below) (first ranges)
      `(loop :for ,var :from ,from :below ,below
             :do (do-range ,(rest ranges) ,@body)))))
</code></pre>

<pre><code class="language-lisp">(defun enumerate (sequence &amp;key (start 0) (step 1) key)
  &quot;Return an alist of `(n . element)` for each element of `sequence`.
  `start` and `step` control the values generated for `n`, NOT which elements of
  the sequence are enumerated.
  Examples:
    (enumerate '(a b c))
    ; =&gt; ((0 . A) (1 . B) (2 . C))
    (enumerate '(a b c) :start 1)
    ; =&gt; ((1 . A) (2 . B) (3 . C))
    (enumerate '(a b c) :key #'ensure-keyword)
    ; =&gt; ((0 . :A) (1 . :B) (2 . :C))
  &quot;
  (iterate (for el :in-whatever sequence)
           (for n :from start :by step)
           (collect (cons n (if key
                              (funcall key el)
                              el)))))
</code></pre>

<p>uses <code>iterate</code>, on Quicklisp (see also Shinmera&rsquo;s <a href="https://github.com/Shinmera/for">For</a>).</p>

<p>The following<code>take</code> is taken from <a href="https://github.com/TBRSS/serapeum/">Serapeum</a> (also available in CL21).</p>

<p>The original helpers (take-list, etc) are originally inlined for optimal performance
with a custom &ldquo;defun-inline&rdquo;.</p>

<pre><code class="language-lisp">(defun take (n seq)
  &quot;Return a fresh sequence of the first `n` elements of `seq`.
  The result will be of the same type as `seq`.
  If `seq` is shorter than `n` a shorter result will be returned.
  Example:
    (take 2 '(a b c))
    =&gt; (a b)
    (take 4 #(1))
    =&gt; #(1)
  From Serapeum.
  &quot;
  (check-type n array-index)
  (ctypecase seq
    (list (take-list n seq))
    (sequence (take-seq n seq))))

(defun take-list (n list)
  (iterate (declare (iterate:declare-variables))
           (repeat n)
           (for item :in list)
           (collect item)))

(defun take-seq (n seq)
  (subseq seq 0 (min n (length seq))))
</code></pre>

<pre><code class="language-lisp">(defun take-while-list (predicate list)
  (iterate (for item :in list)
           (while (funcall predicate item))
           (collect item)))

(defun take-while-seq (predicate seq)
  (subseq seq 0 (position-if-not predicate seq)))

(defun take-while (predicate seq)
  &quot;Take elements from `seq` as long as `predicate` remains true.
  The result will be a fresh sequence of the same type as `seq`.
  Example:
    (take-while #'evenp '(2 4 5 6 7 8))
    ; =&gt; (2 4)
    (take-while #'evenp #(1))
    ; =&gt; #()
  &quot;
  (ctypecase seq
    (list (take-while-list predicate seq))
    (sequence (take-while-seq predicate seq))))
</code></pre>

<pre><code class="language-lisp">(defun drop-list (n list)
  (copy-list (nthcdr n list)))

(defun drop-seq (n seq)
  (subseq seq (min n (length seq))))

(defun drop (n seq)
  &quot;Return a fresh copy of the `seq` without the first `n` elements.
  The result will be of the same type as `seq`.
  If `seq` is shorter than `n` an empty sequence will be returned.
  Example:
    (drop 2 '(a b c))
    =&gt; (c)
    (drop 4 #(1))
    =&gt; #()
  From Serapeum.
  &quot;
  (check-type n array-index)
  (ctypecase seq
    (list (drop-list n seq))
    (sequence (drop-seq n seq))))
</code></pre>

<pre><code class="language-lisp">(defun drop-while-list (predicate list)
  (iterate (for tail :on list)
           (while (funcall predicate (first tail)))
           (finally (return (copy-list tail)))))

(defun drop-while-seq (predicate seq)
  (let ((start (position-if-not predicate seq)))
    (if start
      (subseq seq start)
      (subseq seq 0 0))))

(defun drop-while (predicate seq)
  &quot;Drop elements from `seq` as long as `predicate` remains true.
  The result will be a fresh sequence of the same type as `seq`.
  Example:
    (drop-while #'evenp '(2 4 5 6 7 8))
    ; =&gt; (5 6 7 8)
    (drop-while #'evenp #(2))
    ; =&gt; #(2)
  &quot;
  (ctypecase seq
    (list (drop-while-list predicate seq))
    (sequence (drop-while-seq predicate seq))))
</code></pre>

<pre><code class="language-lisp">(defun extrema (predicate sequence)
  &quot;Return the smallest and largest elements of `sequence` according to `predicate`.
  `predicate` should be a strict ordering predicate (e.g. `&lt;`).
  Returns the smallest and largest elements in the sequence as two values,
  respectively.
  &quot;
  (iterate (with min = (elt sequence 0))
           (with max = (elt sequence 0))
           (for el :in-whatever sequence)
           (when (funcall predicate el min) (setf min el))
           (when (funcall predicate max el) (setf max el))
           (finally (return (values min max)))))
</code></pre>

<pre><code class="language-lisp">(defun summation (sequence &amp;key key)
  &quot;Return the sum of all elements of `sequence`.
  If `key` is given, it will be called on each element to compute the addend.
  This function's ugly name was chosen so it wouldn't clash with iterate's `sum`
  symbol.  Sorry.
  Examples:
    (sum #(1 2 3))
    ; =&gt; 6
    (sum '(\&quot;1\&quot; \&quot;2\&quot; \&quot;3\&quot;) :key #'parse-integer)
    ; =&gt; 6
    (sum '(\&quot;1\&quot; \&quot;2\&quot; \&quot;3\&quot;) :key #'length)
    ; =&gt; 3
  &quot;
  (if key
    (iterate (for n :in-whatever sequence)
             (sum (funcall key n)))
    (iterate (for n :in-whatever sequence)
             (sum n))))
</code></pre>

<pre><code class="language-lisp">(defun product (sequence &amp;key key)
  ;; https://github.com/sjl/cl-losh/blob/master/losh.lisp#L2181
  &quot;Return the product of all elements of `sequence`.
  If `key` is given, it will be called on each element to compute the
  multiplicand.
  Examples:
    (product #(1 2 3))
    ; =&gt; 6
    (product '(\&quot;1\&quot; \&quot;2\&quot; \&quot;3\&quot;) :key #'parse-integer)
    ; =&gt; 6
    (product '(\&quot;1\&quot; \&quot;2\&quot; \&quot;3\&quot;) :key #'length)
    ; =&gt; 1
  &quot;
  (if key
    (iterate (for n :in-whatever sequence)
             (multiplying (funcall key n)))
    (iterate (for n :in-whatever sequence)
             (multiplying n))))
</code></pre>

<h2 id="debugging-and-logging">Debugging and logging</h2>

<pre><code class="language-lisp">(defun pr (&amp;rest args)
  &quot;Print `args` readably, separated by spaces and followed by a newline.
  Returns the first argument, so you can just wrap it around a form without
  interfering with the rest of the program.
  This is what `print` should have been.
  &quot;
  (format t &quot;~{~S~^ ~}~%&quot; args)
  (finish-output)
  (first args))
</code></pre>

<pre><code class="language-lisp">(defmacro prl (&amp;rest args)
  &quot;Print `args` labeled and readably.
  Each argument form will be printed, then evaluated and the result printed.
  One final newline will be printed after everything.
  Returns the last result.
  Examples:
    (let ((i 1)
          (l (list 1 2 3)))
      (prl i (second l)))
    ; =&gt;
    i 1
    (second l) 2
  &quot;
  `(prog1
    (progn ,@(mapcar (lambda (arg) `(pr ',arg ,arg)) args))
    (terpri)
    (finish-output)))
</code></pre>

<pre><code class="language-lisp">(defmacro shut-up (&amp;body body)
  &quot;Run `body` with stdout and stderr redirected to the void.&quot;
  `(let ((*standard-output* (make-broadcast-stream))
         (*error-output* (make-broadcast-stream)))
    ,@body))
</code></pre>

<pre><code class="language-lisp">(defmacro comment (&amp;body body)
  &quot;Do nothing with a bunch of forms.
  Handy for block-commenting multiple expressions.
  &quot;
  (declare (ignore body))
  nil)
</code></pre>

<p>Pretty-print a table.</p>

<p>Didn&rsquo;t test.</p>

<p>See also <a href="https://github.com/vindarel/cl-ansi-term">https://github.com/vindarel/cl-ansi-term</a></p>

<!-- TODO: test -->

<pre><code class="language-lisp">(defun print-table (rows)
  ;; https://github.com/sjl/cl-losh/blob/master/losh.lisp#L2334
  &quot;Print `rows` as a nicely-formatted table.
  Each row should have the same number of colums.
  Columns will be justified properly to fit the longest item in each one.
  Example:
    (print-table '((1 :red something)
                   (2 :green more)))
    =&gt;
    1 | RED   | SOMETHING
    2 | GREEN | MORE
  &quot;
  (when rows
    (iterate
      (with column-sizes =
            (reduce (alexandria:curry #'mapcar #'max)
                    (mapcar (alexandria:curry #'mapcar (compose #'length #'aesthetic-string))
                            rows))) ; lol
      (for row :in rows)
      (format t &quot;~{~vA~^ | ~}~%&quot; (weave column-sizes row))))
  (values))


;; from Quickutil.
(defun ensure-function (function-designator)
    &quot;Returns the function designated by `function-designator`:
if `function-designator` is a function, it is returned, otherwise
it must be a function name and its `fdefinition` is returned.&quot;
    (if (functionp function-designator)
        function-designator
        (fdefinition function-designator)))

;; from Quickutil.
(defun compose (function &amp;rest more-functions)
    &quot;Returns a function composed of `function` and `more-functions` that applies its ;
arguments to to each in turn, starting from the rightmost of `more-functions`,
and then calling the next one with the primary value of the last.&quot;
    (declare (optimize (speed 3) (safety 1) (debug 1)))
    (reduce (lambda (f g)
              (let ((f (ensure-function f))
                    (g (ensure-function g)))
                (lambda (&amp;rest arguments)
                  (declare (dynamic-extent arguments))
                  (funcall f (apply g arguments)))))
            more-functions
            :initial-value function))

(defun make-gensym-list (length &amp;optional (x &quot;G&quot;))
    &quot;Returns a list of `length` gensyms, each generated as if with a call to `make-gensym`,
using the second (optional, defaulting to `\&quot;G\&quot;`) argument.&quot;
    (let ((g (if (typep x '(integer 0)) x (string x))))
      (loop repeat length
            collect (gensym g))))

  (define-compiler-macro compose (function &amp;rest more-functions)
    (labels ((compose-1 (funs)
               (if (cdr funs)
                   `(funcall ,(car funs) ,(compose-1 (cdr funs)))
                   `(apply ,(car funs) arguments))))
      (let* ((args (cons function more-functions))
             (funs (make-gensym-list (length args) &quot;COMPOSE&quot;)))
        `(let ,(loop for f in funs for arg in args
                     collect `(,f (ensure-function ,arg)))
           (declare (optimize (speed 3) (safety 1) (debug 1)))
           (lambda (&amp;rest arguments)
             (declare (dynamic-extent arguments))
             ,(compose-1 funs))))))


;; from Quickutil.
(defun weave (&amp;rest lists)
    &quot;Return a list whose elements alternate between each of the lists
`lists`. Weaving stops when any of the lists has been exhausted.&quot;
    (apply #'mapcan #'list lists))

(defun aesthetic-string (thing)
  &quot;Return the string used to represent `thing` when printing aesthetically.&quot;
  (format nil &quot;~A&quot; thing))

</code></pre>

<p>Pretty print a hash-table:</p>

<pre><code class="language-lisp">(defun print-hash-table (hash-table &amp;optional (stream t))
  &quot;Print a pretty representation of `hash-table` to `stream.`
  Respects `*print-length*` when printing the elements.
  &quot;
  (let* ((keys (alexandria:hash-table-keys hash-table))
         (vals (alexandria:hash-table-values hash-table))
         (count (hash-table-count hash-table))
         (key-width (-&lt;&gt; keys
                      (mapcar (alexandria:compose #'length #'prin1-to-string) &lt;&gt;)
                      (reduce #'max &lt;&gt; :initial-value 0)
                      (clamp 0 20 &lt;&gt;))))
    (print-unreadable-object (hash-table stream :type t)
      (princ
        ;; Something shits the bed and output gets jumbled (in SBCL at least) if
        ;; we try to print to `stream` directly in the format statement inside
        ;; `print-unreadable-object`, so instead we can just render to a string
        ;; and `princ` that.
        (format nil &quot;:test ~A :count ~D {~%~{~{  ~vs ~s~}~%~}}&quot;
                (hash-table-test hash-table)
                count
                (loop
                  :with limit = (or *print-length* 40)
                  :for key :in keys
                  :for val :in vals
                  :for i :from 0 :to limit
                  :collect
                  (if (= i limit)
                    (list key-width :too-many-items (list (- count i) :more))
                    (list key-width key val))))
        stream)))
  (terpri stream)
  (values))

(defun pht (hash-table &amp;optional (stream t))
  &quot;Synonym for `print-hash-table` for less typing at the REPL.&quot;
  (print-hash-table hash-table stream))

(defun print-hash-table-concisely (hash-table &amp;optional (stream t))
  &quot;Print a concise representation of `hash-table` to `stream.`
  Should respect `*print-length*` when printing the elements.
  &quot;
  (print-unreadable-object (hash-table stream :type t)
    (prin1 (hash-table-test hash-table))
    (write-char #\space stream)
    (prin1 (hash-table-contents hash-table) stream)))

;; needed:
(defun clamp (from to value)
  &quot;Clamp `value` between `from` and `to`.&quot;
  (let ((max (max from to))
        (min (min from to)))
    (cond
      ((&gt; value max) max)
      ((&lt; value min) min)
      (t value))))

;; see
(defmacro -&lt;&gt; (expr &amp;rest forms)
  &quot;Thread the given forms, with `&lt;&gt;` as a placeholder.&quot;
  ;; I am going to lose my fucking mind if I have to program lisp without
  ;; a threading macro, but I don't want to add another dep to this library, so
  ;; here we are.
  `(let* ((&lt;&gt; ,expr)
          ,@(mapcar (lambda (form)
                      (if (symbolp form)
                        `(&lt;&gt; (,form &lt;&gt;))
                        `(&lt;&gt; ,form)))
                    forms))
     &lt;&gt;))

</code></pre>

<p>For the <code>-&lt;&gt;</code> threading macro, see <a href="https://github.com/nightfly19/cl-arrows">cl-arrows</a> and <a href="https://github.com/hipeta/arrow-macros">arrow-macros</a>.</p>

<h2 id="profiling-with-sbcl">Profiling (with SBCL)</h2>

<pre><code class="language-lisp">#+sbcl
(defun dump-profile (filename)
  (with-open-file (*standard-output* filename
                                     :direction :output
                                     :if-exists :supersede)
    (sb-sprof:report :type :graph
                     :sort-by :cumulative-samples
                     :sort-order :ascending)
    (sb-sprof:report :type :flat
                     :min-percent 0.5)))

#+sbcl
(defun start-profiling (&amp;key call-count-packages (mode :cpu))
  &quot;Start profiling performance.  SBCL only.
  `call-count-packages` should be a list of package designators.  Functions in
  these packages will have their call counts recorded via
  `sb-sprof::profile-call-counts`.
  &quot;
  (sb-sprof::reset)
  (-&lt;&gt; call-count-packages
    (mapcar #'mkstr &lt;&gt;)
    (mapcar #'string-upcase &lt;&gt;)
    (mapc #'sb-sprof::profile-call-counts &lt;&gt;))
  (sb-sprof::start-profiling :max-samples 50000
                             :mode mode
                             ; :mode :time
                             :sample-interval 0.01
                             :threads :all))

#+sbcl
(defun stop-profiling (&amp;optional (filename &quot;lisp.prof&quot;))
  &quot;Stop profiling performance and dump a report to `filename`.  SBCL only.&quot;
  (sb-sprof::stop-profiling)
  (dump-profile filename))

#+sbcl
(defmacro profile (&amp;body body)
  &quot;Profile `body` and dump the report to `lisp.prof`.&quot;
  `(progn
     (start-profiling)
     (unwind-protect
         (time (progn ,@body))
       (stop-profiling))))
</code></pre>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">(bookmark) Get a list of all the dependencies of a lisp system</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">23 01 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I&rsquo;ll save here
<a href="https://www.reddit.com/r/Common_Lisp/comments/82wiyt/how_to_collect_all_asdf_dependencies_for/">a reddit discussion</a>,
which I find interesting but that will be burried quickly down
reddit&rsquo;s history. The goal is to <strong>get all the dependencies of a
system</strong>.</p>

<p>You&rsquo;d better read the OP&rsquo;s question and the discussion (where the OP
is the experimented <a href="https://github.com/40ants/">svetlyak40wt/40ants</a>,
at the moment doing a god&rsquo;s work on Weblocks).</p>

<p>His solution is <a href="https://gist.github.com/svetlyak40wt/03bc68c820bb3e45bc7871870379c42e">https://gist.github.com/svetlyak40wt/03bc68c820bb3e45bc7871870379c42e</a></p>

<pre><code class="language-lisp">(ql:quickload :fset)

(defun get-dependencies (system)
  &quot;Returns a set with all dependencies of a given system.
   System should be loaded first.&quot;
  (labels ((normalize (name)
             (etypecase name
               (string (string-downcase name))
               (symbol (normalize (symbol-name name)))
               (list
                (let ((dep-type (first name))
                      (supported-dep-types (list :version :feature :require)))
                  (unless (member dep-type
                                  supported-dep-types)
                    (error &quot;This component \&quot;~A\&quot; should have first element from this list: ~A.&quot;
                           name
                           supported-dep-types))

                  (normalize
                   (case dep-type
                     (:version (second name))
                     (:feature (third name))
                     (:require (second name)))))))))

    (let ((processed (fset:set))
          (queue (fset:set (normalize system))))

      (do ((current-name (fset:arb queue)
                         (fset:arb queue)))
          ((null current-name)
           ;; return result
           processed)

        ;; Remove current name from the queue
        (setf queue
              (fset:less queue current-name))
        ;; And put it into the &quot;processed&quot; pool
        (setf processed
              (fset:with processed current-name))

        ;; And add it's dependencies which aren't processed or in the queue already
        ;; Sometimes system can't be found because itself depends on some feature,
        ;; for example, you can specify dependency as a list:
        ;; (:FEATURE :SBCL (:REQUIRE :SB-INTROSPECT))
        ;; and it will be loaded only on SBCL.
        ;; When we are collecting dependencies on another implementation,
        ;; we don't want to fail with an error because ASDF is unable to find
        ;; such dependencies
        (let* ((system (ignore-errors
                        (asdf:find-system current-name)))
               (deps (when system
                       (asdf:component-sideway-dependencies system))))
          (dolist (dep deps)
            (let ((normalized-dep (normalize dep)))
              (unless (or (fset:lookup processed normalized-dep)
                          (fset:lookup queue normalized-dep))
                (setf queue
                      (fset:with queue normalized-dep)))))))

      (values processed))))

#|
DEPENDENCIES&gt; (ql:quickload :clinch)
DEPENDENCIES&gt; (get-dependencies :clinch)
#{
  &quot;cffi&quot;
  &quot;sdl2&quot;
  &quot;uiop&quot;
  &quot;babel&quot;
  &quot;swank&quot;
  &quot;clinch&quot;
  &quot;cl-glut&quot;
  &quot;cl-json&quot;
  &quot;cl-ppcre&quot;
  &quot;rtg-math&quot;
  &quot;cl-opengl&quot;
  &quot;cl-plus-c&quot;
  &quot;alexandria&quot;
  &quot;cl-autowrap&quot;
  &quot;glsl-symbols&quot;
  &quot;defpackage-plus&quot;
  &quot;trivial-garbage&quot;
  &quot;trivial-timeout&quot;
  &quot;bordeaux-threads&quot;
  &quot;trivial-channels&quot;
  &quot;trivial-features&quot; }
|#
</code></pre>

<p>There&rsquo;s also <code>(ql-dist:dependency-tree &quot;mgl&quot;)</code> which has limitations
though, it&rsquo;s only for Quicklisp projects and doesn&rsquo;t work with
everything (see the thread).</p>

<p>That&rsquo;s all folks !</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/74-agile-conspiracy.png" alt="Agile Conspiracy">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Agile Conspiracy</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">23 01 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/74-agile-conspiracy.png" alt="Agile Conspiracy" title="Agile Conspiracy" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Print licences used by a given project and its dependencies</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">22 01 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><a href="https://github.com/vindarel/print-licenses/">print-licenses</a> is a little utility found in
<a href="https://github.com/sjl/cl-losh/blob/master/losh.lisp">Steve Losh&rsquo;s gigantic utilities</a>
and ported to a stand alone project.</p>

<p>Example usage:</p>

<pre><code class="language-lisp">  (print-licenses 'fast-io)
  =&gt;
  alexandria           | Public Domain / 0-clause MIT
  babel                | MIT
  cffi                 | MIT
  cffi-grovel          | MIT
  cffi-toolchain       | MIT
  fast-io              | NewBSD
  static-vectors       | MIT
  trivial-features     | MIT
  trivial-gray-streams | MIT
  uiop                 | Unspecified
</code></pre>

<p>It may be available on february, 2018 Quicklisp update (<a href="https://github.com/quicklisp/quicklisp-projects/issues/1432">request</a>).</p>

<p>One potential source of caution (<a href="https://www.reddit.com/r/Common_Lisp/comments/7qca2v/print_licenses_used_by_the_given_project_and_its/">feedback on reddit</a>):</p>

<blockquote>
<p>what many authors put as the license in their asd file is not the license file that is actually included in the source code.</p>
</blockquote>

<hr />

<p>Let&rsquo;s read the source, there are many useful bits. The core of the job is:</p>

<pre><code class="language-lisp">(defun print-licenses (quicklisp-project-designator)
  (print-table (sort (license-list quicklisp-project-designator)
                     #'string&lt;
                     :key #'car)))

(defun license-list (quicklisp-project-designator)
  (remove-duplicates
    (mapcar (alexandria:rcurry #'coerce 'list)
            (alexandria:flatten (license-tree quicklisp-project-designator)))
    :key #'car :test #'string=))

(defun license-tree (quicklisp-project-designator)
  (let ((sys (ql-dist:dependency-tree quicklisp-project-designator)))
    (assert (not (null sys)) ()
      &quot;Cannot find Quicklisp project for designator ~S&quot;
      quicklisp-project-designator)
    (shut-up
      (ql:quickload quicklisp-project-designator))
    (map-tree
      (lambda (s)
        (vector (slot-value s 'ql-dist:name)
                (or (asdf:system-license
                      (asdf:find-system
                        (ql-dist:system-file-name s)))
                    &quot;Unspecified&quot;)))
      sys)))

</code></pre>

<p>and those are the remaining building blocks, with a useful
<code>print-table</code> function, and three of them taken from
<a href="http://quickutil.org/">Quickutil</a>. See their website and how sjl does
to include them (and only them, to keep lightweight dependencies) in a
project without copy-pasting.</p>

<pre><code class="language-lisp">(defmacro shut-up (&amp;body body)
  &quot;Run `body` with stdout and stderr redirected to the void.&quot;
  `(let ((*standard-output* (make-broadcast-stream))
         (*error-output* (make-broadcast-stream)))
     ,@body))

;; from Quickutil.
(defun map-tree (function tree)
    &quot;Map `function` to each of the leave of `tree`.&quot;
    (check-type tree cons)
    (labels ((rec (tree)
               (cond
                 ((null tree) nil)
                 ((atom tree) (funcall function tree))
                 ((consp tree)
                  (cons (rec (car tree))
                        (rec (cdr tree)))))))
      (rec tree)))

;; from Quickutil
(defun aesthetic-string (thing)
  &quot;Return the string used to represent `thing` when printing aesthetically.&quot;
  (format nil &quot;~A&quot; thing))

;; from Quickutil
(defun weave (&amp;rest lists)
  &quot;Return a list whose elements alternate between each of the lists
`lists`. Weaving stops when any of the lists has been exhausted.&quot;
  (apply #'mapcan #'list lists))

(defun print-table (rows)
  &quot;Print `rows` as a nicely-formatted table.
  Each row should have the same number of colums.
  Columns will be justified properly to fit the longest item in each one.
  Example:
    (print-table '((1 :red something)
                   (2 :green more)))
    =&gt;
    1 | RED   | SOMETHING
    2 | GREEN | MORE
  &quot;
  (when rows
    (iterate
      (with column-sizes =
            (reduce (curry #'mapcar #'max)
                    (mapcar (curry #'mapcar (compose #'length #'aesthetic-string))
                            rows))) ; lol
      (for row :in rows)
      (format t &quot;~{~vA~^ | ~}~%&quot; (weave column-sizes row))))
  (values))
</code></pre>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2018/73-release-day.png" alt="Release day">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Release day</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">16 01 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2018/73-release-day.png" alt="Release day" title="Release day" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Generic, consistent and dotted access of data structures with Access</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">12 01 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>A common frustration for (impatient) beginners is to see <em>different
function names</em> to access common data structures (alists, plists,
hash-tables) and their <em>inconsistencies</em> (the order of arguments).</p>

<p>Now they are well documented in the… Common Lisp Coobook of course:
<a href="https://lispcookbook.github.io/cl-cookbook/data-structures.html">https://lispcookbook.github.io/cl-cookbook/data-structures.html</a>, but
still;</p>

<p>and it is annoying to try things out with a data structure and
<em>refactor</em> the code to use another one.</p>

<p>The library <em><a href="https://github.com/AccelerationNet/access/">Access</a></em>
solves those problems, it&rsquo;s always</p>

<pre><code>(access my-var elt)
</code></pre>

<p>(if you&rsquo;re into this, note that <a href="https://lispcookbook.github.io/cl-cookbook/cl21.html#generic-functions">CL21 also does this with a generic and extensible <code>getf</code></a>).</p>

<p>edit: also <a href="https://github.com/vseloved/rutils">rutils</a> with <code>generic-elt</code> or <code>?</code> in the <code>rutilsx</code> contrib package.</p>

<p>Access also solves another usecase.</p>

<p>Sometimes we deal with <em>nested data structures</em> (alist inside alist
inside alist, or mixed data structures, happens when working with an
API) and, as in other languages, we&rsquo;d like a shortcut to access a
nested element. In Python, we can use <code>addict</code> to write
<code>foo.one.2.three</code> instead of <code>foo['one'][2]['three']</code>, with Access we
have two possibilities, see below.</p>

<p>Oh, and we can be confident <em>it is a battle-tested library</em>, since it
is the one that powers <a href="https://github.com/mmontone/djula/">Djula</a>&rsquo;s
template variables interplolation (doc is
<a href="http://mmontone.github.io/djula/doc/build/html/variables.html">here</a>), where we can write</p>

<pre><code>{{ var.foo }}
</code></pre>

<p>à la Django for the supported data structures, and Djula is in the top 100 of the most downloaded Quicklisp libraries (<a href="http://blog.quicklisp.org/2018/01/download-stats-for-december-2017.html">december 2017 stats</a>).</p>

<p>Let&rsquo;s install it:</p>

<pre><code class="language-lisp">(ql:quickload &quot;access&quot;)
</code></pre>

<p>import its symbols in Slime:</p>

<pre><code class="language-lisp">(use-package :access)
</code></pre>

<h2 id="generic-and-consistent-access-accross-alists-plists-hash-tables-clos-slots">Generic and consistent access accross alists, plists, hash-tables, CLOS slots</h2>

<p>Let&rsquo;s create our test variables first:</p>

<pre><code class="language-lisp">(defparameter my-alist '((:foo . &quot;foo&quot;) (:bar . &quot;bar&quot;)))
MY-ALIST
</code></pre>

<pre><code class="language-lisp">(defparameter my-plist (list :foo &quot;foo&quot; :bar &quot;bar&quot;))
MY-PLIST
</code></pre>

<pre><code class="language-lisp">(defparameter my-hashtable (make-hash-table))
MY-HASHTABLE
(setf (gethash :foo my-hashtable) &quot;foo&quot;)
&quot;foo&quot;
</code></pre>

<pre><code class="language-lisp">(defclass obj-test ()
  ((foo :accessor foo :initarg :foo :initform :foo)
   (bar :accessor bar :initarg :bar :initform :bar)))
;; #&lt;STANDARD-CLASS OBJ-TEST&gt;
(defparameter my-obj (make-instance 'obj-test))
;; MY-OBJ
</code></pre>

<p>Now, let&rsquo;s access the <code>:foo</code> slot.</p>

<p>With <strong>alists</strong>:</p>

<pre><code class="language-lisp">(access my-alist :foo)
&quot;foo&quot;
T
</code></pre>

<p>instead of <code>(cdr (assoc :foo my-alist))</code> (with :foo <em>first</em> argument) or alexandria&rsquo;s <code>(assoc-value my-alist :foo)</code> (:foo <em>second</em> argument).</p>

<p><strong>plists</strong>:</p>

<pre><code class="language-lisp">(access my-plist :foo)
&quot;foo&quot;
T
</code></pre>

<p>instead of <code>(getf my-plist :foo)</code> (unlike alists, with :foo as <em>last</em> argument).</p>

<p><strong>hash-tables</strong>:</p>

<pre><code class="language-lisp">(access my-hashtable :foo)
&quot;foo&quot;
T
</code></pre>

<p>instead of <code>(gethash :foo my-hashtable)</code> (:foo <em>first</em> argument).</p>

<p><strong>objects</strong>:</p>

<pre><code class="language-lisp">(access my-obj :foo) ;; &lt;= accessor, not slot name
;; :FOO
;; T
</code></pre>

<p>instead of… it depends. Here we named the accessor <code>foo</code>, so we would have used simply <code>(foo my-obj)</code>.</p>

<p>Also note that <code>access</code> returns two values, the value and a boolean, t
if the slot exists, nil otherwise.</p>

<p>And <code>access</code> is <code>setf</code>able:</p>

<pre><code class="language-lisp">(setf (access my-alist :foo) &quot;oof&quot;)
</code></pre>

<h3 id="with-access">with-access</h3>

<p>Below, we can bind temporary variables inside <code>with-access</code>:</p>

<pre><code class="language-lisp">(with-access (foo bar (other-name plist))
             my-obj
           (format t &quot;Got: ~a~a~a~&amp;&quot; foo bar other-name)
           ;; we can change variables
           (setf other-name &quot;hello plist&quot;)
           (format t &quot;other-name: ~a~&amp;&quot; other-name)
           ;; it changed the object too
           (format t &quot;object slot: ~a~&amp;&quot; (plist my-obj)))
Got: FOOBAR(FOO foo BAR bar)
other-name: hello plist
object slot: hello plist
NIL
</code></pre>

<h2 id="nested-access">Nested access</h2>

<p>For this example we add a <code>plist</code> slot to our object, which copies our <code>my-plist</code> by default.</p>

<pre><code class="language-lisp">(defclass obj-test ()
  ((foo :accessor foo :initarg :foo :initform :foo)
   (bar :accessor bar :initarg :bar :initform :bar)
   (plist :accessor plist :initarg plist :initform (copy-list MY-PLIST))))
#&lt;STANDARD-CLASS OBJ-TEST&gt;
</code></pre>

<p>(as being a CLOS object, <code>my-obj</code> is automatically updated with the new slot).</p>

<p>We can access the nested plist element <code>:foo</code> inside the object in one go with <code>accesses</code> (plurial):</p>

<pre><code class="language-lisp">(accesses MY-OBJ 'plist :foo)
;; &quot;foo&quot;
</code></pre>

<p>instead of <code>(getf (plist my-obj) :foo)</code>.</p>

<h2 id="dotted-access">Dotted access</h2>

<p><code>with-dot</code> or <code>#D</code></p>

<p>We can rewrite the previous examples with a dot:</p>

<pre><code class="language-lisp">(with-dot ()
    my-alist.foo)
&quot;foo&quot;
</code></pre>

<p>or again</p>

<pre><code class="language-lisp">(with-dot ()
    my-obj.foo)
&quot;hello plist&quot;
</code></pre>

<p>but even shorter, with the <code>#D</code> reader macro that we enable with</p>

<pre><code>(enable-dot-syntax)
</code></pre>

<p>(also works in Slime/Sly, for what I am not sure if I enabled a special feature)</p>

<pre><code class="language-lisp">#Dmy-alist.foo
&quot;foo&quot;
</code></pre>

<p>and so, a <em>nested dotted access</em> through an object and a plist:</p>

<pre><code class="language-lisp">;; back to initial case
(setf my-obj (make-instance 'obj-test))
;; #&lt;OBJ-TEST {1005AA3B13}&gt;
#Dmy-obj.plist.foo
;; &quot;foo&quot;
</code></pre>

<p>It will return <code>nil</code> instead of an error if someone in the middle
doesn&rsquo;t have the requested field.</p>

<hr />

<p>Usage will tell how it is useful, and
I hope it will be to fellow newcomers.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Capturing ClojureScript Errors on the Server</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">12 01 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Logging errors is an important aspect of writing real-world applications. When something goes wrong at runtime it's very helpful to have a log detailing what went wrong in order to fix the problem. This is a straightforward process when we're working on the backend code. We can catch the exception and log it along with the stack trace. However, we need to get a bit more creative in order to handle client-side errors.</p><p>In this post we'll take a look at propagating errors from a <a href='http://reagent-project.github.io/'>Reagent</a> based app back to the server. A naive implementation might look something like the following. We'll write a function that accepts an event containing the error, then send the error message along with the stack trace to the server:</p><pre><code class="clojure">&#40;defn report-error! &#91;event&#93;
  &#40;let &#91;error &#40;.-error event&#41;
        message &#40;.-message error&#41;
        stacktrace &#40;.-stack error&#41;&#93;    
    &#40;ajax/POST &quot;/error&quot;
               {:headers
                {&quot;x-csrf-token&quot;
                 &#40;.-value &#40;js/document.getElementById &quot;&#95;&#95;anti-forgery-token&quot;&#41;&#41;}
                :params
                {:message     message
                 :stacktrace stacktrace}}&#41;&#41;&#41;
</code></pre><p>Next, we'll set the <code>report-error!</code> function as the global <code>error</code> event listener:</p><pre><code class="clojure">&#40;defn init! &#91;&#93;
  &#40;.addEventListener js/window &quot;error&quot; report-error!&#41;
  &#40;reagent/render &#91;home-page&#93; &#40;.getElementById js/document &quot;app&quot;&#41;&#41;&#41;
</code></pre><p>The <code>home-page</code> function will render a button that will throw an error when it's clicked:</p><pre><code class="clojure">&#40;defn home-page &#91;&#93;
  &#91;:div&gt;h2 &quot;Error Test&quot;
   &#91;:div&gt;button
    {:on-click #&#40;throw &#40;js/Error. &quot;I'm an error&quot;&#41;&#41;}
    &quot;throw an error&quot;&#93;&#93;&#41;
</code></pre><p>If we pop up the console in the browser we should see something like the following there:</p><pre><code>Uncaught Error: I'm an error
    at app.core.home&#95;page &#40;core.cljs:25&#41;
    at Object.ReactErrorUtils.invokeGuardedCallback &#40;react-dom.inc.js:9073&#41;
    at executeDispatch &#40;react-dom.inc.js:3031&#41;
    at Object.executeDispatchesInOrder &#40;react-dom.inc.js:3054&#41;
    at executeDispatchesAndRelease &#40;react-dom.inc.js:2456&#41;
    at executeDispatchesAndReleaseTopLevel &#40;react-dom.inc.js:2467&#41;
    at Array.forEach &#40;&lt;anonymous&gt;&#41;
    at forEachAccumulated &#40;react-dom.inc.js:15515&#41;
    at Object.processEventQueue &#40;react-dom.inc.js:2670&#41;
    at runEventQueueInBatch &#40;react-dom.inc.js:9097&#41;
</code></pre><p>This gives us the namespace and the line number in the ClojureScript source that caused the error. However, if we print the message that we received on the server it will look as follows:</p><pre><code> Error: I'm an error
    at app.core.home&#95;page &#40;http://localhost:3000/js/out/app/core.js:51:8&#41;
    at Object.ReactErrorUtils.invokeGuardedCallback &#40;http://localhost:3000/js/out/cljsjs/react-dom/development/react-dom.inc.js:9073:16&#41;
    at executeDispatch &#40;http://localhost:3000/js/out/cljsjs/react-dom/development/react-dom.inc.js:3031:21&#41;
    at Object.executeDispatchesInOrder &#40;http://localhost:3000/js/out/cljsjs/react-dom/development/react-dom.inc.js:3054:5&#41;
    at executeDispatchesAndRelease &#40;http://localhost:3000/js/out/cljsjs/react-dom/development/react-dom.inc.js:2456:22&#41;
    at executeDispatchesAndReleaseTopLevel &#40;http://localhost:3000/js/out/cljsjs/react-dom/development/react-dom.inc.js:2467:10&#41;
    at Array.forEach &#40;&lt;anonymous&gt;&#41;
    at forEachAccumulated &#40;http://localhost:3000/js/out/cljsjs/react-dom/development/react-dom.inc.js:15515:9&#41;
    at Object.processEventQueue &#40;http://localhost:3000/js/out/cljsjs/react-dom/development/react-dom.inc.js:2670:7&#41;
    at runEventQueueInBatch &#40;http://localhost:3000/js/out/cljsjs/react-dom/development/react-dom.inc.js:9097:18&#41;
</code></pre><p>The stack trace is there, but it's no longer source mapped. So we'll know what namespace caused the error, but not the line in question. In order to get a source mapped stack trace we'll have to use a library such as <a href='https://github.com/stacktracejs/stacktrace.js'>stacktrace.js</a>. Unfortunately, we won't be able to use the new <code>:npm-deps</code> option in the ClojureScript compiler. This works as expected when <code>:optimizations</code> are set to <code>:none</code>, but fails to provide us with the source mapped stack trace in the <code>:advanced</code> mode.</p><p>Instead, we'll use the <a href='https://www.webjars.org/'>WebJars</a> dependency along with the <a href='https://github.com/weavejester/ring-webjars'>ring-webjars</a> middleware:</p><pre><code class="clojure">:dependencies
&#91;...
 &#91;ring-webjars &quot;0.2.0&quot;&#93;
 &#91;org.webjars.bower/stacktrace-js &quot;2.0.0&quot;&#93;&#93;
</code></pre><p>The middleware uses the <code>/assets/&lt;webjar&gt;/&lt;asset path&gt;</code> pattern to load the resources packaged in WebJars dependencies. Here's how this would look for loading the stacktrace-js resource. </p><p>We'll require the middleware:  </p><pre><code class="clojure">&#40;ns app.handler
 &#40;:require
  ...
  &#91;ring.middleware.webjars :refer &#91;wrap-webjars&#93;&#93;&#41;&#41;
</code></pre><br /><p>Wrap the Ring handler with it:  </p><pre><code class="clojure"> &#40;defn -main &#91;&#93;
  &#40;run-jetty
   &#40;-&gt; handler
       &#40;wrap-webjars&#41;
       &#40;wrap-defaults site-defaults&#41;&#41;
   {:port 3000 :join? false}&#41;&#41;
</code></pre><p>The <code>stacktrace.min.js</code> file packaged in the <code>org.webjars.bower/stacktrace-js</code> dependency will be available as a resource at the following path <code>/assets/stacktrace-js/dist/stacktrace.min.js</code>:</p><pre><code class="clojure">&#40;defroutes handler
  &#40;GET &quot;/&quot; &#91;&#93;
    &#40;html5
      &#91;:head
       &#91;:meta {:charset &quot;utf-8&quot;}&#93;
       &#40;anti-forgery-field&#41;&#93;
      &#91;:body
       &#91;:div#app&#93;
        &#40;include-js &quot;/assets/stacktrace-js/dist/stacktrace.min.js&quot;
                    &quot;/js/app.js&quot;&#41;&#93;&#41;&#41;
  
  &#40;POST &quot;/error&quot; {:keys &#91;body&#93;}
    &#40;let &#91;{:keys &#91;message stacktrace&#93;}
          &#40;-&gt; body
              &#40;transit/reader :json&#41;
              &#40;transit/read&#41;&#41;&#93;
      &#40;println &quot;Client error:&quot; message &quot;\n&quot; stacktrace&#41;&#41;
    &quot;ok&quot;&#41;
  
  &#40;resources &quot;/&quot;&#41;
  &#40;not-found &quot;Not Found&quot;&#41;&#41;
</code></pre> <br /><p>Finally, the ClojureScript compiler configuration will look as follows:  </p> <pre><code class="clojure">{:output-dir &quot;target/cljsbuild/public/js&quot;
 :output-to  &quot;target/cljsbuild/public/js/app.js&quot;
 :source-map &quot;target/cljsbuild/public/js/app.js.map&quot;
 :optimizations :advanced
 :infer-externs true
 :closure-warnings {:externs-validation :off
                    :non-standard-jsdoc :off}}
</code></pre><p>We need to specify the name of the source map file when using the advanced optimization, tell the compiler to infer the externs, and optionally suppress the warnings.</p><p>The new version of the <code>report-error!</code> function will look similar to the original, except that we'll now be passing the error to the <code>StackTrace.fromError</code> function. This function returns a promise containing the source mapped stack trace that we'll be sending to the server:</p><pre><code class="clojure">&#40;defn report-error! &#91;event&#93;
  &#40;let &#91;error &#40;.-error event&#41;&#93;
    &#40;-&gt; &#40;js/StackTrace.fromError error&#41;
        &#40;.then
         &#40;fn &#91;stacktrace&#93;
           &#40;ajax/POST &quot;/error&quot;
                      {:headers
                       {&quot;x-csrf-token&quot;
                        &#40;.-value &#40;js/document.getElementById &quot;&#95;&#95;anti-forgery-token&quot;&#41;&#41;}
                       :params
                       {:message    &#40;.-message error&#41;
                        :stacktrace &#40;-&gt;&gt; stacktrace
                                          &#40;mapv #&#40;.toString %&#41;&#41;
                                          &#40;string/join &quot;\n &quot;&#41;&#41;}}&#41;&#41;&#41;&#41;&#41;&#41;
</code></pre> <p>This time around we should see the source mapped error on the server with all the information that we need:</p><pre><code>I'm an error
 Error&#40;&#41;@http://localhost:3000/js/app/core.cljs:27:23
 mountComponent&#40;&#41;@http://localhost:3000/js/app.js:40:5631
 focusDOMComponent&#40;&#41;@http://localhost:3000/js/app.js:38:22373
 focusDOMComponent&#40;&#41;@http://localhost:3000/js/app.js:38:22588
 focusDOMComponent&#40;&#41;@http://localhost:3000/js/app.js:38:18970
 focusDOMComponent&#40;&#41;@http://localhost:3000/js/app.js:38:19096
 didPutListener&#40;&#41;@http://localhost:3000/js/app.js:41:12120
 focusDOMComponent&#40;&#41;@http://localhost:3000/js/app.js:38:20154
 mountComponent&#40;&#41;@http://localhost:3000/js/app.js:40:5880
</code></pre><p>We can see that the error occurred on line 27 of the <code>app.core</code> namespace which is indeed where the code that throws the exception resides. The full listing for the example is available on <a href='https://github.com/yogthos/clojurescript-error-reporting-example'>GitHub</a>.</p><p>While the example in this post illustrates bare bones exception handling, we can do more interesting things in a real world application. For example, <a href='https://github.com/Day8/re-frame'>re-frame</a> based application could send the entire state of the re-frame database at the time of the error to the server. This allows us to put the application in the exact state that caused the error when debugging the problem.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">React, Redux and JavaScript Architecture</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">08 01 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Whether you use them or not, React and Redux are important. They have changed the way we think about structuring front-end web applications. They can be very powerful. But they are not magic. JavaScript code does not automatically become better just because it uses React. It is easy to write horrible React code, just like it's easy to write horrible vanilla JavaScript. So, why is React important then? The thing is, understanding <em>how</em> to write React and Redux code is one thing. Understanding <em>why</em> you'd want to use React and Redux is another matter entirely. Once you understand the <em>why</em> of React, then modern JavaScript starts to make more sense. This is true whatever framework you're using. Whether it's React, Vue, Ember, Angular, Web Components, or something else entirely. React and Redux have had a huge impact on how we organise front-end code.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">React, Redux and JavaScript Architecture</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">08 01 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Whether you use them or not, React and Redux are important. They have changed the way we think about structuring front-end web applications. They can be very powerful. But they are not magic. JavaScript code does not automatically become better just because it uses React. It is easy to write horrible React code, just like it's easy to write horrible vanilla JavaScript. So, why is React important then? The thing is, understanding <em>how</em> to write React and Redux code is one thing. Understanding <em>why</em> you'd want to use React and Redux is another matter entirely. Once you understand the <em>why</em> of React, then modern JavaScript starts to make more sense. This is true whatever framework you're using. Whether it's React, Vue, Ember, Angular, Web Components, or something else entirely. React and Redux have had a huge impact on how we organise front-end code.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="Making sense of the trackers on Reddit">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Making sense of the trackers on Reddit</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">07 01 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Using whotracks.me data and sankey diagrams to dissect trackers
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="WhoTracks.me January Update">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">WhoTracks.me January Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">07 01 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        New data and trackers in our monthly update.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Git Deps for Clojure</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">05 01 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div class="paragraph">
<p>Clojure was designed to empower developers by enabling them to leverage existing libraries. When Clojure was first released, this manifest itself in strong interop support for Java. Eventually tooling (Leiningen et al) arose around procuring Java libs from the Maven ecosystem, and Clojure, its contribs, and the community also adopted the Maven approach to <em>delivering</em> libraries via artifacts hosted in well known repositories like Maven Central and Clojars.</p>
</div>
<div class="paragraph">
<p>There were many benefits to this, but, like most things in programming, there were attendant costs. Artifact based releases predate the widespread adoption of content-based addressing systems like Git. Without content-based addressing, they depend on conventions of release naming and weak notions like semantic versioning. They also reflect the nature of languages like Java and C that require a build step prior to execution. Most Clojure libraries do not.</p>
</div>
<div class="paragraph">
<p>The modern reality of Clojure development is that (mostly) we use Git, we use centralized Git repos like Github, Bitbucket et al, and code is executable. Producing and consuming artifacts creates a lot of unnecessary friction between creating code and using it. Let&#8217;s get rid of it when not needed!</p>
</div>
<div class="paragraph">
<p>Today we&#8217;re happy to announce the availability of git deps support in Clojure tools. It leverages the fact that tools.deps does not use the Maven dependency resolver but instead resolves dependencies on its own. This decouples dependency resolution and classpath creation from any single library publishing/procurement mechanism. Git repos become a source of libraries directly.</p>
</div>
<div class="paragraph">
<p>You can now specify git coordinates (in addition to mvn and local) in deps.edn:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">{:deps
 {org.clojure/data.csv {:git/url "https://github.com/clojure/data.csv.git"
                        :sha "e5beccad0bafdb8e78f19cba481d4ecef5fabf36"}}}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The tools support (available as a library in tools.gitlibs) will:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>securely log into the git repository host and clone the repo (if needed)</p>
</li>
<li>
<p>checkout and cache (per library+sha) the specified working tree (if needed)</p>
</li>
<li>
<p>resolve transitive deps and incorporate the cached directory into the classpath</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Of course, not every commit is stable, so one can designate stable points using tags.</p>
</div>
<div class="paragraph">
<p>This greatly reduces the ceremony and tooling required to share and consume libraries, facilitates parallel development of sibling libraries, testing, speculative forks etc. and fosters a greater connection to source truth while preserving the secure centralized hosting, stable repeatability and caching one gets from e.g. Maven.</p>
</div>
<div class="paragraph">
<p>I am hopeful this git support will usher in a new level of agility for Clojure development. Many thanks to Alex Miller for his tireless efforts to convert these ideas into a working system.</p>
</div>
<div class="paragraph">
<p>For more information see:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="xref/../../../../../guides/getting_started">Getting Started</a> - to install or update the Clojure tools</p>
</li>
<li>
<p><a href="xref/../../../../../guides/deps_and_cli">Deps and CLI Guide</a> - on how to use the Clojure tools</p>
</li>
<li>
<p><a href="xref/../../../../../reference/deps_and_cli">Deps and CLI Reference</a> - complete reference info</p>
</li>
<li>
<p><a href="https://www.youtube.com/watch?v=oyLBGkS5ICk">Spec-ulation</a> keynote - on growth versus breakage</p>
</li>
</ul>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Structures: lightweight records, a step before classes</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">03 01 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>Structures offer a way to store data in named slots. They support
single inheritance.</p>

<p>Classes provided by the Common Lisp Object System (CLOS) are more flexible however structures may offer better performance (see for example the SBCL manual).</p>

<p>As usual, this is <em><a href="https://lispcookbook.github.io/cl-cookbook/data-structures.html#structures">best read in the Common Lisp Cookbook</a></em>.</p>

<h2 id="structures">Structures</h2>

<h3 id="creation">Creation</h3>

<p><code>defstruct</code></p>

<pre><code class="language-lisp">(defstruct person
   id name age)
</code></pre>

<p>At creation slots are optional and default to <code>nil</code>.</p>

<p>To set a default value:</p>

<pre><code class="language-lisp">(defstruct person
   id
   (name &quot;john doe&quot;)
   age)
</code></pre>

<p>Also specify the type after the default value:</p>

<pre><code class="language-lisp">(defstruct person
  id
  (name &quot;john doe&quot; :type string)
  age)
</code></pre>

<p>We create an instance with the generated constructor <code>make-</code> +
<code>&lt;structure-name&gt;</code>, so <code>make-person</code>:</p>

<pre><code class="language-lisp">(defparameter *me* (make-person))
*me*
#S(PERSON :ID NIL :NAME &quot;john doe&quot; :AGE NIL)
</code></pre>

<p>note that printed representations can be read back by the reader.</p>

<p>With a bad name type:</p>

<pre><code class="language-lisp">(defparameter *bad-name* (make-person :name 123))
</code></pre>

<pre><code>Invalid initialization argument:
  :NAME
in call for class #&lt;STRUCTURE-CLASS PERSON&gt;.
   [Condition of type SB-PCL::INITARG-ERROR]
</code></pre>

<p>We can set the structure&rsquo;s constructor so as to create the structure
without using keyword arguments, which can be more convenient
sometimes. We give it a name and the order of the arguments:</p>

<pre><code class="language-lisp">(defstruct (person (:constructor create-person (id name age)))
     id
     name
     age)
</code></pre>

<p>Our new constructor is <code>create-person</code>:</p>

<pre><code class="language-lisp">(create-person 1 &quot;me&quot; 7)
#S(PERSON :ID 1 :NAME &quot;me&quot; :AGE 7)
</code></pre>

<p>However, the default <code>make-person</code> does <em>not</em> work any more:</p>

<pre><code class="language-lisp">(make-person :name &quot;me&quot;)
;; debugger:
obsolete structure error for a structure of type PERSON
[Condition of type SB-PCL::OBSOLETE-STRUCTURE]
</code></pre>

<h3 id="slot-access">Slot access</h3>

<p>We access the slots with accessors created by <code>&lt;name-of-the-struct&gt;-</code> + <code>slot-name</code>:</p>

<pre><code class="language-lisp">(person-name *me*)
;; &quot;john doe&quot;
</code></pre>

<p>we then also have <code>person-age</code> and <code>person-id</code>.</p>

<h3 id="setting">Setting</h3>

<p>Slots are <code>setf</code>-able:</p>

<pre><code class="language-lisp">(setf (person-name *me*) &quot;Cookbook author&quot;)
(person-name *me*)
;; &quot;Cookbook author&quot;
</code></pre>

<h3 id="predicate">Predicate</h3>

<pre><code class="language-lisp">(person-p *me*)
T
</code></pre>

<h3 id="single-inheritance">Single inheritance</h3>

<p>With the <code>:include &lt;struct&gt;</code> argument:</p>

<pre><code class="language-lisp">(defstruct (female (:include person))
     (gender &quot;female&quot; :type string))
(make-female :name &quot;Lilie&quot;)
;; #S(FEMALE :ID NIL :NAME &quot;Lilie&quot; :AGE NIL :GENDER &quot;female&quot;)
</code></pre>

<h3 id="limitations">Limitations</h3>

<p>After a change, instances are not updated.</p>

<p>If we try to add a slot (<code>email</code> below), we have the choice to lose
all instances, or to continue using the new definition of
<code>person</code>. But the effects of redefining a structure are undefined by
the standard, so it is best to re-compile and re-run the changed
code.</p>

<pre><code class="language-lisp">(defstruct person
       id
       (name &quot;john doe&quot; :type string)
       age
       email)

attempt to redefine the STRUCTURE-OBJECT class PERSON
incompatibly with the current definition
   [Condition of type SIMPLE-ERROR]

Restarts:
 0: [CONTINUE] Use the new definition of PERSON, invalidating already-loaded code and instances.
 1: [RECKLESSLY-CONTINUE] Use the new definition of PERSON as if it were compatible, allowing old accessors to use new instances and allowing new accessors to use old instances.
 2: [CLOBBER-IT] (deprecated synonym for RECKLESSLY-CONTINUE)
 3: [RETRY] Retry SLIME REPL evaluation request.
 4: [*ABORT] Return to SLIME's top level.
 5: [ABORT] abort thread (#&lt;THREAD &quot;repl-thread&quot; RUNNING {1002A0FFA3}&gt;)
</code></pre>

<p>If we choose restart <code>0</code>, to use the new definition, we lose access to <code>*me*</code>:</p>

<pre><code class="language-lisp">*me*
obsolete structure error for a structure of type PERSON
   [Condition of type SB-PCL::OBSOLETE-STRUCTURE]
</code></pre>

<p>There is also very little introspection.
Portable Common Lisp does not define ways of finding out defined super/sub-structures nor what slots a structure has.</p>

<p>The Common Lisp Object System (which came after into the language)
doesn&rsquo;t have such limitations. See the <a href="https://lispcookbook.github.io/cl-cookbook/clos.html">CLOS section</a>.</p>

<ul>
<li><a href="http://www.lispworks.com/documentation/HyperSpec/Body/08_.htm">structures on the hyperspec</a></li>
<li>David B. Lamkins, <a href="http://www.communitypicks.com/r/lisp/s/17592186045679-successful-lisp-how-to-understand-and-use-common">&ldquo;Successful Lisp, How to Undertsand and Use Common Lisp&rdquo;</a>.</li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="simple-restarts.png" alt="Error and condition handling">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Error and condition handling</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">02 01 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>Common Lisp has mechanisms for error and condition handling as found
in other languages, and can do more.</p>

<p>What is a condition ?</p>

<blockquote>
<p>Just like in languages that support exception handling (Java, C++,
Python, etc.), a condition represents, for the most part, an
“exceptional” situation. However, even more so that those languages,
<em>a condition in Common Lisp can represent a general situation where
some branching in program logic needs to take place</em>, not
necessarily due to some error condition. Due to the highly
interactive nature of Lisp development (the Lisp image in
conjunction with the REPL), this makes perfect sense in a language
like Lisp rather than say, a language like Java or even Python,
which has a very primitive REPL. In most cases, however, we may not
need (or even allow) the interactivity that this system offers
us. Thankfully, the same system works just as well even in
non-interactive mode.</p>

<p><a href="https://z0ltan.wordpress.com/2016/08/06/conditions-and-restarts-in-common-lisp/">z0ltan</a></p>
</blockquote>

<p>Let&rsquo;s dive into it step by step. More resources are given afterwards.</p>

<p>Now <em><a href="https://lispcookbook.github.io/cl-cookbook/error_handling.html">best read in the Common Lisp Cookbook</a></em>.</p>

<p>Credit: our <a href="https://vindarel.github.io/cl-torrents/tutorial.html">cl-torrents tutorial</a>.</p>

<p>Note: you can contribute any fix or addition to the Cookbook or this page via git ;)</p>

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-generate-toc again -->

<p><strong>Table of Contents</strong></p>

<ul>
<li><a href="#ignore-all-errors-and-return-nil">Ignore all errors (and return nil)</a></li>
<li><a href="#catching-any-condition---handler-case">Catching any condition - handler-case</a></li>
<li><a href="#catching-a-specific-condition">Catching a specific condition</a>

<ul>
<li><a href="#ignoring-the-condition-argument">Ignoring the condition argument</a></li>
</ul></li>
<li><a href="#handler-case-vs-handler-bind">handler-case VS handler-bind</a></li>
<li><a href="#handling-conditions---handler-bind">Handling conditions - handler-bind</a></li>
<li><a href="#creating-conditions">Creating conditions</a></li>
<li><a href="#signaling-throwing-conditions">Signaling (throwing) conditions</a></li>
<li><a href="#restarts-interactive-choices-in-the-debugger">Restarts, interactive choices in the debugger</a>

<ul>
<li><a href="#defining-restarts">Defining restarts</a></li>
<li><a href="#calling-restarts-programmatically">Calling restarts programmatically</a></li>
<li><a href="#using-other-restarts">Using other restarts</a></li>
<li><a href="#prompting-the-user-to-enter-a-new-value">Prompting the user to enter a new value</a></li>
<li><a href="#hide-and-show-restarts">Hide and show restarts</a></li>
</ul></li>
<li><a href="#run-some-code-condition-or-not-finally">Run some code, condition or not (&ldquo;finally&rdquo;)</a></li>
<li><a href="#resources">Resources</a></li>
</ul>

<!-- markdown-toc end -->

<h2 id="ignore-all-errors-and-return-nil">Ignore all errors (and return nil)</h2>

<p>Sometimes you know that a function can fail and you just want to
ignore it: use <code>ignore-errors</code>:</p>

<pre><code class="language-lisp">(ignore-errors
  (/ 3 0))
; in: IGNORE-ERRORS (/ 3 0)
;     (/ 3 0)
;
; caught STYLE-WARNING:
;   Lisp error during constant folding:
;   arithmetic error DIVISION-BY-ZERO signalled
;   Operation was (/ 3 0).
;
; compilation unit finished
;   caught 1 STYLE-WARNING condition
NIL
#&lt;DIVISION-BY-ZERO {1008FF5F13}&gt;
</code></pre>

<p>We get a welcome <code>division-by-zero</code> warning but the code runs well and
it returns two things: <code>nil</code> and the condition that was signaled. We
could not choose what to return.</p>

<p>Rembember that we can <code>inspect</code> the condition with a right click in Slime.</p>

<h2 id="catching-any-condition-handler-case">Catching any condition - handler-case</h2>

<!-- we will say "handling" for handler-bind -->

<p><code>ignore-error</code> is built from <code>handler-case</code>. We can write the previous
example by catching the general <code>error</code> but now we can return whatever
we want:</p>

<pre><code class="language-lisp">(handler-case (/ 3 0)
  (error (c)
    (format t &quot;We caught a condition.~&amp;&quot;)
    (values 0 c)))
; in: HANDLER-CASE (/ 3 0)
;     (/ 3 0)
;
; caught STYLE-WARNING:
;   Lisp error during constant folding:
;   Condition DIVISION-BY-ZERO was signalled.
;
; compilation unit finished
;   caught 1 STYLE-WARNING condition
We caught a condition.
0
#&lt;DIVISION-BY-ZERO {1004846AE3}&gt;
</code></pre>

<p>We also returned two values, 0 and the signaled condition.</p>

<p>The general form of <code>handler-case</code> is</p>

<pre><code class="language-lisp">(handler-case (code that errors out)
   (condition-type (the-condition) ;; &lt;-- optional argument
      (code))
   (another-condition (the-condition)
       ...))
</code></pre>

<p>We can also catch all conditions by matching <code>t</code>, like in a <code>cond</code>:</p>

<pre><code class="language-lisp">(handler-case
    (progn
      (format t &quot;This won't work…~%&quot;)
      (/ 3 0))
  (t (c)
    (format t &quot;Got an exception: ~a~%&quot; c)
    (values 0 c)))
;; …
;; This won't work…
;; Got an exception: arithmetic error DIVISION-BY-ZERO signalled
;; Operation was (/ 3 0).
;; 0
;; #&lt;DIVISION-BY-ZERO {100608F0F3}&gt;
</code></pre>

<h2 id="catching-a-specific-condition">Catching a specific condition</h2>

<p>We can specify what condition to handle:</p>

<pre><code class="language-lisp">(handler-case (/ 3 0)
  (division-by-zero (c)
    (format t &quot;Caught division by zero: ~a~%&quot; c)))
;; …
;; Caught division by zero: arithmetic error DIVISION-BY-ZERO signalled
;; Operation was (/ 3 0).
;; NIL
</code></pre>

<p>This workflow is similar to a try/catch as found in other languages, but we can do more.</p>

<h3 id="ignoring-the-condition-argument">Ignoring the condition argument</h3>

<p>If you don&rsquo;t access the condition object in your handlers, but you still keep it has an argument for good practice, you&rsquo;ll see this compiler warning often:</p>

<pre><code>; caught STYLE-WARNING:
;   The variable C is defined but never used.
</code></pre>

<p>To remove it, use a <code>declare</code> call as in:</p>

<pre><code class="language-lisp">(handler-case (/ 3 0)
  (division-by-zero (c)
   (declare (ignore c))
   (format t &quot;Caught division by zero~%&quot;))) ;; we don't print &quot;c&quot; here and don't get the warning.
</code></pre>

<h2 id="handler-case-vs-handler-bind">handler-case VS handler-bind</h2>

<p><code>handler-case</code> is similar to the <code>try/catch</code> forms that we find in
other languages.</p>

<p><code>handler-bind</code> (see the next examples), is what to use
when we need absolute control over what happens when a signal is
raised. It allows us to use the debugger and restarts, either
interactively or programmatically.</p>

<p>If some library doesn&rsquo;t catch all conditions and lets some bubble out
to us, we can see the restarts (established by <code>restart-case</code>)
anywhere deep in the stack, including restarts established by other
libraries whose this library called.  And <em>we can see the stack
trace</em>, with every frame that was called and, in some lisps, even see
local variables and such. Once we <code>handler-case</code>, we &ldquo;forget&rdquo; about
this, everything is unwound. <code>handler-bind</code> does <em>not</em> rewind the
stack.</p>

<h2 id="handling-conditions-handler-bind">Handling conditions - handler-bind</h2>

<p>Here we use <code>handler-bind</code>.</p>

<p>Its general form is:</p>

<pre><code class="language-lisp">(handler-bind ((a-condition #'function-to-handle-it)
               (another-one #'another-function))
    (code that can...)
    (...error out))
</code></pre>

<p>So, our simple example:</p>

<pre><code class="language-lisp">(handler-bind
             ((division-by-zero #'(lambda (c) (format t &quot;hello condition~&amp;&quot;))))
           (/ 3 0))
</code></pre>

<p>This prints some warnings, then it prints our &ldquo;hello&rdquo; <em>and still
enters the debugger</em>. If we don&rsquo;t want to enter the debugger, we have
to define a restart and invoke it.</p>

<p>A real example with the
<a href="https://github.com/mrkkrp/unix-opts"><code>unix-opts</code></a> library, that
parses command line arguments. It defined some conditions:
<code>unknown-option</code>, <code>missing-arg</code> and <code>arg-parser-failed</code>, and it is up
to use to write what to do in these cases.</p>

<pre><code class="language-lisp">(handler-bind ((opts:unknown-option #'unknown-option)
               (opts:missing-arg #'missing-arg)
               (opts:arg-parser-failed #'arg-parser-failed))
  (opts:get-opts))
</code></pre>

<p>Our <code>unknown-option</code> function is simple and looks like this:</p>

<pre><code class="language-lisp">(defun unknown-option (condition)
  (format t &quot;~s option is unknown.~%&quot; (opts:option condition))
  (opts:describe)
  (exit)) ;; &lt;-- we return to the command line, no debugger.
</code></pre>

<p>it takes the condition as parameter, so we can read information from
it if needed. Here we get the name of the erronous option with the
defined reader <code>(opts:option condition)</code> (see below).</p>

<h2 id="creating-conditions">Creating conditions</h2>

<p>With <code>define-condition</code>, and we can inherit from <code>error</code> or <code>simple-error</code>:</p>

<!-- todo: differences ? -->

<!-- make-condition ? -->

<pre><code class="language-lisp">(define-condition my-division-by-zero (error) ())
</code></pre>

<p>It is a regular class, so we can add information into slots. Here, we
add a custom message:</p>

<pre><code class="language-lisp">(define-condition my-division-by-zero (error)
  ((dividend :initarg :dividend
            :reader dividend)) ;; &lt;= so we'll get the dividend with (dividend condition), as soon as on the next line.
  ;; the :report is the message into the debugger:
  (:report (lambda (condition stream) (format stream &quot;You were going to divide ~a by zero.~&amp;&quot; (dividend condition)))))
</code></pre>

<p>The general form looks like a regular class definition:</p>

<pre><code class="language-lisp">(define-condition my-condition (condition-it-inherits-from)
  ;; list of arguments, can be &quot;()&quot;.
  ((message :initarg :message
            :reader my-condition-message)
   (second ...))
  ;; class arguments
  (:report (lambda (condition stream) (...))) ;; what is printed in the REPL.
  (:documentation &quot;a string&quot;)) ;; good practice ;)
</code></pre>

<p>Now when we throw this condition we must pass it an error message (it
is a required argument), and read it with <code>error-message</code> (the
<code>:reader</code>).</p>

<p>What&rsquo;s in <code>:report</code> will be printed in the REPL.</p>

<p>Let&rsquo;s try our condition. We define a simple function that checks our
divisor, and signals our condition if it is equal to zero:</p>

<pre><code class="language-lisp">(defun my-division (x y)
    (if (= y 0)
        (error 'MY-DIVISION-BY-ZERO :dividend x))
    (/ x y))
</code></pre>

<p>When we use it, we enter the debugger:</p>

<pre><code class="language-lisp">(my-division 3 0)
;;
;; into the debugger:
;;
You were going to divide 3 by zero.
   [Condition of type MY-DIVISION-BY-ZERO]

Restarts:
 0: [RETRY] Retry SLIME REPL evaluation request.
 1: [*ABORT] Return to SLIME's top level.
 2: [ABORT] abort thread (#&lt;THREAD &quot;repl-thread&quot; RUNNING {1002957FA3}&gt;)

Backtrace:
  0: (MY-DIVISION 3 0)
</code></pre>

<p>We can inspect the backtrace, go to the source (<code>v</code> in Slime), etc.</p>

<hr />

<p>Here is how <code>unix-opts</code> defines its <code>unknown-option</code> condition:</p>

<pre><code class="language-lisp">(define-condition troublesome-option (simple-error)
  ((option
    :initarg :option
    :reader option))
  (:report (lambda (c s) (format s &quot;troublesome option: ~s&quot; (option c))))
  (:documentation &quot;Generalization over conditions that have to do with some
particular option.&quot;))

(define-condition unknown-option (troublesome-option)
  ()
  (:report (lambda (c s) (format s &quot;unknown option: ~s&quot; (option c))))
  (:documentation &quot;This condition is thrown when parser encounters
unknown (not previously defined with `define-opts') option.&quot;))
</code></pre>

<h2 id="signaling-throwing-conditions">Signaling (throwing) conditions</h2>

<p>We can use <code>error</code>, like we did above. Two ways:</p>

<ul>
<li><code>(error &quot;some text&quot;)</code>: signals a condition of type <code>simple-error</code></li>
<li><code>(error 'my-error :message &quot;We did this and this and it didn't work.&quot;)</code></li>
</ul>

<p>Throwing these conditions will enter the interactive debugger,
where a few options will be presented by default. We can give
more options with <em>restarts</em>,
and we can prevent from entering the debugger by handling the condition and invoking a restart.</p>

<p>Simple example from <code>unix-opts</code>: it adds information into the <code>option</code> slot:</p>

<pre><code class="language-lisp">(error 'unknown-option
        :option opt)
</code></pre>

<h2 id="restarts-interactive-choices-in-the-debugger">Restarts, interactive choices in the debugger</h2>

<h3 id="defining-restarts">Defining restarts</h3>

<p>Restarts are the choices we get in the debugger, which always has the
<code>RETRY</code> and <code>ABORT</code> ones. We can add choices to the top of the list:</p>

<pre><code class="language-lisp">(defun division-restarter ()
  (restart-case (/ 3 0)
    (return-zero () 0)
    (divide-by-one () (/ 3 1))))
</code></pre>

<p>By calling this stupid function we get two new choices at the top of the debugger:</p>

<p><img src="simple-restarts.png" alt="" /></p>

<p>Note: read in lisper.in&rsquo;s blogpost on csv parsing (see Resources) how
this system was used effectively in production.</p>

<p>But that&rsquo;s not all, by handling restarts we can start over the
operation as if the error didn&rsquo;t occur (as seen in the stack).</p>

<h3 id="calling-restarts-programmatically">Calling restarts programmatically</h3>

<p>With <code>invoke-restart</code>.</p>

<pre><code class="language-lisp">(defun division-and-bind ()
           (handler-bind
               ((error (lambda (c)
                         (format t &quot;Got error: ~a~%&quot; c) ;; error-message
                         (format t &quot;and will divide by 1~&amp;&quot;)
                         (invoke-restart 'divide-by-one))))
             (division-restarter)))
;; (DIVISION-AND-BIND)
;; Got error: arithmetic error DIVISION-BY-ZERO signalled
;; and will divide by 1
;; Operation was (/ 3 0).
;; 3
</code></pre>

<p>Note that we called the form that contains our restarts
(<code>division-restarter</code>) and not the function that throws the error.</p>

<h3 id="using-other-restarts">Using other restarts</h3>

<p><code>find-restart 'name-of-restart</code> will return the most recent bound
restart with the given name, or <code>nil</code>. We can invoke it with
<code>invoke-restart</code>.</p>

<h3 id="prompting-the-user-to-enter-a-new-value">Prompting the user to enter a new value</h3>

<p>Let&rsquo;s add a restart in our <code>division-restarter</code> to offer the user to
enter a new dividend, and run the division again.</p>

<pre><code class="language-lisp">(defun division-restarter ()
  (restart-case (/ 3 0)
    (return-nil () nil)
    (divide-by-one () (/ 3 1))
    (choose-another-dividend (new-dividend)
      :report &quot;Please choose another dividend&quot;
      :interactive (lambda ()
                     (format t &quot;Enter a new dividend: &quot;)
                     (list (read))) ;; &lt;-- must return a list.
      (format t &quot;New division: 3/~a = ~a~&amp;&quot; new-dividend (/ 3 new-dividend)))))
</code></pre>

<p>We get prompted in the debugger:</p>

<pre><code>arithmetic error DIVISION-BY-ZERO signalled
Operation was (/ 3 0).
  [Condition of type DIVISION-BY-ZERO]

Restarts:
 0: [RETURN-NIL] RETURN-NIL
 1: [DIVIDE-BY-ONE] DIVIDE-BY-ONE
 2: [CHOOSE-ANOTHER-DIVIDEND] Please choose another dividend &lt;-- new
 3: [RETRY] Retry SLIME REPL evaluation request.
 4: [*ABORT] Return to SLIME's top level.
 5: [ABORT] abort thread (#&lt;THREAD &quot;repl-thread&quot; RUNNING {1002A47FA3}&gt;)
</code></pre>

<p>The new <code>choose-another-dividend</code> restart takes an argument for the
new dividend, that will be fed by the <code>:interactive</code> lambda, which
<code>read</code>s for user input and must return a list.</p>

<p>We use it like this:</p>

<pre><code class="language-lisp">(division-restarter)
;;
;; Entered debugger, chose the 2nd restart.
;;
Enter a new dividend: 10  &lt;-- got prompted to enter a new value.
New division: 3/10 = 3/10
NIL
</code></pre>

<p>In a real situation we might want to call our &ldquo;restarter&rdquo; recursively,
to get into the debugger again if we enter a bad value.</p>

<h3 id="hide-and-show-restarts">Hide and show restarts</h3>

<p>Restarts can be hidden. In <code>restart-case</code>, in addition to <code>:report</code>
and <code>:interactive</code>, they also accept a <code>:test</code> key:</p>

<pre><code class="language-lisp">(restart-case
   (return-zero ()
     :test (lambda ()
             (some-test))
    ...
</code></pre>

<h2 id="run-some-code-condition-or-not-finally">Run some code, condition or not (&ldquo;finally&rdquo;)</h2>

<p>The &ldquo;finally&rdquo; part of others <code>try/catch/finally</code> forms is done with <code>unwind-protect</code>.</p>

<p>It is the construct used in &ldquo;with-&rdquo; macros, like <code>with-open-file</code>,
which always closes the file after it.</p>

<p>You&rsquo;re now more than ready to write some code and to dive into other resources !</p>

<h2 id="resources">Resources</h2>

<ul>
<li><a href="http://gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts.html">Practical Common Lisp: &ldquo;Beyond Exception Handling: Conditions and Restarts&rdquo;</a> - the go-to tutorial, more explanations and primitives.</li>
<li>Common Lisp Recipes, chap. 12, by E. Weitz</li>
<li><a href="https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node317.html">language reference</a></li>
<li><a href="https://lisper.in/restarts#signaling-validation-errors">lisper.in</a> - example with parsing a csv file and using restarts with success, <a href="https://www.reddit.com/r/lisp/comments/7k85sf/a_tutorial_on_conditions_and_restarts/drceozm/">in a flight travel company</a>.</li>
<li><a href="http://www.nhplace.com/kent/Papers/Condition-Handling-2001.html">Condition Handling in the Lisp family of languages</a></li>
<li><a href="https://z0ltan.wordpress.com/2016/08/06/conditions-and-restarts-in-common-lisp/">z0ltan.wordpress.com</a></li>
<li><a href="https://github.com/svetlyak40wt/python-cl-conditions">https://github.com/svetlyak40wt/python-cl-conditions</a> - implementation of the CL conditions system in Python.</li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title"> Scripting. Parsing command line arguments, building self-contained executables.</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">02 01 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>Using a program from a REPL is fine and well, but if we want to
distribute our program easily, we&rsquo;ll want to build an executable.</p>

<p>Lisp implementations differ in their processes, but they all create
<strong>self-contained executables</strong>, for the architecture they are built on. The
final user doesn&rsquo;t need to install a Lisp implementation, he can run
the software right away.</p>

<p><strong>Start-up times</strong> are near to zero, specially with SBCL and CCL.</p>

<p>Binaries <strong>size</strong> are large-ish. They include the whole Lisp
including its libraries, the names of all symbols, information about
argument lists to functions, the compiler, the debugger, source code
location information, and more.</p>

<p>Note that we can similarly build self-contained executables for <strong>web apps</strong>.</p>

<p>Now <em><a href="https://lispcookbook.github.io/cl-cookbook/scripting.html">best read in the Common Lisp Cookbook</a></em>.</p>

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-generate-toc again -->

<p><strong>Table of Contents</strong></p>

<ul>
<li><a href="#building-a-self-contained-executable">Building a self-contained executable</a>

<ul>
<li><a href="#with-sbcl">With SBCL</a></li>
<li><a href="#with-asdf-updated">With ASDF [updated]</a></li>
<li><a href="#with-buildapp-or-roswell">With Buildapp or Roswell</a></li>
<li><a href="#for-web-apps">For web apps</a></li>
<li><a href="#size-and-startup-times-of-executables-per-implementation">Size and startup times of executables per implementation</a></li>
</ul></li>
<li><a href="#parsing-command-line-arguments">Parsing command line arguments</a>

<ul>
<li><a href="#declaring-arguments">Declaring arguments</a></li>
<li><a href="#parsing">Parsing</a>

<ul>
<li><a href="#handling-malformed-or-missing-arguments">Handling malformed or missing arguments</a></li>
<li><a href="#catching-a-c-c-termination-signal">Catching a C-c termination signal</a></li>
</ul></li>
</ul></li>
<li><a href="#continuous-delivery-of-executables">Continuous delivery of executables</a></li>
<li><a href="#credit">Credit</a></li>
</ul>

<!-- markdown-toc end -->

<h1 id="building-a-self-contained-executable">Building a self-contained executable</h1>

<h2 id="with-sbcl">With SBCL</h2>

<p>How to build (self-contained) executables is implementation-specific (see
below Buildapp and Rowsell). With SBCL, as says
<a href="http://www.sbcl.org/manual/index.html#Function-sb_002dext_003asave_002dlisp_002dand_002ddie">its documentation</a>,
it is a matter of:</p>

<pre><code class="language-lisp">(sb-ext:save-lisp-and-die #P&quot;path/name-of-executable&quot; :toplevel #'my-app:main-function :executable t)
</code></pre>

<p><code>sb-ext</code> is an SBCL extension to run external processes.  See other
<a href="http://www.sbcl.org/manual/index.html#Extensions">SBCL extensions</a>
(many of them are made implementation-portable in other libraries).</p>

<p><code>:executable  t</code>  tells  to  build  an  executable  instead  of  an
image. We  could build an  image to save  the state of  our current
Lisp image, to come back working with it later. Specially useful if
we made a lot of work that is computing intensive.</p>

<p>If you try to run this in Slime, you&rsquo;ll get an error about threads running:</p>

<blockquote>
<p>Cannot save core with multiple threads running.</p>
</blockquote>

<p>Run the command from a simple SBCL repl.</p>

<p>I suppose your project has Quicklisp dependencies. You must then:</p>

<ul>
<li>ensure Quicklisp is installed and loaded at Lisp startup (you
completed Quicklisp installation)</li>
<li><code>load</code> the project&rsquo;s .asd</li>
<li>install dependencies</li>
<li>build the executable.</li>
</ul>

<p>That gives:</p>

<pre><code class="language-lisp">(load &quot;my-app.asd&quot;)
(ql:quickload :my-app)
(sb-ext:save-lisp-and-die #p&quot;my-app-binary&quot; :toplevel #'my-app:main :executable t)
</code></pre>

<p>From the command line, or from a Makefile, use <code>--load</code> and <code>--eval</code>:</p>

<pre><code>build:
	sbcl --load my-app.asd \
	     --eval '(ql:quickload :my-app)' \
         --eval &quot;(sb-ext:save-lisp-and-die #p\&quot;my-app\&quot; :toplevel #my-app:main :executable t)&quot;
</code></pre>

<h2 id="with-asdf-updated">With ASDF [updated]</h2>

<p>Now that we&rsquo;seen the basics, we need a portable method. Since its
version 3.1, ASDF allows to do that. It introduces the <a href="https://common-lisp.net/project/asdf/asdf.html#Convenience-Functions"><code>make</code> command</a>,
that reads parameters from the .asd. Add this to your .asd declaration:</p>

<pre><code>:build-operation &quot;program-op&quot; ;; leave as is
:build-pathname &quot;&lt;binary-name&gt;&quot;
:entry-point &quot;&lt;my-package:main-function&gt;&quot;
</code></pre>

<p>and call <code>asdf:make :my-package</code>.</p>

<p>So, in a Makefile:</p>

<pre><code class="language-lisp">LISP ?= sbcl

build:
    $(LISP) --load torrents.asd \
    	--eval '(ql:quickload :my-app)' \
		--eval '(asdf:make :my-app)' \
		--eval '(quit)'
</code></pre>

<h2 id="with-buildapp-or-roswell">With Buildapp or Roswell</h2>

<p>We might  like a more  shell-friendly way to build  our executable,
and while  we&rsquo;re at it  a portable one, so  we would have  the same
command to work with various implementations.</p>

<p><a href="http://www.xach.com/lisp/buildapp/">Buildapp</a> is a battle-tested
&ldquo;application for SBCL or CCL that configures and saves an executable
Common Lisp image&rdquo;.</p>

<p>Example usage:</p>

<pre><code class="language-lisp">buildapp --output myapp \
         --asdf-path . \
         --asdf-tree ~/quicklisp/dists \
         --load-system my-app \
         --entry my-app:main
</code></pre>

<p>Many applications use it (for example,
<a href="https://github.com/dimitri/pgloader">pgloader</a>).  It is available on
Debian: <code>apt install buildapp</code>.</p>

<p><a href="https://roswell.github.io">Roswell</a>, an implementation manager and much
more, also has the <code>ros build</code> command, that should work for more
implementations than Buildapp.</p>

<p>We can also make our app installable with Roswell by a <code>ros install
my-app</code>. See its documentation</p>

<h2 id="for-web-apps">For web apps</h2>

<p>We can similarly build a self-contained executable for our web-app. It
would thus contain a web server and would be able to run on the
command line:</p>

<pre><code>$ ./my-web-app
Hunchentoot server is started.
Listening on localhost:9003.
</code></pre>

<p>Note that this runs the production webserver, not a development one,
so we can run the binary on our VPS right away and access the app from
outside.</p>

<p>We have one thing to take care of, it is to find and put the thread of
the running web server on the foreground. In our <code>main</code> function, we
can do something like this:</p>

<pre><code class="language-lisp">(defun main ()
  (start-app :port 9003) ;; our start-app, for example clack:clack-up
  ;; let the webserver run.
  ;; warning: hardcoded &quot;hunchentoot&quot;.
  (handler-case (bt:join-thread (find-if (lambda (th)
                                            (search &quot;hunchentoot&quot; (bt:thread-name th)))
                                         (bt:all-threads)))
    ;; Catch a user's C-c
    (#+sbcl sb-sys:interactive-interrupt
      #+ccl  ccl:interrupt-signal-condition
      #+clisp system::simple-interrupt-condition
      #+ecl ext:interactive-interrupt
      #+allegro excl:interrupt-signal
      () (progn
           (format *error-output* &quot;Aborting.~&amp;&quot;)
           (clack:stop *server*)
           (uiop:quit)))
    (error (c) (format t &quot;Woops, an unknown error occured:~&amp;~a~&amp;&quot; c))))
</code></pre>

<p>We used the <code>bordeaux-threads</code> library (<code>(ql:quickload
&quot;bordeaux-threads&quot;)</code>, alias <code>bt</code>) and <code>uiop</code>, which is part of ASDF so
already loaded, in order to exit in a portable way (<code>uiop:quit</code>, with
an optional return code, instead of <code>sb-ext:quit</code>).</p>

<h2 id="size-and-startup-times-of-executables-per-implementation">Size and startup times of executables per implementation</h2>

<p>SBCL isn&rsquo;t the only Lisp implementation.
<a href="https://gitlab.com/embeddable-common-lisp/ecl/">ECL</a>, Embeddable
Common Lisp, transpiles Lisp programs to C.  That creates a smaller
executable.</p>

<p>According to
<a href="https://www.reddit.com/r/lisp/comments/46k530/tackling_the_eternal_problem_of_lisp_image_size/">this reddit source</a>, ECL produces indeed the smallest executables of all,
an order of magnituted smaller than SBCL, but with a longer startup time.</p>

<p>CCL&rsquo;s binaries seem to be as fast as SBCL and nearly half the size.</p>

<pre><code>| program size | implementation |  CPU | startup time |
|--------------+----------------+------+--------------|
|           28 | /bin/true      |  15% |        .0004 |
|         1005 | ecl            | 115% |        .5093 |
|        48151 | sbcl           |  91% |        .0064 |
|        27054 | ccl            |  93% |        .0060 |
|        10162 | clisp          |  96% |        .0170 |
|         4901 | ecl.big        | 113% |        .8223 |
|        70413 | sbcl.big       |  93% |        .0073 |
|        41713 | ccl.big        |  95% |        .0094 |
|        19948 | clisp.big      |  97% |        .0259 |
</code></pre>

<!-- ? We may have another trick  to distribute small executables: to make the fasl files executables. ?-->

<h1 id="parsing-command-line-arguments">Parsing command line arguments</h1>

<p>SBCL stores the command line arguments into <code>sb-ext:*posix-argv*</code>.</p>

<p>But that variable name differs from implementations, so we may want a
library to handle the differences for us.</p>

<p>We also want to parse the arguments.</p>

<p>A quick look at the
<a href="https://github.com/CodyReichert/awesome-cl#scripting">awesome-cl#scripting</a>
list and we&rsquo;ll do that with the
<a href="https://github.com/mrkkrp/unix-opts">unix-opts</a> library.</p>

<pre><code>(ql:quickload &quot;unix-opts&quot;)
</code></pre>

<p>We can call it with its <code>opts</code> alias (nickname).</p>

<p>As often work happens in two phases:</p>

<ul>
<li>declaring the options our app accepts, their optional argument, defining their type
(string, integer,…), long and short names, and the required ones,</li>
<li>parsing them (and handling missing or malformed parameters).</li>
</ul>

<h2 id="declaring-arguments">Declaring arguments</h2>

<p>We define the arguments with <code>opts:define-opts</code>:</p>

<pre><code class="language-lisp">(opts:define-opts
    (:name :help
           :description &quot;print this help text&quot;
           :short #\h
           :long &quot;help&quot;)
    (:name :nb
           :description &quot;here we want a number argument&quot;
           :short #\n
           :long &quot;nb&quot;
           :arg-parser #'parse-integer) ;; &lt;- takes an argument
    (:name :info
           :description &quot;info&quot;
           :short #\i
           :long &quot;info&quot;))
</code></pre>

<p>Here <code>parse-integer</code> is a built-in CL function.</p>

<p>Example output on the command line (auto-generated help text):</p>

<pre><code>$ my-app -h
my-app. Usage:

Available options:
  -h, --help               print this help text
  -n, --nb ARG             here we want a number argument
  -i, --info               info
</code></pre>

<h2 id="parsing">Parsing</h2>

<p>We parse and get the arguments with <code>opts:get-opts</code>, which returns two
values: the list of valid options and the remaining free arguments. We
then must use <code>multiple-value-bind</code> to assign both into variables:</p>

<pre><code class="language-lisp">  (multiple-value-bind (options free-args)
      ;; There is no error handling yet.
      (opts:get-opts)
      ...
</code></pre>

<p>We can test this by giving a list of strings to <code>get-opts</code>:</p>

<pre><code class="language-lisp">(multiple-value-bind (options free-args)
                   (opts:get-opts '(&quot;hello&quot; &quot;-h&quot; &quot;-n&quot; &quot;1&quot;))
                 (format t &quot;Options: ~a~&amp;&quot; options)
                 (format t &quot;free args: ~a~&amp;&quot; free-args))
Options: (HELP T NB-RESULTS 1)
free args: (hello)
NIL
</code></pre>

<p>If we  put an unknown option,  we get into the  debugger. We&rsquo;ll see
error handling in a moment.</p>

<p>So <code>options</code> is a
<a href="https://lispcookbook.github.io/cl-cookbook/data-structures.html#plist">property list</a>. We
use <code>getf</code> and <code>setf</code> with plists, so that&rsquo;s how we do our
logic. Below we print the help with <code>opts:describe</code> and then <code>exit</code>
(in a portable way).</p>

<pre><code class="language-lisp">  (multiple-value-bind (options free-args)
      (opts:get-opts)

    (if (getf options :help)
        (progn
          (opts:describe
           :prefix &quot;You're in my-app. Usage:&quot;
           :args &quot;[keywords]&quot;) ;; to replace &quot;ARG&quot; in &quot;--nb ARG&quot;
          (opts:exit))) ;; &lt;= optional return status.
    (if (getf options :nb)
       ...)
</code></pre>

<p>For a full example, see its
<a href="https://github.com/mrkkrp/unix-opts/blob/master/example/example.lisp">official example</a>
and
<a href="https://vindarel.github.io/cl-torrents/tutorial.html">cl-torrents&rsquo; tutorial</a>.</p>

<p>The  example in  the unix-opts  repository suggests  a macro  to do
slightly better. Now to error handling.</p>

<h3 id="handling-malformed-or-missing-arguments">Handling malformed or missing arguments</h3>

<p>There are 4 situations that unix-opts doesn&rsquo;t handle, but signals
conditions for us to take care of:</p>

<ul>
<li>for an unknown argument: an <code>unknown-option</code> condition is signaled</li>
<li>also <code>missing-arg</code></li>
<li><code>arg-parser-failed</code> when, for example, it expected an integer but got text</li>
<li><code>missing-required-option</code></li>
</ul>

<p>So, we must create simple functions to handle those conditions, and
surround the parsing of the options with an <code>handler-bind</code>:</p>

<pre><code class="language-lisp">  (multiple-value-bind (options free-args)
      (handler-bind ((opts:unknown-option #'unknown-option) ;; the condition / our function
                     (opts:missing-arg #'missing-arg)
                     (opts:arg-parser-failed #'arg-parser-failed)
                     (opts:missing-required-option))
         (opts:get-opts))
    …
    ;; use &quot;options&quot; and &quot;free-args&quot;
</code></pre>

<p>Here we suppose we want one function to handle each case, but it could
be a simple one. They take the condition as argument.</p>

<pre><code class="language-lisp">(defun handle-arg-parser-condition (condition)
  (format t &quot;Problem while parsing option ~s: ~a .~%&quot; (opts:option condition) ;; reader to get the option from the condition.
                                                       condition)
  (opts:describe) ;; print help
  (opts:exit)) ;; portable exit
</code></pre>

<p>For more about condition handling, see <a href="error_handling.html">error and condition handling</a>.</p>

<h3 id="catching-a-c-c-termination-signal">Catching a C-c termination signal</h3>

<p>Let&rsquo;s build a simple binary, run it, try a <code>C-c</code> and read the stacktrace:</p>

<pre><code>$ ./my-app
sleep…
^C
debugger invoked on a SB-SYS:INTERACTIVE-INTERRUPT in thread   &lt;== condition name
#&lt;THREAD &quot;main thread&quot; RUNNING {1003156A03}&gt;:
  Interactive interrupt at #x7FFFF6C6C170.

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [CONTINUE     ] Return from SB-UNIX:SIGINT.               &lt;== it was a SIGINT indeed
  1: [RETRY-REQUEST] Retry the same request.
</code></pre>

<p>The signaled condition is named after our implementation:
<code>sb-sys:interactive-interrupt</code>. We just have to surround our
application code with a <code>handler-case</code>:</p>

<pre><code class="language-lisp">(handler-case
    (run-my-app free-args)
  (sb-sys:interactive-interrupt () (progn
                                     (format *error-output* &quot;Abort.~&amp;&quot;)
                                     (opts:exit))))
</code></pre>

<p>This code only for SBCL though. We know about
<a href="https://github.com/guicho271828/trivial-signal/">trivial-signal</a>,
but we were not satisfied with our test yet. So we can use something
like this:</p>

<pre><code class="language-lisp">(handler-case
    (run-my-app free-args)
  (#+sbcl sb-sys:interactive-interrupt
   #+ccl  ccl:interrupt-signal-condition
   #+clisp system::simple-interrupt-condition
   #+ecl ext:interactive-interrupt
   #+allegro excl:interrupt-signal
   ()
   (opts:exit)))
</code></pre>

<p>here <code>#+</code> includes the line at compile time depending on
the  implementation.  There&rsquo;s  also <code>#-</code>.  What <code>#+</code> does is to look for
symbols in the <code>*features*</code> list.  We can also combine symbols with
<code>and</code>, <code>or</code> and <code>not</code>.</p>

<h1 id="continuous-delivery-of-executables">Continuous delivery of executables</h1>

<p>We can make a Continuous Integration system (Travis CI, Gitlab CI,…)
build binaries for us at every commit, or at every tag pushed or at
wichever other policy.</p>

<p>See <a href="testing.html#continuous-integration">Continuous Integration</a>.</p>

<h1 id="credit">Credit</h1>

<ul>
<li><a href="https://vindarel.github.io/cl-torrents/tutorial.html">cl-torrents&rsquo; tutorial</a></li>
<li><a href="https://lisp-journey.gitlab.io/web-dev/">lisp-journey/web-dev</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to Add a Text Filter to Django Admin</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">01 01 2018</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Django Admin search fields are great, throw a bunch of fields in search_fields and Django will handle the rest. The problem with search field begins when there are too many of them. This is how we replaced Django search with text filters for specific fields, and made Django admin much faster.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Let&#39;s hand write DNS messages</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">28 12 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        In this post, we&rsquo;ll explore the Domain Name Service (DNS) binary message format, and we&rsquo;ll write one by hand. This is deeper than you need to use DNS, but I think it&rsquo;s fun and educational to see how these things work under the hood.
We&rsquo;ll learn how to:
 Write binary DNS query messages Send our message as the body of a UDP datagram using Python Read the response from the DNS server  Writing binary sounds difficult, but I actually found it quite approachable.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/72-santas-smart-contract.png" alt="Santa&#39;s Smart Contract">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Santa&#39;s Smart Contract</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">24 12 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/72-santas-smart-contract.png" alt="Merry X-MAS everybody" title="Merry X-MAS everybody" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://vindarel.github.io/cl-torrents/img-colored-results.png" alt="cl-torrents, app and (extensive) tutorial: web scraping and building executables">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">cl-torrents, app and (extensive) tutorial: web scraping and building executables</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">20 12 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Lately we exercised our Lisp skills by writing
<a href="https://github.com/vindarel/cl-torrents">cl-torrents</a>, an app that
<strong>searches for torrents</strong> on several sources (the Pirate Bay through
piratebay.to, Kickass torrents and torrent.cd), and we wrote an
<a href="https://vindarel.github.io/cl-torrents/tutorial.html">extensive tutorial</a>
in the making (that was actually our primary goal). It comes as a
library to use from the REPL and as a <strong>self-contained executable</strong>
(download and run, nothing more to install). You&rsquo;ll find the following
topics in the tutorial:</p>

<ul>
<li>how to <strong>create and load a new project</strong>,</li>
<li>common pitfalls, basic data structures, useful libraries, where to find documentation,</li>
<li>(async) <strong>web scraping</strong>,</li>
<li><strong>unit testing, with mocks</strong>,</li>
<li><strong>continuous integration</strong> and delivery of executables (Gitlab CI, Docker),</li>
<li>parsing <strong>command line arguments</strong>,</li>
<li><strong>building self-contained executables</strong>,</li>
<li>basics of <strong>error handling</strong>,</li>
<li>…</li>
</ul>

<p>Some topics have been ported to the Cookbook, some not (yet).</p>

<p><img src="https://vindarel.github.io/cl-torrents/img-colored-results.png" alt="" /></p>

<p>The next iteration will be about a self-contained web app.</p>

<p><img src="https://raw.githubusercontent.com/vindarel/cl-torrents/master/img-cli.png" alt="" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/71-bugfixing-cars-using.png" alt="(bug)fixing car using">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">(bug)fixing car using</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">12 12 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/71-bugfixing-cars-using.png" alt="(bug)fixing car using" title="(bug)fixing car using" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Django Admin Range-Based Date Hierarchy</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">10 12 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>A few weeks ago we encountered a major performance regression in one of our main admin pages. The page took more than 10 seconds to load (at best) and hit the query execution timeout at worst. When we investigated the issue, we found that the date hierarchy was the cause for most of the time spent loading the admin page. In the article we describe how we significantly improved the performance of Django Admin date hierarchy</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure 1.9 is now available</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">08 12 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Clojure 1.9 is now available!</p>
</div>
<div class="paragraph">
<p>Clojure 1.9 introduces two major new features: integration with spec and command line tools.</p>
</div>
<div class="paragraph">
<p>spec (<a href="xref/../../../../../about/spec">rationale</a>, <a href="xref/../../../../../guides/spec">guide</a>) is a library for describing the structure of data and functions with support for:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Validation</p>
</li>
<li>
<p>Error reporting</p>
</li>
<li>
<p>Destructuring</p>
</li>
<li>
<p>Instrumentation</p>
</li>
<li>
<p>Test-data generation</p>
</li>
<li>
<p>Generative test generation</p>
</li>
<li>
<p>Documentation</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Clojure integrates spec via two new libraries (still in alpha):</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/clojure/spec.alpha">spec.alpha</a> - spec implementation</p>
</li>
<li>
<p><a href="https://github.com/clojure/core.specs.alpha">core.specs.alpha</a> - specifications for Clojure itself</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>This modularization facilitates refinement of spec separate from the Clojure release cycle.</p>
</div>
<div class="paragraph">
<p>The command line tools (<a href="xref/../../../../../guides/getting_started">getting started</a>, <a href="xref/../../../../../guides/deps_and_cli">guide</a>, <a href="xref/../../../../../reference/deps_and_cli">reference</a>) provide:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Quick and easy install</p>
</li>
<li>
<p>Clojure REPL and runner</p>
</li>
<li>
<p>Use of Maven and local dependencies</p>
</li>
<li>
<p>A functional API for classpath management (<a href="https://github.com/clojure/tools.deps.alpha">tools.deps.alpha</a>)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The installer is available for Mac developers in brew, for Linux users in a script, and for more platforms in the future.</p>
</div>
<div class="paragraph">
<p>For more information, see the <a href="https://github.com/clojure/clojure/blob/master/changes.md">complete list of all changes</a> in Clojure 1.9 for more details.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_contributors"><a class="anchor" href="#_contributors"></a>Contributors</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Thanks to all of the community members who contributed to Clojure 1.9 (first time contributors in bold):</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Adam Clements</strong></p>
</li>
<li>
<p>Andy Fingerhut</p>
</li>
<li>
<p>Brandon Bloom</p>
</li>
<li>
<p><strong>Cameron Desautels</strong></p>
</li>
<li>
<p><strong>Chad Taylor</strong></p>
</li>
<li>
<p>Chris Houser</p>
</li>
<li>
<p><strong>David Bürgin</strong></p>
</li>
<li>
<p><strong>Eli Lindsey</strong></p>
</li>
<li>
<p><strong>Gerrit Jansen Van Vuuren</strong></p>
</li>
<li>
<p>Ghadi Shayban</p>
</li>
<li>
<p><strong>Greg Leppert</strong></p>
</li>
<li>
<p><strong>Jason Whitlark</strong></p>
</li>
<li>
<p><strong>Johan Mena</strong></p>
</li>
<li>
<p>Jozef Wagner</p>
</li>
<li>
<p><strong>Lee Yen-Chin</strong></p>
</li>
<li>
<p><strong>Matthew Boston</strong></p>
</li>
<li>
<p>Michael Blume</p>
</li>
<li>
<p>Michał Marczyk</p>
</li>
<li>
<p>Nicola Mometto</p>
</li>
<li>
<p><strong>Ruslan Al-Fakikh</strong></p>
</li>
<li>
<p><strong>Steffen Dienst</strong></p>
</li>
<li>
<p>Steve Miner</p>
</li>
<li>
<p><strong>Yegor Timoshenko</strong></p>
</li>
<li>
<p><strong>Zhuang XiaoDan</strong></p>
</li>
</ul>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="WhoTracks.me December Update">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">WhoTracks.me December Update</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">07 12 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        New data and trackers in our monthly update.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Who&#39;s using Common Lisp ?</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">05 12 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <blockquote>
<p>Everyone says “Nobody uses Lisp” and Lispers say “Yes they do, there’s ITA, and, um, Autocad, and, uh, oh yeah, Paul Graham wrote Viaweb in Lisp!” Not very helpful for either side.</p>
</blockquote>

<p>Following <a href="http://pchristensen.com/blog/lisp-companies/">Lisp Companies blog post</a> (2008, many dead links).</p>

<p>Reddit and <a href="https://lispjobs.wordpress.com/">lispjobs</a> are the major sources. Sponsors can be found on the <a href="http://www.european-lisp-symposium.org/">European Lisp Symposium</a> website.</p>

<p>Of course, see</p>

<ul>
<li><a href="http://lisp-lang.org/success/">lisp-lang.org&rsquo;s success stories</a> for
a showcase of projects and companies in aerospace, AI &amp; Machine
Learning, Science, Graphics etc.</li>
<li><a href="https://franz.com/success/">franz.com success stories</a></li>
<li><a href="https://lisp-journey.gitlab.io/software/">lisp-journey&rsquo;s short software list</a> (pgloader,…)</li>
<li><a href="https://github.com/azzamsa/awesome-cl-software/commits/master">awesome-cl-software</a> (old and current),</li>
<li><a href="https://github.com/CodyReichert/awesome-cl">awesome-cl</a> libraries.</li>
<li><a href="https://github.com/azzamsa/awesome-lisp-companies/"><strong>awesome-lisp-companies</strong></a>, a bigger list.</li>
</ul>

<p>Let&rsquo;s quote Kent Pitman&rsquo;s famous answer:</p>

<blockquote>
<p>But please don&rsquo;t assume this is an exhaustive list, and please don&rsquo;t assume Lisp is only useful for Animation and Graphics, AI, Bioinformatics, B2B and Ecommerce, Data Mining, EDA/Semiconductor applications, Expert Systems, Finance, Intelligent Agents, Knowledge Management, Mechanical CAD, Modeling and Simulation, Natural Language, Optimization, Research, Risk Analysis, Scheduling, Telecom, and Web Authoring just because these are the only things they happened to list. Common Lisp really is a general language capable of a lot more than these few incidental application areas, even if this web page doesn&rsquo;t totally bring that out.</p>
</blockquote>

<p>(and this list doesn&rsquo;t mention that it was used for auto-piloting the
DS1 spaceship by the NASA for several days)</p>

<hr />

<ul>
<li><a href="http://www.dwavesys.com">D-wave systems</a>, &ldquo;quantum processor development&rdquo;. &ldquo;The software is implemented in Common Lisp (SBCL) and is an integral part of the quantum computing system.&rdquo; <a href="https://lispjobs.wordpress.com/2015/03/16/software-developer-for-quantum-processor-development-group-d-wave-systems-vancouver-british-columbia/">lispjobs announce</a>.</li>
<li><a href="https://github.com/emotiq/emotiq">Emotiq</a> - a next-generation
blockchain with an innovative natural-language approach to smart
contracts.</li>
<li><a href="https://tech.grammarly.com/blog/posts/Running-Lisp-in-Production.html">Grammarly</a>,
an English language writing-enhancement platform.</li>
<li><a href="http://www.m-creations.com/">m-creations</a>, custom software
solutions for mid-size to big companies in finance/payment, health
care, and media. Using Common Lisp in different fields ranging from
dynamic web applications and Natural Language Processing to systems
engineering infrastructure in container clusters (DNS, dynamic load
balancer).</li>
<li><a href="https://www.ravenpack.com/careers/junior-common-lisp-developer">Ravenpack</a>, &ldquo;the leading big data analytics provider for financial services&rdquo;. <a href="https://www.reddit.com/r/Common_Lisp/comments/7ldiyg/suggestion_for_common_lisp_internship/">reddit announce</a>.</li>
<li><a href="http://rigetti.com/about">Rigetti</a>, new quantum computing company. They already sponsored a Quicklisp development. They chose Common Lisp (SBCL). <a href="https://www.reddit.com/r/Common_Lisp/comments/7ifq92/lisp_at_the_frontier_of_computation_by_robert/">Video</a>. <em>Their</em> Lisp even runs 40% faster than <em>their</em> C code.</li>
<li><a href="http://www.secureoutcomes.net/">Secure Outcomes</a> &ldquo;builds and provides digital livescan fingerprinting systems for use by law enforcement, military, airports, schools, Fortune 500s, etc.&rdquo;. &ldquo;All of our systems are constructed in Common Lisp.&rdquo;. <a href="https://lispjobs.wordpress.com/2016/06/03/secure-outcomes-contract-common-lisp-programmer/">lispjobs announce</a>.</li>
<li><a href="http://somewrite.jp/">Somewrite.jp</a>, a &ldquo;native advertising network platform&rdquo;. Common Lisp web development. <a href="https://lispjobs.wordpress.com/2015/04/24/common-lisp-web-developer-somewrite-tokyo-or-remote/">lispjobs announce</a>. A <a href="https://github.com/fukamachi/">Fukamachi</a> company. <a href="http://thebridge.jp/en/2016/04/asahi-shimbun-acquires-somewrite">press write up</a>.</li>
<li><a href="https://defungames.com/index.html">Spycursion</a> PC game. <a href="https://www.reddit.com/r/Common_Lisp/comments/7ik1iw/seeking_cofounder_for_lisp_game_studio/">Reddit announce</a>.</li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/70-runtime-vs-compile-time-errors.png" alt="Compile vs Runtime Error">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Compile vs Runtime Error</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">05 12 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/70-runtime-vs-compile-time-errors.png" alt="Compile vs Runtime Error" title="Compile vs Runtime Error" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://lispcookbook.github.io/cl-cookbook/assets/img-ci-build.png" alt="Continuous Integration and delivery on Gitlab CI, testing locally with Docker">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Continuous Integration and delivery on Gitlab CI, testing locally with Docker</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">01 12 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><em>Best read in the <a href="https://lispcookbook.github.io/cl-cookbook/testing.html#gitlab-ci">Cookbook</a> !</em> also Travis CI, code coverage, testing with Prove.</p>

<p><a href="https://docs.gitlab.com/ce/ci/README.html">Gitlab CI</a> is part of
Gitlab and is available on <a href="https://gitlab.com/">Gitlab.com</a>, for
public and private repositories. Let&rsquo;s see straight away a simple
<code>.gitlab-ci.yml</code>:</p>

<pre><code>image: daewok/lisp-devel

before_script:
  - apt-get update -qy
  - apt-get install -y git-core
  - git clone https://github.com/foo/bar ~/quicklisp/local-projects/

test:
  script:
    - make test
</code></pre>

<p>Gitlab CI is based on Docker. With <code>image</code> we tell it to use the
<a href="https://hub.docker.com/r/daewok/lisp-devel/">daewok/lisp-devel</a>
one. It includes SBCL, ECL, CCL and ABCL, and Quicklisp is installed
in the home (<code>/home/lisp/</code>), so we can <code>quickload</code> packages right
away. If you&rsquo;re interested it also has a more bare bones option. Gitlab will load the
image, clone our project and put us at the project root with
administrative rights to run the rest of the commands.</p>

<p><code>test</code> is a &ldquo;job&rdquo; we define, <code>script</code> is a
recognized keywords that takes a list of commands to run.</p>

<p>Suppose we must install dependencies before running our tests:
<code>before_script</code> will run before each job. Here we clone a library
where Quicklisp can find it, and for doing so we must install git
(Docker images are usually pretty bare bones).</p>

<p>We can try locally ourselves. If we already installed <a href="https://docs.docker.com/">Docker</a> and
started its daemon (<code>sudo service docker start</code>), we can do:</p>

<pre><code>docker run --rm -it -v /path/to/local/code:/usr/local/share/common-lisp/source daewok/lisp-devel:latest bash
</code></pre>

<p>This will download the lisp image (±400Mo), mount some local code in
the image where indicated, and drop us in bash. Now we can try a <code>make
test</code>.</p>

<p>To show you a more complete example:</p>

<pre><code>image: daewok/lisp-devel

stages:
  - test
  - build

before_script:
  - apt-get update -qy
  - apt-get install -y git-core
  - git clone https://github.com/foo/bar ~/quicklisp/local-projects/

test:
  stage: test
  script:
    - make test

build:
  stage: build
  only:
    - tags
  script:
    - make build
  artifacts:
    paths:
      - some-file-name
</code></pre>

<p>Here we defined two <code>stages</code> (see
<a href="https://docs.gitlab.com/ce/ci/environments.html">environments</a>),
&ldquo;test&rdquo; and &ldquo;build&rdquo;, defined to run one after another. A &ldquo;build&rdquo; stage
will start only if the &ldquo;test&rdquo; one succeesds.</p>

<p>&ldquo;build&rdquo; is asked to run <code>only</code> when a
new tag is pushed, not at every commit. When it succeeds, it will make
the files listed in <code>artifacts</code>&rsquo;s <code>paths</code> available for download. We can
download them from Gitlab&rsquo;s Pipelines UI, or with an url. This one will download
the file &ldquo;some-file-name&rdquo; from the latest &ldquo;build&rdquo; job:</p>

<pre><code>https://gitlab.com/username/project-name/-/jobs/artifacts/master/raw/some-file-name?job=build
</code></pre>

<p>When the pipelines pass, you will see:</p>

<p><img src="https://lispcookbook.github.io/cl-cookbook/assets/img-ci-build.png" alt="" /></p>

<p>You now have a ready to use Gitlab CI.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Using a logbook to improve your programming</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">23 11 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        In this post, I&rsquo;ll describe the engineering practice of keeping a logbook, and show how it can be applied to programming work.
Logbooks I studied engineering at university. Part of my course involved practical work, which we recorded in a logbook. To use a logbook successfully, you have to:
 Consider the problem you&rsquo;re attempting to solve Describe your method for solving it Describe the process of carrying out the method Record what happened, and ask how it could be improved  This process is well suited to problem solving and active learning, and is described by George Pólya in his book How to Solve It, which describes a method for solving mathematical problems.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/69-specs.png" alt="Specs...">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Specs...</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">21 11 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/69-specs.png" alt="Specs" title="Specs" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="Generating Ad-Blocker filters from whotracks.me data">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Generating Ad-Blocker filters from whotracks.me data</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">19 11 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Let's never miss a new tracker again.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/68-step-by-step-debugging.png" alt="Step By Step Debugging">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Step By Step Debugging</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">14 11 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/68-step-by-step-debugging.png" alt="Step Over, Step Over, Step Into, Step Over" title="Step Over, Step Over, Step Into, Step Over" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Introducing Clojurists Together</h1>
                            <h2 class="article__feed"><a target="_blank" href="">News on Clojurists Together</a> <span class="article__date">13 11 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Keeping Clojure open source sustainable The Clojure ecosystem is built on open source. From the Clojure and ClojureScript projects, to the build tools, web frameworks, and the hundreds of innovative and useful libraries that we all depend on every day. The pervasive use of open source has enabled a flourishing Clojure ecosystem, but it also has some hidden downsides. The vast majority of Clojure projects are maintained by a small handful of people, often only one person.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/67-merging-branches.png" alt="Merging Branches">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Merging Branches</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">07 11 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/67-merging-branches.png" alt="The comic opens depicting clear blue skies with small puffs of white clouds in the distance. In the foreground, a tall castle stands atop a green hill, proudly displaying a blue flag marked with a 'B' from the tallest tower. Down below, simple huts litter the landscape.
A king is depicted in a throne room wearing a large golden crown, adorning a blue velvet robe with a trident in his left hand. Kneeling before him, holding a scroll marked as 'changelog', is a developer dressed in drab gray garb.
Developer: &quot;It has taken so much but it is finally complete.&quot;
King: &quot;Very good. Prepare the troops for merge.&quot;
Once again, clear blue skies are depicted. This time, the castle is no longer in view, and the smaller huts from the periphery are now the focus of the panel. These huts wave a white flag marked with an 'M' atop them. Approaching is a large mass of individuals, obfuscated by a cloud of dust that is being kicked up by their approach.
The simple tribes people, standing together and rubbing their heads in confusion, look upon the mass of approaching soldiers in contemplation of the King's reasoning. They each wear stereotypical caveman clothing: cheetah fur togas and bones through their high ponytails.
Tribesman 1: &quot;What's that?&quot;
Tribesman 2: &quot;Oh no! We're getting merged.&quot;
Now the in foreground and taking up most of the image, the soldiers are shown running upon horseback, their faces determined as they approach the tribal gathering.
Soldiers (in unison): &quot;MERGE!!&quot; Panel 6 A sole onlooker, one of the soldiers from the battle, holds the blue flag of his kingdom which is marked with an engraved 'B'. The mass of soldiers collapse upon the village, the dust cloud consuming the area. In the background, feint images depicting green towers and red huts are displayed, alluding to the conflicts that may arise in a merge. Panel 7 The battle is over, and staring at the viewer in confusion is one of the tribesman, holding his spear with a blank expression. In the background, the tribal village remains unscathed from the battle. Further behind, the kingdom is similarly unscathed save for one change: the proud blue flag that once displayed a valiant 'B' has now been replaced with an 'M'." title="The conflict never stops" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="The Impact of Tracking on User Experience">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Impact of Tracking on User Experience</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">06 11 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Beyond privacy - a survey of hidden and visible effects of tracking on user experience.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Intermediate Testing in Golang</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">05 11 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I&rsquo;ve been writing Golang in production at Monzo for a couple of months now. This post shares some things I&rsquo;ve learnt about testing Go code.
Parallelisation Golang tests can be easily parallelised by calling t.Parallel() at the beginning of a test:
func TestThing(t *testing.T) { t.Parallel() // test code } This test will now be run in parallel with other tests marked as parallel. Parallel tests are run in a number of goroutines.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">First impressions of Elm</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">31 10 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        This week, I&rsquo;ve been learning Elm. While at the Recurse Center, I came across the book Seven Languages in Seven Weeks. The book&rsquo;s concept appealed to me. While I don&rsquo;t think it&rsquo;s possible to learn a programming language in a week, I think there&rsquo;s value in broadening your horizons with the quick study of a wide range of concepts.
This post summarises my initial thoughts about Elm, and lists some resources which may help you learn it.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Installing libraries, dependencies management</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">27 10 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>Common Lisp may have more libraries than you think. See:</p>

<ul>
<li><a href="http://quickdocs.org/">Quickdocs</a> - the library documentation hosting for CL.</li>
<li>the <a href="https://github.com/CodyReichert/awesome-cl">Awesome-cl</a> list, a
curated list of libraries.</li>
<li><a href="http://lisp-lang.org/wiki/article/recommended-libraries">lisp-lang.org&rsquo;s recommended libraries</a> (from <a href="http://borretti.me/article/common-lisp-sotu-2015">State of the CL ecosystem, 2015</a>)</li>
</ul>

<p>Quicklisp is the de-facto package manager, but not the only tool.</p>

<h2 id="some-terminology-first">Some terminology first</h2>

<ul>
<li><p>In the Common Lisp world, a <strong>package</strong> is a way of grouping symbols
together and of providing encapsulation. It is similar to a C++
namespace, a Python module or a Java package.</p></li>

<li><p>A <strong>system</strong> is a collection of CL source files bundled with an .asd
file which tells how to compile and load them. There is often a
one-to-one relationship between systems and packages, but this is in
no way mandatory. A system may declare a dependency on other
systems. Systems are managed by <a href="https://common-lisp.net/project/asdf/asdf.html">ASDF</a> (Another System Definition
Facility), which offers functionalities similar to those of make and
ld.so, and has become a de facto standard.</p></li>

<li><p>A Common Lisp library or project typically consists of one or
several ASDF systems (and is distributed as one Quicklisp project).</p></li>
</ul>

<h2 id="install-quicklisp">Install Quicklisp</h2>

<p><a href="https://www.quicklisp.org/beta/">Quicklisp</a> is more than a package
manager, it is also a central repository (a <em>dist</em>) that ensures that
all libraries build together. This involves some manual work (like
reporting errors to package authors), so this is why Quicklisp
releases its dist updates once a month (but fear not, we have other
tools).</p>

<p>It provides its own <em>dist</em> but it is also possible to build our own.</p>

<p>To install it, we can either:</p>

<p>1- run this command, anywhere:</p>

<pre><code>curl -O https://beta.quicklisp.org/quicklisp.lisp
</code></pre>

<p>and enter a Lisp REPL and load this file:</p>

<pre><code>sbcl --load quicklisp.lisp
</code></pre>

<p>or</p>

<p>2- install the Debian package:</p>

<pre><code>apt-get install cl-quicklisp
</code></pre>

<p>and load it, from a REPL:</p>

<pre><code class="language-lisp">(load &quot;/usr/share/cl-quicklisp/quicklisp.lisp&quot;)
</code></pre>

<p>Then, in both cases, still from the REPL:</p>

<pre><code class="language-lisp">(quicklisp-quickstart:install)
</code></pre>

<p>This will create the <code>~/quicklisp/</code> directory, where Quicklisp will
maintain its state and downloaded projects.</p>

<p>If you want Quicklisp to always be loaded in your Lisp sessions, run
<code>(ql:add-to-init-file)</code>: this adds the right stuff to the init file of
your CL implementation. Otherwise, you have to run <code>(load
&quot;~/quicklisp/setup.lisp&quot;)</code> in every session if you want to use
Quicklisp or any of the libraries installed through it.</p>

<p>It adds the following in your (for example) <code>~/.sbclrc</code>:</p>

<pre><code class="language-lisp">#-quicklisp
  (let ((quicklisp-init (merge-pathnames &quot;quicklisp/setup.lisp&quot;
                                         (user-homedir-pathname))))
    (when (probe-file quicklisp-init)
      (load quicklisp-init)))
</code></pre>

<h2 id="install-libraries">Install libraries</h2>

<p>In the REPL:</p>

<pre><code class="language-lisp">(ql:quickload &quot;package-name&quot;)
</code></pre>

<p>and voilà. See Quicklisp&rsquo;s documentation for more commands.</p>

<p>Note also that dozens of Common Lisp libraries are packaged in
Debian. The package names usually begin with the cl- prefix (use
<code>apt-cache search --names-only &quot;^cl-.*&quot;</code> to list them all).</p>

<p>For example, in order to use the CL-PPCRE library (for regular
expressions), one should first install the <code>cl-ppcre</code> package.</p>

<p>Then, in SBCL and ECL, it can be used with:</p>

<pre><code class="language-lisp">(require &quot;asdf&quot;)
(require &quot;cl-ppcre&quot;)
(cl-ppcre:regex-replace &quot;fo+&quot; &quot;foo bar&quot; &quot;frob&quot;)
</code></pre>

<p>See more: <a href="https://wiki.debian.org/CommonLisp">https://wiki.debian.org/CommonLisp</a></p>

<h2 id="advanced-dependencies-management">Advanced dependencies management</h2>

<p>Quicklisp installs the libraries into <code>~/quicklisp/local-projects/</code>. A
library installed here is automatically available for every project.</p>

<h3 id="providing-our-own-version-of-a-library-cloning-projects">Providing our own version of a library. Cloning projects.</h3>

<p>Given the property above, we can clone any library into the
local-projects directory and it will be found by quicklisp and
available right-away:</p>

<pre><code class="language-lisp">(ql:quickload &quot;package&quot;)
</code></pre>

<p>And also given the <code>M-.</code> &ldquo;go to this symbol definition&rdquo; feature in
Slime (and <code>M-,</code> to go back), it&rsquo;s really easy to not only explore but
start tweaking and extending other libraries.</p>

<h3 id="how-to-work-with-local-versions-of-libraries">How to work with local versions of libraries</h3>

<p>If we need libraries to be installed locally, for only one project, or
in order to easily ship a list of dependencies with an application, we
can use <a href="https://github.com/fukamachi/qlot">Qlot</a>. This is like
Python&rsquo;s virtual environments.</p>

<p>Quicklisp also provides
<a href="https://www.quicklisp.org/beta/bundles.html">Quicklisp bundles</a>. They
are self-contained sets of systems that are exported from Quicklisp
and loadable without involving Quicklisp.</p>

<p>At last, there&rsquo;s
<a href="https://github.com/quicklisp/quicklisp-controller">Quicklisp controller</a>
to help us build <em>dists</em>. Some projects use this, like CL21.</p>

<h2 id="read-more">Read more</h2>

<ul>
<li>Source code organization, libraries and packages:  <a href="https://lispmethods.com/libraries.html">https://lispmethods.com/libraries.html</a></li>
<li><a href="https://wiki.debian.org/CommonLisp">https://wiki.debian.org/CommonLisp</a></li>
</ul>

<h2 id="see-also">See also</h2>

<ul>
<li><a href="https://github.com/CodyReichert/qi">Qi</a> - a package manager for Common Lisp</li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://www.emezeta.com/img/logo.png" alt="Dreaming Sarah: Guía de curiosidades y teorías">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Dreaming Sarah: Guía de curiosidades y teorías</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Emezeta blog</a> <span class="article__date">27 10 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Dreaming Sarah es un videojuego indie que consigue unir pixel art, música y el extraño y surrealista mundo de los sueños. ¿Qué crees que le ocurrió a Sarah?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/66-opinions.png" alt="Opinions">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Opinions</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">24 10 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/66-opinions.png" alt="Don't mess with The Internet" title="Don't mess with The Internet" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Lisp software</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">19 10 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>There&rsquo;s a fantastic showcase of succesfull Common Lisp software on
lisp-lang.org: <a href="http://lisp-lang.org/success/">http://lisp-lang.org/success/</a> so go there first.</p>

<p>However all are not open source and it doesn&rsquo;t list new or not so
awesome but very cool or interesting software. That&rsquo;s what we&rsquo;ll do
here to see that yeah Lisp is used today and to have code bases to
look at.</p>

<p>If you are looking for CL <em>libraries</em>, you of course had a look to the
<a href="https://github.com/CodyReichert/awesome-cl">Awesome CL</a> list.</p>

<h2 id="awesome-lisp-software">Awesome Lisp software</h2>

<ul>
<li><a href="https://github.com/dimitri/pgloader">pgloader</a> - <strong>re-written from
Python with a 20 to 30x speed gain</strong> and more O_o -
<a href="http://tapoueh.org/blog/2014/05/14-pgloader-got-faster.html">blog post</a>
By Dimitri Fontaine working at Postgres in 2014. He also maintains
around 50 Debian packages of Lisp libraries for these needs. He gave
a
<a href="http://tapoueh.org/confs/2014/05/05-ELS-2014">lightning talk at the 7th European Lisp Symposium</a>. Uses <a href="http://marijnhaverbeke.nl/postmodern/">Postmodern</a> and <a href="http://lparallel.org/">lparallel</a> for asynchronous IO. Also,</li>
</ul>

<blockquote>
<p>the new code base and feature set seems to attract way more users than the previous implementation ever did, despite using a less popular programming language.</p>
</blockquote>

<ul>
<li><p><a href="https://github.com/dimitri/pgcharts">pgchart</a> - a <strong>self-contained web application</strong> that takes as input an SQL query text and outputs its data as a chart. By the same Dimitri Fontaine.</p></li>

<li><p><a href="https://github.com/cicakhq/potato">potato</a> - a <strong>Slack-like conversation platform</strong>. Many features. CL in the backend, ClojureScript to the frontend. Apache Solr, RabbitMQ, email updates,… Web, Emacs and Android clients. <a href="https://www.youtube.com/watch?v=bl8jQ2wRh6k">web coding video</a>.</p></li>

<li><p><a href="https://github.com/turtl/api">turtl</a> - a security focused online <strong>note taking app</strong>. Deployed at scale at <a href="https://framanotes.org/">Framanotes</a>. Backend in CL.</p></li>
</ul>

<h3 id="internet">Internet</h3>

<ul>
<li><a href="https://github.com/nEXT-Browser/nEXT">nEXT browser</a> - Qt based <strong>web browser</strong>.</li>
<li><a href="https://github.com/vindarel/cl-torrents">cl-torrents</a> - (my) library, cli and readline app to search for torrents on popular trackers, with an extensive tutorial.</li>
</ul>

<h3 id="publishing-software">Publishing software</h3>

<ul>
<li><a href="https://github.com/kingcons/coleslaw/">Coleslaw</a> - a <strong>static site generator</strong> similar to Jekyll. With nifty features (build on git push,…). Example blog: <a href="http://40ants.com/">http://40ants.com/</a></li>
<li><a href="https://shirakumo.github.io/radiance/">Radiance</a> - publishing software, between CMS and framework.</li>
<li><a href="https://github.com/Shirakumo/reader">Reader</a> - a simple blogging platform for Radiance.</li>
<li><a href="https://github.com/Shirakumo/purplish">Purplish</a> - an imageboard app for Radiance.</li>
</ul>

<h3 id="editors">Editors</h3>

<ul>
<li><p><a href="https://github.com/tamamu/darkmatter">Darkmatter</a> - Common Lisp <strong>notebook</strong> (also exists cl-jupyter). Built on Clack.</p></li>

<li><p><a href="https://github.com/cxxxr/lem">Lem</a> - an Emacs clone tailored for Common Lisp development, for the terminal or Electron. <a href="https://www.youtube.com/watch?v=YkSJ3p7Z9H0">Screencast</a>.</p></li>
</ul>

<h3 id="gui-apps">GUI apps</h3>

<ul>
<li><a href="https://github.com/Shinmera/halftone">Halftone</a> - a multiplatform
and portable image viewer. Simple app to demo building Qt GUIs with
Qtools.</li>
</ul>

<h3 id="terminal-apps">Terminal apps</h3>

<p><code>todo: enhance !</code></p>

<ul>
<li><a href="https://github.com/pierre-lecocq/pml/blob/master/src/parse.lisp">Pml</a> - cli tool to parse my nginx logs and print statistics (and <a href="https://bitbucket.org/mihailp/tankfeeder/src/ccb6025348243bb98cb3ec27810501492313861f/apache/?at=default">Tankfeeder for apache</a>)</li>
<li><a href="http://vintage-digital.com/hefner/software/shuffletron/">shuffletron</a> -
a terminal music player. [staling]</li>
<li><a href="https://github.com/mrkkrp/shtookovina">shtookovina</a> - a program to
help learn natural languages, based on audio recording by the
<a href="http://shtooka.net/">Shtooka project</a>, with an advanced readline
interface and fully hackable in Common Lisp. Deprecated since 2015.</li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/65-it-hell.png" alt="IT Hell">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">IT Hell</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">17 10 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/65-it-hell.png" alt="Choose your spot" title="Choose your spot" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Advice on starting a programming blog</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">15 10 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I started writing this blog earlier this year. So far, I&rsquo;ve found it to be a valuable experience. It encourages me to:
 Look for interesting things in the work I do Deeply understand the topic I&rsquo;m writing about  In this post, I cover some of the challenges I face when blogging, and the techniques I use to get around them.
Content I face two main problems when trying to write: perfectionism and difficulty with correctly scoping posts.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/64-deadline.png" alt="Deadline">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Deadline</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">10 10 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/64-deadline.png" alt="Agile 101" title="Agile 101" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Implementing &#39;undo&#39; in a text editor</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">08 10 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        This post explores an elegant method for implementing undo/redo functionality in text editors.
Problem We wish to implement functionality that allows the user of a text editor to undo their last action. If they accidentally undo an action, we want to let them redo it.
For the purposes of this post, let&rsquo;s assume that a text editor makes edits to a text object. This text object is an array of string pointers1, with each string representing a line of text2.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Scaling Django Admin Date Hierarchy</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">05 10 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The date hierarchy is a great feature but it comes at a price. On very large tables, the way date hierarchy is implemented can make an admin page nearly unusable. In this article we describe the limitations of the date hierarchy, and suggest a way to overcome them.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Yo conozco mi fauna</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">04 10 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Moving Forward by Letting Go</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">03 10 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Lisps are famous for having powerful metaprogramming facilities derived from their homoiconic nature. Core language consists of a small set of built in primitives, and the rest is implemented using macros and functions in the standard library.</p><p>Since these same tools are available to the users, anybody can easily extend the language to add semantics for their problem domain. This is the aspect of macros that's discussed most often.</p><p>While this is certainly the case, Clojure community tends to discourage using macros if they can be avoided. The rationale behind this being that macros introduce additional complexity, and Clojure values simplicity. I generally agree with this sentiment, and I find that I tend to use macros sparingly myself. However, saying that macros shouldn’t be overused is not the same as saying they shouldn’t be used at all.</p><p>One place where macros work well is library APIs. Libraries that express a particular domain can create a DSL in their API that cleanly maps to that domain. <a href='https://github.com/weavejester/compojure'>Compojure</a>, <a href='https://github.com/nathanmarz/specter'>Specter</a>, and <a href='http://www.clara-rules.org/'>Clara Rules</a> are great examples of effective macro use. Such libraries are a powerful demonstration of users extending semantics of the language.</p><p>Since most ideas can be expressed via libraries, it becomes possible to experiment with different approaches to solving problems without modifying the core language. Extending the language through libraries has the advantage of keeping these extensions contained. It also lets them fade away when you no longer use them.</p><p>Clojure has been around for a decade now, and the core language hasn't changed much in that time. Some new features have been added, most notably reducers and transducers, but overall the language has stayed small and focused. In fact, I've even seen concerns that Clojure is stagnating because features aren't being added at the rate of other languages.</p><p>The idea of using libraries to add features is used by the Clojure core team as well. Consider the example of the <a href='https://github.com/clojure/core.async'>core.async</a> library that brings Go channel semantics and the CSP programming model to Clojure.</p><p>Perhaps, in time a better idea will come along, and core.async library will become deprecated. At that point developers would stop using the library and move on to use whatever happens to replace it.</p><p>Meanwhile, existing projects will not be affected as they can continue using the library. The community will move on, and most people won't have to learn about core.async semantics. This cycle may happen many times with many different ideas, without any baggage being accumulate by the language itself.</p><p>Unfortunately, mainstream languages are designed in a way where it's not practical to add new features without updating the language specification to accommodate them. Popular languages such as Java, Python, and JavaScript have accumulated a lot of complexity over the years.</p><p>As usage patterns change, new features are being added, while existing features become deprecated. Removing features is difficult since many projects in the wild end up relying on them, so they're typically left in place.</p><p>Having lots of features in a language can seem like a positive at first glance, but in practice, features often turn into <a href='http://yogthos.net/posts/2013-08-18-Why-I-m-Productive-in-Clojure.html'>a mental burden</a> for the developer. Eventually languages become too large to understand fully, and developers settle on a subset of the features considered to be the current best practice. </p><p>In my opinion, this is the real power of homoiconicity. A language that can be extended in user space can evolve without accumulating baggage. New ideas can be implemented as libraries, and later discarded when better ideas come along. The end result is a small and focused language that doesn't sacrifice flexibility.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/63-visualized-codebase.png" alt="Visualized Codebase">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Visualized Codebase</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">03 10 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/63-visualized-codebase.png" alt="Or how to convince management" title="Or how to convince management" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/62-design-patterns-bureaucracy.png" alt="Design Patterns - Bureaucracy">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Design Patterns - Bureaucracy</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">26 09 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/62-design-patterns-bureaucracy.png" alt="Code by the rules" title="Code by the rules" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/Dragtoshareipad_small.png" alt="Instapaper is now optimized for iOS 11">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Instapaper is now optimized for iOS 11</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Instapaper</a> <span class="article__date">20 09 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Today we’re launching our iOS 11-tailored update with drag and drop support for iPad and iPad Pro as well as performance improvements for Instapaper across all iOS devices.</p>
<p><b>Drop to save</b><br/></p><iframe src="https://player.vimeo.com/video/234592989" width="540" height="304" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
<p>iOS 11 makes saving articles and videos to Instapaper more seamless. To save from another app, first multitask Instapaper using Slide Over or Split View. From there, long-press on a link in another app, such as Safari, and drag it into Instapaper to save it. If you drag a link into an open folder, it will save directly to that folder.</p><p><b>Drag into other apps</b></p>
<p><figure class="tmblr-full" data-orig-height="424" data-orig-width="600" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/Dragtoshareipad_small.png"><img src="https://64.media.tumblr.com/2db4c47eead119b7f4e19382912e61c9/tumblr_inline_p7mho752X11rof3ra_540.png" data-orig-height="424" data-orig-width="600" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/Dragtoshareipad_small.png"/></figure></p>
<p>It’s now easier to share articles from your Instapaper account to other apps. Just long-press on an article entry and drop it into a compatible app, like Mail or a browser. Dragging from Instapaper also works from search results, so it’s simple to find and share anything in your account, regardless of whether it’s synced to your device. Article highlights and notes can be shared by dragging from the Notes section.<br/></p><p><b></b></p><p><b>iOS 11 Password AutoFill</b></p><p>We added support for iOS 11’s new Password AutoFill feature. If your Instapaper credentials are stored in your iCloud Keychain, you’ll now see the option to use your saved password above the keyboard when logging in on iOS.</p><p><b></b></p><p><b>Bug fixes</b></p><p><b></b></p><p>This update addresses a variety of user-reported issues from the last release. We’ve improved our handling of embedded video content, particularly for poor connection scenarios, to ensure better and faster opening of saves in all conditions.</p><p>We also fixed a recent issue where exiting an article with a swipe gesture could result in your current reading position not saving.</p><p>Lastly, we made several search UI improvements, including a fix for a small line that would occasionally appear across the search tab.<br/></p><p>We hope these updates make reading, sharing and multitasking with Instapaper better than ever.<br/></p><p>If you’ve got any questions or feedback, just let us know via <a href="mailto:support@help.instapaper.com">support@help.instapaper.com</a> or <a href="https://twitter.com/InstapaperHelp">@InstapaperHelp</a> on Twitter. </p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/61-web-app-visualized.png" alt="Web App - Visualized">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Web App - Visualized</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">19 09 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/61-web-app-visualized.png" alt="Now you can explain your grandma what is that you are doing" title="Now you can explain your grandma what is that you are doing" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/60-productive-scrum-meetings.png" alt="Productive Scrum Meetings">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Productive Scrum Meetings</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">12 09 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/60-productive-scrum-meetings.png" alt="Time's up" title="Time's up" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">RITA LEVI-MONTALCINI</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">09 09 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Volvemos!!! Septiembre mi mes favorito</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">03 09 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Gap Buffers: a data structure for editable text</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">01 09 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I&rsquo;ve recently been writing a text editor. One of the first problems I faced was deciding how to store the contents of the file being edited. This post looks at gap buffers, the data structure I ended up using.
Problem We wish to find a data structure which supports the following operations:
 Insert or delete a character at column x, row y Insert or delete the column x  A naive solution: array of strings The simplest way to represent text is with an array of strings.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Why do we have to wait one month for Quicklisp updates ?</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">31 08 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>If you didn&rsquo;t know that, now you do. Quicklisp releases software
updates once a month (see
<a href="http://blog.quicklisp.org/">Quicklisp&rsquo;s blog</a>). I didn&rsquo;t know why, it
isn&rsquo;t explained on its website, so I asked
(<a href="https://github.com/quicklisp/quicklisp-client/issues/148">issue #148</a>). I
found the discussion very insightful, everybody being constructive,
existing solutions being discussed and architectural choices
explained. But it ended up brutally with one more Common Lisp oddity.</p>

<p>My first impression was that this fact is annoying, because it already
prevented me a couple of times to use my own library and its most
recent updates into other projects. They would pull the lib from
Quicklisp but wouldn&rsquo;t benefit from its latest features.</p>

<p>This way of doing was also not the package management model I was most
used to (pip, npm,…), but by wording things differently it makes more
sense to me. As an user says:</p>

<blockquote>
<p>I think it is a very unique to quicklisp, making sure that everything compiles together. I can&rsquo;t think of any other libraries/frameworks system on other languages/platforms that would go as far. Really great work.</p>
</blockquote>

<p>So <em>Quicklisp is more than a package manager</em>, it is a &ldquo;dist&rdquo; builder
ensuring everything works together, closer to apt than to pip.</p>

<p>The situation and shortcomings is well described by axity on
<a href="https://www.axity.net/blog/article/8">his blog post</a> (now showing a
404):</p>

<blockquote>
<p>Zach Beane has done an excellent job with Quicklisp, and it is far better than what we previously had available, but still has a few problems. Zach puts a lot of effort into curating a list of compatible software together into the form of a “Quicklisp dist” rolled out approximately every month. While this is great and puts near-zero maintenance on developers, it poses a few problems.</p>

<p>Firstly, Zach is a single point of failure. Yes, anyone can maintain their very own Quicklisp dist, but it isn&rsquo;t going to see the masses, and the Quicklisp internals are not very well understood by anyone other than Zach.</p>

<p>Also the fact that the official dists are rolled out so far apart (a month or longer in the software world is an eternity), means developers cannot push hot-fixes or address user-reported bugs in a timely manner, without pushing maintenance onto the users by having them checkout upstream sources.</p>

<p>Modern languages such as Julia and Racket offer central repositories where a developer can register their software projects, and will be automatically indexed periodically, so that users can continue to install and update software without any maintenance, and still receive updates quickly when needed. Additionally, they push managing version dependencies onto the developer, which I do not believe to be a bad thing. In contrast, Common Lisp libraries are rarely versioned, and all of that maintenance is forced upon the Quicklisp dist curator.</p>
</blockquote>

<p>I also like /u/ruricolist&rsquo;s explanations
(<a href="https://www.reddit.com/r/lisp/comments/6snw5d/questions_for_2017_common_lisp_experts/dljcuz9/">on reddit</a>):</p>

<blockquote>
<p>Quicklisp provides more assurance than you might expect. The criterion for inclusion, and maintenance, of a project in Quicklisp is that the project successfully load in SBCL alongside all the libraries in that Quicklisp distribution, and load without any errors or warnings. SBCL has extensive type inference and can catch and warn about many potential issues at compile time. And because of the pervasive use of macros in CL, successfully loading a library usually exercises a lot of code paths in its dependencies. To a surprising extent, &ldquo;if it loads, it runs.&rdquo;</p>

<p>Qlot isn&rsquo;t something a library would use. You use it to set up the dependencies for an application. My approach (with TBRSS) is this. Obviously, every time I upgrade to a new Quicklisp dist, I run a test suite to make sure everything is working together. On the rare occasion there&rsquo;s a problem, I either pin the offending library to an older version (with Qlot) or I fork it and fix it, again using Qlot to pull from the fork until the fix makes it into the next Quicklisp dist. And of course I also use Qlot for dependencies that are not, for whatever reason, available in Quicklisp.</p>
</blockquote>

<hr />

<p>So Quicklisp&rsquo;s author answers:</p>

<blockquote>
<p>The work relying on me is that I build everything in Quicklisp to make sure they build together before making a release. This covers a useful class of bugs. I&rsquo;d love to incorporate more tests in the process to catch release problems that don&rsquo;t manifest at build time.</p>

<p>I hope to make it easier for people to learn how to make their own dists. Then people will have the opportunity to make new software sets following the policies that are most important to them. I think there&rsquo;s also plenty of room for other package managers for Common Lisp - maybe something styled more like clbuild would suit people who want instant access to updates.</p>
</blockquote>

<p>Why a month ?</p>

<blockquote>
<p>A month between updates is a compromise between chaos and stability.</p>

<p>I don&rsquo;t think shorter release cycles are an unqualified good. In my experience, short release cycles can lead to instability and unpredictability, and I chose one month as a balance between getting timely updates and having a reliable, stable base.</p>

<p>The most labor-intensive part of making releases is monitoring daily failures and reporting bugs to the right people. The daily failure report is automated, but reporting bugs (and following up) can be a slog.</p>
</blockquote>

<p>Then the discussion began. When voices support more frequent releases,
Zach advertises again
<a href="https://github.com/quicklisp/quicklisp-controller">quicklisp-controller</a>;
I read one (and only one) small but direct criticism towards the
maintainer:</p>

<blockquote>
<p>@Hexstream I don&rsquo;t think a fork will be required. I think this is less of an issue with @xach not willing to make changes required by the community and more of lack of manpower that&rsquo;s willing and able to take up the burden of building and maintaining an automated Quicklisp dist/repository.</p>
</blockquote>

<p>A one month update has its supporters, of course:</p>

<blockquote>
<p>I have benefited multiple times from the 1 month release cycle and the due diligence that Xach and others put in every month. Even if they had a team of 50 I&rsquo;d still vote to keep it as it is now. Making a separate dist is far more sensible if you need extra control over delivery times and it will still play well with quicklisp and your other projects.</p>
</blockquote>

<p>I asked whether it would be possible to specify a git version, and I had an explanation:</p>

<blockquote>
<p>Regarding pulling from git in the client, Quicklisp doesn&rsquo;t work like that. I did not want to rely on external processes in order to be portable to all Common Lisp implementations and platforms. This was a real issue in clbuild and asdf-install.</p>

<p>If you want to update a bugfix of your library, fix it, and wait a month.</p>
</blockquote>

<p>and the reminder to try <a href="https://github.com/fukamachi/qlot">Qlot</a>,
which allows exactly that (and to set dependencies locally).</p>

<blockquote>
<p>Qlot will not help if you are writing a library and want to push fixes to its users quickly. It only helps for end-user application development. It works similar to virtualenv + pip (requirements.txt) from Python&rsquo;s world, for example.</p>
</blockquote>

<p>Phoe summed up the situation:</p>

<blockquote>
<p>This thread is turning into a discussion about &ldquo;why X approach is better than Quicklisp approach&rdquo; which leads to a fruitful, but dead point.</p>

<p>If someone is not satisfied with the way the current Quicklisp dist works and would rather have a more automated solution, then they are free to extend the quicklisp-controller to their liking and implement the required functionality for:</p>

<ul>
<li>creating a centralized service that acts as a QL repository and dist manager,</li>
<li>allowing the authors to upload and/or update their projects on that service,</li>
<li>setting up a CI test loop on that service for verifying that the packages build,</li>
<li>automatically updating the service&rsquo;s dists with new releases,</li>
<li>maintaining all of the above.</li>
</ul>

<p>Until such a person or group of people appears, nothing is going to be be achieved and nothing in Quicklisp is going to change.</p>

<p>Talk is cheap - @xach has at least built something that works and can act as a foundation.</p>
</blockquote>

<p>And now, after only 17 messages to the thread, Zach Beane closes the thread:</p>

<blockquote>
<p>I can appreciate there are other approaches that have advantages over how Quicklisp works. I hope this thread has helped shed some light on why it works the way it does, and my hopes for the future. I&rsquo;m not against requests for changes, but not all of them can or will be accommodated. I&rsquo;m also fully in favour of people doing their own thing if they have other priorities, experiences, and preferences - I think it would be great if there were even more options for Common Lisp project management.</p>

<p>Closing this for now - thanks for the discussion.</p>
</blockquote>

<p>Hexstream had just the time to disagree</p>

<blockquote>
<p>Generally agree with your last comment, but I just wanted to express my discontent at the premature closing of this thread, it seemed pretty fruitful to me and I don&rsquo;t think it had yet reached a point of serious diminishing returns.</p>

<p>(Your project, your rules, though.)</p>
</blockquote>

<p>and this is it.</p>

<hr />

<p>I think, and I&rsquo;m not the only one, that the thread was fruitful.</p>

<p>Indeed, we had explanations (that don&rsquo;t appear in the doc), we had
presentation of means to the resolution (in no doc), we had the
presentation of how to fix the mentioned problem for library
developers (Qlot, comprehensibly not referenced in Quicklisp doc, and little talked
about over here), we had questions regarding the lack of documentation
that could be tracked from this thread (Zach too said he wanted to
write more doc). And I think the discussion was professional, with no
animosity. So we could have tracked some progress, maybe we would have
received more tips, but more importantly we&rsquo;d have been done with this
question.</p>

<p>But the thread is closed O_o Preventing people from communicating
means preventing people from learning from each
other, and thus makes the CL world evolving slower. Or people
quitting, or simply be very surprised and not staying here. Indeed,
it&rsquo;s a negative feeling to see that. Why did Zach close the thread ?
Is he bored of this discussion ? He can ignore it. Bored of being
asked that ? It&rsquo;s a recurrent question in reddit and in blogs. But
this issue is the only mention of the subject on Quicklisp&rsquo;s website and
repository. Closing it makes it much less visible.</p>

<p>Thus it is more likely newcomers will ask again. It&rsquo;s sure newcomers
won&rsquo;t learn why Quicklisp works like it does, which appears in good
light in that issue (and below in reddit). What happened is again a
thing that makes the CL world impenetrable (or with great effort) and
subject to rants. It doesn&rsquo;t need more reasons, seriously.</p>

<p>I wouldn&rsquo;t bother if this subject was documented, but it is not. The
issue about documenting Quicklisp, which Zach wanted to fix &ldquo;soon&rdquo;,
stalls since 2014. It&rsquo;s still open, at least.</p>

<hr />

<p>Final links, with a glimpse of light:</p>

<ul>
<li><p><a href="https://www.reddit.com/r/Common_Lisp/comments/6x7c85/why_do_we_have_to_wait_one_month_before_quicklisp/">the reddit thread</a></p></li>

<li><p><a href="https://github.com/CodyReichert/qi">Qi</a>, a Common Lisp package
manager in the making - more traditional, no surprises - didn&rsquo;t try.</p></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/59-testing-in-a-nutshell.png" alt="Testing - in a nutshell">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Testing - in a nutshell</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">22 08 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/59-testing-in-a-nutshell.png" alt="Testing - in a nutshell" title="Testing - in a nutshell" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Analyse and test C with Python</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">16 08 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I&rsquo;ve recently been implementing data structures in C. Writing C is fun and educational, because it&rsquo;s lower level than most other common languages. It&rsquo;s fast, and writing it teaches you to understand what&rsquo;s happening at a machine level.
However, C is also relatively difficult to write, making it harder to analyse and test. It would be helpful to be able to do this with a higher level language, such as Python.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How We Replaced Dozens of Test Fixtures With One Simple Function</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">15 08 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>We had a large codebase and a lot of tests. Unfortunately, a lot of our tests were a relic from when we were using fixtures extensively. In this article, we describe a different approach that reduced the number of fixtures we maintain.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Life after the Recurse Center</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">15 08 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        My batch at the Recurse Center finished last week. This seems like an appropriate moment to reflect on what I&rsquo;ve learnt, and what I want to prioritise over the coming months.
Past three months Technical I learnt:
 How programming languages work C x86 Assembly JavaScript Scheme Forth Principles of web security P5.js Algorithms + data structures A large amount of &lsquo;osmosis&rsquo; knowledge from being around so many talented people  I wrote:
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/58-interview-vs-reality.png" alt="Interview vs. Reality">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Interview vs. Reality</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">15 08 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/58-interview-vs-reality.png" alt="Be careful on the next interview" title="Be careful on the next interview" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Improve Python testing with parameterisation</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">09 08 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Parameterisation is a technique which makes testing simpler, more concise and more effective. It does this by separating test logic from test data. Let&rsquo;s consider a test for a simple function, and how it can be improved by parameterisation.
Simple test Let&rsquo;s test the following function:
# prime.py import math def is_prime(x): &#34;&#34;&#34; is_prime returns True or False indicating whether x is prime or not. &#34;&#34;&#34; if x &lt;= 1: return False for i in range(2, int(math.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Flavours of prayer</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">08 08 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Have you ever visited different types of churches and listened to how they pray? Growing up, I had the privilege of visiting several churches. They were all different. And the people in them prayed with different styles.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/57-future-self.png" alt="Future Self">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Future Self</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">08 08 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/57-future-self.png" alt="Be careful with that last commit. Time travel might be just around the corner" title="Be careful with that last commit. Time travel might be just around the corner" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/56-refactor-man.png" alt="Refactor Man">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Refactor Man</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">01 08 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/56-refactor-man.png" alt="The hero every code deserves" title="The hero every code deserves" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to do Functional Programming in Common Lisp ?</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">28 07 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>or &ldquo;Common Lisp is not very functional-programming oriented&rdquo;. What are the options ?</p>

<p>I mean, <code>map</code> is uncommon and there is no short words like <code>take</code> etc
for functional composition. Right ?</p>

<p><strong>edit</strong> see those <a href="/blog/snippets-functional-style-more/">snippets</a>.</p>

<p><strong>edit january, 2019</strong>: see this <a href="https://stackoverflow.com/questions/54375478/can-lisp-be-easily-used-in-an-immutable-functional-manner/54378903#54378903">SO answer</a> and the <a href="https://github.com/smithzvk/modf">modf</a> library.</p>

<h3 id="map-and-filter">Map and filter</h3>

<p>Indeed, there are 8 or so <code>map</code> functions. The one we&rsquo;re used to is
<code>mapcar</code>. The simple <code>map</code> needs a second argument to specify its return
type: <code>(map 'list (lambda…</code>. &ldquo;filter&rdquo; is named <code>remove-if-not</code>.</p>

<p><code>mapcan</code> can also be useful. It concatenates the items into one
list. So with <code>mapcar</code> we get a list of lists with our items, with
<code>mapcan</code> simply a list of our items.</p>

<p>=&gt; improved in <a href="http://cl21.org/">cl21</a>. It defines the usual <code>map</code>
and <code>keep-if</code> and more functional verbs: <code>take</code>, <code>drop</code>, <code>take-while</code>,
<code>drop-while</code>, <code>butlast</code>, <code>sum</code>,… in addition to <code>fill</code>, <code>last</code>,
<code>find-if[-not]</code>, <code>remove-if[-not]</code>, <code>delete[-if[-not]]</code>, <code>reverse</code>,
<code>reduce</code>, <code>sort</code>, <code>remove-duplicates</code>, <code>every</code>, <code>some</code>,…</p>

<p><em>Note</em>: remember that we still have access to <code>cl</code> symbols in CL21.</p>

<h3 id="functional-composition">Functional composition</h3>

<p>Lack of functional composition ? There is the
<a href="https://github.com/tokenrove/series/wiki">Series</a> library since 1989
that seems great, it lets us <em>&ldquo;write our program in a functional style
without any runtime penalty at all !&rdquo;</em>
[<a href="http://malisper.me/2016/04/13/loops-in-lisp-part-4-series/">malisper</a>
on his blog post]</p>

<p>But yes again, it has not the modern vocabulary we expect
and it seems abandonware (and its documentation is an old pdf paper
but now hopefully this wiki is better).</p>

<p><strong>edit 2021</strong>: <a href="https://github.com/cbeo/gtwiwtg">GTWIWTG</a> is a &ldquo;generators&rdquo; library similar in scope from Series, with modern idioms, but probably not as efficient. BTW, there are now lots of Series example snippets in the <a href="https://lispcookbook.github.io/cl-cookbook/iteration.html">Cookbook/iteration</a> page.</p>

<p>CL21 has an operator to compose functions: <a href="https://github.com/cl21/cl21/wiki/Language-Difference-between-CL21-and-Common-Lisp#function">https://github.com/cl21/cl21/wiki/Language-Difference-between-CL21-and-Common-Lisp#function</a></p>

<h3 id="threading-macros-pipes">Threading macros (pipes)</h3>

<p>We have two packages in Quicklisp:</p>

<ul>
<li><a href="https://github.com/nightfly19/cl-arrows">cl-arrows</a> defines <code>-&gt;</code>,
<code>-&gt;&gt;</code> and the generalized ones <code>-&lt;&gt;</code> and <code>-&lt;&gt;&gt;</code>. At the time of
writing it has two unanswered PRs to add more, like the
&ldquo;when-guarded&rdquo;-&ldquo;nil shortcuting diamond wand&rdquo; <code>some-&gt;</code>.</li>
<li><a href="https://github.com/hipeta/arrow-macros">arrow-macros</a> is a bit more
complete but has more dependencies (it needs a code walker) which
are not portable (failed on ECL, Allegro, ABCL, Clisp). It has the
<code>some-&gt;</code>, <code>cond-&gt;</code> and <code>as-&gt;</code> ones.</li>
</ul>

<h3 id="data-structures">Data structures</h3>

<p>We have the nice <a href="https://github.com/slburson/fset">FSet</a>, the functional collection for Common Lisp.</p>

<h3 id="anaphoric-macros-for-shorter-lambdas">Anaphoric macros (for shorter lambdas)</h3>

<p>I like anaphoric macros but I didn&rsquo;t find one ready to use in a library to write shorter lambdas. The first macro I wrote was directly to mimick elisp&rsquo;s <code>dash.el</code> excellent library:</p>

<pre><code class="language-common-lisp">(defmacro --map (form list)
  `(mapcar (lambda (it) ,form) ,list))
</code></pre>

<p>so than we can write</p>

<pre><code class="language-common-lisp">(--map (* it 2) '(2 3))
</code></pre>

<p>instead of <code>(mapcar (lambda (it) (* it 2) '(2 3)))</code>.
This macro is very simple. It should be in a library, I don&rsquo;t want to copy-paste it in every project of mine. =&gt; in CL21 ? In Anaphora ?</p>

<p>=&gt; Personnally I&rsquo;m very happy with
<a href="https://lispcookbook.github.io/cl-cookbook/cl21.html#shorter-lambda">cl21&rsquo;s short lambdas</a>
(that were not documented…):</p>

<pre><code>(map ^(foo-bar %) items)
</code></pre>

<p>or with <code>(lm (x)…</code>. Unused arguments will be ignored automatically.</p>

<p>I also quite like the Arc way of doing, that I found in the
<a href="https://github.com/malisper/Clamp">Clamp</a> project. Arc is another
language and Clamp is more of a POC I guess.</p>

<p>For shorter lambdas we also have
<a href="http://quickdocs.org/f-underscore/api">f-underscore</a>, that I see used
in the wild. It defines some macros to write shorter lambdas:</p>

<ul>
<li><code>f</code> is a synonym for lambda</li>
<li><code>f0</code> is a lambda that takes 0 arguments</li>
<li><code>f_</code> takes one, accessible in <code>_</code> (underscore)</li>
<li><code>f_n</code> takes one <code>&amp;rest</code> argument</li>
<li><code>f_%</code> ignores its rest argument</li>
<li><code>m</code> is a lambda &ldquo;that has a macro-lambda-list instead of an ordinary lambda-list&rdquo;.</li>
</ul>

<p>You might like <a href="https://github.com/guicho271828/trivia">Trivia</a> for <strong>pattern matching</strong> too.</p>

<p>Hope this helps !</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Data Structures</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">27 07 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>What the heck are alists and plists exactly, how do we manipulate data
structures ? It seems tedious sometimes, are there helpers ?</p>

<p><strong>Best read in the <a href="https://lispcookbook.github.io/cl-cookbook/data-structures.html">Cookbook</a></strong>.</p>

<p>We hope to give here a clear reference of the common data
structures. To really learn the language, you should take the time to
read other resources. The following ones, which we relied upon,
have many more details:</p>

<ul>
<li><a href="http://gigamonkeys.com/book/they-called-it-lisp-for-a-reason-list-processing.html">Practical CL</a>, by Peter Seibel</li>
<li><a href="http://weitz.de/cl-recipes/">CL Recipes</a>, by E. Weitz, full of explanations and tips,</li>
<li>the
<a href="http://cvberry.com/tech_writings/notes/common_lisp_standard_draft.html">CL standard</a>
with a nice TOC, functions reference, extensive descriptions, more
examples and warnings (i.e: everything).</li>
<li>a <a href="http://clqr.boundp.org/">Common Lisp quick reference</a></li>
</ul>

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-generate-toc again -->

<p><strong>Table of Contents</strong></p>

<ul>
<li><a href="#building-lists-cons-cells-lists">Building lists. Cons cells, lists.</a>

<ul>
<li><a href="#carcdr-or-firstrest-and-second-to-tenth">car/cdr or first/rest (and second&hellip; to tenth)</a></li>
<li><a href="#last-butlast-nbutlast-optional-n">last, butlast, nbutlast (&amp;optional n)</a></li>
<li><a href="#reverse-nreverse">reverse, nreverse</a></li>
<li><a href="#append">append</a></li>
<li><a href="#push-item-place">push (item, place)</a></li>
<li><a href="#pop">pop</a></li>
<li><a href="#nthcdr-index-list">nthcdr (index, list)</a></li>
<li><a href="#carcdr-and-composites-cadr-caadr---accessing-lists-inside-lists">car/cdr and composites (cadr, caadr…) - accessing lists inside lists</a></li>
<li><a href="#destructuring-bind-parameter-list">destructuring-bind (parameter*, list)</a></li>
<li><a href="#predicates-null-listp">Predicates: null, listp</a></li>
<li><a href="#ldiff-tailp-list-make-list-fill-revappend-nreconc-consp-atom">ldiff, tailp, list*, make-list, fill, revappend, nreconc, consp, atom</a></li>
</ul></li>
<li><a href="#sequences">Sequences</a>

<ul>
<li><a href="#predicates-every-some">Predicates: every, some,…</a></li>
<li><a href="#functions">Functions</a>

<ul>
<li><a href="#length-sequence">length (sequence)</a></li>
<li><a href="#member-elt-sequence">member (elt, sequence)</a></li>
<li><a href="#elt-sequence-index">elt (sequence, index)</a></li>
<li><a href="#count-foo-sequence">count (foo sequence)</a></li>
<li><a href="#subseq-sequence-start-end">subseq (sequence start, [end])</a></li>
<li><a href="#sort-stable-sort-sequence-test--key-function">sort, stable-sort (sequence, test [, key function])</a></li>
<li><a href="#find-position-foo-sequence">find, position (foo, sequence)</a></li>
<li><a href="#search-sequence-a-sequence-b">search (sequence-a, sequence-b)</a></li>
<li><a href="#substitute-nsubstituteifif-not">substitute, nsubstitute[if,if-not]</a></li>
<li><a href="#sort-stable-sort-merge">sort, stable-sort, merge</a></li>
<li><a href="#replace-sequence-a-sequence-b">replace (sequence-a, sequence-b)</a></li>
<li><a href="#remove-delete-foo-sequence">remove, delete (foo sequence)</a></li>
</ul></li>
<li><a href="#mapping-map-mapcar-remove-if-not">mapping (map, mapcar, remove-if[-not],&hellip;)</a></li>
<li><a href="#flatten-a-list-alexandria">Flatten a list (Alexandria)</a></li>
<li><a href="#creating-lists-with-variables">Creating lists with variables</a></li>
<li><a href="#comparing-lists">Comparing lists</a></li>
</ul></li>
<li><a href="#set">Set</a></li>
<li><a href="#fset---immutable-data-structure">Fset - immutable data structure</a></li>
<li><a href="#arrays-and-vectors">Arrays and vectors</a>

<ul>
<li><a href="#create-an-array-one-or-many-dimensions">Create an array, one or many dimensions</a></li>
<li><a href="#access-aref-array-i-j-">Access: aref (array i [j …])</a></li>
<li><a href="#sizes">Sizes</a></li>
<li><a href="#vectors">Vectors</a></li>
<li><a href="#transforming-a-vector-to-a-list">Transforming a vector to a list.</a></li>
</ul></li>
<li><a href="#hash-table">Hash Table</a>

<ul>
<li><a href="#creating-a-hash-table">Creating a Hash Table</a></li>
<li><a href="#getting-a-value-from-a-hash-table">Getting a value from a Hash Table</a>

<ul>
<li><a href="#getting-a-key-that-does-not-exist-with-a-default-value">Getting a key that does not exist with a default value</a></li>
<li><a href="#getting-all-keys-or-all-values-of-a-hash-table">Getting all keys or all values of a hash table</a></li>
</ul></li>
<li><a href="#adding-an-element-to-a-hash-table">Adding an Element to a Hash Table</a></li>
<li><a href="#testing-for-the-presence-of-a-key-in-a-hash-table">Testing for the Presence of a Key in a Hash Table</a></li>
<li><a href="#deleting-from-a-hash-table">Deleting from a Hash Table</a></li>
<li><a href="#traversing-a-hash-table">Traversing a Hash Table</a>

<ul>
<li><a href="#traversign-keys-or-values">Traversign keys or values</a></li>
</ul></li>
<li><a href="#counting-the-entries-in-a-hash-table">Counting the Entries in a Hash Table</a></li>
<li><a href="#performance-issues-the-size-of-your-hash-table">Performance Issues: The Size of your Hash Table</a></li>
</ul></li>
<li><a href="#alist">Alist</a></li>
<li><a href="#plist">Plist</a></li>
<li><a href="#tree">Tree</a>

<ul>
<li><a href="#sycamore---purely-functional-weight-balanced-binary-trees">Sycamore - purely functional weight-balanced binary trees</a></li>
</ul></li>
</ul>

<!-- markdown-toc end -->

<h2 id="lists">Lists</h2>

<h3 id="building-lists-cons-cells-lists">Building lists. Cons cells, lists.</h3>

<p><em>A list is also a sequence, so we can use the functions shown below.</em></p>

<p>The list basic element is the cons cell. We build lists by assembling
cons cells.</p>

<pre><code class="language-lisp">(cons 1 2)
;; =&gt; (1 . 2) ;; representation with a point, a dotted pair.
</code></pre>

<p>It looks like this:</p>

<pre><code>[o|o]--- 2
 |
 1
</code></pre>

<p>If the <code>cdr</code> of the first cell is another cons cell, and if the <code>cdr</code> of
this last one is <code>nil</code>, we build a list:</p>

<pre><code class="language-lisp">(cons 1 (cons 2 nil))
;; =&gt; (1 2)
</code></pre>

<p>It looks like this:</p>

<pre><code>[o|o]---[o|/]
 |       |
 1       2
</code></pre>

<p>(ascii art by <a href="https://github.com/cbaggers/draw-cons-tree">draw-cons-tree</a>).</p>

<p>See that the representation is not a dotted pair ? The Lisp printer
understands the convention.</p>

<p>Finally we can simply build a literal list with <code>list</code>:</p>

<pre><code class="language-lisp">(list 1 2)
;; =&gt; (1 2)
</code></pre>

<p>or by calling quote:</p>

<pre><code class="language-lisp">'(1 2)
;; =&gt; (1 2)
</code></pre>

<p>which is shorthand notation for the function call <code>(quote (1 2))</code>.</p>

<h3 id="car-cdr-or-first-rest-and-second-to-tenth">car/cdr or first/rest (and second&hellip; to tenth)</h3>

<pre><code class="language-lisp">(car (cons 1 2)) ;; =&gt; 1
(cdr (cons 1 2)) ;; =&gt; 2
(first (cons 1 2)) ;; =&gt; 1
(first '(1 2 3)) ;; =&gt; 1
(rest '(1 2 3)) ;; =&gt; (2 3)
</code></pre>

<p>We can assign <em>any</em> new value with <code>setf</code>.</p>

<h3 id="last-butlast-nbutlast-optional-n">last, butlast, nbutlast (&amp;optional n)</h3>

<p>return the last cons cell in a list (or the nth last cons cells).</p>

<pre><code class="language-lisp">(last '(1 2 3))
;; =&gt; (3)
(car (last '(1 2 3)) )
;; =&gt; 3
(butlast '(1 2 3))
;; =&gt; (1 2)
</code></pre>

<h3 id="reverse-nreverse">reverse, nreverse</h3>

<p><code>reverse</code> and <code>nreverse</code> return a new sequence.</p>

<p><code>nreverse</code> is destructive. The N stands for <strong>non-consing</strong>, meaning
it doesn&rsquo;t need to allocate any new cons cells. It <em>might</em> (but in
practice, does) reuse and modify the original sequence:</p>

<pre><code class="language-lisp">(defparameter mylist '(1 2 3))
;; =&gt; (1 2 3)
(reverse mylist)
;; =&gt; (3 2 1)
mylist
;; =&gt; (1 2 3)
(nreverse mylist)
;; =&gt; (3 2 1)
mylist
;; =&gt; (1) in SBCL but implementation dependant.
</code></pre>

<h3 id="append">append</h3>

<p><code>append</code> takes any number of list arguments and returns a new list
containing the elements of all its arguments:</p>

<pre><code class="language-lisp">(append (list 1 2) (list 3 4))
;; =&gt; (1 2 3 4)
</code></pre>

<p>The new list shares some cons cells with the <code>(3 4)</code>:</p>

<p><a href="http://gigamonkeys.com/book/figures/after-append.png">http://gigamonkeys.com/book/figures/after-append.png</a></p>

<p><strong>Note</strong>: <a href="cl21.htm">cl21</a>&rsquo;s <code>append</code> is generic (for strings, lists, vectors and
its abstract-sequence).</p>

<p><code>nconc</code> is the recycling equivalent.</p>

<h3 id="push-item-place">push (item, place)</h3>

<p><code>push</code> prepends <em>item</em> to the list that is stored in <em>place</em>, stores
the resulting list in <em>place</em>, and returns the list.</p>

<pre><code class="language-lisp">(defparameter mylist '(1 2 3))
(push 0 mylist)
;; =&gt; (0 1 2 3)
</code></pre>

<pre><code class="language-lisp">(defparameter x ’(a (b c) d))
;; =&gt; (A (B C) D)
(push 5 (cadr x))
;; =&gt; (5 B C)
x
;; =&gt; (A (5 B C) D)
</code></pre>

<p><code>push</code> is equivalent to <code>(setf place (cons item place ))</code> except that
the subforms of <em>place</em> are evaluated only once, and <em>item</em> is evaluated
before <em>place</em>.</p>

<p>There is no built-in function to <strong>add to the end of a list</strong>. It is a
more costly operation (have to traverse the whole list). So if you
need to do this: either consider using another data structure, either
just <code>reverse</code> your list when needed.</p>

<h3 id="pop">pop</h3>

<p>a destructive operation.</p>

<h3 id="nthcdr-index-list">nthcdr (index, list)</h3>

<p>Use this if <code>first</code>, <code>second</code> and the rest up to <code>tenth</code> are not
enough.</p>

<h3 id="car-cdr-and-composites-cadr-caadr-accessing-lists-inside-lists">car/cdr and composites (cadr, caadr…) - accessing lists inside lists</h3>

<p>They make sense when applied to lists containing other lists.</p>

<pre><code class="language-lisp">(caar (list 1 2 3))                  ==&gt; error
(caar (list (list 1 2) 3))           ==&gt; 1
(cadr (list (list 1 2) (list 3 4)))  ==&gt; (3 4)
(caadr (list (list 1 2) (list 3 4))) ==&gt; 3
</code></pre>

<h3 id="destructuring-bind-parameter-list">destructuring-bind (parameter*, list)</h3>

<p>It binds the parameter values to the list elements. We can destructure
trees, plists and even provide defaults.</p>

<p>Simple matching:</p>

<pre><code class="language-lisp">(destructuring-bind (x y z) (list 1 2 3)
  (list :x x :y y :z z))
;; =&gt; (:X 1 :Y 2 :Z 3)
</code></pre>

<p>Matching inside sublists:</p>

<pre><code class="language-lisp">(destructuring-bind (x (y1 y2) z) (list 1 (list 2 20) 3)
  (list :x x :y1 y1 :y2 y2 :z z))
;; =&gt; (:X 1 :Y1 2 :Y2 20 :Z 3)
</code></pre>

<p>The parameter list can use the usual <code>&amp;optional</code>, <code>&amp;rest</code> and <code>&amp;key</code>
parameters.</p>

<pre><code class="language-lisp">(destructuring-bind (x (y1 &amp;optional y2) z) (list 1 (list 2) 3)
  (list :x x :y1 y1 :y2 y2 :z z))
;; =&gt; (:X 1 :Y1 2 :Y2 NIL :Z 3)
</code></pre>

<pre><code class="language-lisp">(destructuring-bind (&amp;key x y z) (list :z 1 :y 2 :x 3)
  (list :x x :y y :z z))
;; =&gt; (:X 3 :Y 2 :Z 1)
</code></pre>

<p>The <code>&amp;whole</code> parameter is bound to the whole list. It must be the
first one and others can follow.</p>

<pre><code class="language-lisp">(destructuring-bind (&amp;whole whole-list &amp;key x y z) (list :z 1 :y 2 :x 3)
  (list :x x :y y :z z :whole whole-list))
;; =&gt; (:X 3 :Y 2 :Z 1 :WHOLE-LIST (:Z 1 :Y 2 :X 3))
</code></pre>

<p>Destructuring a plist, giving defaults:</p>

<p>(example from Common Lisp Recipes, by E. Weitz, Apress, 2016)</p>

<pre><code class="language-lisp">(destructuring-bind (&amp;key a (b :not-found) c
                     &amp;allow-other-keys)
    ’(:c 23 :d &quot;D&quot; :a #\A :foo :whatever)
  (list a b c))
;; =&gt; (#\A :NOT-FOUND 23)
</code></pre>

<p>If this gives you the will to do pattern matching, see
<a href="pattern_matching.html">pattern matching</a>.</p>

<h3 id="predicates-null-listp">Predicates: null, listp</h3>

<p><code>null</code> is equivalent to <code>not</code>, but considered better style.</p>

<p><code>listp</code> tests wether an object is a cons cell or nil.</p>

<p>and sequences&rsquo; predicates.</p>

<h3 id="ldiff-tailp-list-make-list-fill-revappend-nreconc-consp-atom">ldiff, tailp, list*, make-list, fill, revappend, nreconc, consp, atom</h3>

<pre><code class="language-lisp">(make-list 3 :initial-element &quot;ta&quot;)
;; =&gt; (&quot;ta&quot; &quot;ta&quot; &quot;ta&quot;)
</code></pre>

<pre><code class="language-lisp">(make-list 3)
;; =&gt; (NIL NIL NIL)
(fill * &quot;hello&quot;)
;; =&gt; (&quot;hello&quot; &quot;hello&quot; &quot;hello&quot;)
</code></pre>

<h2 id="sequences">Sequences</h2>

<p><strong>lists</strong> and <strong>vectors</strong> (and thus <strong>strings</strong>) are sequences.</p>

<p><em>Note</em>: see also the <a href="https://lispcookbook.github.io/cl-cookbook/strings.html">strings</a> page.</p>

<p>Many of the sequence functions take keyword arguments. All keyword
arguments are optional and, if specified, may appear in any order.</p>

<p>Pay attention to the <code>:test</code> argument. It defaults to <code>eql</code> (for
strings, use <code>:equal</code>).</p>

<p>The <code>:key</code> argument should be passed either nil, or a function of one
argument. This key function is used as a filter through which the
elements of the sequence are seen. For instance, this:</p>

<pre><code class="language-lisp">(find x y :key 'car)
</code></pre>

<p>is similar to <code>(assoc* x y)</code>: It searches for an element of the list
whose car equals x, rather than for an element which equals x
itself. If <code>:key</code> is omitted or nil, the filter is effectively the
identity function.</p>

<p>Example with an alist (see definition below):</p>

<pre><code class="language-lisp">(defparameter my-alist (list (cons 'foo &quot;foo&quot;)
                             (cons 'bar &quot;bar&quot;)))
;; =&gt; ((FOO . &quot;foo&quot;) (BAR . &quot;bar&quot;))
(find 'bar my-alist)
;; =&gt; NIL
(find 'bar my-alist :key 'car)
;; =&gt; (BAR . &quot;bar&quot;)
</code></pre>

<p>For more, use a <code>lambda</code> that takes one parameter.</p>

<pre><code class="language-lisp">(find 'bar my-alist :key (lambda (it) (car it)))
</code></pre>

<p><em>Note</em>: and <a href="https://lispcookbook.github.io/cl-cookbook/cl21.html#shorter-lambda">cl21</a> has short lambdas:</p>

<pre><code class="language-lisp">(find 'bar my-alist :key ^(car %))
(find 'bar my-alist :key (lm (it) (car it)))
</code></pre>

<h3 id="predicates-every-some">Predicates: every, some,…</h3>

<p><code>every, notevery (test, sequence)</code>: return nil or t, respectively, as
soon as one test on any set of the corresponding elements of sequences
returns nil.</p>

<pre><code class="language-lisp">(defparameter foo '(1 2 3))
(every #'evenp foo)
;; =&gt; NIL
(some #'evenp foo)
;; =&gt; T
</code></pre>

<p>with a list of strings:</p>

<pre><code class="language-lisp">(defparameter str '(&quot;foo&quot; &quot;bar&quot; &quot;team&quot;))
(every #'stringp str)
;; =&gt; T
(some #'(lambda (it) (= 3 (length it))) str)
;; =&gt; T
(some ^(= 3 (length %)) str) ;; in CL21
;; =&gt; T
</code></pre>

<p><code>some</code>, <code>notany</code> <em>(test, sequence)</em>: return either the value of the test, or nil.</p>

<p><code>mismatch</code> <em>(sequence-a, sequence-b)</em>: Return position in sequence-a where
sequence-a and sequence-b begin to mismatch. Return NIL if they match
entirely. Other parameters: <code>:from-end bool</code>, <code>:start1</code>, <code>:start2</code> and
their <code>:end[1,2]</code>.</p>

<h3 id="functions">Functions</h3>

<p>See also sequence functions defined in
<a href="https://common-lisp.net/project/alexandria/draft/alexandria.html#Sequences">Alexandria</a>:
<code>starts-with</code>, <code>ends-with</code>, <code>ends-with-subseq</code>, <code>length=</code>, <code>emptyp</code>,…</p>

<h4 id="length-sequence">length (sequence)</h4>

<h4 id="member-elt-sequence">member (elt, sequence)</h4>

<h4 id="elt-sequence-index">elt (sequence, index)</h4>

<p>beware, here the sequence comes first.</p>

<h4 id="count-foo-sequence">count (foo sequence)</h4>

<p>Return the number of elements in sequence that match <em>foo</em>.</p>

<p>Additional paramaters: <code>:from-end</code>, <code>:start</code>, <code>:end</code>.</p>

<p>See also <code>count-if</code>, <code>count-not</code> <em>(test-function sequence)</em>.</p>

<h4 id="subseq-sequence-start-end">subseq (sequence start, [end])</h4>

<p>It is &ldquo;setf&rdquo;able, but only works if the new sequence has the same
length of the one to replace.</p>

<h4 id="sort-stable-sort-sequence-test-key-function">sort, stable-sort (sequence, test [, key function])</h4>

<h4 id="find-position-foo-sequence">find, position (foo, sequence)</h4>

<p>also <code>find-if</code>, <code>find-if-not</code>, <code>position-if</code>, <code>position-if-not</code> <em>(test
sequence)</em>. See <code>:key</code> and <code>:test</code> parameters.</p>

<h4 id="search-sequence-a-sequence-b">search (sequence-a, sequence-b)</h4>

<p>Search sequence-b for a subsequence matching sequence-a. Return
position in sequence-b, or NIL. Has the <code>from-end</code>, <code>end1/2</code> and others
parameters.</p>

<h4 id="substitute-nsubstitute-if-if-not">substitute, nsubstitute[if,if-not]</h4>

<h4 id="sort-stable-sort-merge">sort, stable-sort, merge</h4>

<h4 id="replace-sequence-a-sequence-b">replace (sequence-a, sequence-b)</h4>

<p>Replace elements of sequence-a with elements of
sequence-b.</p>

<h4 id="remove-delete-foo-sequence">remove, delete (foo sequence)</h4>

<p>Make a copy of sequence without elements matching foo. Has
<code>:start/end</code>, <code>:key</code> and <code>:count</code> parameters.</p>

<p><code>delete</code> is the recycling version of <code>remove</code>.</p>

<pre><code class="language-lisp">(remove &quot;foo&quot; '(&quot;foo&quot; &quot;bar&quot; &quot;foo&quot;) :test 'equal)
;; =&gt; (&quot;bar&quot;)
</code></pre>

<p>see also <code>remove-if[-not]</code> below.</p>

<h3 id="mapping-map-mapcar-remove-if-not">mapping (map, mapcar, remove-if[-not],&hellip;)</h3>

<p>If you&rsquo;re used to map and filter in other languages, you probably want
<code>mapcar</code>. But it only works on lists, so to iterate on vectors (and
produce either a vector or a list, use <code>(map 'list function vector)</code>.</p>

<p>mapcar also accepts multiple lists with <code>&amp;rest more-seqs</code>.  The
mapping stops as soon as the shortest sequence runs out.</p>

<p><em>Note: cl21&rsquo;s <code>map</code> is a generic <code>mapcar</code> for lists and vectors.</em></p>

<p><code>map</code> takes the output-type as first argument (<code>'list</code>, <code>'vector</code> or
<code>'string</code>):</p>

<pre><code class="language-lisp">(defparameter foo '(1 2 3))
(map 'list (lambda (it) (* 10 it)) foo)
</code></pre>

<p><code>reduce</code> <em>(function, sequence)</em>. Special parameter: <code>:initial-value</code>.</p>

<pre><code class="language-lisp">(reduce '- '(1 2 3 4))
;; =&gt; -8
(reduce '- '(1 2 3 4) :initial-value 100)
;; =&gt; 90
</code></pre>

<p><strong>Filter</strong> is here called <code>remove-if-not</code>.</p>

<h3 id="flatten-a-list-alexandria">Flatten a list (Alexandria)</h3>

<p>With
<a href="https://common-lisp.net/project/alexandria/draft/alexandria.html">Alexandria</a>,
we have the <code>flatten</code> function.</p>

<h3 id="creating-lists-with-variables">Creating lists with variables</h3>

<p>That&rsquo;s one use of the <code>backquote</code>:</p>

<pre><code class="language-lisp">(defparameter *var* &quot;bar&quot;)
;; First try:
'(&quot;foo&quot; *var* &quot;baz&quot;) ;; no backquote
;; =&gt; (&quot;foo&quot; *VAR* &quot;baz&quot;) ;; nope
</code></pre>

<p>Second try, with backquote interpolation:</p>

<pre><code class="language-lisp">`(&quot;foo&quot; ,*var* &quot;baz&quot;)     ;; backquote, comma
;; =&gt; (&quot;foo&quot; &quot;bar&quot; &quot;baz&quot;) ;; good
</code></pre>

<p>The backquote first warns we&rsquo;ll do interpolation, the comma introduces
the value of the variable.</p>

<p>If our variable is a list:</p>

<pre><code class="language-lisp">(defparameter *var* '(&quot;bar&quot; &quot;baz&quot;))
;; First try:
`(&quot;foo&quot; ,*var*)
;; =&gt; (&quot;foo&quot; (&quot;bar&quot; &quot;baz&quot;)) ;; nested list
`(&quot;foo&quot; ,@*var*)            ;; backquote, comma-@ to
;; =&gt; (&quot;foo&quot; &quot;bar&quot; &quot;baz&quot;)
</code></pre>

<p>E. Weitz warns that &ldquo;objects generated this way will very likely share
structure (see Recipe 2-7)&ldquo;.</p>

<h3 id="comparing-lists">Comparing lists</h3>

<p>We can use sets functions.</p>

<h2 id="set">Set</h2>

<p><code>intersection</code></p>

<p>What elements are both in list-a and list-b ?</p>

<pre><code class="language-lisp">(defparameter list-a '(0 1 2 3))
(defparameter list-b '(0 2 4))
(intersection list-a list-b)
;; =&gt; (2 0)
</code></pre>

<p><code>set-difference</code></p>

<p>Remove the elements of list-b from list-a:</p>

<pre><code class="language-lisp">(set-difference list-a list-b)
;; =&gt; (3 1)
(set-difference list-b list-a)
;; =&gt; (4)
</code></pre>

<p><code>union</code></p>

<p>join the two lists:</p>

<pre><code class="language-lisp">(union list-a list-b)
;; =&gt; (3 1 0 2 4) ;; order can be different in your lisp
</code></pre>

<p><code>set-exclusive-or</code></p>

<p>Remove the elements that are in both lists:</p>

<pre><code class="language-lisp">(set-exclusive-or list-a list-b)
;; =&gt; (4 3 1)
</code></pre>

<p>and their recycling &ldquo;n&rdquo; counterpart (<code>nintersection</code>,…).</p>

<p>See also functions in
<a href="https://common-lisp.net/project/alexandria/draft/alexandria.html#Conses">Alexandria</a>:
<code>setp</code>, <code>set-equal</code>,…</p>

<h2 id="fset-immutable-data-structure">Fset - immutable data structure</h2>

<p>You may want to have a look at the
<a href="https://common-lisp.net/project/fset/Site/FSet-Tutorial.html">FSet</a>
library (in Quicklisp).</p>

<h2 id="arrays-and-vectors">Arrays and vectors</h2>

<p><strong>Arrays</strong> have constant-time access characteristics.</p>

<p>They can be fixed or adjustable. A <em>simple array</em> is neither displaced
(using <code>:displaced-to</code>, to point to another array) nor adjustable
(<code>:adjust-array</code>), nor does it have a fill pointer (<code>fill-pointer</code>,
that moves when we add or remove elements).</p>

<p>A <strong>vector</strong> is an array with rank 1 (of one dimension). It is also a
<em>sequence</em> (see above).</p>

<p>A <em>simple vector</em> is a simple array that is also not specialized (it
doesn&rsquo;t use <code>:element-type</code> to set the types of the elements).</p>

<h3 id="create-an-array-one-or-many-dimensions">Create an array, one or many dimensions</h3>

<p><code>make-array</code> <em>(sizes-list :adjustable bool)</em></p>

<p><code>adjust-array</code> <em>(array, sizes-list, :element-type, :initial-element)</em></p>

<h3 id="access-aref-array-i-j">Access: aref (array i [j …])</h3>

<p><code>aref</code> <em>(array i j k …)</em> or <code>row-major-aref</code> <em>(array i)</em> equivalent to
<code>(aref i i i …)</code>.</p>

<p>The result is <code>setf</code>able.</p>

<pre><code class="language-lisp">(defparameter myarray (make-array '(2 2 2) :initial-element 1))
myarray
;; =&gt; #3A(((1 1) (1 1)) ((1 1) (1 1)))
(aref myarray 0 0 0)
;; =&gt; 1
(setf (aref myarray 0 0 0) 9)
;; =&gt; 9
(row-major-aref myarray 0)
;; =&gt; 9
</code></pre>

<h3 id="sizes">Sizes</h3>

<p><code>array-total-size</code> <em>(array)</em>: how many elements will fit in the array ?</p>

<p><code>array-dimensions</code> <em>(array)</em>: list containing the length of the array&rsquo;s dimensions.</p>

<p><code>array-dimension</code> <em>(array i)</em>: length of the *i*th dimension.</p>

<p><code>array-rank</code> number of dimensions of the array.</p>

<pre><code class="language-lisp">(defparameter myarray (make-array '(2 2 2)))
;; =&gt; MYARRAY
myarray
;; =&gt; #3A(((0 0) (0 0)) ((0 0) (0 0)))
(array-rank myarray)
;; =&gt; 3
(array-dimensions myarray)
;; =&gt; (2 2 2)
(array-dimension myarray 0)
;; =&gt; 2
(array-total-size myarray)
;; =&gt; 8
</code></pre>

<h3 id="vectors">Vectors</h3>

<p>Create with <code>vector</code> or the reader macro <code>#()</code>. It returns a <em>simple
vector.</em></p>

<pre><code class="language-lisp">(vector 1 2 3)
;; =&gt; #(1 2 3)
#(1 2 3)
;; =&gt; #(1 2 3)
</code></pre>

<p><code>vector-push</code> <em>(foo vector)</em>: replace the vector element pointed to by
the fill pointer by foo. Can be destructive.</p>

<p><code>vector-push-extend</code> *(foo vector [extension-num])*t</p>

<p><code>vector-pop</code> <em>(vector)</em>: return the element of vector its fill pointer
points to.</p>

<p><code>fill-pointer</code> <em>(vector)</em>. <code>setf</code>able.</p>

<p>and see also the <em>sequence</em> functions.</p>

<h3 id="transforming-a-vector-to-a-list">Transforming a vector to a list.</h3>

<p>If you&rsquo;re mapping over it, see the <code>map</code> function whose first parameter
is the result type.</p>

<p>Or use <code>(coerce vector 'list)</code>.</p>

<h2 id="hash-table">Hash Table</h2>

<p>Hash Tables are a powerful data structure, associating keys with
values in a very efficient way. Hash Tables are often preferred over
association lists whenever performance is an issue, but they introduce
a little overhead that makes assoc lists better if there are only a
few key-value pairs to maintain.</p>

<p>Alists can be used sometimes differently though:</p>

<ul>
<li>they can be ordered</li>
<li>we can push cons cells that have the same key, remove the one in
front and we have a stack</li>
<li>they have a human-readable printed representation</li>
<li>they can be easily (de)serialized</li>
<li>because of RASSOC, keys and values in alists are essentially
interchangeable; whereas in hash tables, keys and values play very
different roles (as usual, see CL Recipes for more).</li>
</ul>

<p><a name="create"></a></p>

<h3 id="creating-a-hash-table">Creating a Hash Table</h3>

<p>Hash Tables are created using the function
<a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_mk_has.htm"><code>make-hash-table</code></a>. It
has no required argument. Its most used optional keyword argument is
<code>:test</code>, specifying the function used to test the equality of keys.</p>

<p>If we are using the <a href="http://cl21.org/">cl21</a> extension library, we can
create a hash table and add elements in the same time with the new
<code>#H</code> reader syntax:</p>

<pre><code class="language-lisp">(defparameter *my-hash* #H(:name &quot;Eitaro Fukamachi&quot;))
</code></pre>

<p>then we access an element with</p>

<pre><code class="language-lisp">(getf *my-hash* :name)
</code></pre>

<p><a name="get"></a></p>

<h3 id="getting-a-value-from-a-hash-table">Getting a value from a Hash Table</h3>

<p>The function
<a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_gethas.htm"><code>gethash</code></a>
takes two required arguments: a key and a hash table. It returns two
values: the value corresponding to the key in the hash table (or <code>nil</code>
if not found), and a boolean indicating whether the key was found in
the table. That second value is necessary since <code>nil</code> is a valid value
in a key-value pair, so getting <code>nil</code> as first value from <code>gethash</code>
does not necessarily mean that the key was not found in the table.</p>

<h4 id="getting-a-key-that-does-not-exist-with-a-default-value">Getting a key that does not exist with a default value</h4>

<p><code>gethash</code> has an optional third argument:</p>

<pre><code class="language-lisp">(gethash 'bar *my-hash* &quot;default-bar&quot;)
;; =&gt; &quot;default-bar&quot;
;;     NIL
</code></pre>

<h4 id="getting-all-keys-or-all-values-of-a-hash-table">Getting all keys or all values of a hash table</h4>

<p>The
<a href="https://common-lisp.net/project/alexandria/draft/alexandria.html">Alexandria</a>
library (in Quicklisp) has the functions <code>hash-table-keys</code> and
<code>hash-table-values</code> for that.</p>

<pre><code class="language-lisp">(ql:quickload :alexandria)
;; […]
(alexandria:hash-table-keys *my-hash*)
;; =&gt; (BAR)
</code></pre>

<p><a name="add"></a></p>

<h3 id="adding-an-element-to-a-hash-table">Adding an Element to a Hash Table</h3>

<p>If you want to add an element to a hash table, you can use <code>gethash</code>,
the function to retrieve elements from the hash table, in conjunction
with
<a href="http://www.lispworks.com/documentation/HyperSpec/Body/m_setf_.htm"><code>setf</code></a>.</p>

<pre><code class="language-lisp">CL-USER&gt; (defparameter *my-hash* (make-hash-table))
*MY-HASH*
CL-USER&gt; (setf (gethash 'one-entry *my-hash*) &quot;one&quot;)
&quot;one&quot;
CL-USER&gt; (setf (gethash 'another-entry *my-hash*) 2/4)
1/2
CL-USER&gt; (gethash 'one-entry *my-hash*)
&quot;one&quot;
T
CL-USER&gt; (gethash 'another-entry *my-hash*)
1/2
T
</code></pre>

<p><a name="test"></a></p>

<h3 id="testing-for-the-presence-of-a-key-in-a-hash-table">Testing for the Presence of a Key in a Hash Table</h3>

<p>The first value returned by <code>gethash</code> is the object in the hash table
that&rsquo;s associated with the key you provided as an argument to
<code>gethash</code> or <code>nil</code> if no value exists for this key. This value can act
as a
<a href="http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_g.htm#generalized_boolean&quot;&gt;generalized
boolean">generalized boolean</a> if you want to test for the presence of keys.</p>

<pre><code class="language-lisp">CL-USER&gt; (defparameter *my-hash* (make-hash-table))
*MY-HASH*
CL-USER&gt; (setf (gethash 'one-entry *my-hash*) &quot;one&quot;)
&quot;one&quot;
CL-USER&gt; (if (gethash 'one-entry *my-hash*)
           &quot;Key exists&quot;
           &quot;Key does not exist&quot;)
&quot;Key exists&quot;
CL-USER&gt; (if (gethash 'another-entry *my-hash*)
           &quot;Key exists&quot;
           &quot;Key does not exist&quot;)
&quot;Key does not exist&quot;
</code></pre>

<p>But note that this does <em>not</em> work if <code>nil</code> is amongst the values that
you want to store in the hash.</p>

<pre><code class="language-lisp">CL-USER&gt; (setf (gethash 'another-entry *my-hash*) nil)
NIL
CL-USER&gt; (if (gethash 'another-entry *my-hash*)
           &quot;Key exists&quot;
           &quot;Key does not exist&quot;)
&quot;Key does not exist&quot;
</code></pre>

<p>In this case you&rsquo;ll have to check the <em>second</em> return value of <code>gethash</code> which will always return <code>nil</code> if no value is found and T otherwise.</p>

<pre><code class="language-lisp">CL-USER&gt; (if (nth-value 1 (gethash 'another-entry *my-hash*))
           &quot;Key exists&quot;
           &quot;Key does not exist&quot;)
&quot;Key exists&quot;
CL-USER&gt; (if (nth-value 1 (gethash 'no-entry *my-hash*))
           &quot;Key exists&quot;
           &quot;Key does not exist&quot;)
&quot;Key does not exist&quot;
</code></pre>

<p><a name="del"></a></p>

<h3 id="deleting-from-a-hash-table">Deleting from a Hash Table</h3>

<p>Use
<a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_remhas.htm"><code>remhash</code></a>
to delete a hash entry. Both the key and its associated value will be
removed from the hash table. <code>remhash</code> returns T if there was such an
entry, <code>nil</code> otherwise.</p>

<pre><code class="language-lisp">CL-USER&gt; (defparameter *my-hash* (make-hash-table))
*MY-HASH*
CL-USER&gt; (setf (gethash 'first-key *my-hash*) 'one)
ONE
CL-USER&gt; (gethash 'first-key *my-hash*)
ONE
T
CL-USER&gt; (remhash 'first-key *my-hash*)
T
CL-USER&gt; (gethash 'first-key *my-hash*)
NIL
NIL
CL-USER&gt; (gethash 'no-entry *my-hash*)
NIL
NIL
CL-USER&gt; (remhash 'no-entry *my-hash*)
NIL
CL-USER&gt; (gethash 'no-entry *my-hash*)
NIL
NIL
</code></pre>

<p><a name="traverse"></a></p>

<h3 id="traversing-a-hash-table">Traversing a Hash Table</h3>

<p>If you want to perform an action on each entry (i.e., each key-value
pair) in a hash table, you have several options:</p>

<p>You can use
<a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_maphas.htm"><code>maphash</code></a>
which iterates over all entries in the hash table. Its first argument
must be a function which accepts <em>two</em> arguments, the key and the
value of each entry. Note that due to the nature of hash tables you
<em>can&rsquo;t</em> control the order in which the entries are provided by
<code>maphash</code> (or other traversing constructs). <code>maphash</code> always returns
<code>nil</code>.</p>

<pre><code class="language-lisp">CL-USER&gt; (defparameter *my-hash* (make-hash-table))
*MY-HASH*
CL-USER&gt; (setf (gethash 'first-key *my-hash*) 'one)
ONE
CL-USER&gt; (setf (gethash 'second-key *my-hash*) 'two)
TWO
CL-USER&gt; (setf (gethash 'third-key *my-hash*) nil)
NIL
CL-USER&gt; (setf (gethash nil *my-hash*) 'nil-value)
NIL-VALUE
CL-USER&gt; (defun print-hash-entry (key value)
    (format t &quot;The value associated with the key ~S is ~S~%&quot; key value))
PRINT-HASH-ENTRY
CL-USER&gt; (maphash #'print-hash-entry *my-hash*)
The value associated with the key FIRST-KEY is ONE
The value associated with the key SECOND-KEY is TWO
The value associated with the key THIRD-KEY is NIL
The value associated with the key NIL is NIL-VALUE
</code></pre>

<p>You can also use
<a href="http://www.lispworks.com/documentation/HyperSpec/Body/m_w_hash.htm"><code>with-hash-table-iterator</code></a>,
a macro which turns (via
<a href="http://www.lispworks.com/documentation/HyperSpec/Body/s_flet_.htm"><code>macrolet</code></a>)
its first argument into an iterator that on each invocation returns
three values per hash table entry - a generalized boolean that&rsquo;s true
if an entry is returned, the key of the entry, and the value of the
entry. If there are no more entries, only one value is returned -
<code>nil</code>.</p>

<pre><code class="language-lisp">;;; same hash-table as above
CL-USER&gt; (with-hash-table-iterator (my-iterator *my-hash*)
           (loop
              (multiple-value-bind (entry-p key value)
                  (my-iterator)
                (if entry-p
                    (print-hash-entry key value)
                    (return)))))
The value associated with the key FIRST-KEY is ONE
The value associated with the key SECOND-KEY is TWO
The value associated with the key THIRD-KEY is NIL
The value associated with the key NIL is NIL-VALUE
NIL
</code></pre>

<p>Note the following caveat from the HyperSpec: &ldquo;It is unspecified what
happens if any of the implicit interior state of an iteration is
returned outside the dynamic extent of the <code>with-hash-table-iterator</code>
form such as by returning some closure over the invocation form.&rdquo;</p>

<p>And there&rsquo;s always <a href="http://www.lispworks.com/documentation/HyperSpec/Body/06_a.htm"><code>loop</code></a>:</p>

<pre><code class="language-lisp">;;; same hash-table as above
CL-USER&gt; (loop for key being the hash-keys of *my-hash*
           do (print key))
FIRST-KEY
SECOND-KEY
THIRD-KEY
NIL
NIL
CL-USER&gt; (loop for key being the hash-keys of *my-hash*
           using (hash-value value)
           do (format t &quot;The value associated with the key ~S is ~S~%&quot; key value))
The value associated with the key FIRST-KEY is ONE
The value associated with the key SECOND-KEY is TWO
The value associated with the key THIRD-KEY is NIL
The value associated with the key NIL is NIL-VALUE
NIL
CL-USER&gt; (loop for value being the hash-values of *my-hash*
           do (print value))
ONE
TWO
NIL
NIL-VALUE
NIL
CL-USER&gt; (loop for value being the hash-values of *my-hash*
           using (hash-key key)
           do (format t &quot;~&amp;~A -&gt; ~A&quot; key value))
FIRST-KEY -&gt; ONE
SECOND-KEY -&gt; TWO
THIRD-KEY -&gt; NIL
NIL -&gt; NIL-VALUE
NIL
</code></pre>

<p>Last, we also have <a href="cl21.htm">cl21</a>&rsquo;s <code>(doeach ((key val) *hash*) …)</code>.</p>

<h4 id="traversign-keys-or-values">Traversign keys or values</h4>

<p>To map over keys or values we can again rely on Alexandria with
<code>maphash-keys</code> and <code>maphash-values</code>.</p>

<p><a name="count"></a></p>

<h3 id="counting-the-entries-in-a-hash-table">Counting the Entries in a Hash Table</h3>

<p>No need to use your fingers - Common Lisp has a built-in function to
do it for you:
<a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_hash_1.htm"><code>hash-table-count</code></a>.</p>

<pre><code class="language-lisp">CL-USER&gt; (defparameter *my-hash* (make-hash-table))
*MY-HASH*
CL-USER&gt; (hash-table-count *my-hash*)
0
CL-USER&gt; (setf (gethash 'first *my-hash*) 1)
1
CL-USER&gt; (setf (gethash 'second *my-hash*) 2)
2
CL-USER&gt; (setf (gethash 'third *my-hash*) 3)
3
CL-USER&gt; (hash-table-count *my-hash*)
3
CL-USER&gt; (setf (gethash 'second *my-hash*) 'two)
TWO
CL-USER&gt; (hash-table-count *my-hash*)
3
CL-USER&gt; (clrhash *my-hash*)
#&lt;EQL hash table, 0 entries {48205F35}&gt;
CL-USER&gt; (hash-table-count *my-hash*)
0
</code></pre>

<p><a name="size"></a></p>

<h3 id="performance-issues-the-size-of-your-hash-table">Performance Issues: The Size of your Hash Table</h3>

<p>The <code>make-hash-table</code> function has a couple of optional parameters
which control the initial size of your hash table and how it&rsquo;ll grow
if it needs to grow. This can be an important performance issue if
you&rsquo;re working with large hash tables. Here&rsquo;s an (admittedly not very
scientific) example with <a href="http://www.cons.org/cmucl">CMUCL</a> pre-18d on
Linux:</p>

<pre><code class="language-lisp">CL-USER&gt; (defparameter *my-hash* (make-hash-table))
*MY-HASH*
CL-USER&gt; (hash-table-size *my-hash*)
65
CL-USER&gt; (hash-table-rehash-size *my-hash*)
1.5
CL-USER&gt; (time (dotimes (n 100000) (setf (gethash n *my-hash*) n)))
Compiling LAMBDA NIL:
Compiling Top-Level Form:

Evaluation took:
  0.27 seconds of real time
  0.25 seconds of user run time
  0.02 seconds of system run time
  0 page faults and
  8754768 bytes consed.
NIL
CL-USER&gt; (time (dotimes (n 100000) (setf (gethash n *my-hash*) n)))
Compiling LAMBDA NIL:
Compiling Top-Level Form:

Evaluation took:
  0.05 seconds of real time
  0.05 seconds of user run time
  0.0 seconds of system run time
  0 page faults and
  0 bytes consed.
NIL
</code></pre>

<p>The values for
<a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_hash_4.htm"><code>hash-table-size</code></a>
and
<a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_hash_2.htm"><code>hash-table-rehash-size</code></a>
are implementation-dependent. In our case, CMUCL chooses and initial
size of 65, and it will increase the size of the hash by 50 percent
whenever it needs to grow. Let&rsquo;s see how often we have to re-size the
hash until we reach the final size&hellip;</p>

<pre><code class="language-lisp">CL-USER&gt; (log (/ 100000 65) 1.5)
18.099062
CL-USER&gt; (let ((size 65)) (dotimes (n 20) (print (list n size)) (setq size (* 1.5 size))))
(0 65)
(1 97.5)
(2 146.25)
(3 219.375)
(4 329.0625)
(5 493.59375)
(6 740.3906)
(7 1110.5859)
(8 1665.8789)
(9 2498.8184)
(10 3748.2275)
(11 5622.3413)
(12 8433.512)
(13 12650.268)
(14 18975.402)
(15 28463.104)
(16 42694.656)
(17 64041.984)
(18 96062.98)
(19 144094.47)
NIL
</code></pre>

<p>The hash has to be re-sized 19 times until it&rsquo;s big enough to hold
100,000 entries. That explains why we saw a lot of consing and why it
took rather long to fill the hash table. It also explains why the
second run was much faster - the hash table already had the correct
size.</p>

<p>Here&rsquo;s a faster way to do it:
If we know in advance how big our hash will be, we can start with the right size:</p>

<pre><code class="language-lisp">CL-USER&gt; (defparameter *my-hash* (make-hash-table :size 100000))
*MY-HASH*
CL-USER&gt; (hash-table-size *my-hash*)
100000
CL-USER&gt; (time (dotimes (n 100000) (setf (gethash n *my-hash*) n)))
Compiling LAMBDA NIL:
Compiling Top-Level Form:

Evaluation took:
  0.04 seconds of real time
  0.04 seconds of user run time
  0.0 seconds of system run time
  0 page faults and
  0 bytes consed.
NIL
</code></pre>

<p>That&rsquo;s obviously much faster. And there was no consing involved
because we didn&rsquo;t have to re-size at all. If we don&rsquo;t know the final
size in advance but can guess the growth behaviour of our hash table
we can also provide this value to <code>make-hash-table</code>. We can provide an
integer to specify absolute growth or a float to specify relative
growth.</p>

<pre><code class="language-lisp">CL-USER&gt; (defparameter *my-hash* (make-hash-table :rehash-size 100000))
*MY-HASH*
CL-USER&gt; (hash-table-size *my-hash*)
65
CL-USER&gt; (hash-table-rehash-size *my-hash*)
100000
CL-USER&gt; (time (dotimes (n 100000) (setf (gethash n *my-hash*) n)))
Compiling LAMBDA NIL:
Compiling Top-Level Form:

Evaluation took:
  0.07 seconds of real time
  0.05 seconds of user run time
  0.01 seconds of system run time
  0 page faults and
  2001360 bytes consed.
NIL
</code></pre>

<p>Also rather fast (we only needed one re-size) but much more consing
because almost the whole hash table (minus 65 initial elements) had to
be built during the loop.</p>

<p>Note that you can also specify the <code>rehash-threshold</code> while creating a
new hash table. One final remark: Your implementation is allowed to
<em>completely ignore</em> the values provided for <code>rehash-size</code> and
<code>rehash-threshold</code>&hellip;</p>

<h2 id="alist">Alist</h2>

<p>An association list is a list of cons cells.</p>

<p>This simple example:</p>

<pre><code class="language-lisp">(defparameter my-alist (list (cons 'foo &quot;foo&quot;)
                             (cons 'bar &quot;bar&quot;)))
;; =&gt; ((FOO . &quot;foo&quot;) (BAR . &quot;bar&quot;))
</code></pre>

<p>looks like this:</p>

<pre><code>[o|o]---[o|/]
 |       |
 |      [o|o]---&quot;bar&quot;
 |       |
 |      BAR
 |
[o|o]---&quot;foo&quot;
 |
FOO
</code></pre>

<p>The constructor <code>pairlis</code> associates a list of keys and a list of values:</p>

<pre><code class="language-lisp">(pairlis '(:foo :bar)
         '(&quot;foo&quot; &quot;bar&quot;))
;; =&gt; ((:BAR . &quot;bar&quot;) (:FOO . &quot;foo&quot;))
</code></pre>

<p>To get a key, we have <code>assoc</code> (use <code>:test 'equal</code> when your keys are
strings, as usual). It returns the whole cons cell, so you may want to
use <code>cdr</code> or <code>second</code> to get the value. There is <code>assoc-if</code>, and
<code>rassoc</code> to get a cons cell by its value.</p>

<p>To add a key, we <code>push</code> another cons cell:</p>

<pre><code class="language-lisp">(push (cons 'team &quot;team&quot;) my-alist)
;; =&gt; ((TEAM . &quot;team&quot;) (FOO . &quot;foo&quot;) (BAR . &quot;bar&quot;))
</code></pre>

<p>We can use <code>pop</code> and other functions that operate on lists, like <code>remove</code>:</p>

<pre><code class="language-lisp">(remove :team my-alist)
;; =&gt; ((:TEAM . &quot;team&quot;) (FOO . &quot;foo&quot;) (BAR . &quot;bar&quot;)) ;; didn't remove anything
(remove :team my-alist :key 'car)
;; =&gt; ((FOO . &quot;foo&quot;) (BAR . &quot;bar&quot;)) ;; returns a copy
</code></pre>

<p>Remove only one element with <code>:count</code>:</p>

<pre><code class="language-lisp">(push (cons 'bar &quot;bar2&quot;) my-alist)
;; =&gt; ((BAR . &quot;bar2&quot;) (TEAM . &quot;team&quot;) (FOO . &quot;foo&quot;) (BAR . &quot;bar&quot;)) ;; twice the 'bar key
(remove 'bar my-alist :key 'car :count 1)
;; =&gt; ((TEAM . &quot;team&quot;) (FOO . &quot;foo&quot;) (BAR . &quot;bar&quot;))
;; because otherwise:
(remove 'bar my-alist :key 'car)
;; =&gt; ((TEAM . &quot;team&quot;) (FOO . &quot;foo&quot;)) ;; no more 'bar
</code></pre>

<p>In the
<a href="https://common-lisp.net/project/alexandria/draft/alexandria.html#Conses">Alexandria</a>
library, see some functions like <code>remove-from-plist</code>, <code>alist-plist</code>,…</p>

<h2 id="plist">Plist</h2>

<p>A property list is simply a list that alternates a key, a value, and
so on, where its keys are symbols (we can not set its <code>:test</code>). More
precisely, it first has a cons cell whose <code>car</code> is the key, whose
<code>cdr</code> points to the following cons cell whose <code>car</code> is the
value.</p>

<p>For example this plist:</p>

<pre><code class="language-lisp">(defparameter my-plist (list 'foo &quot;foo&quot; 'bar &quot;bar&quot;))
</code></pre>

<p>looks like this:</p>

<pre><code>[o|o]---[o|o]---[o|o]---[o|/]
 |       |       |       |
FOO     &quot;foo&quot;   BAR     &quot;bar&quot;

</code></pre>

<p>We access an element with <code>getf (list elt)</code> (it returns the value)
(the list comes as first element),</p>

<p>we remove an element with <code>remf</code>.</p>

<pre><code class="language-lisp">(defparameter my-plist (list 'foo &quot;foo&quot; 'bar &quot;bar&quot;))
;; =&gt; (FOO &quot;foo&quot; BAR &quot;bar&quot;)
(setf (getf my-plist 'foo) &quot;foo!!!&quot;)
;; =&gt; &quot;foo!!!&quot;
</code></pre>

<h2 id="tree">Tree</h2>

<p><code>tree-equal</code>, <code>copy-tree</code>. They descend recursively into the car and
the cdr of the cons cells they visit.</p>

<h3 id="sycamore-purely-functional-weight-balanced-binary-trees">Sycamore - purely functional weight-balanced binary trees</h3>

<p><a href="https://github.com/ndantam/sycamore">https://github.com/ndantam/sycamore</a></p>

<p>Features:</p>

<ul>
<li>Fast, purely functional weight-balanced binary trees.

<ul>
<li>Leaf nodes are simple-vectors, greatly reducing tree height.</li>
</ul></li>
<li>Interfaces for tree Sets and Maps (dictionaries).</li>
<li><a href="http://en.wikipedia.org/wiki/Rope_(data_structure)">Ropes</a></li>
<li>Purely functional <a href="http://en.wikipedia.org/wiki/Pairing_heap">pairing heaps</a></li>
<li>Purely functional amortized queue.</li>
</ul>

<p>See more in other resources !</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/55-programmer-walks-into-bar.png" alt="A Programmer Walks Into A Bar">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">A Programmer Walks Into A Bar</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">26 07 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/55-programmer-walks-into-bar.png" alt="Such waste of empty space" title="Such waste of empty space" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="Fingerprinting">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Fingerprinting</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">21 07 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Let me tell you what's unique about your device.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="How facebook knows exactly what turns you on">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">How facebook knows exactly what turns you on</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">21 07 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A technical analysis of the methods used to track users as a third party. Deep dive into a couple of case studies.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="Tracker Categories">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Tracker Categories</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">21 07 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Definitions for different types of trackers
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="Where does the data come from?">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Where does the data come from?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">21 07 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        An explanation of the origin of the data in this site, and why its collection is private.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="Tracking Pixel">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Tracking Pixel</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">21 07 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        So, ... did you read my email?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="What is a tracker?">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">What is a tracker?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">21 07 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Explaining what makes a particular domain a  tracker
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="Cookies">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cookies</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">21 07 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A small piece of data sent from a website, meant to 'help', used to track.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://whotracks.me/static/img/who-tracksme-logo.png" alt="How Cliqz anti-tracking protects users">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">How Cliqz anti-tracking protects users</h1>
                            <h2 class="article__feed"><a target="_blank" href="">WhoTracksMe blog</a> <span class="article__date">21 07 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Using an algorithmic, data-driven approach to remove unique identifiers that track users.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Simplify Golang test fixtures with this one weird trick</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">20 07 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        When testing code, test functions may depend on some external dependency. For example, if we have written a:
 Web crawler, we may want to test it on a real website Web server, we may want to test GET methods against a real database  Test fixtures are functions which launch the external dependencies our test code requires.
Say we&rsquo;re writing a web crawler and want to test it against a real website.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">PSA: cp -r behaves differently on linux and macOS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">20 07 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Today I found out (the hard way) that the GNU (available on linux) and BSD (available on macOS) implementations of cp behave differently when used to recursively copy.
The differing behaviour comes when running cp with the -r flag on a source directory that ends with a slash (/):
 GNU/linux: copy the whole directory BSD/macOS: copy the contents of the directory  While this is documented behaviour (see man pages below), it can lead to unwanted behaviour if you develop on a mac and build on a linux-based CI system.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/54-bottom-of-backlog.png" alt="Bottom of the backlog">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Bottom of the backlog</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">18 07 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/54-bottom-of-backlog.png" alt="If you see this you've gone too far" title="If you see this you've gone too far" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Investigating tries: writing a spell-checking algorithm</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">16 07 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        This article walks through writing a spell-checking algorithm, making use of a neat data structure called a trie, which is particularly suited to the problem.
We will look at:
 The spell-checking problem and naive solutions What a trie is and how it can offer us a better solution The trie-based solution Analysis of our solution How our solution can be improved Other problems that can be solved with tries  Problem We wish to write a spell-checking algorithm which should return a boolean indicating whether the word might be valid or not.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/53-big-decisions.png" alt="Big Decisions">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Big Decisions</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">10 07 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/53-big-decisions.png" alt="Forget Global Warming" title="Forget Global Warming" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to Manage Concurrency in Django Models</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">06 07 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The days of desktop systems serving single users are long gone. Web applications nowadays are serving millions of users at the same time. With many users comes a wide range of new problems: concurrency problems. In this article we describe two approaches for managing concurrency in Django models.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Microplásticos, enemigos del mar (III)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">04 07 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/52-npm-delivery.png" alt="NPM Delivery">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">NPM Delivery</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">04 07 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/52-npm-delivery.png" alt="Relax, it's NPM" title="Relax, it's NPM" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://www.monstruosfelices.es/legiondelespacio/wp-content/uploads/2016/10/cropped-banner-32x32.jpg" alt="Cuentidubi: la app de los cuentos infantiles">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cuentidubi: la app de los cuentos infantiles</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Legión del Espacio</a> <span class="article__date">03 07 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Si os gusta el trabajo que hacemos en La legión del espacio, también os gustará nuestro proyecto dedicados a los libros infantiles ilustrados. Cuentidubi es una app con cuentos infantiles ilustrados, gratis, y preparada para leer a los más pequeños antes de ir a dormir. Un proyecto de libros infantiles de los Hermanos Grimm, Perrault [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Common Lisp Async Web Scraping</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">29 06 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>The set of tools to do web scraping in Common Lisp is pretty complete
and pleasant. In this short tutorial we&rsquo;ll see how to make http
requests, parse html, extract content and do asynchronous requests.</p>

<p>Our simple task will be to extract the list of links on the CL
Cookbook&rsquo;s index page and check if they are reachable.</p>

<p><em>Best read in <a href="https://lispcookbook.github.io/cl-cookbook/web-scraping.html">the Cookbook</a> !</em></p>

<p>We&rsquo;ll use the following libraries:</p>

<ul>
<li><a href="https://github.com/fukamachi/dexador">Dexador</a> - an HTTP client
(that aims at replacing the venerable Drakma),</li>
<li><a href="https://shinmera.github.io/plump/">Plump</a> - a markup parser, that works on malformed HTML,</li>
<li><a href="https://shinmera.github.io/lquery/">Lquery</a> - a DOM manipulation
library, to extract content from our Plump result,</li>
<li><a href="https://lparallel.org/pmap-family/">lparallel</a> -  a library for parallel programming (read more in the <a href="process.html">process section</a>).</li>
</ul>

<p>Before starting let&rsquo;s install those libraries with Quicklisp:</p>

<pre><code class="language-lisp">(ql:quickload '(:dexador :plump :lquery :lparallel))
</code></pre>

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-generate-toc again -->

<p><strong>Table of Contents</strong></p>

<ul>
<li><a href="#http-requests">HTTP Requests</a></li>
<li><a href="#parsing-and-extracting-content-with-css-selectors">Parsing and extracting content with CSS selectors</a></li>
<li><a href="#async-requests">Async requests</a></li>
</ul>

<!-- markdown-toc end -->

<h2 id="http-requests">HTTP Requests</h2>

<p>Easy things first. Install Dexador. Then we use the <code>get</code> function:</p>

<pre><code class="language-lisp">(defvar *url* &quot;https://lispcookbook.github.io/cl-cookbook/&quot;)
(defvar *request* (dex:get *url*))
</code></pre>

<p>This returns a list of values: the whole page content, the return code
(200), the response headers, the uri and the stream.</p>

<pre><code>&quot;&lt;!DOCTYPE html&gt;
 &lt;html lang=\&quot;en\&quot;&gt;
  &lt;head&gt;
    &lt;title&gt;Home &amp;ndash; the Common Lisp Cookbook&lt;/title&gt;
    […]
    &quot;
200
#&lt;HASH-TABLE :TEST EQUAL :COUNT 19 {1008BF3043}&gt;
#&lt;QURI.URI.HTTP:URI-HTTPS https://lispcookbook.github.io/cl-cookbook/&gt;
#&lt;CL+SSL::SSL-STREAM for #&lt;FD-STREAM for &quot;socket 192.168.0.23:34897, peer: 151.101.120.133:443&quot; {100781C133}&gt;&gt;

</code></pre>

<p>Remember, in Slime we can inspect the objects with a right-click on
them.</p>

<h2 id="parsing-and-extracting-content-with-css-selectors">Parsing and extracting content with CSS selectors</h2>

<p>We&rsquo;ll use <code>Plump</code> to parse the html and <code>Lquery</code> to extract
content. They have nice documentation:</p>

<ul>
<li><a href="https://shinmera.github.io/plump/">https://shinmera.github.io/plump/</a></li>
<li><a href="https://shinmera.github.io/lquery/">https://shinmera.github.io/lquery/</a></li>
</ul>

<pre><code class="language-lisp">(defvar *parsed-content* (plump:parse *request*))
;; =&gt; *PARSED-CONTENT**
*parsed-content**
;; =&gt; #&lt;PLUMP-DOM:ROOT {1009EE5FE3}&gt;
</code></pre>

<p>Now we&rsquo;ll extract the links with CSS selectors.</p>

<p><strong>Note</strong>: to find out what should be the CSS selector of the element
I&rsquo;m interested in, I right click on an element in the browser and I
choose &ldquo;Inspect element&rdquo;. This opens up the inspector of my browser&rsquo;s
web dev tool and I can study the page structure.</p>

<p>So the links I want to extract are in a page with an <code>id</code> of value
&ldquo;content&rdquo;, and they are in regular list elements (<code>li</code>).</p>

<p>Let&rsquo;s try something:</p>

<pre><code class="language-lisp">(lquery:$  *parsed-content* &quot;#content li&quot;)
;; =&gt; #(#&lt;PLUMP-DOM:ELEMENT li {100B3263A3}&gt; #&lt;PLUMP-DOM:ELEMENT li {100B3263E3}&gt;
;;  #&lt;PLUMP-DOM:ELEMENT li {100B326423}&gt; #&lt;PLUMP-DOM:ELEMENT li {100B326463}&gt;
;;  #&lt;PLUMP-DOM:ELEMENT li {100B3264A3}&gt; #&lt;PLUMP-DOM:ELEMENT li {100B3264E3}&gt;
;;  #&lt;PLUMP-DOM:ELEMENT li {100B326523}&gt; #&lt;PLUMP-DOM:ELEMENT li {100B326563}&gt;
;;  #&lt;PLUMP-DOM:ELEMENT li {100B3265A3}&gt; #&lt;PLUMP-DOM:ELEMENT li {100B3265E3}&gt;
;;  #&lt;PLUMP-DOM:ELEMENT li {100B326623}&gt; #&lt;PLUMP-DOM:ELEMENT li {100B326663}&gt;
;;  […]
</code></pre>

<p>Wow it works ! We get here a vector of plump elements.</p>

<p>Since it is a vector we could map over them with <code>(map 'vector (lambda
(elt) (…)) *)</code>.</p>

<p>But I&rsquo;d like to easily check what those elements are. To see their textual
content we can append <code>(text)</code> to our lquery form:</p>

<pre><code class="language-lisp">(lquery:$  *parsed-content* &quot;#content&quot; (text))
#(&quot;License&quot; &quot;Editor support&quot; &quot;Strings&quot; &quot;Dates and Times&quot; &quot;Hash Tables&quot;
  &quot;Pattern Matching / Regular Expressions&quot; &quot;Functions&quot; &quot;Loop&quot; &quot;Input/Output&quot;
  &quot;Files and Directories&quot; &quot;Packages&quot; &quot;Macros and Backquote&quot;
  &quot;CLOS (the Common Lisp Object System)&quot; &quot;Sockets&quot; &quot;Interfacing with your OS&quot;
  &quot;Foreign Function Interfaces&quot; &quot;Threads&quot; &quot;Defining Systems&quot;
  &quot;Using the Win32 API&quot; &quot;Testing&quot; &quot;Miscellaneous&quot; &quot;License&quot; &quot;Marco Antoniotti&quot;
  &quot;Zach Beane&quot; &quot;Pierpaolo Bernardi&quot; &quot;Christopher Brown&quot; &quot;Frederic Brunel&quot;
  &quot;Jeff Caldwell&quot; &quot;Bill Clementson&quot; &quot;Martin Cracauer&quot; &quot;Gerald Doussot&quot;
  &quot;Paul Foley&quot; &quot;Jörg-Cyril
  […]
  &quot;Edi Weitz&quot; &quot;Fernando Borretti&quot; &quot;lisp-lang.org&quot; &quot;The Awesome-cl list&quot;
  &quot;The Common Lisp HyperSpec by Kent M. Pitman&quot; &quot;The Common Lisp UltraSpec&quot;
  &quot;Practical Common Lisp by Peter Seibel&quot;
  &quot;Common Lisp Recipes by Edmund Weitz, published in 2016,&quot;
  […]
  &quot;A Tutorial on Good Lisp Style by Peter Norvig and Kent Pitman&quot;
  &quot;Lisp and Elements of Style by Nick Levine&quot;
  &quot;Pascal Costanza’s Highly Opinionated Guide to Lisp&quot;
  &quot;Loving Lisp - the Savy Programmer’s Secret Weapon by Mark Watson&quot;
  &quot;FranzInc, a company selling Common Lisp and Graph Database solutions.&quot;)
</code></pre>

<p>Allright, so we see we are manipulating what we want. Now to get their
href, a quick look at lquery&rsquo;s doc and:</p>

<pre><code class="language-lisp">(lquery:$  *parsed-content* &quot;#content li a&quot; (attr :href))
;; =&gt; #(&quot;license.html&quot; &quot;editor-support.html&quot; &quot;strings.html&quot; &quot;dates_and_times.html&quot;
;;  &quot;hashes.html&quot; &quot;pattern_matching.html&quot; &quot;functions.html&quot; &quot;loop.html&quot; &quot;io.html&quot;
;;  &quot;files.html&quot; &quot;packages.html&quot; &quot;macros.html&quot;
;;  &quot;/cl-cookbook/clos-tutorial/index.html&quot; &quot;sockets.html&quot; &quot;os.html&quot; &quot;ffi.html&quot;
;;  &quot;process.html&quot; &quot;systems.html&quot; &quot;win32.html&quot; &quot;testing.html&quot; &quot;misc.html&quot;
;;  &quot;license.html&quot; &quot;mailto:xach@xach.com&quot; &quot;mailto:skeptomai@mac.com&quot;
;;  &quot;mailto:brunel@mail.dotcom.fr&quot; &quot;mailto:jdcal@yahoo.com&quot;
;;  &quot;mailto:bill_clementson@yahoo.com&quot; &quot;mailto:gdoussot@yahoo.com&quot;
;;  […]
;;  &quot;mailto:matthieu@matthieu-villeneuve.net&quot; &quot;mailto:edi@agharta.de&quot;
;;  &quot;http://lisp-lang.org/&quot; &quot;https://github.com/CodyReichert/awesome-cl&quot;
;;  &quot;http://www.lispworks.com/documentation/HyperSpec/Front/index.htm&quot;
;;  &quot;http://phoe.tymoon.eu/clus/doku.php&quot; &quot;http://www.gigamonkeys.com/book/&quot;
;;  […]
;;  &quot;http://www.nicklevine.org/declarative/lectures/&quot;
;;  &quot;http://www.p-cos.net/lisp/guide.html&quot; &quot;https://leanpub.com/lovinglisp/&quot;
;;  &quot;https://franz.com/&quot;)
</code></pre>

<p>Nice, we now have the list (well, a vector) of links of the
page. We&rsquo;ll now write an async program to check and validate they are
reachable.</p>

<p>External resources:</p>

<ul>
<li><a href="https://codingsec.net/2016/12/select-specific-text-css-using-selectors/">CSS selectors by example</a></li>
</ul>

<h2 id="async-requests">Async requests</h2>

<p>In this example we&rsquo;ll take the list of url from above and we&rsquo;ll check
if they are reachable. We want to do this asynchronously, but to see
the benefits we&rsquo;ll first do it synchronously !</p>

<p>We need a bit of filtering first to exclude the email adresses (maybe
that was doable in the CSS selector ?).</p>

<p>We put the vector of urls in a variable:</p>

<pre><code class="language-lisp">(defvar *urls* (lquery:$  *parsed-content* &quot;#content li a&quot; (attr :href)))
</code></pre>

<p>We remove the elements that start with &ldquo;mailto:&rdquo;: (a quick look at the
<a href="https://lispcookbook.github.io/cl-cookbook/strings.html">strings</a> page will help)</p>

<pre><code class="language-lisp">(remove-if (lambda (it) (string= it &quot;mailto:&quot; :start1 0 :end1 (length &quot;mailto:&quot;))) *urls*)
;; =&gt; #(&quot;license.html&quot; &quot;editor-support.html&quot; &quot;strings.html&quot; &quot;dates_and_times.html&quot;
;;  […]
;;  &quot;process.html&quot; &quot;systems.html&quot; &quot;win32.html&quot; &quot;testing.html&quot; &quot;misc.html&quot;
;;  &quot;license.html&quot; &quot;http://lisp-lang.org/&quot;
;;  &quot;https://github.com/CodyReichert/awesome-cl&quot;
;;  &quot;http://www.lispworks.com/documentation/HyperSpec/Front/index.htm&quot;
;;  […]
;;  &quot;https://franz.com/&quot;)
</code></pre>

<p>Actually before writting the <code>remove-if</code> (which works on any sequence,
including vectors) I tested with a <code>(map 'vector …)</code> to see that the
results where indeed <code>nil</code> or <code>t</code>.</p>

<p>As a side note, there is a handy <code>starts-with-p</code> function in
<a href="https://github.com/vindarel/cl-str/">cl-strings</a> (disclainer: that&rsquo;s our lib),
available in Quicklisp. So we could do:</p>

<pre><code class="language-lisp">(map 'vector (lambda (it) (str:starts-with-p &quot;mailto:&quot; it)) *urls*)
</code></pre>

<p>it also has an option to ignore or respect the case.</p>

<p>While we&rsquo;re at it, we&rsquo;ll only consider links starting with &ldquo;http&rdquo;, in
order not to write too much stuff irrelevant to web scraping:</p>

<pre><code class="language-lisp">(remove-if-not (lambda (it) (string= it &quot;http&quot; :start1 0 :end1 (length &quot;http&quot;))) *) ;; note the remove-if-NOT
</code></pre>

<p>Allright, we put this result in another variable:</p>

<pre><code class="language-lisp">(defvar *filtered-urls* *)
</code></pre>

<p>and now to the real work. For every url, we want to request it and
check that its return code is 200. We have to ignore certain
errors. Indeed, a request can timeout, be redirected (we don&rsquo;t want
that) or return an error code.</p>

<p>To be in real conditions we&rsquo;ll add a link that times out in our list:</p>

<pre><code class="language-lisp">(setf (aref *filtered-urls* 0) &quot;http://lisp.org&quot;)  ;; too bad indeed
</code></pre>

<p>We&rsquo;ll take the simple approach to ignore errors and return <code>nil</code> in
that case. If all goes well, we return the return code, that should be
200.</p>

<p>As we saw at the beginning, <code>dex:get</code> returns many values, including
the return code. We&rsquo;ll catch only this one with <code>nth-value</code> (instead
of all of them with <code>multiple-value-bind</code>) and we&rsquo;ll use
<code>ignore-errors</code>, that returns nil in case of an error. We could also
use <code>handler-case</code> and catch specific error types (see examples in
dexador&rsquo;s documentation) or (better yet ?) use <code>handler-bind</code> to catch
any <code>condition</code>.</p>

<p>(ignore-errors has the caveat that when there&rsquo;s an error, we can not
return the element it comes from. We&rsquo;ll get to our ends though.)</p>

<pre><code class="language-lisp">(map 'vector (lambda (it)
  (ignore-errors
    (nth-value 1 (dex:get it))))
  *filtered-urls*)
</code></pre>

<p>we get:</p>

<pre><code>#(NIL 200 200 200 200 200 200 200 200 200 200 NIL 200 200 200 200 200 200 200
  200 200 200 200)
</code></pre>

<p><em>update</em>: we could write something like the following with
<code>handler-case</code> to be more flexible:</p>

<pre><code class="language-lisp"> (handler-case ( &lt;code&gt; )
   (error (c)
     ( &lt;return sthg&gt; )))
</code></pre>

<p>it works, but <em>it took a very long time</em>. How much time precisely ?
with <code>(time …)</code>:</p>

<pre><code>Evaluation took:
  21.554 seconds of real time
  0.188000 seconds of total run time (0.172000 user, 0.016000 system)
  0.87% CPU
  55,912,081,589 processor cycles
  9,279,664 bytes consed
</code></pre>

<p>21 seconds ! Obviously this synchronous method isn&rsquo;t efficient. We
wait 10 seconds for links that time out. It&rsquo;s time to write and
measure and async version.</p>

<p>After installing <code>lparallel</code> and looking at
<a href="https://lparallel.org/">its documentation</a>, we see that the parallel
map <a href="https://lparallel.org/pmap-family/">pmap</a> seems to be what we
want. And it&rsquo;s only a one word edit. Let&rsquo;s try:</p>

<pre><code class="language-lisp">(time (lparallel:pmap 'vector
  (lambda (it)
    (ignore-errors (let ((status (nth-value 1 (dex:get it)))) status)))
  *filtered-urls*)
;;  Evaluation took:
;;  11.584 seconds of real time
;;  0.156000 seconds of total run time (0.136000 user, 0.020000 system)
;;  1.35% CPU
;;  30,050,475,879 processor cycles
;;  7,241,616 bytes consed
;;
;;#(NIL 200 200 200 200 200 200 200 200 200 200 NIL 200 200 200 200 200 200 200
;;  200 200 200 200)
</code></pre>

<p>Bingo. It still takes more than 10 seconds because we wait 10 seconds
for one request that times out. But otherwise it proceeds all the http
requests in parallel and so it is much faster.</p>

<p>Shall we get the urls that aren&rsquo;t reachable, remove them from our list
and measure the execution time in the sync and async cases ?</p>

<p>What we do is: instead of returning only the return code, we check it
is valid and we return the url:</p>

<pre><code class="language-lisp">... (if (and status (= 200 status)) it) ...
(defvar *valid-urls* *)
</code></pre>

<p>we get a vector of urls with a couple of <code>nil</code>s: indeed, I thought I
would have only one unreachable url but I discovered another
one. Hopefully I have pushed a fix before you try this tutorial.</p>

<p>But what are they ? We saw the status codes but not the urls :S We
have a vector with all the urls and another with the valid ones. We&rsquo;ll
simply treat them as sets and compute their difference. This will show
us the bad ones. We must transform our vectors to lists for that.</p>

<pre><code class="language-lisp">(set-difference (coerce *filtered-urls* 'list)
                (coerce *valid-urls* 'list))
;; =&gt; (&quot;http://lisp-lang.org/&quot; &quot;http://www.psg.com/~dlamkins/sl/cover.html&quot;)
</code></pre>

<p>Gotcha !</p>

<p>BTW it takes 8.280 seconds of real time to me to check the list of
valid urls synchronously, and 2.857 seconds async.</p>

<p>Have fun doing web scraping in CL !</p>

<p>More helpful libraries:</p>

<ul>
<li>we could use <a href="https://github.com/tsikov/vcr">VCR</a>, a store and
replay utility to set up repeatable tests or to speed up a bit our
experiments in the REPL.</li>
<li><a href="https://github.com/orthecreedence/cl-async">cl-async</a>,
<a href="https://github.com/orthecreedence/carrier">carrier</a> and others
network, parallelism and concurrency libraries to see on the
<a href="https://github.com/CodyReichert/awesome-cl">awesome-cl</a> list,
<a href="http://www.cliki.net/">Cliki</a> or
<a href="http://quickdocs.org/search?q=web">Quickdocs</a>.</li>
<li><a href="https://github.com/Chream/mockingbird">Mockingbird</a> is nice to mock
network requests in unit tests.</li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/51-todo.png" alt="// TODO">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">// TODO</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">27 06 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/51-todo.png" alt="Memento is a great movie" title="Memento is a great movie" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/30-adlitteram.png" alt="AdLitteram 30">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 30</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">23 06 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/30-adlitteram.png" alt="AdLitteram #29" title="AdLitteram #29" /></p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/50-seeking-answer.png" alt="Seeking Answer">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Seeking Answer</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">20 06 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/50-seeking-answer.png" alt="The single point of truth is always the source code" title="The single point of truth is always the source code" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A system time bug with Vagrant and Make</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">19 06 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I&rsquo;ve recently been writing a Forth interpreter in x86 assembly. As my laptop runs masOS, I&rsquo;m using an Ubuntu virtual machine to compile and run my code. I&rsquo;m using Vagrant to manage the VM.
I experienced an issue with Make:
$ make clean make: Warning: File &#39;Makefile&#39; has modification time 1153 s in the future rm -f forth forth.o make: warning: Clock skew detected. Your build may be incomplete. This turned out to be an issue with clock drift on the VM.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Natas wargame walkthrough, levels 1-20</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">17 06 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        One of my objectives while I&rsquo;m at the [Recurse Center]({% post_url tech/2017-05-23-starting-at-recurse-center %}) is to improve my knowedge of securing computer systems. A good way of learning this is to play an attacker and to try to break into insecure systems1. I&rsquo;ve been working through Natas, a &lsquo;wargame&rsquo; developed by Over The Wire. Natas is a series of insecure webapps, which aim to teach the basics of web security.
This post covers solutions to the first twenty levels of Natas.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to Get a File Size (and others Posix Attributes like its mtime) in Common Lisp</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">16 06 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>There is nothing built-in since CL predates the posix standard.</p>

<p>After a look at
<a href="https://github.com/CodyReichert/awesome-cl">Awesome CL</a>, the
<a href="https://www.common-lisp.net/project/osicat/manual/osicat.html">Osicat library</a>
was my go-to package to look for such functionnality. There is its
<code>osicat-posix</code> package indeed, even though it is undocumented
(<a href="https://github.com/osicat/osicat/issues/20">issue</a>)…</p>

<p>Now a look at the <a href="https://lispcookbook.github.io/cl-cookbook/files.html#getting-file-attributes-size-access-time-with-the-osicat-library">Cookbook</a> is ok.</p>

<h2 id="osicat-osicat-posix">osicat, osicat-posix</h2>

<p><code>osicat-posix</code> is included in <code>osicat</code>.</p>

<pre><code>(ql:quickload :osicat)
</code></pre>

<pre><code class="language-lisp">(describe (osicat-posix:stat #P&quot;/tmp/file&quot;))

#&lt;OSICAT-POSIX:STAT {1004F20C93}&gt;
  [standard-object]

Slots with :INSTANCE allocation:
  DEV      = 2065
  INO      = 7349974
  MODE     = 33204
  NLINK    = 1
  UID      = 1000
  GID      = 1000
  RDEV     = 0
  SIZE     = 4304
  BLKSIZE  = 4096
  BLOCKS   = 16
  ATIME    = 1497626097
  MTIME    = 1497347216
  CTIME    = 1497347216
; No value
</code></pre>

<p>and so we can access the slots with their related functions:</p>

<pre><code>osicat-posix:stat-dev
osicat-posix:stat-gid
osicat-posix:stat-ino
osicat-posix:stat-uid
osicat-posix:stat-mode
osicat-posix:stat-rdev
osicat-posix:stat-size
osicat-posix:stat-atime
osicat-posix:stat-ctime
osicat-posix:stat-mtime
osicat-posix:stat-nlink
osicat-posix:stat-blocks
osicat-posix:stat-blksize
</code></pre>

<p>so for example:</p>

<pre><code class="language-lisp">(let ((stat (osicat-posix:stat #P&quot;./files.md&quot;)))
  (osicat-posix:stat-size stat))  ;; =&gt; 10629
</code></pre>

<h2 id="trivial-file-size">Trivial-file-size</h2>

<p>Now for the size there&rsquo;s also the lightweight (and portable)
<a href="https://github.com/TBRSS/trivial-file-size">trivial-file-size</a>.</p>

<blockquote>
<p>This library exports a single function, file-size-in-octets. It returns the size of a file in bytes, using system calls when possible.</p>

<p>The canonical way to determine the size of a file in bytes, using Common Lisp, is to open the file with an element type of (unsigned-byte 8) and then calculate the length of the stream. This is less than ideal. In most cases it would be better to get the size of the file from its metadata, using a system call.</p>
</blockquote>

<p>The author new about osicat-posix.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/29-adlitteram.png" alt="AdLitteram 29">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 29</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">16 06 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/29-adlitteram.png" alt="AdLitteram #29" title="AdLitteram #29" /></p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/49-keep-up-to-date.png" alt="Keep Up To Date">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Keep Up To Date</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">13 06 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/49-keep-up-to-date.png" alt="And make sure you go to the issues section" title="And make sure you go to the issues section" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Slingshot: an interplanetary physics game</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">12 06 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Over the weekend, Recurse Center held a game jam. Over 72 hours, I built a phyics game named Slingshot. In the game, you play the pilot of a spaceship with little fuel. To survive, you must navigate around planets and neutron stars to reach a series of checkpoints. You can play Slingshot here, and view the source code here.
This post describes how the game is implemented.
Drawing All drawing was done using the P5.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/28-adlitteram.png" alt="AdLitteram 28">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 28</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">09 06 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/28-adlitteram.png" alt="AdLitteram #28" title="AdLitteram #28" /></p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">5 Ways to Make Django Admin Safer</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">08 06 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>With great power comes great responsibility. The more powerful your Django admin is, the safer it should be. Making a Django admin safer and more secure doesn't have to be hard - you just have to pay attention. In this article I present 5 ways to protect the Django Admin from human errors and attackers.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">FELIZ DÍA MUNDIAL DEL MEDIO AMBIENTE!!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">06 06 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/48-open-source-issues.png" alt="Open Source Issues">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Open Source Issues</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">06 06 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/48-open-source-issues.png" alt="The oops and downs of open source" title="The oops and downs of open source" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Tail recursion for imperative programmers</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">04 06 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        At the Recurse Center, I&rsquo;ve been working my way through The Structure and Interpretation of Computer Programs (SICP) book. It&rsquo;s an introductory programming book written for an MIT course in 1985. It teaches programming using the language Scheme, a LISP dialect. Scheme is functional, and I&rsquo;ve been enjoying learning new functional concepts.
This article aims to explain tail recursion to programmers without experience in functional languages or concepts.
Before looking at tail recursion, let&rsquo;s look at recursion in an imperative language, Python.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A guide to installing Cordova on Windows 10</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">30 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Please note that this guide was last updated on 30th May 2017. I haven&rsquo;t worked with Cordova since 2018 and so the steps below are likely out of date and may not work. I&rsquo;m keeping the guide here as a historical reference. If you are interested in providing updated instructions, please reach out to me and I will look to update this post accordingly.
This is the second part of a guide to installing the Cordova framework, and deals with installation on Windows 10.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A guide to installing Cordova on Windows 10</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">30 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Please note that this guide was last updated on 30th May 2017. I haven&rsquo;t worked with Cordova since 2018 and so the steps below are likely out of date and may not work. I&rsquo;m keeping the guide here as a historical reference. If you are interested in providing updated instructions, please reach out to me and I will look to update this post accordingly.
This is the second part of a guide to installing the Cordova framework, and deals with installation on Windows 10.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/47-angular-vs-react.png" alt="Angular vs. React">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Angular vs. React</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">30 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/47-angular-vs-react.png" alt="Programmers need alternatives to argue" title="Programmers need alternatives to argue" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A guide to installing Cordova on your Mac</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">29 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Please note that this guide was last updated on 29th May 2017. I haven&rsquo;t worked with Cordova since 2018 and so the steps below are likely out of date and may not work. I&rsquo;m keeping the guide here as a historical reference. If you are interested in providing updated instructions, please reach out to me and I will look to update this post accordingly.
Cordova is a popular framework for building hybrid mobile applications.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A guide to installing Cordova on your Mac</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">29 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Please note that this guide was last updated on 29th May 2017. I haven&rsquo;t worked with Cordova since 2018 and so the steps below are likely out of date and may not work. I&rsquo;m keeping the guide here as a historical reference. If you are interested in providing updated instructions, please reach out to me and I will look to update this post accordingly.
Cordova is a popular framework for building hybrid mobile applications.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://www.emezeta.com/img/logo.png" alt="Alternativas minimalistas a Bootstrap: Frameworks CSS (III)">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Alternativas minimalistas a Bootstrap: Frameworks CSS (III)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Emezeta blog</a> <span class="article__date">27 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ¿Quieres una alternativa ligera y rápida a Bootstrap? En esta tercera entrega encontrarás varios frameworks CSS para crear diseños web minimalistas.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Faster, Better, Cheaper—The art of making software</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">26 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Nobody wants to deliver late, over-budget software. I don’t know a single software developer who wakes up in the morning and thinks “I’d like to do a rubbish job today. How can I cost my employer more money?” And yet, so many software projects don’t go well. And with every new project, there seems to be more and more pressure to go faster. So, if we’re in the business of making software, what do we do? How do we go faster without compromising quality?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Faster, Better, Cheaper—The art of making software</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">26 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Nobody wants to deliver late, over-budget software. I don’t know a single software developer who wakes up in the morning and thinks “I’d like to do a rubbish job today. How can I cost my employer more money?” And yet, so many software projects don’t go well. And with every new project, there seems to be more and more pressure to go faster. So, if we’re in the business of making software, what do we do? How do we go faster without compromising quality?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/27-adlitteram.png" alt="AdLitteram 27">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 27</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">26 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/27-adlitteram.png" alt="AdLitteram #27" title="AdLitteram #27" /></p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://www.emezeta.com/img/logo.png" alt="Alternativas ligeras a Bootstrap: Frameworks CSS (II)">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Alternativas ligeras a Bootstrap: Frameworks CSS (II)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Emezeta blog</a> <span class="article__date">23 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ¿Buscas alternativas ligeras y rápidas a Bootstrap? Esta segunda entrega incluye una colección de frameworks CSS alternativos para nuestro sitio web.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Starting at the Recurse Center</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">23 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I&rsquo;ve recently started at the Recurse Center (RC), a self-directed, three-month coding program based in New York. The main objective of the course is to improve as a programmer, but the way that&rsquo;s gone about is left up to the individual. Having the opportunity to build anything for an extended period of time in an encouraging and nurturing environment is a privillage offered to few, and it&rsquo;s important to make the most of it.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/46-code-review-stages.png" alt="Code Review Stages">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Code Review Stages</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">23 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/46-code-review-stages.png" alt="kill or be killed" title="kill or be killed" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://www.emezeta.com/img/logo.png" alt="Alternativas a Bootstrap: Frameworks CSS (I)">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Alternativas a Bootstrap: Frameworks CSS (I)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Emezeta blog</a> <span class="article__date">19 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ¿Buscas alternativas a Bootstrap para el diseño de una web? En este primer artículo encontrarás varios frameworks CSS diferentes para utilizar en tu web.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/26-adlitteram.png" alt="AdLitteram 26">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 26</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">19 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/26-adlitteram.png" alt="AdLitteram #26" title="AdLitteram #26" /></p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/45-code-progression.png" alt="Code Progression">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Code Progression</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">16 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/45-code-progression.png" alt="There is no alien technology - We are living in a computer simulation" title="There is no alien technology - We are living in a computer simulation" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">ROSALIND FRANKLIN</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">12 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/25-adlitteram.png" alt="AdLitteram 25">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 25</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">12 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/25-adlitteram.png" alt="AdLitteram #25" title="AdLitteram #25" /></p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Many Faces of DISTINCT in PostgreSQL</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">10 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I started my programming career as an Oracle DBA. It took a few years but eventually I got fed up with the corporate world and I went about doing my own thing. After I gotten over not having proper partitions and MERGE statement, I found some nice unique features in PostgreSQL. Oddly enough, a lot of them contained the word DISTINCT.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/44-unit-tests-coverage-degradation.png" alt="Unit Tests Coverage Degradation">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Unit Tests Coverage Degradation</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">09 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/44-unit-tests-coverage-degradation.png" alt="In the initial phase unit tests covered 110% of code - we tested even the 3rd party libs" title="In the initial phase unit tests covered 110% of code - we tested even the 3rd party libs" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/24-adlitteram.png" alt="AdLitteram 24">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 24</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">05 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/24-adlitteram.png" alt="AdLitteram #24" title="AdLitteram #24" /></p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to access url query parameters in Clack, Lucerne or Caveman</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">04 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p><strong>edit</strong>: I found <a href="https://github.com/joaotavora/snooze">Snooze</a> (by
Sly and Yasnippet&rsquo;s author) easier and cleaner in this regard. It also
has built-in settings to choose where to catch errors: with Slime&rsquo;s
debugger, with a full stacktrace in the browser or displaying a custom
error page.</p>

<p>If you&rsquo;re using Lucerne don&rsquo;t search more like I did, its
<code>with-params</code> macro works with url query parameters (as well as POST
parameters).</p>

<p>If you&rsquo;re accessing the url <code>hello?search=kw</code>, this works:</p>

<pre><code class="language-lisp">@route app &quot;/hello&quot;
(defview index (name)
  (with-params (search)
    (render-template (+index+)
                     :search search)))
</code></pre>

<p>An illustration with a POST parameter from the &ldquo;utweet&rdquo; example:</p>

<pre><code class="language-lisp">@route app (:post &quot;/tweet&quot;)
(defview tweet ()
  (if (lucerne-auth:logged-in-p)
      (let ((user (current-user)))
        (with-params (tweet)
          (utweet.models:tweet user tweet))
        (redirect &quot;/&quot;))
      (render-template (+index+)
                       :error &quot;You are not logged in.&quot;)))
</code></pre>

<p>The macro is implemented like this:</p>

<pre><code class="language-lisp">;; https://github.com/eudoxia0/lucerne/blob/master/src/http.lisp
(defmacro with-params (params &amp;body body)
  &quot;Extract the parameters in @cl:param(param) from the @c(*request*), and bind
them for use in @cl:param(body).&quot;
  `(let ,(loop for param in params collecting
               `(,param (let ((str (parameter *request*
                                              ,(intern (string-downcase
                                                        (symbol-name param))
                                                       :keyword))))
                          (if (equal str &quot;&quot;)
                              nil
                              str))))
     ,@body))
</code></pre>

<p>For Caveman it is <a href="https://github.com/fukamachi/caveman#structured-querypost-parameters">possible</a> but a bit awkward and <a href="https://github.com/fukamachi/caveman/issues/22">inconsistent</a>.</p>

<p>There&rsquo;s an example for Ningle
<a href="https://stackoverflow.com/questions/43778570/how-to-get-url-query-parameters-in-clack-lucerne-or-caveman">on the related StackOverflow question</a>.</p>

<h3 id="and-in-clack-generally">And in Clack generally ?</h3>

<p>It is only scarcely documented on Clack&rsquo;s
<a href="http://quickdocs.org/clack/api#package-CLACK.REQUEST">api documentation</a>.</p>

<p>We can access the parameters with <code>(clack.request:query-parameter
lucerne:*request*)</code>. So to get the value of a given param:</p>

<pre><code class="language-lisp">(assoc &quot;a-param&quot; (clack.request:query-parameter lucerne:*request*) :test 'string=)
</code></pre>

<p>and this returns the key and the value, so we need another <code>cdr</code> to get the value…</p>

<pre><code class="language-lisp">(defun query-param (param)
  (cdr (assoc param (clack.request:query-parameter lucerne:*request*) :test #'string=)))
</code></pre>

<p>See also:</p>

<ul>
<li><a href="https://jasom.github.io/clack-tutorial/pages/getting-started-with-clack/">https://jasom.github.io/clack-tutorial/pages/getting-started-with-clack/</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Is There Something Like Clojure&#39;s Figwheel for interactive web dev with the browser in Common Lisp ?</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">04 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Looks like there is:
<a href="https://github.com/johnmastro/trident-mode.el">trident-mode</a>, an
<em>&ldquo;Emacs minor mode for live Parenscript interaction&rdquo;</em>, based on
<a href="https://github.com/skeeto/skewer-mode">skewer</a> but: trident-mode
doesn&rsquo;t seem to be used in the wild (while skewer-mode is) and I don&rsquo;t
know Figwheel so all I can say is that it seems a bit different:
instead of letting us selectively evaluate and send code to the
browser, Figwheels seems to rebuild the entire project and send the
result when we write a file.</p>

<p>I tried trident-mode quickly, it works and the author was
responsive. It offers commands and shortcuts to see the Javascript
code produced by Parenscript forms and (optionally) send them to the
browser.</p>

<p>An example use:</p>

<pre><code class="language-lisp">((@ document write)
  (ps-html ((:a :href &quot;foobar&quot;) &quot;blorg&quot;)))
</code></pre>

<p>to evaluate with <code>trident-eval-dwim</code>, which generates</p>

<pre><code>document.write(&quot;&lt;A HREF=\&quot;foobar\&quot;&gt;blorg&lt;/A&gt;&quot;)
</code></pre>

<p>so it uses js to insert html into the DOM.
It doesn&rsquo;t leverage Skewer&rsquo;s capacity to send only html.</p>

<p>I&rsquo;ll update this post if/when I can.</p>

<hr />

<p><a href="https://github.com/bhauman/lein-figwheel">Figwheel</a></p>

<blockquote>
<p>builds your ClojureScript code and hot loads it into the
 browser as you are coding!</p>
</blockquote>

<p>Skewer</p>

<blockquote>
<p>Provides live interaction with JavaScript, CSS, and HTML in a web browser. Expressions are sent on-the-fly from an editing buffer to be evaluated in the browser, just like Emacs does with an inferior Lisp process in Lisp modes.</p>
</blockquote>

<p>and we can also connect to sites on servers we don&rsquo;t control.</p>

<p>They have demo videos.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Getting started: how to install a Common Lisp development environment</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">03 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>or &ldquo;could not find recent and easy installation steps [fixed]&ldquo;.</p>

<p>When I started I was a bit confused by old instructions (google is not
good at CL), so hopefully this post will help show up recent and easy
steps and most of all, help every CL enthousiast discover
<strong>Portacle</strong>.</p>

<p>(and this post is editable through its <a href="https://gitlab.com/lisp-journey/lisp-journey.gitlab.io/">Gitlab repository</a>)</p>

<h2 id="portable-a-multiplatform-development-environment">Portable, a multiplatform development environment</h2>

<p>The productive Shinmera was waiting for the last details to be fixed
before showing <a href="https://portacle.github.io/">Portacle</a> but it was
already great. On GNU/Linux, MacOs or Windows, just download an
archive and click an icon to open Emacs ready to use for CL
development. It is that easy.</p>

<p>It ships: Emacs (customized), the SBCL implementation, Slime (Emacs
IDE), Quicklisp (package manager) and Git. Emacs comes with a nice
theme, autocompletion in drop-downs (company-mode) and
<a href="https://magit.vc/">Magit</a>.</p>

<h2 id="manual-install">Manual install</h2>

<h3 id="lisp-implementation">Lisp implementation</h3>

<p>Install a CL implementation:</p>

<pre><code>apt-get install sbcl
</code></pre>

<p>Now you can run <code>sbcl</code> and write lisp at the prompt:</p>

<pre><code class="language-lisp">(print &quot;hello lisp!&quot;)
(quit) ;; or C-d
</code></pre>

<p>More are packaged for Debian and probably for your distro, notably
<a href="https://gitlab.com/embeddable-common-lisp/ecl/">ECL</a>, and note that
you can install more easily with <a href="https://github.com/roswell/roswell/wiki">Roswell</a>.</p>

<p>If you find the prompt horribly unfriendly (no history, no navigation…) use rlwrap:</p>

<pre><code>apt-get install rlwrap
</code></pre>

<p>and now this will be slightly better:</p>

<pre><code>rwrap sbcl
</code></pre>

<p>Even better, a slight wrapper around the SBCL REPL with readline
support (Emacs and Vim modes, history, etc):
<a href="https://github.com/hellerve/sbcli">sbcli</a>, straightforward to use.</p>

<p>But still, we really need an editor.</p>

<h3 id="editors-support">Editors support</h3>

<p>You&rsquo;re not bound to Emacs, there&rsquo;s good support for Vim, Sublime Text
(via the SublimeREPL package) and Atom.</p>

<p>See the <a href="https://lispcookbook.github.io/cl-cookbook/editor-support.html">Cookbook#editors</a>.</p>

<p>For Emacs, <a href="https://github.com/slime/slime">Slime</a> is the de-facto
solution (there&rsquo;s also the Sly fork). It is in the GNU Elpa default
Emacs package repository, so:</p>

<pre><code>M-x package-install RET slime RET
</code></pre>

<p>(you may need a <code>M-x package-refresh-content</code>).</p>

<p>Now start Slime with <code>M-x slime</code> and wait a few seconds that it starts
its backend (Swank server).</p>

<p>Might help:</p>

<ul>
<li>using Emacs (and other instructions): <a href="https://www.darkchestnut.com/2017/getting-started-with-common-lisp/#using-emacs">https://www.darkchestnut.com/2017/getting-started-with-common-lisp/#using-emacs</a></li>
<li><a href="http://wikemacs.org/wiki/Common_Lisp">http://wikemacs.org/wiki/Common_Lisp</a></li>
<li>Slime manual: <a href="https://common-lisp.net/project/slime/doc/html/">https://common-lisp.net/project/slime/doc/html/</a> (see
the Emacs menu). In very short: compile a file with <code>C-c C-k</code>,
compile one function with <code>C-c C-c</code> and use it at the REPL.</li>
</ul>

<h3 id="quicklisp-package-manager">Quicklisp package manager</h3>

<p>To install <a href="https://www.quicklisp.org/beta/">Quicklisp</a>:</p>

<p>from anywhere, download this file:</p>

<pre><code> wget https://beta.quicklisp.org/quicklisp.lisp
</code></pre>

<p>start a Lisp and load this file:</p>

<pre><code>sbcl --load quicklisp.lisp
</code></pre>

<p>we get in the sbcl prompt. We have one Quicklisp command to type to
install it:</p>

<pre><code>(quicklisp-quickstart:install)
</code></pre>

<p>it will install itself in <code>~/quicklisp/quicklisp/</code>.</p>

<p>it should output something like this, showing the basic commands:</p>

<pre><code>==================================================
2,846 bytes in 0.001 seconds (2779.30KB/sec)
Upgrading ASDF package from version 2.004 to version 2.009
; Fetching #&lt;URL &quot;http://beta.quicklisp.org/dist/quicklisp.txt&quot;&gt;
; 0.40KB
==================================================
408 bytes in 0.003 seconds (132.81KB/sec)

  ==== quicklisp installed ====

    To load a system, use: (ql:quickload &quot;system-name&quot;)

    To find systems, use: (ql:system-apropos &quot;term&quot;)

    To load Quicklisp every time you start Lisp, use: (ql:add-to-init-file)

    For more information, see http://www.quicklisp.org/beta/

NIL
</code></pre>

<p>Does it work ? Let&rsquo;s try to install something:</p>

<pre><code>(ql:quickload &quot;dexador&quot;)
</code></pre>

<p>It is installed but we want to have Quicklisp available everytime we
start sbcl. Otherwise we&rsquo;d have to <code>load</code> the file located at
<code>~/quicklisp/quicklisp/setup.lisp</code>.</p>

<p>Each implementation uses a startup file, like our shells, so we can
add this into our <code>~/.sbclrc</code>:</p>

<pre><code class="language-lisp">;;; The following lines added by ql:add-to-init-file:
  #-quicklisp
  (let ((quicklisp-init (merge-pathnames &quot;quicklisp/setup.lisp&quot;
                                         (user-homedir-pathname))))
    (when (probe-file quicklisp-init)
      (load quicklisp-init)))
</code></pre>

<p>To quit sbcl, <code>(quit)</code> or <code>C-d</code>.</p>

<p>Quicklisp is a bit different than others package managers and it is
not the only solution. That&rsquo;s for another post.</p>

<h2 id="starting-a-project">Starting a project</h2>

<p>I advise <a href="https://github.com/fukamachi/cl-project">cl-project</a> which,
unlike others (quickproject) also sets up tests.</p>

<p>Now we can <code>C-c C-k</code> the <code>.asd</code> file and <code>(ql:quickload &quot;my-app&quot;)</code> our
app in the Slime REPL. But this is for another post.</p>

<h2 id="managing-implementations-and-installing-libraries-in-the-command-line-roswell">Managing implementations and installing libraries in the command line: Roswell</h2>

<p>This is done together with <a href="https://github.com/roswell/roswell/wiki">Roswell</a>.</p>

<p>Roswell is in brew for MacOS, in linuxbrew, and it has a Debian package.</p>

<p>It allows to install pinned versions of SBCL or of other
implementations (Embedable CL, Clozure CL,…) easily:</p>

<pre><code>ros install sbcl/1.2.14
ros install sbcl  # the latest
ros install ccl-bin
</code></pre>

<p>what&rsquo;s available ?</p>

<pre><code>ros list versions
</code></pre>

<p>change the current lisp:</p>

<pre><code>ros use sbcl/1.2.14
</code></pre>

<p>Install scripts:</p>

<pre><code>ros install qlot
</code></pre>

<p>Install packages:</p>

<pre><code>ros install dexador  # http client
</code></pre>

<p>and it does more to help scripting and distributing software. See its wiki !</p>

<h2 id="see-also">See also</h2>

<ul>
<li>a Debian package for CCL (2016): <a href="http://mr.gy/blog/clozure-cl-deb.html">http://mr.gy/blog/clozure-cl-deb.html</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">String manipulation is frustrating [fixed]</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">02 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>One of the first things I wanted to do in the REPL was some string
manipulation. But it was tedious.</p>

<p>To trim whitespace, and I mean all whitespaces, we had to define
<code>#\Space #\Newline #\Backspace #\Tab #\Linefeed #\Page #\Return
#\Rubout</code>.</p>

<p>To concatenate two strings: either giving an unusual <code>'string</code> argument to
<code>concatenate</code>, like this:</p>

<pre><code class="language-lisp">(concatenate 'string &quot;fo&quot; &quot;o&quot;)
</code></pre>

<p>either we had to use a <code>format</code> construct, which is another source of
frustration for (impatient) beginners, and sure isn&rsquo;t straightforward
and self-explanatory.</p>

<p>Many common stuff was split in various external libraries
(<code>cl-ppcre</code>), and many common stuff was made more difficult than
necessary (weird format construct again, entering a regexp, thus
esaping what&rsquo;s necessary, when all you want to do is simple search and
replace, dealing with strings&rsquo; lengths and corner cases, lack of
verbs,… see below).</p>

<p>And all of that with many inconsistencies (the string as first
argument, then as the last, etc).</p>

<p>So I just joined everything in a little library, which has now more
features. Let&rsquo;s see its code and its tests to learn at the canonical
way to do stuff, their shortcomings, and the library api at the same
time.</p>

<p>I just don&rsquo;t know how come this lib didn&rsquo;t exist yet.</p>

<h2 id="str"><code>str</code></h2>

<p>You can install it with</p>

<pre><code>(ql:quickload &quot;str&quot;)
</code></pre>

<p>See on <a href="https://github.com/vindarel/cl-str">https://github.com/vindarel/cl-str</a>.</p>

<h3 id="package-definition">Package definition</h3>

<pre><code class="language-lisp">(in-package #:asdf-user)

(defsystem :str
  :source-control (:git &quot;git@github.com:vindarel/cl-s.git&quot;)
  :description &quot;Modern, consistent and terse Common Lisp string manipulation library.&quot;
  :depends-on (:prove :cl-ppcre)  ;; &lt;= depends only on cl-ppcre.
  :components ((:file &quot;str&quot;))
  )
</code></pre>

<h3 id="trim">Trim</h3>

<pre><code class="language-lisp">(defvar *whitespaces* '(#\Space #\Newline #\Backspace #\Tab
                        #\Linefeed #\Page #\Return #\Rubout))

(defun trim-left (s)
  &quot;Remove whitespaces at the beginning of s. &quot;
  (string-left-trim *whitespaces* s))

(defun trim-right (s)
  &quot;Remove whitespaces at the end of s.&quot;
  (string-right-trim *whitespaces* s))


(defun trim (s)
  (string-trim *whitespaces* s))

</code></pre>

<h3 id="concat">Concat</h3>

<pre><code class="language-lisp">(defun concat (&amp;rest strings)
  &quot;Join all the string arguments into one string.&quot;
  (apply #'concatenate 'string strings))
</code></pre>

<h3 id="join">Join</h3>

<p>Snippets on the old cookbook or stackoverflow advised to use a
<code>format</code> construct. Which is weird, and causes problems if your
separator contains the <code>~</code> symbol.</p>

<pre><code class="language-lisp">(defun join (separator strings)
  (let ((separator (replace-all &quot;~&quot; &quot;~~&quot; separator)))
    (format nil
            (concatenate 'string &quot;~{~a~^&quot; separator &quot;~}&quot;)
            strings)))
</code></pre>

<p>Now:</p>

<pre><code class="language-lisp">(is &quot;foo~bar&quot;
    (join &quot;~&quot; '(&quot;foo&quot; &quot;bar&quot;)))
</code></pre>

<h3 id="split">Split</h3>

<p><code>cl-ppcre</code> takes a regexp, but we don&rsquo;t need this for the basic cases
of <code>split</code>. And disabling this regexp was not straightforward:</p>

<pre><code class="language-lisp">(defun split (separator s &amp;key omit-nulls)
  &quot;Split s into substring by separator (cl-ppcre takes a regex, we do not).&quot;
  ;; cl-ppcre:split doesn't return a null string if the separator appears at the end of s.
  (let* ((val (concat s
                      (string separator)
                      ;; so we need an extra character, but not the user's.
                      (if (string-equal separator #\x) &quot;y&quot; &quot;x&quot;)))
         (res (butlast (cl-ppcre:split (cl-ppcre:quote-meta-chars (string separator)) val))))
    (if omit-nulls
        (remove-if (lambda (it) (empty? it)) res)
        res)))
</code></pre>

<p>Now: <code>(split &quot;.&quot; &quot;foo.bar&quot;)</code> just works.</p>

<h3 id="repeat">Repeat</h3>

<pre><code class="language-lisp">(defun repeat (count s)
  &quot;Make a string of S repeated COUNT times.&quot;
  (let ((result nil))
    (dotimes (i count)
      (setf result (cons s result)))
    (apply #'concat result)))
</code></pre>

<h3 id="replace-all">Replace-all</h3>

<p>This required to use cl-ppcre and one switch of it to avoid regexps.</p>

<pre><code class="language-lisp">(defun replace-all (old new s)
  &quot;Replace `old` by `new` in `s`. Arguments are not regexs.&quot;
  (let* ((cl-ppcre:*allow-quoting* t)
         (old (concatenate 'string  &quot;\\Q&quot; old))) ;; treat metacharacters as normal.
    (cl-ppcre:regex-replace-all old s new)))
</code></pre>

<h3 id="starts-with-start-string">starts-with? start string</h3>

<p>The Lisp way was to check if the beginning of &ldquo;string&rdquo; contains
&ldquo;start&rdquo;, taking its length, dealing with corner cases,…</p>

<pre><code class="language-lisp">(defun starts-with? (start s &amp;key (ignore-case nil))
  &quot;Return t if s starts with the substring 'start', nil otherwise.&quot;
  (when (&gt;= (length s) (length start))
    (let ((fn (if ignore-case #'string-equal #'string=)))
      (funcall fn s start :start1 0 :end1 (length start)))))

;; An alias:
;; Serapeum defines a &quot;defalias&quot;.
(setf (fdefinition 'starts-with-p) #'starts-with?)

(defun ends-with? (end s &amp;key (ignore-case nil))
  &quot;Return t if s ends with the substring 'end', nil otherwise.&quot;
  (when (&gt;= (length s) (length end))
    (let ((fn (if ignore-case #'string-equal #'string=)))
      (funcall fn s end :start1 (- (length s) (length end))))))

(setf (fdefinition 'ends-with-p) #'ends-with?)
</code></pre>

<p>Usage illustrated by the tests:</p>

<pre><code class="language-lisp">(subtest &quot;starts-with?&quot;
  (ok (starts-with? &quot;foo&quot; &quot;foobar&quot;) &quot;default case&quot;)
  (ok (starts-with? &quot;&quot; &quot;foo&quot;) &quot;with blank start&quot;)
  (ok (not (starts-with? &quot;rs&quot; &quot;&quot;)) &quot;with blank s&quot;)
  (ok (not (starts-with? &quot;foobar&quot; &quot;foo&quot;)) &quot;with shorter s&quot;)
  (ok (starts-with? &quot;&quot; &quot;&quot;) &quot;with everything blank&quot;)
  (ok (not (starts-with? &quot;FOO&quot; &quot;foobar&quot;)) &quot;don't ignore case&quot;)
  (ok (starts-with-p &quot;f&quot; &quot;foo&quot;) &quot;starts-with-p alias&quot;)
  (ok (starts-with? &quot;FOO&quot; &quot;foobar&quot; :ignore-case t) &quot;ignore case&quot;))
</code></pre>

<h3 id="predicates-empty-blank">Predicates: empty? blank?</h3>

<p>There was no built-in to make those differences.</p>

<pre><code class="language-lisp">(defun empty? (s)
  &quot;Is s nil or the empty string ?&quot;
  (or (null s) (string-equal &quot;&quot; s)))

(defun emptyp (s)
  &quot;Is s nil or the empty string ?&quot;
  (empty? s))

(defun blank? (s)
  &quot;Is s nil or only contains whitespaces ?&quot;
  (or (null s) (string-equal &quot;&quot; (trim s))))

(defun blankp (s)
  &quot;Is s nil or only contains whitespaces ?&quot;
  (blank? s))
</code></pre>

<h3 id="words-unwords-lines-unlines">words, unwords, lines, unlines</h3>

<p>Classic stuff:</p>

<pre><code class="language-lisp">(defun words (s &amp;key (limit 0))
  &quot;Return list of words, which were delimited by white space. If the optional limit is 0 (the default), trailing empty strings are removed from the result list (see cl-ppcre).&quot;
  (if (not s)
      nil
      (cl-ppcre:split &quot;\\s+&quot; (trim-left s) :limit limit)))

(defun unwords (strings)
  &quot;Join the list of strings with a whitespace.&quot;
  (join &quot; &quot; strings))

(defun lines (s &amp;key omit-nulls)
  &quot;Split the string by newline characters and return a list of lines.&quot;
  (split #\NewLine s :omit-nulls omit-nulls))

(defun unlines (strings)
  &quot;Join the list of strings with a newline character.&quot;
  (join (make-string 1 :initial-element #\Newline) strings))
</code></pre>

<h3 id="substring">Substring</h3>

<p>The builtin <code>subseq</code> is much poorer compared to what we have in other languages.</p>

<p>Take Python, we can do:</p>

<pre><code>&quot;foo&quot;[:-1] # negative index and starting from the end
&quot;foo&quot;[0:100] # end is too large, thus it returns the entire array.
</code></pre>

<p>This was not possible with <code>subseq</code>, it throws a condition. Nothing
found in Alexandria or other helper libraries.</p>

<pre><code class="language-lisp">(defun substring (start end s)
  &quot;Return the substring of `s' from `start' to `end'.

It uses `subseq' with differences:
- argument order, s at the end
- `start' and `end' can be lower than 0 or bigger than the length of s.

- for convenience `end' can be nil or t to denote the end of the string.
&quot;
  (let* ((s-length (length s))
         (end (cond
                ((null end) s-length)
                ((eq end t) s-length)
                (t end))))
    (setf start (max 0 start))
    (if (&gt; start s-length)
        &quot;&quot;
        (progn
          (setf end (min end s-length))
          (when (&lt; end (- s-length))
            (setf end 0))
          (when (&lt; end 0)
            (setf end (+ s-length end)))
          (if (&lt; end start)
              &quot;&quot;
              (subseq s start end))))))
</code></pre>

<p>Usage:</p>

<pre><code class="language-lisp">(subtest &quot;substring&quot;
  (is &quot;abcd&quot; (substring 0 4 &quot;abcd&quot;) &quot;normal case&quot;)
  (is &quot;ab&quot; (substring 0 2 &quot;abcd&quot;) &quot;normal case substing&quot;)
  (is &quot;bc&quot; (substring 1 3 &quot;abcd&quot;) &quot;normal case substing middle&quot;)
  (is &quot;&quot; (substring 4 4 &quot;abcd&quot;) &quot;normal case&quot;)
  (is &quot;&quot; (substring 0 0 &quot;abcd&quot;) &quot;normal case&quot;)
  (is &quot;d&quot; (substring 3 4 &quot;abcd&quot;) &quot;normal case&quot;)
  (is &quot;abcd&quot; (substring 0 t &quot;abcd&quot;) &quot;end is t&quot;)
  (is &quot;abcd&quot; (substring 0 nil &quot;abcd&quot;) &quot;end is nil&quot;)
  (is &quot;abcd&quot; (substring 0 100 &quot;abcd&quot;) &quot;end is too large&quot;)
  (is &quot;abc&quot; (substring 0 -1 &quot;abcd&quot;) &quot;end is negative&quot;)
  (is &quot;b&quot; (substring 1 -2 &quot;abcd&quot;) &quot;end is negative&quot;)
  (is &quot;&quot; (substring 2 1 &quot;abcd&quot;) &quot;start is bigger than end&quot;)
  (is &quot;&quot; (substring 0 -100 &quot;abcd&quot;) &quot;end is too low&quot;)
  (is &quot;&quot; (substring 100 1 &quot;abcd&quot;) &quot;start is too big&quot;)
  (is &quot;abcd&quot; (substring -100 4 &quot;abcd&quot;) &quot;start is too low&quot;)
  (is &quot;abcd&quot; (substring -100 100 &quot;abcd&quot;) &quot;start and end are too low and big&quot;)
  (is &quot;&quot; (substring 100 -100 &quot;abcd&quot;) &quot;start and end are too big and low&quot;)
  )
</code></pre>

<h3 id="see-also">See also</h3>

<p>and afterwards I saw
<a href="https://github.com/diogoalexandrefranco/cl-strings">cl-strings</a> which
does help but can have its shortcomings.</p>

<p>The Cookbook is updated: <a href="https://lispcookbook.github.io/cl-cookbook/strings.html">https://lispcookbook.github.io/cl-cookbook/strings.html</a></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/43-shady-logic-gates.png" alt="Shady Logic Gates">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Shady Logic Gates</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">02 05 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/43-shady-logic-gates.png" alt="3 IFs" title="3 IFs" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">All You Need To Know About Prefetching in Django</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">28 04 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>A rundown of all the ways you can use Prefetch to speed up queries in Django.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/23-adlitteram.png" alt="AdLitteram 23">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 23</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">28 04 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/23-adlitteram.png" alt="AdLitteram #23" title="AdLitteram #23" /></p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Prevención de riesgos laborales PRL</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">24 04 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/42-qa-engineer-buying-bed.png" alt="QA Engineer - Bed Shopping">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">QA Engineer - Bed Shopping</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">24 04 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/42-qa-engineer-buying-bed.png" alt="The lion was not hurt" title="The lion was not hurt" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/22-adlitteram.png" alt="AdLitteram 22">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 22</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">21 04 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/22-adlitteram.png" alt="AdLitteram #22" title="AdLitteram #22" /></p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/41-easter-eggs.png" alt="Easter Eggs">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Easter Eggs</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">18 04 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/41-easter-eggs.png" alt="what are the odds to catch them all" title="what are the odds to catch them all" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Why is there no generic operators ?</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">14 04 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p><em>TLDR;</em> because the object system came afterwards (and it was not the
 intention to make CL entirely object oriented).</p>

<p>As a CL enthousiast coming from Python, I feel the pain not to have
generic or polymorphic operators but having to learn about many
specialized operators instead. Why is it so and are there solutions ?</p>

<hr />

<p>I <a href="https://stackoverflow.com/questions/43416293/why-is-there-no-generic-operators-for-common-lisp">asked</a> on SO.</p>

<p>In CL, there are many operators to check for equality that depend on
the data type: <code>=</code>, <code>string-equal</code>, <code>char=</code>, then <code>equal</code>, <code>eql</code> and
whatnot, so on for other data types, and the same for comparison
operators. There are no generic and extendible operators. For our
own types, we define its own functions.</p>

<p>As a reminder for those equality operators: <code>equal</code> does work on
integers, strings and characters and <code>equalp</code> also works for lists,
vectors and hash tables an other Common Lisp types but objects. See
<a href="https://stackoverflow.com/questions/43416293/why-is-there-no-generic-operators-for-common-lisp">the SO answers</a>
for precisions and experienced lispers debatting of the inner
subtilities and traps of those functions.</p>

<p>The language has mechanisms to create generics though, see
<a href="http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html">generics (defgeneric, defmethod)</a>
as described in Practical Common Lisp.</p>

<p>There have been work in that direction (<a href="https://common-lisp.net/project/cdr/document/8/cleqcmp.html">https://common-lisp.net/project/cdr/document/8/cleqcmp.html</a>) but no library as of today.</p>

<p>It&rsquo;s a recurrent concern, also
<a href="https://www.reddit.com/r/programming/comments/65ct5j/a_pythonist_finds_a_new_home_at_clojure_land/">this blog post</a>
(&ldquo;Not a monad tutorial&rdquo;, great serie) points to this. The guy moved
to Clojure, for other reasons too of course, where there are only one (or
two?) equality operators.</p>

<p>So it seems that the reason is mostly historical, the object system
(CLOS) appearing afterwards. Of course the generics would be
slower. But how much slower ? I really don&rsquo;t care, as a beginner and
for web stuff.</p>

<blockquote>
<p>Generic CLOS functions were added several years after CL was originally designed (82-84). The variant with CLOS was widely published with CLtL2 (1990) and then ANSI CL. The language was only slightly updated. It was not the intention to make Common Lisp fully object oriented. Also performance of CLOS for relatively low-level functions is kind of problematic. Dylan, which is something like Scheme + CLOS - s-expression syntax, did this: it defines more of the language in terms of generic functions. [Rainer Joswig on SO]</p>
</blockquote>

<h3 id="the-cl21-way">The CL21 way</h3>

<p>Fortunately <a href="http://cl21.org/">CL21</a> introduces (more) generic
operators, particularly for sequences it defines <code>length</code>, <code>append</code>,
<code>setf</code>, <code>getf</code>, <code>first</code>, <code>rest</code>, <code>subseq</code>, <code>replace</code>, <code>take</code>, <code>drop</code>, <code>fill</code>,
<code>take-while</code>, <code>drop-while</code>, <code>last</code>, <code>butlast</code>, <code>find-if</code>, <code>search</code>,
<code>remove-if</code>, <code>delete-if</code>, <code>reverse</code>, <code>reduce</code>, <code>sort</code>, <code>split</code>,
<code>join</code>, <code>remove-duplicates</code>, <code>every</code>, <code>some</code>, <code>map</code>, <code>sum</code> (and some
more). Those should work at least for <strong>strings</strong>, <strong>lists</strong>,
<strong>vectors</strong> and extend the new <code>abstract-sequence</code> type.</p>

<p>Now CL21 is something worth presenting and debatting in another post.</p>

<p>More:</p>

<ul>
<li><a href="https://github.com/cl21/cl21/wiki">https://github.com/cl21/cl21/wiki</a></li>
<li><a href="https://lispcookbook.github.io/cl-cookbook/cl21.html">https://lispcookbook.github.io/cl-cookbook/cl21.html</a></li>
</ul>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Example of interactively changing the current executed Lisp code in the debugger</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">14 04 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The awesome example we will read comes from a comment by user lispm
inside a discussion on this reddit thread:
<a href="https://www.reddit.com/r/programming/comments/65ct5j/a_pythonist_finds_a_new_home_at_clojure_land/">https://www.reddit.com/r/programming/comments/65ct5j/a_pythonist_finds_a_new_home_at_clojure_land/</a>.</p>

<p>The article it discusses is a
<a href="https://notamonadtutorial.com/a-pythonist-finds-a-new-home-at-clojure-land-761ad8612b47">&ldquo;Not a monad tutorial&rdquo;</a>
post, where the interviewee is experienced in C++, Java, Javascript and Python and
turns into Clojure. He wrote about his first impressions with Common
Lisp
<a href="https://facundoolano.wordpress.com/2012/01/31/first-impressions-on-common-lisp/">here</a>,
where he raises usual concerns that I agree with but IMO that stay
supercifial (&ldquo;not readable&rdquo; because of stuff like <code>(format t
&quot;~{~{~a:~10t~a~%~}~%~}&quot; *db*)</code>, &ldquo;huge operators set&rdquo;, &ldquo;macros look
promising&rdquo;…).</p>

<p>Here starts the discussion.</p>

<hr />

<p><code>dzecniv</code> On Common Lisp, I agree with the criticisms except</p>

<blockquote>
<p>the code was very difficult to read</p>
</blockquote>

<p>I find it very easy, always well expressed, with concise
functions. And I find Clojure&rsquo;s harder, with more
<code>[</code>, <code>{</code> and the same number of other symbols (<code>#</code>, <code>*</code>).</p>

<p>Anyway, I&rsquo;m in the process of trying to go from python to CL.
The CL ecosystem is quite good nowadays (equivalents of pip, venvs, pyenv, implementations (even
for the JVM or iOS), CI, sphinx, readthedocs, wsgi, setup.py,,…), it&rsquo;s moving, we can do quite a
lot (<a href="https://github.com/CodyReichert/awesome-cl">awesome list</a>),
it has unique features but yeah, the ecosystem is tiny compared to
clojure&rsquo;s…</p>

<p>ps: interested ? <a href="http://lisp-lang.org/">http://lisp-lang.org/</a> !</p>

<p><code>lispm</code></p>

<blockquote>
<p>tiny compared to clojure</p>
</blockquote>

<p>In many ways is it much broader than Clojure, since there is much more
choice. Interpreters, compilers, native code compilers, batch
compilers, compilers targeting
C/LLVM/JVM/ARM/ARM64/x86/x86-64/SPARC64/POWER/&hellip;</p>

<p>Clojure on the JVM uses a relatively simple and not very user-friendly
compiler to the JVM. No Interpreter. No mixed use of interpreted and
compiled code. Functions need to be declared before used. Error
messages are exposing the underlying JVM. No TCO. No images. Slow
startup.</p>

<p>The Roomba cleans your home with a CL program.</p>

<p><code>MagicMurderBagYT</code></p>

<blockquote>
<p>No Interpreter.</p>
</blockquote>

<p>Hol up. What about the REPL?</p>

<p><code>lispm</code></p>

<p>That&rsquo;s not an interpreter. A REPL is not the same as a Lisp
interpreter. REPL means read eval print loop. EVAL can be implemented
by a compiler or an interpreter. Common Lisp has both and mixed
implementations with both compiler and interpreter.</p>

<p>A Lisp interpreter is executing Lisp code directly. Clojure does not have an Interpreter.</p>

<blockquote>
<p><a href="https://clojure.org/reference/evaluation">https://clojure.org/reference/evaluation</a></p>

<p>Clojure has no interpreter.</p>
</blockquote>

<p>Example in LispWorks, which uses the Interpreter in the REPL:</p>

<pre><code class="language-lisp">CL-USER 29 &gt; (let ((f (lambda (a b)
                         (+ (prog1 2 (break))  ; we have a break here
                            (* a b)))))
              (funcall f 2 3))

Break.
  1 (continue) Return from break.
  2 (abort) Return to level 0.
  3 Return to top loop level 0.

Type :b for backtrace or :c &lt;option number&gt; to proceed.
Type :bug-form &quot;&lt;subject&gt;&quot; for a bug report template or :? for other options.
</code></pre>

<p>As you see Lisp comes with a sub-repl in the break. The sub-repl is
just another repl, but in the context of the break. The break could be
done by the debugger when it sees an error or by user code - as above.</p>

<p>Now we ask the interpreter for the current lambda expression:</p>

<pre><code class="language-lisp">CL-USER 30 : 1 &gt; :lambda
(LAMBDA (A B) (+ (PROG1 2 (BREAK)) (* A B)))
</code></pre>

<p>Above is actually Lisp data. Code as data.</p>

<p>Now I&rsquo;m changing the + function in the code to be expt,
exponentiation. To be clear: I&rsquo;m changing in the debugger the current
executed Lisp function on the Lisp level. We take the third element of
the list, and then the first one of that. This is the + symbol. We
change it to be expt. * holds the last evaluation result of the REPL.</p>

<pre><code class="language-lisp">CL-USER 31 : 1 &gt; (setf (first (third *)) 'expt)
EXPT
</code></pre>

<p>Then I&rsquo;m restarting the current stack frame:</p>

<pre><code class="language-lisp">CL-USER 32 : 1 &gt; :res
</code></pre>

<p>We get another break, which we just continue from:</p>

<pre><code>Break.
  1 (continue) Return from break.
  2 (abort) Return to level 0.
  3 Return to top loop level 0.

Type :b for backtrace or :c &lt;option number&gt; to proceed.
Type :bug-form &quot;&lt;subject&gt;&quot; for a bug report template or :? for other options.

CL-USER 33 : 1 &gt; :c 1
64                                   ; we computed 2^(2*3)  instead of 2+(2*3)
</code></pre>

<p>What did we see? We saw that the interpreter uses actual Lisp
code. Lisp code we can change with Lisp code in the debugger.</p>

<p>A second example.</p>

<p>What can we do with that for debugging? Well, we can for example write
our own evaluation tracer. The Evaluator prints each expression and
its result nicely indented, while walking the expression tree and
evaluating subexpressions. Remember: this is now user-level code. The
example is from CLtL2. You will also see that LispWorks can freely mix
compiled and interpreted functions. The function COMPILE takes a
function name and compiles its Lisp code to machine code.</p>

<pre><code class="language-lisp">CL-USER 1 &gt; (defvar *hooklevel* 0)
*HOOKLEVEL*

CL-USER 2 &gt; (defun hook (x)
              (let ((*evalhook* 'eval-hook-function))
                (eval x)))
HOOK

CL-USER 3 &gt; (compile 'hook)
HOOK
NIL
NIL

CL-USER 4 &gt; (defun eval-hook-function (form &amp;rest env)
              (let ((*hooklevel* (+ *hooklevel* 1)))
                (format *trace-output* &quot;~%~V@TForm:  ~S&quot;
                        (* *hooklevel* 2) form)
                (let ((values (multiple-value-list
                               (evalhook form
                                         #'eval-hook-function
                                         nil
                                         env))))
                  (format *trace-output* &quot;~%~V@TValue:~{ ~S~}&quot;
                          (* *hooklevel* 2) values)
                  (values-list values))))
EVAL-HOOK-FUNCTION

CL-USER 5 &gt; (compile 'eval-hook-function)
EVAL-HOOK-FUNCTION
NIL
NIL
</code></pre>

<p>Now we can trace the evaluation of expressions on the Lisp level:</p>

<pre><code>CL-USER 6 &gt; (hook '(cons (floor *print-base* 2) 'b))

  Form:  (CONS (FLOOR *PRINT-BASE* 2) (QUOTE B))
    Form:  (FLOOR *PRINT-BASE* 2)
      Form:  *PRINT-BASE*
      Value: 10
      Form:  2
      Value: 2
    Value: 5 0
    Form:  (QUOTE B)
    Value: B
  Value: (5 . B)
(5 . B)
</code></pre>

<p><code>dzecniv</code></p>

<p>that&rsquo;s an awesome example and tutorial that I&rsquo;d love to see on a blog
post or just a gist or something for further reference and better
archiving, this will be buried too quickly on reddit !</p>

<hr />

<p>So here it is.</p>

<p>Epilogue: <a href="https://duckduckgo.com/?q=the+roomba&amp;ia=web">the Roomba robot vacuums</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/21-adlitteram.png" alt="AdLitteram 21">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 21</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">14 04 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/21-adlitteram.png" alt="AdLitteram #21" title="AdLitteram #21" /></p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/40-steps-to-reproduce.png" alt="Steps to reproduce">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Steps to reproduce</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">11 04 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/40-steps-to-reproduce.png" alt="the result of dumping all sensor data to the bug tracker" title="the result of dumping all sensor data to the bug tracker" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Persistent Undo in Vim</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Jovica Ilic</a> <span class="article__date">07 04 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>As you already saw in the chapter on Undo/redo, Vim is pretty powerful when it comes to these features. However, there&#8217;s one more feature which I didn&#8217;t mention, as it takes a bit of configuration. In Vim, like in every other text editor, you can perform undo/redo in your current session. Once the session is... <a class="more-link" href="https://jovicailic.org/2017/04/vim-persistent-undo/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a rel="nofollow" href="https://jovicailic.org/2017/04/vim-persistent-undo/">Persistent Undo in Vim</a> appeared first on <a rel="nofollow" href="https://jovicailic.org">Jovica Ilic</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/20-adlitteram.png" alt="AdLitteram 20">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 20</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">07 04 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/20-adlitteram.png" alt="AdLitteram #20" title="AdLitteram #20" /></p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">MARGARITA SALAS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">04 04 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/39-different-perspectives.png" alt="Different Perspectives">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Different Perspectives</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">04 04 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/39-different-perspectives.png" alt="This applies for all routing frameworks" title="This applies for all routing frameworks" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/19-adlitteram.png" alt="AdLitteram 19">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 19</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">31 03 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/19-adlitteram.png" alt="AdLitteram #19" title="AdLitteram #19" /></p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to Turn Django Admin Into a Lightweight Dashboard</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">30 03 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Django Admin is a powerful tool for managing data in your app. However, it was not designed with summary tables and charts in mind. Luckily, the developers of Django Admin made it easy for us to customize. We are going to turn Django Admin into a dashboard by adding a chart and a summary table.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/38-product-stages.png" alt="Product Stages">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Product Stages</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">28 03 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/38-product-stages.png" alt="At the release point the product already has a quite amount of tech debt" title="At the release point the product already has a quite amount of tech debt" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/img/reagent-perf/reagent.png" alt="Comparing Reagent to React.js and Vue.js for dynamic tabular data">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Comparing Reagent to React.js and Vue.js for dynamic tabular data</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">26 03 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I recently ran across a <a href='https://engineering.footballradar.com/a-fairer-vue-of-react-comparing-react-to-vue-for-dynamic-tabular-data-part-2/?utm_content=buffer0e901'>comparison of React.js to Vue.js for rendering dynamic tabular data</a>, and I got curious to see how <a href='https://github.com/reagent-project/reagent'>Reagent</a> would stack up against them.</p><p>The benchmark simulates a view of football games represented by a table. Each row in the table represents the state of a particular game. The game states are updated once a second triggering UI repaints.</p><p>I structured the application similarly to the way that React.js version was structured in the original benchmark. The application has a <code>football.data</code> namespace to handle the business logic, and a <code>football.core</code> namespace to render the view.</p><h3 id="implementing&#95;the&#95;business&#95;logic">Implementing the Business Logic</h3><p>Let's start by implementing the business logic in the <code>football.data</code> namespace. First, we'll need to provide a container to hold the state of the games. To do that we'll create a Reagent atom called <code>games</code>:</p><pre><code class="clojure">&#40;ns football.data
  &#40;:require &#91;reagent.core :as reagent&#93;&#41;&#41;

&#40;defonce games &#40;reagent/atom nil&#41;&#41;
</code></pre><p>Next, we'll add a function to generate the fake players:</p><pre><code class="clojure">&#40;defn generate-fake-player &#91;&#93;
  {:name               &#40;-&gt; js/faker .-name &#40;.findName&#41;&#41;
   :effort-level       &#40;rand-int 10&#41;
   :invited-next-week? &#40;&gt; &#40;rand&#41; 0.5&#41;}&#41;
</code></pre><p>You can see that we're using JavaScript interop to leverage the <a href='https://github.com/marak/Faker.js/'>Faker.js</a> library for generating the player names. One nice aspect of working with ClojureScript is that JavaScript interop tends to be seamless as seen in the code above.</p><p>Now that we have a way to generate the players, let's add a function to generate fake games:</p><pre><code class="clojure">&#40;defn generate-fake-game &#91;&#93;
  {:id                 &#40;-&gt; js/faker .-random &#40;.uuid&#41;&#41;
   :clock              0
   :score              {:home 0 :away 0}
   :teams              {:home &#40;-&gt; js/faker .-address &#40;.city&#41;&#41;
                        :away &#40;-&gt; js/faker .-address &#40;.city&#41;&#41;}
   :outrageous-tackles 0
   :cards              {:yellow 0 :read 0}
   :players            &#40;mapv generate-fake-player &#40;range 4&#41;&#41;}&#41;
</code></pre><p>With the functions to generate the players and the games in place, we'll now add a function to generate a set of initial game states:</p><pre><code class="clojure">&#40;defn generate-games &#91;game-count&#93;
  &#40;reset! games &#40;mapv generate-fake-game &#40;range game-count&#41;&#41;&#41;&#41;
</code></pre><p>The next step is to write the functions to update the games and players to simulate the progression of the games. This code translates pretty much directly from the JavaScript version:</p><pre><code class="clojure">&#40;defn maybe-update &#91;game prob path f&#93;
  &#40;if &#40;&lt; &#40;rand-int 100&#41; prob&#41;
    &#40;update-in game path f&#41;
    game&#41;&#41;

&#40;defn update-rand-player &#91;game idx&#93;
  &#40;-&gt; game
      &#40;assoc-in &#91;:players idx :effort-level&#93; &#40;rand-int 10&#41;&#41;
      &#40;assoc-in &#91;:players idx :invited-next-week?&#93; &#40;&gt; &#40;rand&#41; 0.5&#41;&#41;&#41;&#41;

&#40;defn update-game &#91;game&#93;
  &#40;-&gt; game
      &#40;update :clock inc&#41;
      &#40;maybe-update 5 &#91;:score :home&#93; inc&#41;
      &#40;maybe-update 5 &#91;:score :away&#93; inc&#41;
      &#40;maybe-update 8 &#91;:cards :yellow&#93; inc&#41;
      &#40;maybe-update 2 &#91;:cards :red&#93; inc&#41;
      &#40;maybe-update 10 &#91;:outrageous-tackles&#93; inc&#41;
      &#40;update-rand-player &#40;rand-int 4&#41;&#41;&#41;&#41;
</code></pre><p>The last thing we need to do is to add the functions to update the game states at a specified interval. The original code uses <a href='https://github.com/Reactive-Extensions/RxJS'>Rx.js</a> to accomplish this, but it's just as easy to do using the <code>setTimeout</code> function with Reagent:</p><pre><code class="clojure">&#40;defn update-game-at-interval &#91;interval idx&#93;
  &#40;swap! games update idx update-game&#41;
  &#40;js/setTimeout update-game-at-interval interval interval idx&#41;&#41;

&#40;def event-interval 1000&#41;

&#40;defn update-games &#91;game-count&#93;
  &#40;dotimes &#91;i game-count&#93;
    &#40;swap! games update i update-game&#41;
    &#40;js/setTimeout #&#40;update-game-at-interval event-interval i&#41;
                   &#40;&#42; i event-interval&#41;&#41;&#41;&#41;
</code></pre><p>The <code>update-games</code> function updates the state of each game, then sets up a timeout for the recurring updates using the <code>update-game-at-interval</code> function.</p><h3 id="implementing&#95;the&#95;view">Implementing the View</h3><p>We're now ready to write the view portion of the application. We'll start by referencing the <code>football.data</code> namespace in the <code>football.core</code> namespace:</p><pre><code class="clojure">&#40;ns football.core
  &#40;:require
    &#91;football.data :as data&#93;
    &#91;reagent.core :as reagent&#93;&#41;&#41;
</code></pre><p>Next, we'll write the components to display the players and the games:</p><pre><code class="clojure">&#40;defn player-component &#91;{:keys &#91;name invited-next-week? effort-level&#93;}&#93;
  &#91;:td
   &#91;:div.player
    &#91;:p.player&#95;&#95;name
     &#91;:span name&#93;
     &#91;:span.u-small &#40;if invited-next-week? &quot;Doing well&quot; &quot;Not coming again&quot;&#41;&#93;&#93;
    &#91;:div {:class-name &#40;str &quot;player&#95;&#95;effort &quot;
                            &#40;if &#40;&lt; effort-level 5&#41;
                              &quot;player&#95;&#95;effort--low&quot;
                              &quot;player&#95;&#95;effort--high&quot;&#41;&#41;}&#93;&#93;&#93;&#41;

&#40;defn game-component &#91;game&#93;
  &#91;:tr
   &#91;:td.u-center &#40;:clock game&#41;&#93;
   &#91;:td.u-center &#40;-&gt; game :score :home&#41; &quot;-&quot; &#40;-&gt; game :score :away&#41;&#93;
   &#91;:td.cell--teams &#40;-&gt; game :teams :home&#41; &quot;-&quot; &#40;-&gt; game :teams :away&#41;&#93;
   &#91;:td.u-center &#40;:outrageous-tackles game&#41;&#93;
   &#91;:td
    &#91;:div.cards
     &#91;:div.cards&#95;&#95;card.cards&#95;&#95;card--yellow &#40;-&gt; game :cards :yellow&#41;&#93;
     &#91;:div.cards&#95;&#95;card.cards&#95;&#95;card--red &#40;-&gt; game :cards :red&#41;&#93;&#93;&#93;
   &#40;for &#91;player &#40;:players game&#41;&#93;
     &#94;{:key player}
     &#91;player-component player&#93;&#41;&#93;&#41;

&#40;defn games-component &#91;&#93;
  &#91;:tbody
   &#40;for &#91;game @data/games&#93;
     &#94;{:key game}
     &#91;game-component game&#93;&#41;&#93;&#41;

&#40;defn games-table-component &#91;&#93;
  &#91;:table
   &#91;:thead
    &#91;:tr
     &#91;:th {:width &quot;50px&quot;} &quot;Clock&quot;&#93;
     &#91;:th {:width &quot;50px&quot;} &quot;Score&quot;&#93;
     &#91;:th {:width &quot;200px&quot;} &quot;Teams&quot;&#93;
     &#91;:th &quot;Outrageous Tackles&quot;&#93;
     &#91;:th {:width &quot;100px&quot;} &quot;Cards&quot;&#93;
     &#91;:th {:width &quot;100px&quot;} &quot;Players&quot;&#93;
     &#91;:th {:width &quot;100px&quot;} &quot;&quot;&#93;
     &#91;:th {:width &quot;100px&quot;} &quot;&quot;&#93;
     &#91;:th {:width &quot;100px&quot;} &quot;&quot;&#93;
     &#91;:th {:width &quot;100px&quot;} &quot;&quot;&#93;&#93;&#93;
   &#91;games-component&#93;&#93;&#41;
</code></pre><p>You can see that HTML elements in Reagent components are represented using Clojure vectors and maps. Since s-expressions cleanly map to HTML, there's no need to use an additional DSL for that. You'll also notice that components can be nested within one another same way as plain HTML elements.</p><p>Noe thing to note is that the <code>games-component</code> dereferences the <code>data/games</code> atom using the <code>@</code> notation. Dereferencing simply means that we'd like to view the current state of a mutable variable.</p><p>Reagent atoms are reactive, and listeners are created when the atoms are dereferenced. Whenever the state of the atom changes, any components that are observing the atom will be notified of the change.</p><p>In our case, changes in the state of the <code>games</code> atom will trigger the <code>games-component</code> function to be evaluated. The function will pass the current state of the games down to its child components, and this will trigger any necessary repaints in the UI.</p><p>Finally, we have a bit of code to create the root component represented by the <code>home-page</code> function, and initialize the application:</p><pre><code class="clojure">&#40;defn home-page &#91;&#93;
  &#91;games-table-component&#93;&#41;

&#40;defn mount-root &#91;&#93;
  &#40;reagent/render &#91;home-page&#93; &#40;.getElementById js/document &quot;app&quot;&#41;&#41;&#41;

&#40;def game-count 50&#41;

&#40;defn init! &#91;&#93;
  &#40;data/generate-games game-count&#41;
  &#40;data/update-games game-count&#41;
  &#40;mount-root&#41;&#41;
</code></pre><p>We now have a naive implementation of the benchmark using Reagent. The entire project is <a href='https://github.com/yogthos/ReagentPerf'>available on GitHub</a>. Next, let's take a look at how it performs.</p><h3 id="profiling&#95;with&#95;chrome">Profiling with Chrome</h3><p>When we profile the app in Chrome, we'll see the following results:</p><p><img src="/img/reagent-perf/reagent.png" alt="Reagent Results" /></p><p>Here are the results for React.js and Vue.js running in the same environment for comparison:</p><p><img src="/img/reagent-perf/react.png" alt="React.js Results" /></p><p><img src="/img/reagent-perf/vue.png" alt="Vue.js Results" /></p><p>As you can see, the naive Reagent version spends about double the time scripting compared to React.js, and about four times as long rendering.</p><p>The reason is that we're dereferencing the <code>games</code> atom at top level. This forces the top level component to be reevaluated whenever the sate of any game changes.</p><p>Reagent provides a mechanism for dealing with this problem in the form of cursors. A cursor allows subscribing to changes at a specified path within the atom. A component that dereferences a cursor will only be updated when the data the cursor points to changes. This allows us to granularly control what components will be repainted when a particular piece of data changes in the <code>games</code> atom. Let's update the view logic as follows:</p><pre><code class="clojure">&#40;defn player-component &#91;player&#93;
  &#91;:td
   &#91;:div.player
    &#91;:p.player&#95;&#95;name
     &#91;:span &#40;:name @player&#41;&#93;
     &#91;:span.u-small
      &#40;if &#40;:invited-next-week? @player&#41;
        &quot;Doing well&quot; &quot;Not coming again&quot;&#41;&#93;&#93;
    &#91;:div {:class-name &#40;str &quot;player&#95;&#95;effort &quot;
                            &#40;if &#40;&lt; &#40;:effort-level @player&#41; 5&#41;
                              &quot;player&#95;&#95;effort--low&quot;
                              &quot;player&#95;&#95;effort--high&quot;&#41;&#41;}&#93;&#93;&#93;&#41;

&#40;defn game-component &#91;game&#93;
  &#91;:tr
   &#91;:td.u-center &#40;:clock @game&#41;&#93;
   &#91;:td.u-center &#40;-&gt; @game :score :home&#41; &quot;-&quot; &#40;-&gt; @game :score :away&#41;&#93;
   &#91;:td.cell--teams &#40;-&gt; @game :teams :home&#41; &quot;-&quot; &#40;-&gt; @game :teams :away&#41;&#93;
   &#91;:td.u-center &#40;:outrageous-tackles @game&#41;&#93;
   &#91;:td
    &#91;:div.cards
     &#91;:div.cards&#95;&#95;card.cards&#95;&#95;card--yellow &#40;-&gt; @game :cards :yellow&#41;&#93;
     &#91;:div.cards&#95;&#95;card.cards&#95;&#95;card--red &#40;-&gt; @game :cards :red&#41;&#93;&#93;&#93;
   &#40;for &#91;idx &#40;range &#40;count &#40;:players @game&#41;&#41;&#41;&#93;
     &#94;{:key idx}
     &#91;player-component &#40;reagent/cursor game &#91;:players idx&#93;&#41;&#93;&#41;&#93;&#41;

&#40;def game-count 50&#41;

&#40;defn games-component &#91;&#93;
  &#91;:tbody
   &#40;for &#91;idx &#40;range game-count&#41;&#93;
     &#94;{:key idx}
     &#91;game-component &#40;reagent/cursor data/games &#91;idx&#93;&#41;&#93;&#41;&#93;&#41;

&#40;defn games-table-component &#91;&#93;
  &#91;:table
   &#91;:thead
    &#91;:tr
     &#91;:th {:width &quot;50px&quot;} &quot;Clock&quot;&#93;
     &#91;:th {:width &quot;50px&quot;} &quot;Score&quot;&#93;
     &#91;:th {:width &quot;200px&quot;} &quot;Teams&quot;&#93;
     &#91;:th &quot;Outrageous Tackles&quot;&#93;
     &#91;:th {:width &quot;100px&quot;} &quot;Cards&quot;&#93;
     &#91;:th {:width &quot;100px&quot;} &quot;Players&quot;&#93;
     &#91;:th {:width &quot;100px&quot;} &quot;&quot;&#93;
     &#91;:th {:width &quot;100px&quot;} &quot;&quot;&#93;
     &#91;:th {:width &quot;100px&quot;} &quot;&quot;&#93;
     &#91;:th {:width &quot;100px&quot;} &quot;&quot;&#93;&#93;&#93;
   &#91;games-component&#93;&#93;&#41;

&#40;defn home-page &#91;&#93;
  &#91;games-table-component&#93;&#41;
</code></pre><p>The above version creates a cursor for each game in the <code>games-components</code>. The <code>game-component</code> in turn creates a cursor for each player. This way only the components that actually need updating end up being rendered as the state of the games is updated. Let's profile the application again to see how much impact this has on its performance:</p><p><img src="/img/reagent-perf/reagent-cursor.png" alt="Reagent Results" /></p><p>The performance of the Reagent code using cursors now looks similar to that of the Vue.js implementation. You can see the entire source for the updated version <a href='https://github.com/yogthos/ReagentPerf/tree/reagent-cursors'>here</a>.</p><h3 id="conclusion">Conclusion</h3><p>In this post we saw that ClojureScript with Reagent provides a compelling alternative to JavaScript offerings such as React.js and Vue.js.</p><p>Reagent allows writing succinct solutions that perform as well as those implemented using native JavaScript libraries. It also provides us with tools to intuitively reason about what parts of the view are going to be updated.</p><p>Likewise, we get many benefits by simply switching from using JavaScript to ClojureScript.</p><p>For example, We already saw that we didn't need any additional syntax, such as JSX, to represent HTML elements. Since HTML templates are represented using regular data structures, they follows the same rules as any other code. This allows us to transform them just like we would any other data in our project.</p><p>In general, I find ClojureScript to be much more consistent and less noisy than equivalent JavaScript code. Consider the implementation of the <code>updateGame</code> function in the original JavaScript version:</p><pre><code class="javascript">function updateGame&#40;game&#41; {
    game = game.update&#40;&quot;clock&quot;, &#40;sec&#41; =&gt; sec + 1&#41;;

    game = maybeUpdate&#40;5, game, &#40;&#41; =&gt; game.updateIn&#40;&#91;&quot;score&quot;, &quot;home&quot;&#93;, &#40;s&#41; =&gt; s + 1&#41;&#41;;
    game = maybeUpdate&#40;5, game, &#40;&#41; =&gt; game.updateIn&#40;&#91;&quot;score&quot;, &quot;away&quot;&#93;, &#40;s&#41; =&gt; s + 1&#41;&#41;;
    
    game = maybeUpdate&#40;8, game, &#40;&#41; =&gt; game.updateIn&#40;&#91;&quot;cards&quot;, &quot;yellow&quot;&#93;, &#40;s&#41; =&gt; s + 1&#41;&#41;;
    game = maybeUpdate&#40;2, game, &#40;&#41; =&gt; game.updateIn&#40;&#91;&quot;cards&quot;, &quot;red&quot;&#93;, &#40;s&#41; =&gt; s + 1&#41;&#41;;

    game = maybeUpdate&#40;10, game, &#40;&#41; =&gt; game.update&#40;&quot;outrageousTackles&quot;, &#40;t&#41; =&gt; t + 1&#41;&#41;;

    const randomPlayerIndex = randomNum&#40;0, 4&#41;;
    const effortLevel = randomNum&#40;&#41;;
    const invitedNextWeek = faker.random.boolean&#40;&#41;;

    game = game.updateIn&#40;&#91;&quot;players&quot;, randomPlayerIndex&#93;, &#40;player&#41; =&gt; {
        return player.set&#40;&quot;effortLevel&quot;, effortLevel&#41;.set&#40;&quot;invitedNextWeek&quot;, invitedNextWeek&#41;;
    }&#41;;

    return game;
}
</code></pre><p>Compare it with the equivalent ClojureScript code:</p><pre><code class="clojure">&#40;defn update-rand-player &#91;game idx&#93;
  &#40;-&gt; game
      &#40;assoc-in &#91;:players idx :effort-level&#93; &#40;rand-int 10&#41;&#41;
      &#40;assoc-in &#91;:players idx :invited-next-week?&#93; &#40;&gt; &#40;rand&#41; 0.5&#41;&#41;&#41;&#41;

&#40;defn update-game &#91;game&#93;
  &#40;-&gt; game
      &#40;update :clock inc&#41;
      &#40;maybe-update 5 &#91;:score :home&#93; inc&#41;
      &#40;maybe-update 5 &#91;:score :away&#93; inc&#41;
      &#40;maybe-update 8 &#91;:cards :yellow&#93; inc&#41;
      &#40;maybe-update 2 &#91;:cards :red&#93; inc&#41;
      &#40;maybe-update 10 &#91;:outrageous-tackles&#93; inc&#41;
      &#40;update-rand-player &#40;rand-int 4&#41;&#41;&#41;&#41;
</code></pre><p>ClojureScript version has a lot less syntactic noise, and I find this has direct impact on my ability to reason about the code. The more quirks there are, the more likely I am to misread the intent. Noisy syntax results in situations where code looks like it's doing one thing, while it's actually doing something subtly different.</p><p>Another advantage is that ClojureScript is backed by immutable data structures by default. My experience is that immutability is crucial for writing large maintainable projects, as it allows safely reasoning about parts of the code in isolation.</p><p>Since immutability is pervasive as opposed to opt-in, it allows for tooling to be designed with it in mind. For example, <a href='https://github.com/bhauman/lein-figwheel'>Figwheel</a> plugin relies on this property to provide live hot reloading in the browser.</p><p>Finally, ClojureScript compiler can do many optimizations, such as <a href='http://swannodette.github.io/2015/01/06/the-false-promise-of-javascript-microlibs'>dead code elimination</a>, that are difficult to do with JavaScript. I highly recommend the <a href='https://www.youtube.com/watch?v=cH4ZJAKZHjQ'>Now What?</a> talk by David Nolen that goes into more details regarding this.</p><p>Overall, I'm pleased to see that ClojureScript and Reagent perform so well when stacked up against native JavaScript libraries. It's hard to overstate the fact that a ClojureScript library built on top of React.js can outperform React.js itself.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">JavaScript. But less iffy.</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">24 03 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Have you ever started writing some code that seemed so simple? But then you had to validate the input? And handle an edge case? Oh yeah, and that weird thing the server sometimes does? And somehow this oh-so-simple piece of code turned into a mess? This article looks at how we can reduce the complexity introduced by conditionals.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">JavaScript. But less iffy.</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">24 03 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Have you ever started writing some code that seemed so simple? But then you had to validate the input? And handle an edge case? Oh yeah, and that weird thing the server sometimes does? And somehow this oh-so-simple piece of code turned into a mess? This article looks at how we can reduce the complexity introduced by conditionals.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/18-adlitteram.png" alt="AdLitteram 18">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 18</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">24 03 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/18-adlitteram.png" alt="AdLitteram #18" title="AdLitteram #18" /></p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/37-testing-vs-prod.png" alt="Testing Vs Production Environment">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Testing Vs Production Environment</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">21 03 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/37-testing-vs-prod.png" alt="The production environment is full of strange people" title="The production environment is full of strange people" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/17-adlitteram.png" alt="AdLitteram 17">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 17</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">17 03 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/17-adlitteram.png" alt="AdLitteram #17" title="AdLitteram #17" /></p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://www.emezeta.com/img/logo.png" alt="10 juegos Indie gratuitos estilo pixel art">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">10 juegos Indie gratuitos estilo pixel art</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Emezeta blog</a> <span class="article__date">16 03 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ¿Te gustan los juegos con estética retro o pixel art? Aquí tienes 10 juegos Indie gratuitos que no te puedes perder.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/36-trivial-bug.png" alt="Trivial Bug">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Trivial Bug</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">16 03 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/36-trivial-bug.png" alt="Sometimes a trivial bug has deeper roots" title="Sometimes a trivial bug has deeper roots" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/35-shared-db.png" alt="Shared DB">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Shared DB</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">14 03 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/35-shared-db.png" alt="Sharing the DB with th QA Environment is not caring" title="Sharing the DB with th QA Environment is not caring" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">CARNAVALES Y RESIDUOS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">13 03 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/16-adlitteram.png" alt="AdLitteram 16">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 16</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">10 03 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>
<div class="center">Suggested by: <a href="https://twitter.com/jaivalis"><i class="ssk ssk-icon ssk-twitter"></i>@jaivalis</a> </div>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/16-adlitteram.png" alt="AdLitteram #16" title="AdLitteram #16" /></p>


                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/34-bugshots.png" alt="Bugshots">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Bugshots</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">07 03 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/34-bugshots.png" alt="We know that tardigrade is not a bug" title="We know that tardigrade is not a bug" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/15-adlitteram.png" alt="AdLitteram 15">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 15</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">03 03 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/15-adlitteram.png" alt="AdLitteram #15" title="AdLitteram #15" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/33-sha-1-collision.png" alt="SHA-1 Collision">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">SHA-1 Collision</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">28 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/33-sha-1-collision.png" alt="SHA-1 Collision" title="SHA-1 Collision" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/31-staticvsdynamiclinking.png" alt="Static vs. Dynamic Linking">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Static vs. Dynamic Linking</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">27 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/31-staticvsdynamiclinking.png" alt="Static vs. Dynamic Linking" title="Static vs. Dynamic Linking" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/14-adlitteram.png" alt="AdLitteram 14">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 14</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">24 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/14-adlitteram.png" alt="AdLitteram #14" title="AdLitteram #14" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Mastering Vim Quickly: Introduction</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Jovica Ilic</a> <span class="article__date">23 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>This post presents a chapter from my upcoming book Mastering Vim Quickly: From WTF to OMG in no time &#160; Introduction There&#8217;s so much you want to do in life, and so little time. The story of our modern lives. Take a moment and consider how many things you want to learn. Since you&#8217;re reading... <a class="more-link" href="https://jovicailic.org/2017/02/mastering-vim-quickly-intro/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a rel="nofollow" href="https://jovicailic.org/2017/02/mastering-vim-quickly-intro/">Mastering Vim Quickly: Introduction</a> appeared first on <a rel="nofollow" href="https://jovicailic.org">Jovica Ilic</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/31-tales-of-regex-42.png" alt="Tales of RegEx&amp;#58; &amp;#35;42">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Tales of RegEx&amp;#58; &amp;#35;42</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">21 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/31-tales-of-regex-42.png" alt="Tales of RegEx: #42" title="Tales of RegEx: #42" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to Test Django Signals Like a Pro</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">17 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Django signals are extremely useful for decoupling modules. They allow a low-level Django app to send events for other apps to handle without creating a direct dependency. Signals are easy to set up, but harder to test. In this article we implement a context manager for testing Django signals, step by step.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/13-adlitteram.png" alt="AdLitteram 13">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 13</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">17 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/13-adlitteram.png" alt="AdLitteram #13" title="AdLitteram #13" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/30-devops-life.png" alt="DevOps Life">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">DevOps Life</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">16 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/30-devops-life.png" alt="DevOps Life" title="DevOps Life" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Instapaper Service Fully Restored</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Instapaper</a> <span class="article__date">14 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>After suffering from <a href="http://blog.instapaper.com/post/157027537441">an extended outage</a> on Wednesday, February 9 at 12:30PM PT through Thursday, February 10 at 7:30PM PT, we brought the Instapaper service back up with <a href="http://blog.instapaper.com/post/157045376396">limited access to archives</a> as a short-term solution while we worked to restore the service completely.</p><p>Today at 1AM PT we completely restored the Instapaper service, including access to all archives. We performed the restoration without losing any of your older articles, changes made to more recent articles or articles saved after recovering from the outage.</p><p><b></b></p><p>We apologize for the extended downtime and the time it took to regain access to your complete archives. Instapaper has operated as a high availability service over the last nine years without many hiccups. The root cause of this outage was both difficult to predict and prevent, and the nature of the outage is extremely rare and unlikely to recur. We appreciate your patience during this time. </p><p><b></b></p><p>We’d like to thank the Pinterest Site Reliability Engineering team for guiding us through the recovery, and the Amazon Relational Database Service team for working with us throughout the weekend to dramatically expedite the recovery process.</p><p><b></b>Lastly, if you’re interested in a more detailed overview of the issue that caused the outage and our process to recover the service, you can learn more on our <a href="https://medium.com/making-instapaper/3c32a7e9cc5f">Engineering Blog</a>.<br/></p><p>– Instapaper Team</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/29-hotfix.png" alt="Hotfix">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hotfix</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">14 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/29-hotfix.png" alt="Hotfix" title="Hotfix" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">¿Han sido los Reyes Magos Sostenibles?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">13 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">MUJERES Y CIENCIA</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Andanzas de una ambientóloga . . .</a> <span class="article__date">13 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://www.emezeta.com/img/logo.png" alt="Navegadores web: ¿Cuál es el mejor navegador para mi?">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Navegadores web: ¿Cuál es el mejor navegador para mi?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Emezeta blog</a> <span class="article__date">12 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Existen multitud de navegadores web, aunque casi siempre optamos por Chrome o Firefox. ¿Quieres saber qué otros navegadores existen y qué tienen de especial?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Instapaper Restored, Access to Archives Limited</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Instapaper</a> <span class="article__date">10 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>As we <a href="http://blog.instapaper.com/post/157027537441">shared earlier today</a>, Instapaper is experiencing an extended outage. After 31 hours of downtime, we were able to rebuild a database instance to get Instapaper back online! In the interest of coming back up as soon as possible, this instance only has the last six weeks of articles. For now, anything you’ve saved since December 20, 2016 is accessible.<br/></p><p>We’re working on getting the rest of your articles restored, but wanted to give you access to  your most recently saved articles in the meantime. Again, there hasn’t been any data loss. The full database exports are taking much longer than anticipated. </p><p>We’re aiming to get the full archives available by next Friday, February 17 at the latest. We appreciate your patience and understanding in the interim.</p><p>– Instapaper Team<br/></p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/12-adlitteram.png" alt="AdLitteram 12">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 12</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">10 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/12-adlitteram.png" alt="AdLitteram #12" title="AdLitteram #12" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">JavaScript Without Loops</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">09 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        We've been talking about writing less complex JavaScript. We do this by choosing the right abstraction to solve a problem. But how do you know which abstraction to use? So far, we haven't looked at any concrete examples of how to do this. In this article we look at how to deal with JavaScript arrays, without using any loops. The end result is less complex code.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">JavaScript Without Loops</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">09 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        We've been talking about writing less complex JavaScript. We do this by choosing the right abstraction to solve a problem. But how do you know which abstraction to use? So far, we haven't looked at any concrete examples of how to do this. In this article we look at how to deal with JavaScript arrays, without using any loops. The end result is less complex code.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Extended Outage</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Instapaper</a> <span class="article__date">09 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Yesterday, February 8th, at 12:30PM PT Instapaper suffered from an outage that has extended through this morning.</p><p>After spending multiple hours on the phone with our cloud service provider, it appears we hit a system limit for our hosted database that’s preventing new articles from being saved. At this time, our only option is to export all data from our old database and import it into a new one. We expect the service to be fully recovered today, February 9.<b><br/></b></p><p>We pride ourselves on being a reliable service with minimal downtime (we were up for 99.93% of 2016), and know many of you rely on Instapaper every day. We apologize that this issue has resulted in an extended period of downtime.</p><p>We assure you we haven’t lost any data. While you may not have been able to save articles during the outage, anything you’ve already saved to Instapaper is safe. We appreciate your patience while we work diligently to get it resolved.</p><p>- Instapaper Team</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/28-programming-languages-as-humans.png" alt="Programming languages as humans">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Programming languages as humans</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">07 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/28-programming-languages-as-humans.png" alt="Programming languages as humans" title="Programming languages as humans" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://camo.githubusercontent.com/17dd6e0a7a916c8118f0134a94404f6757bee9dc/68747470733a2f2f7261772e6769746875622e636f6d2f6575646f786961302f636c61636b2d6572726f72732f6d61737465722f73637265656e73686f742d6465762e706e67" alt="State of Common Lisp Web Development - an overview">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">State of Common Lisp Web Development - an overview</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">05 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<p>Caution: this is a draft. I take notes and write more in other resources (the Cookbook, my blog).</p>

<p><strong>update july, 5th 2019</strong>: I put this content into the Cookbook: <a href="https://lispcookbook.github.io/cl-cookbook/web.html">https://lispcookbook.github.io/cl-cookbook/web.html</a>, fixing a long-standing request.</p>

<p><strong>new post: why and how to live-reload one&rsquo;s running web application</strong>: <a href="https://lisp-journey.gitlab.io/blog/i-realized-that-to-live-reload-my-web-app-is-easy-and-convenient/">https://lisp-journey.gitlab.io/blog/i-realized-that-to-live-reload-my-web-app-is-easy-and-convenient/</a></p>

<p><strong>new project skeleton</strong>: <a href="https://github.com/vindarel/lisp-web-template-productlist">lisp-web-template-productlist</a>: Hunchentoot + easy-routes + Djula templates + Bulma CSS + a Makefile to build the project</p>

<p>See also the
<a href="https://github.com/CodyReichert/awesome-cl#network-and-internet">Awesome CL list</a>.</p>

<p>Information is at the moment scarce and spread appart, Lisp web
frameworks and libraries evolve and take different approaches.</p>

<p>I&rsquo;d like to know what&rsquo;s possible, what&rsquo;s lacking, see how to
quickstart everything, see code snippets and, most of all, see how to
do things that I couldn&rsquo;t do before such as hot reloading, building
self-contained executables, shipping a multiplatform web app.</p>

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-generate-toc again -->

<p><strong>Table of Contents</strong></p>

<ul>
<li><a href="#web-application-environments">Web application environments</a>

<ul>
<li><a href="#clack-lack">Clack, Lack</a></li>
</ul></li>
<li><a href="#web-frameworks">Web frameworks</a>

<ul>
<li><a href="#hunchentoot">Hunchentoot</a></li>
<li><a href="#caveman">Caveman</a></li>
<li><a href="#lucerne">Lucerne</a></li>
<li><a href="#snooze">Snooze</a></li>
<li><a href="#radiance">Radiance</a></li>
<li><a href="#cl-rest-server">cl-rest-server</a></li>
<li><a href="#wookie">Wookie</a></li>
<li><a href="#weblocks-solving-the-javascript-problem">Weblocks (solving the Javascript problem)</a></li>
</ul></li>
<li><a href="#tasks">Tasks</a>

<ul>
<li><a href="#accessing-url-parameters">Accessing url parameters</a></li>
<li><a href="#session-an-cookies">Session an cookies</a></li>
<li><a href="#data-storage">Data storage</a></li>
<li><a href="#sql">SQL</a>

<ul>
<li><a href="#persistent-datastores">Persistent datastores</a></li>
<li><a href="#migrations">Migrations</a></li>
</ul></li>
<li><a href="#forms">Forms</a>

<ul>
<li><a href="#form-validation">Form validation</a></li>
</ul></li>
<li><a href="#debugging">Debugging</a></li>
<li><a href="#testing">Testing</a></li>
<li><a href="#misc">Misc</a>

<ul>
<li><a href="#oauth-job-queues-etc">Oauth, Job queues, etc</a></li>
</ul></li>
</ul></li>
<li><a href="#templating-engines">Templating engines</a>

<ul>
<li><a href="#html-based">HTML-based</a></li>
<li><a href="#lisp-based">Lisp-based</a></li>
</ul></li>
<li><a href="#javascript">Javascript</a>

<ul>
<li><a href="#parenscript">Parenscript</a></li>
<li><a href="#jscl">JSCL</a></li>
<li><a href="#ajax">Ajax</a></li>
<li><a href="#the-case-webblocks---reblocks-2017">The case Webblocks - Reblocks, 2017</a></li>
</ul></li>
<li><a href="#shipping">Shipping</a>

<ul>
<li><a href="#building">Building</a></li>
<li><a href="#multiplatform-delivery-with-electron-ceramic">Multiplatform delivery with Electron (Ceramic)</a></li>
</ul></li>
<li><a href="#deployment">Deployment</a>

<ul>
<li><a href="#running-the-app-on-a-web-server">Running the app on a web server</a>

<ul>
<li><a href="#manually">Manually</a></li>
<li><a href="#with-clackhttpquickdocsorgclack">with <a href="http://quickdocs.org/clack/">Clack</a></a></li>
<li><a href="#with-docker">with Docker</a></li>
<li><a href="#on-heroku">On Heroku</a></li>
<li><a href="#daemonizing-restarting-in-case-of-crashes-handling-logs">Daemonizing, restarting in case of crashes, handling logs</a></li>
<li><a href="#debugging-sbcl-error-ensurespace-failed-to-allocate-n-bytes">Debugging SBCL error: ensure_space: failed to allocate n bytes</a></li>
</ul></li>
<li><a href="#connecting-to-a-remote-swank-server">Connecting to a remote Swank server</a></li>
<li><a href="#hot-reload">Hot reload</a></li>
</ul></li>
<li><a href="#appendice-i-example-websites-built-with-lisp">Appendice I: Example websites built with Lisp:</a></li>
<li><a href="#appendice-ii-example-software">Appendice II: Example software</a></li>
</ul>

<!-- markdown-toc end -->

<h1 id="web-application-environments">Web application environments</h1>

<h2 id="clack-lack">Clack, Lack</h2>

<p>Clack is to Lisp what WSGI is to Python. However it is mostly undocumented and not as battle-proofed as Hunchentoot.</p>

<h1 id="web-frameworks">Web frameworks</h1>

<h2 id="hunchentoot">Hunchentoot</h2>

<p>The de-facto web server, with the best documentation (cough looking old cough),
the most websites on production. Lower level than a web framework
(defining routes seems weird at first). I think worth knowing.</p>

<p>Its terminology is different from what we are used to (&ldquo;routes&rdquo; are
not called routes but we create handlers), part I don&rsquo;t know why and
part because the Lisp image-based development allows for more, and
thus needs more terminology. For example, we can run two applications
on different URLs on the same image.</p>

<p><a href="https://edicl.github.io/hunchentoot/">https://edicl.github.io/hunchentoot/</a></p>

<p><strong>edit</strong>: here&rsquo;s a modern looking page: <a href="https://digikar99.github.io/common-lisp.readthedocs/hunchentoot/">https://digikar99.github.io/common-lisp.readthedocs/hunchentoot/</a></p>

<h2 id="caveman">Caveman</h2>

<p>A popular web framework, or so it seems by the github stars, written by a super-productive lisper, with nice documentation for basic
stuff but lacking for the rest, based on Clack (webserver interface,
think Python&rsquo;s WSGI), uses Hunchentoot by default.</p>

<p>I feel like basic functions are too cumbersome (accessing url parameters).</p>

<p><a href="https://github.com/fukamachi/caveman">https://github.com/fukamachi/caveman</a></p>

<h2 id="snooze">Snooze</h2>

<p>By the maintainer of Sly, Emacs&rsquo; Yasnippet,…</p>

<p>Defining routes is like defining functions. Built-in features that are
available as extensions in Clack-based frameworks (setting to get a
stacktrace on the browser, to fire up the debugger or to return a
404,…). Definitely worth exploring.</p>

<p><a href="https://github.com/joaotavora/snooze">https://github.com/joaotavora/snooze</a></p>

<h2 id="radiance">Radiance</h2>

<p><a href="https://github.com/Shirakumo/radiance">Radiance</a>, with extensive tutorial and existing apps.</p>

<p>It doesn&rsquo;t look like a web framework to me. It has ready-to-use components:</p>

<ul>
<li>admin page (but what does it do?)</li>
<li>auth system</li>
<li>user: provide user accounts and permissions</li>
<li>image hosting</li>
<li>there is an email marketing system in development…</li>
</ul>

<h2 id="cl-rest-server">cl-rest-server</h2>

<p><a href="https://github.com/mmontone/cl-rest-server">cl-rest-server</a></p>

<blockquote>
<p>a library for writing REST Web APIs in Common Lisp.</p>
</blockquote>

<p>Features: validation via schemas, Swagger support, authentication, logging, caching, permission checking…</p>

<p>It seems complete, it is maintained, the author seems to be doing web development in CL for a living. Note to self: I want to interview him.</p>

<h2 id="wookie">Wookie</h2>

<p><a href="https://github.com/orthecreedence/wookie">https://github.com/orthecreedence/wookie</a></p>

<p>An asynchronous web server, by an impressive lisper, who built many async
libraries. Used for the <a href="https://github.com/turtl/api/">Turtl</a> api
backend. Dealing with async brings its own set of problems (how will
be debugging ?).</p>

<p>Nice api to build routes, good documentation: <a href="http://wookie.lyonbros.com/">http://wookie.lyonbros.com/</a></p>

<h2 id="weblocks-solving-the-javascript-problem">Weblocks (solving the Javascript problem)</h2>

<p>Weblocks allows to create dynamic pages without a line of JavaScript,
all in Lisp. It was started years ago and it saw a large update and
refactoring lately.</p>

<p>It isn&rsquo;t the easy path to web development in CL but there&rsquo;s great potential IMO.</p>

<p>It doesn&rsquo;t do double data binding as in modern JS frameworks. But new projects are being developed…</p>

<p>See our presentation below.</p>

<p><a href="http://40ants.com/weblocks/quickstart.html">http://40ants.com/weblocks/quickstart.html</a></p>

<h1 id="tasks">Tasks</h1>

<h2 id="accessing-url-parameters">Accessing url parameters</h2>

<p>It is easy and well explained with Hunchentoot or <code>easy-routes</code> in the Cookbook.</p>

<p><a href="http://borretti.me/lucerne/docs/overview.html">Lucerne</a> has a nice
<code>with-params</code> macro that makes accessing post or url query parameters a breeze:</p>

<pre><code class="language-lisp">@route app (:post &quot;/tweet&quot;)
(defview tweet ()
  (if (lucerne-auth:logged-in-p)
      (let ((user (current-user)))
        (with-params (tweet)
          (utweet.models:tweet user tweet))
        (redirect &quot;/&quot;))
      (render-template (+index+)
                       :error &quot;You are not logged in.&quot;)))
</code></pre>

<hr />

<p><a href="https://github.com/joaotavora/snooze">Snooze</a>&rsquo;s way is simple and
lispy: we define routes like methods and parameters as keys:</p>

<pre><code class="language-lisp">(defroute lispdoc (:get :text/* name &amp;key (package :cl) (doctype 'function))
   ...
</code></pre>

<p>matches <code>/lispdoc</code>, <code>/lispdoc/foo</code> and <code>/lispdoc/foo?package=arg</code>.</p>

<hr />

<p>On the contrary, I find Caveman&rsquo;s and Ningle&rsquo;s ways cumbersome.</p>

<p>Ningle:</p>

<pre><code class="language-lisp">(setf (ningle:route *app* &quot;/hello/:name&quot;)
      #'(lambda (params)
          (format nil &quot;Hello, ~A&quot; (cdr (assoc &quot;name&quot; params :test #'string=)))))
</code></pre>

<blockquote>
<p>The above controller will be invoked when you access to &ldquo;/hello/Eitaro&rdquo; or &ldquo;/hello/Tomohiro&rdquo;, and then (cdr (assoc &ldquo;name&rdquo; params :test #&lsquo;string=)) will be &ldquo;Eitaro&rdquo; and &ldquo;Tomohiro&rdquo;.</p>
</blockquote>

<p>and it doesn&rsquo;t say about query parameters. I had to <a href="https://stackoverflow.com/questions/43778570/how-to-get-url-query-parameters-in-clack-lucerne-or-caveman">ask</a>:</p>

<pre><code class="language-lisp">(assoc &quot;the-query-param&quot; (clack.request:query-parameter lucerne:*request*) :test 'string=)
</code></pre>

<p>Caveman:</p>

<blockquote>
<p>Parameter keys contain square brackets (&rdquo;[&rdquo; &amp; &ldquo;]&rdquo;) will be parsed as structured parameters. You can access the parsed parameters as _parsed in routers.</p>
</blockquote>

<pre><code class="language-lisp">(defroute &quot;/edit&quot; (&amp;key _parsed)
  (format nil &quot;~S&quot; (cdr (assoc &quot;person&quot; _parsed :test #'string=))))
;=&gt; &quot;((\&quot;name\&quot; . \&quot;Eitaro\&quot;) (\&quot;email\&quot; . \&quot;e.arrows@gmail.com\&quot;) (\&quot;birth\&quot; . ((\&quot;year\&quot; . 2000) (\&quot;month\&quot; . 1) (\&quot;day\&quot; . 1))))&quot;
</code></pre>

<h2 id="session-an-cookies">Session an cookies</h2>

<h2 id="data-storage">Data storage</h2>

<h2 id="sql">SQL</h2>

<p><a href="https://github.com/fukamachi/mito">Mito</a> works for MySQL, Postgres
and SQLite3 on SBCL and CCL.</p>

<p><a href="https://lispcookbook.github.io/cl-cookbook/databases.html">https://lispcookbook.github.io/cl-cookbook/databases.html</a></p>

<p>We can define models with a regular class which has a <code>mito:dao-table-class</code> <code>:metaclass</code>:</p>

<pre><code class="language-lisp">(defclass user ()
  ((name :col-type (:varchar 64)
         :initarg :name
         :accessor user-name)
   (email :col-type (:varchar 128)
          :initarg :email
          :accessor user-email))
  (:metaclass mito:dao-table-class)
  (:unique-keys email))
</code></pre>

<p>We create the table with <code>ensure-table-exists</code>:</p>

<pre><code class="language-lisp">(ensure-table-exists 'user)
;-&gt; ;; CREATE TABLE IF NOT EXISTS &quot;user&quot; (
;       &quot;id&quot; BIGSERIAL NOT NULL PRIMARY KEY,
;       &quot;name&quot; VARCHAR(64) NOT NULL,
;       &quot;email&quot; VARCHAR(128),
;       &quot;created_at&quot; TIMESTAMP,
;       &quot;updated_at&quot; TIMESTAMP
;   ) () [0 rows] | MITO.DAO:ENSURE-TABLE-EXISTS
</code></pre>

<h3 id="persistent-datastores">Persistent datastores</h3>

<h3 id="migrations">Migrations</h3>

<p><a href="https://github.com/fukamachi/mito">Mito</a> has migrations support and
DB schema versioning for MySQL, Postgres and SQLite3, on SBCL and
CCL. Once we have changed our model definition, we have commands to
see the generated SQL and to apply the migration.</p>

<p>We inspect the SQL: (suppose we just added the email field into the <code>user</code> class above)</p>

<pre><code class="language-lisp">(mito:migration-expressions 'user)
;=&gt; (#&lt;SXQL-STATEMENT: ALTER TABLE user ALTER COLUMN email TYPE character varying(128), ALTER COLUMN email SET NOT NULL&gt;
;    #&lt;SXQL-STATEMENT: CREATE UNIQUE INDEX unique_user_email ON user (email)&gt;)
</code></pre>

<p>and we can apply the migration:</p>

<pre><code class="language-lisp">(mito:migrate-table 'user)
;-&gt; ;; ALTER TABLE &quot;user&quot; ALTER COLUMN &quot;email&quot; TYPE character varying(128), ALTER COLUMN &quot;email&quot; SET NOT NULL () [0 rows] | MITO.MIGRATION.TABLE:MIGRATE-TABLE
;   ;; CREATE UNIQUE INDEX &quot;unique_user_email&quot; ON &quot;user&quot; (&quot;email&quot;) () [0 rows] | MITO.MIGRATION.TABLE:MIGRATE-TABLE
;-&gt; (#&lt;SXQL-STATEMENT: ALTER TABLE user ALTER COLUMN email TYPE character varying(128), ALTER COLUMN email SET NOT NULL&gt;
;    #&lt;SXQL-STATEMENT: CREATE UNIQUE INDEX unique_user_email ON user (email)&gt;)
</code></pre>

<p><a href="https://github.com/eudoxia0/crane">Crane</a> advertises <strong>automatic</strong>
migrations, i.e. it would run them after a <code>C-c C-c</code>. Unfortunately Crane has
some issues, it doesn&rsquo;t work with sqlite yet and the author is busy
elsewhere. It didn&rsquo;t work for me at first try.</p>

<p>Let&rsquo;s hope the author comes back to work on this in a near future.</p>

<h2 id="forms">Forms</h2>

<p>There are a few libraries, see the awesome-cl list. At least one is well active.</p>

<h2 id="debugging">Debugging</h2>

<p>On an error we are usually dropped into the interactive debugger by default.</p>

<p>Snooze gives options:</p>

<ul>
<li>use the debugger,</li>
<li>print the stacktrace in the browser (like clack-errors below, but built-in),</li>
<li>display a custom 404.</li>
</ul>

<p><a href="https://github.com/eudoxia0/clack-errors">clack-errors</a>. Like a Flask
or Django stacktrace in the browser. For Caveman, Ningle and family.</p>

<blockquote>
<p>By default, when Clack throws an exception when rendering a page, the server waits for the response until it times out while the exception waits in the REPL. This isn&rsquo;t very useful. So now there&rsquo;s this.</p>
</blockquote>

<p>It prints the stacktrace along with some request details on the
browser. Can return a custom error page in production.</p>

<p><img src="https://camo.githubusercontent.com/17dd6e0a7a916c8118f0134a94404f6757bee9dc/68747470733a2f2f7261772e6769746875622e636f6d2f6575646f786961302f636c61636b2d6572726f72732f6d61737465722f73637265656e73686f742d6465762e706e67" width="800px"></img></p>

<p><a href="https://github.com/BnMcGn/clack-pretend">clack-pretend</a></p>

<blockquote>
<p>Are you tired of jumping to your web browser every time you need to test your work in Clack? Clack-pretend will capture and replay calls to your clack middleware stack. When developing a web application with clack, you will often find it inconvenient to run your code from the lisp REPL because it expects a clack environment, including perhaps, cookies or a logged-in user. With clack-pretend, you can run prior web requests from your REPL, moving development back where it belongs.</p>
</blockquote>

<h2 id="testing">Testing</h2>

<p>Testing with a local DB: example of a <a href="https://lispcookbook.github.io/cl-cookbook/databases.html#testing">testing macro</a>.</p>

<p>We would use <a href="https://github.com/fukamachi/envy">envy</a> to switch configurations.</p>

<h2 id="misc">Misc</h2>

<h3 id="oauth-job-queues-etc">Oauth, Job queues, etc</h3>

<h1 id="templating-engines">Templating engines</h1>

<h2 id="html-based">HTML-based</h2>

<p><strong><a href="https://mmontone.github.io/djula/">Djula</a></strong>: as Django
templates. Good documentation. Comes by default in Lucerne and Caveman.</p>

<p>We also use a dot to access attributes of dict-like variables (plists,
alists, hash-tables, arrays and CLOS objects), such a feature being
backed by the <a href="https://github.com/AccelerationNet/access">access</a>
library.</p>

<p>We wanted once to use structs and didn&rsquo;t find how to it directly in
Djula, so we resorted in a quick helper function to transform the
struct in an alist.</p>

<p>Defining custom template filters is straightforward in Djula, really a
breeze compared to Django.</p>

<p><strong><a href="https://github.com/eudoxia0/eco">Eco</a></strong> - a mix of html with lisp expressions.</p>

<p>Truncated example:</p>

<pre><code>&lt;body&gt;
      &lt;% if posts %&gt;
        &lt;h1&gt;Recent Posts&lt;/h1&gt;
        &lt;ul id=&quot;post-list&quot;&gt;
          &lt;% loop for (title . snippet) in posts %&gt;
            &lt;li&gt;&lt;%= title %&gt; - &lt;%= snippet %&gt;&lt;/li&gt;
          &lt;% end %&gt;
        &lt;/ul&gt;
        ...
</code></pre>

<h2 id="lisp-based">Lisp-based</h2>

<p>I prefer the semantics of
<a href="https://github.com/ruricolist/spinneret">Spinneret</a> over cl-who. It
also has more features (like embeddable markdown, warns on malformed html, and more).</p>

<h1 id="javascript">Javascript</h1>

<h2 id="parenscript">Parenscript</h2>

<blockquote>
<p>Parenscript is a translator from an extended subset of Common Lisp to JavaScript. Parenscript code can run almost identically on both the browser (as JavaScript) and server (as Common Lisp).
Parenscript code is treated the same way as Common Lisp code, making the full power of Lisp macros available for JavaScript. This provides a web development environment that is unmatched in its ability to reduce code duplication and provide advanced meta-programming facilities to web developers.</p>
</blockquote>

<p><a href="https://common-lisp.net/project/parenscript/">https://common-lisp.net/project/parenscript/</a></p>

<h2 id="jscl">JSCL</h2>

<blockquote>
<p>A Lisp-to-Javascript compiler bootstrapped from Common Lisp and executed from the browser.</p>
</blockquote>

<p><a href="https://github.com/jscl-project/jscl">https://github.com/jscl-project/jscl</a></p>

<p><a href="https://t-cool.github.io/jscl-playground/">https://t-cool.github.io/jscl-playground/</a></p>

<h2 id="ajax">Ajax</h2>

<p>Is it possible to write Ajax-based pages only in CL?</p>

<h2 id="the-case-webblocks-reblocks-2017">The case Webblocks - Reblocks, 2017</h2>

<p>Weblocks is an &ldquo;isomorphic&rdquo; web frameworks that solves the &ldquo;Javascript
problem&rdquo;. It allows to write the backend and an interactive client
interface in Lisp, without a line of Javascript, in our usual Lisp
development environment.</p>

<p>The framework evolves around widgets, that are updated server-side
and are automatically redisplayed with transparent ajax calls on the
client.</p>

<p>It is being massively refactored, simplified, rewritten and documented
since 2017. See the new quickstart:</p>

<p><a href="http://40ants.com/weblocks/quickstart.html">http://40ants.com/weblocks/quickstart.html</a></p>

<p>Writing a dynamic todo-app resolves in:</p>

<ul>
<li>defining a widget class for a task:</li>
</ul>

<pre><code class="language-lisp">(defwidget task ()
        ((title
          :initarg :title
          :accessor title)
         (done
          :initarg :done
          :initform nil
          :accessor done)))
</code></pre>

<ul>
<li>doing the same for a list of tasks:</li>
</ul>

<pre><code class="language-lisp">(defwidget task-list ()
        ((tasks
          :initarg :tasks
          :accessor tasks)))
</code></pre>

<ul>
<li>saying how to render these widgets in html by extending the <code>render</code> method:</li>
</ul>

<pre><code class="language-lisp">(defmethod render ((task task))
        &quot;Render a task.&quot;
        (with-html
              (:span (if (done task)
                         (with-html
                               (:s (title task)))
                       (title task)))))

(defmethod render ((widget task-list))
        &quot;Render a list of tasks.&quot;
        (with-html
              (:h1 &quot;Tasks&quot;)
              (:ul
                (loop for task in (tasks widget) do
                      (:li (render task))))))
</code></pre>

<ul>
<li>telling how to initialize the Weblocks app:</li>
</ul>

<pre><code class="language-lisp">(defmethod weblocks/session:init ((app tasks))
         (declare (ignorable app))
         (let ((tasks (make-task-list &quot;Make my first Weblocks app&quot;
                                      &quot;Deploy it somewhere&quot;
                                      &quot;Have a profit&quot;)))
           (make-instance 'task-list :tasks tasks)))
</code></pre>

<ul>
<li>and then writing functions to interact with the widgets, for example adding a task:</li>
</ul>

<pre><code class="language-lisp">(defmethod add-task ((task-list task-list) title)
        (push (make-task title)
              (tasks task-list))
        (update task-list))
</code></pre>

<p>Adding an html form and calling the new <code>add-task</code> function:</p>

<pre><code class="language-lisp">(defmethod render ((task-list task-list))
        (with-html
          (:h1 &quot;Tasks&quot;)
          (loop for task in (tasks task-list) do
            (render task))
          (with-html-form (:POST (lambda (&amp;key title &amp;allow-other-keys)
                                         (add-task task-list title)))
            (:input :type &quot;text&quot;
                    :name &quot;title&quot;
                    :placeholder &quot;Task's title&quot;)
            (:input :type &quot;submit&quot;
                    :value &quot;Add&quot;))))
</code></pre>

<h1 id="shipping">Shipping</h1>

<h2 id="building">Building</h2>

<p>We can build an executable also for web apps. That makes for a simple deployment process.</p>

<p>We can even get a Lisp REPL and interact with the running web app,
including installing new Quicklisp dependencies. That&rsquo;s quite
incredible, and it&rsquo;s very useful, if not to hot-reload a web app
(which I do anyways), at least to reload a user configuration file.</p>

<p>This is the general way:</p>

<pre><code class="language-lisp">(sb-ext:save-lisp-and-die #p&quot;name-of-executable&quot; :toplevel #'main :executable t)
</code></pre>

<p>we need a step more for web apps:</p>

<pre><code class="language-lisp">(defun main ()
    ;; with bordeaux-threads. Also sb-ext: join-thread, thread-name, list-all-threads.
    (bt:join-thread (find-if (lambda (th)
                                (search &quot;hunchentoot&quot; (bt:thread-name th)))
                              (bt:all-threads))))
</code></pre>

<p>I can now build my web app, send it to my VPS and see it live.</p>

<p>When I run it, Hunchentoot stays listening at the foreground:</p>

<pre><code>$ ./my-webapp
Hunchentoot server is started.
Listening on localhost:9003.
</code></pre>

<p>I need to put it in the background (<code>C-z bg</code>), or use a <code>tmux</code> session
(<code>tmux</code>, then <code>C-b d</code> to detach it).</p>

<p>To be complete, you&rsquo;ll notice that we can not <code>C-c</code> our running app,
we get trapped into the debugger (which responds only to <code>C-z</code> and
<code>kill</code>). As with any command line, we have to catch the corresponding
signal. We also <code>stop</code> our app. See
<a href="https://vindarel.github.io/cl-torrents/tutorial.html#org8567d07">our cl-torrents tutorial</a>
on how to build command-line applications.</p>

<pre><code class="language-lisp">(defun main ()
  (start-app :port 9003)
  ;; with bordeaux-threads
  (handler-case (bt:join-thread (find-if (lambda (th)
                                             (search &quot;hunchentoot&quot; (bt:thread-name th)))
                                         (bt:all-threads)))
    (#+sbcl sb-sys:interactive-interrupt
      #+ccl  ccl:interrupt-signal-condition
      #+clisp system::simple-interrupt-condition
      #+ecl ext:interactive-interrupt
      #+allegro excl:interrupt-signal
      () (progn
           (format *error-output* &quot;Aborting.~&amp;&quot;)
           (clack:stop *server*)
           (uiop:quit 1)) ;; portable exit, included in ASDF, already loaded.
    ;; for others, unhandled errors (we might want to do the same).
    (error (c) (format t &quot;Woops, an unknown error occured:~&amp;~a~&amp;&quot; c)))))
</code></pre>

<p>See also how to daemonize an application (below in Deployment).</p>

<p>To see:</p>

<ul>
<li>a Debian package for every Quicklisp system: <a href="http://margaine.com/2015/12/22/quicklisp-packagecloud-debian-packages.html">http://margaine.com/2015/12/22/quicklisp-packagecloud-debian-packages.html</a>.</li>
</ul>

<h2 id="multiplatform-delivery-with-electron-ceramic">Multiplatform delivery with Electron (Ceramic)</h2>

<p><a href="https://ceramic.github.io/">Ceramic</a> makes all the work for us.</p>

<p>It is as simple as this:</p>

<pre><code class="language-lisp">;; Load Ceramic and our app
(ql:quickload '(:ceramic :our-app))

;; Ensure Ceramic is set up
(ceramic:setup)
(ceramic:interactive)

;; Start our app (here based on the Lucerne framework)
(lucerne:start our-app.views:app :port 8000)

;; Open a browser window to it
(defvar window (ceramic:make-window :url &quot;http://localhost:8000/&quot;))

;; start Ceramic
(ceramic:show-window window)
</code></pre>

<p>and we can ship this on Linux, Mac and Windows.</p>

<p>More:</p>

<blockquote>
<p>Ceramic applications are compiled down to native code, ensuring both performance and enabling you to deliver closed-source, commercial applications.</p>
</blockquote>

<p>(so no need to minify our JS)</p>

<p>with one more line:</p>

<pre><code class="language-lisp">(ceramic.bundler:bundle :ceramic-hello-world
                                 :bundle-pathname #p&quot;/home/me/app.tar&quot;)
Copying resources...
Compiling app...
Compressing...
Done!
#P&quot;/home/me/app.tar&quot;
</code></pre>

<p>This last line was buggy for us.</p>

<h1 id="deployment">Deployment</h1>

<p>When you build a self-contained binary, deployment gets easy.</p>

<p>Radiance&rsquo;s tutorial talks about deployment. <a href="https://github.com/Shirakumo/radiance-tutorial/blob/master/Part%207.md">https://github.com/Shirakumo/radiance-tutorial/blob/master/Part%207.md</a></p>

<h2 id="running-the-app-on-a-web-server">Running the app on a web server</h2>

<h3 id="manually">Manually</h3>

<pre><code>sbcl --load &lt;my-app&gt; --eval (start-my-app)
</code></pre>

<p>For example, a <code>run</code> Makefile target:</p>

<pre><code>run:
	sbcl --load my-app.asd \
	     --eval '(ql:quickload :my-app)' \
	     --eval '(my-app:start-app)'  ;; given this function starts clack or hunchentoot.
</code></pre>

<p>this keeps sbcl in the foreground. Can use <code>tmux</code> or just <code>C-z bg</code> to put it in background.</p>

<p>Then, we need of a task supervisor, that will restart our app on failures, start it after a reboot, handle logging. See the section below and example projects (such as Quickutil).</p>

<h3 id="with-clack-http-quickdocs-org-clack">with <a href="http://quickdocs.org/clack/">Clack</a></h3>

<pre><code>$ clackup app.lisp
Hunchentoot server is started.
Listening on localhost:5000.
</code></pre>

<h3 id="with-docker">with Docker</h3>

<p>So we have various implementations ready to use: sbcl, ecl, ccl… with Quicklisp well configured.</p>

<p><a href="https://lispcookbook.github.io/cl-cookbook/testing.html#gitlab-ci">https://lispcookbook.github.io/cl-cookbook/testing.html#gitlab-ci</a></p>

<h3 id="on-heroku">On Heroku</h3>

<p>See <a href="https://gitlab.com/duncan-bayne/heroku-buildpack-common-lisp">heroku-buildpack-common-lisp</a> and the <a href="https://github.com/CodyReichert/awesome-cl#deployment">Awesome CL#deploy</a> section.</p>

<h3 id="daemonizing-restarting-in-case-of-crashes-handling-logs-systemd">Daemonizing, restarting in case of crashes, handling logs (Systemd)</h3>

<p>Generally, this depends on your system. But most GNU/Linux distros now come with Systemd. Write a service file like this:</p>

<pre><code>$ /etc/systemd/system/my-app.service
[Unit]
Description=stupid simple example

[Service]
WorkingDirectory=/path/to/your/app
ExecStart=sbcl --load run.lisp  # your command
Type=simple
Restart=always
RestartSec=10
</code></pre>

<p>run a command to start it:</p>

<pre><code>sudo systemctl start my-app.service
</code></pre>

<p>a command to check its status:</p>

<pre><code>systemctl status my-app.service
</code></pre>

<p>Systemd handles <strong>logging</strong>. We write to stdout or stderr, it writes logs:</p>

<pre><code>journalctl -f -u my-app.service
</code></pre>

<p>and it handles crashes and <strong>restarts the app</strong>:</p>

<pre><code>Restart=always
</code></pre>

<p>and it can <strong>start the app after a reboot</strong>:</p>

<pre><code>[Install]
WantedBy=basic.target
</code></pre>

<p>to enable it:</p>

<pre><code>sudo systemctl enable my-app.service
</code></pre>

<h3 id="debugging-sbcl-error-ensure-space-failed-to-allocate-n-bytes">Debugging SBCL error: ensure_space: failed to allocate n bytes</h3>

<p>If you get this error with SBCL on your server:</p>

<pre><code>mmap: wanted 1040384 bytes at 0x20000000, actually mapped at 0x715fa2145000
ensure_space: failed to allocate 1040384 bytes at 0x20000000
(hint: Try &quot;ulimit -a&quot;; maybe you should increase memory limits.)
</code></pre>

<p>then disable <a href="https://en.wikipedia.org/wiki/Address_space_layout_randomization">ASLR</a>:</p>

<pre><code>sudo bash -c &quot;echo 0 &gt; /proc/sys/kernel/randomize_va_space&quot;
</code></pre>

<h2 id="connecting-to-a-remote-swank-server">Connecting to a remote Swank server</h2>

<p>Little example here: <a href="http://cvberry.com/tech_writings/howtos/remotely_modifying_a_running_program_using_swank.html">http://cvberry.com/tech_writings/howtos/remotely_modifying_a_running_program_using_swank.html</a>.</p>

<p>It defines a simple function that prints forever:</p>

<pre><code class="language-lisp">;; a little common lisp swank demo
;; while this program is running, you can connect to it from another terminal or machine
;; and change the definition of doprint to print something else out!
;; (ql:quickload '(:swank :bordeaux-threads))

(require :swank)
(require :bordeaux-threads)

(defparameter *counter* 0)

(defun dostuff ()
  (format t &quot;hello world ~a!~%&quot; *counter*))

(defun runner ()
  (bt:make-thread (lambda ()
                    (swank:create-server :port 4006)))
  (format t &quot;we are past go!~%&quot;)
  (loop while t do
       (sleep 5)
       (dostuff)
       (incf *counter*)))

(runner)
</code></pre>

<p>On our server, we run it with</p>

<pre><code>sbcl --load demo.lisp
</code></pre>

<p>we do port forwarding on our development machine:</p>

<pre><code>ssh -L4006:127.0.0.1:4006 username@example.com
</code></pre>

<p>this will securely forward port 4006 on the server at example.com to
our local computer&rsquo;s port 4006 (swanks accepts connections from
localhost).</p>

<p>We connect to the running swank with <code>M-x slime-connect</code>, typing in
port 4006.</p>

<p>We can write new code:</p>

<pre><code class="language-lisp">(defun dostuff ()
  (format t &quot;goodbye world ~a!~%&quot; *counter*))
(setf *counter* 0)
</code></pre>

<p>and eval it as usual with <code>M-x slime-eval-region</code> for instance. The output should change.</p>

<p>There are more pointers on CV Berry&rsquo;s page.</p>

<h2 id="hot-reload">Hot reload</h2>

<p>When we run the app as a script we get a Lisp REPL, so we can
hot-reload the running web app. Here we demonstrate a recipe to update
it remotely.</p>

<p>Example taken from <a href="https://github.com/tarballs-are-good/quickutil/blob/master/quickutil-server/">Quickutil</a>.</p>

<p>It has a Makefile target:</p>

<pre><code class="language-lisp">hot_deploy:
	$(call $(LISP), \
		(ql:quickload :quickutil-server) (ql:quickload :swank-client), \
		(swank-client:with-slime-connection (conn &quot;localhost&quot; $(SWANK_PORT)) \
			(swank-client:slime-eval (quote (handler-bind ((error (function continue))) \
				(ql:quickload :quickutil-utilities) (ql:quickload :quickutil-server) \
				(funcall (symbol-function (intern &quot;STOP&quot; :quickutil-server))) \
				(funcall (symbol-function (intern &quot;START&quot; :quickutil-server)) $(start_args)))) conn)) \
		$($(LISP)-quit))
</code></pre>

<p>It has to be run on the server (a simple fabfile command can call this
through ssh). Beforehand, a <code>fab update</code> has run <code>git pull</code> on the
server, so new code is present but not running. It connects to the
local swank server, loads the new code, stops and starts the app in a
row.</p>

<hr />

<p><a href='https://ko-fi.com/K3K828W0V' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://cdn.ko-fi.com/cdn/kofi2.png?v=2' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a></p>

<iframe src="https://github.com/sponsors/vindarel/card" title="Sponsor vindarel" height="225" width="600" style="border: 0;"></iframe>

<p>(yes that currently helps, thanks!)</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://defungames.com/wp-content/uploads/2019/01/eavesdropping.png" alt="Resources">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Resources</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">05 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        

<ul>
<li><a href="http://lisp-lang.org/">lisp-lang.org</a></li>
<li><a href="https://github.com/CodyReichert/awesome-cl">awesome-cl</a></li>
<li><a href="https://lispcookbook.github.io/cl-cookbook/">Common Lisp Cookbook</a></li>
</ul>

<p>search libraries on</p>

<ul>
<li><a href="http://quickdocs.org/">http://quickdocs.org/</a></li>
</ul>

<h2 id="individual-sites">Individual sites:</h2>

<ul>
<li><a href="http://stevelosh.com/blog/2018/08/a-road-to-common-lisp/">sjl&rsquo;s road to Lisp</a></li>
<li><a href="https://medium.com/@MartinCracauer/a-gentle-introduction-to-compile-time-computing-part-3-scientific-units-8e41d8a727ca">Martin Cracauer&rsquo;s Gentle Introduction to compile-time computing</a> - excellent article series</li>
<li><a href="https://www.darkchestnut.com/">https://www.darkchestnut.com/</a> - he encountered deployment obstacles, wrote a book and blogs about it.</li>
<li><a href="http://lispmethods.com/">http://lispmethods.com/</a></li>
<li><a href="http://malisper.me//debugging-lisp-part-1-recompilation/">Malisper&rsquo;s series on debugging</a></li>
</ul>

<h2 id="screencasts">Screencasts:</h2>

<ul>
<li><a href="https://www.youtube.com/playlist?list=PL2VAYZE_4wRJi_vgpjsH75kMhN4KsuzR_">Little Bits of Lisp</a> -
short videos on various topics: inspecting a condition, basics of
lisp&rsquo;s evaluation model,…</li>
<li><a href="https://www.youtube.com/playlist?list=PL2VAYZE_4wRIoHsU5cEBIxCYcbHzy4Ypj">Common Lisp Tutorials</a>, of which <a href="https://www.youtube.com/watch?v=sBcPNr1CKKw&amp;index=4&amp;list=PL2VAYZE_4wRIoHsU5cEBIxCYcbHzy4Ypj">Emacs and Slime - useful keyboard shortcuts</a></li>
<li><a href="https://www.youtube.com/watch?v=CNFr7zIfyeM">Programming a message bus in Common Lisp</a> - shows the interactive nature of lisp, good use of the debugger, test-driven development to shape the api, bordeaux-threads.</li>
<li><a href="https://www.youtube.com/watch?v=_B_4vhsmRRI">Marco Baringer&rsquo;s SLIME Tutorial Video</a> - a video showing Marco develop a package and explaining Slime and Lisp features, with many little important explanations (1 hour). It only has some rotten bits, for example it installs packages with asdf-install and not Quicklisp.</li>
<li><a href="https://www.youtube.com/watch?v=KsHxgP3SRTs">Interactively fixing failing tests</a> - very short video to showcase the interactive debugger and that we can re-compile a failing function and resume the execution from where it failed to see it finally pass.</li>
<li><a href="https://www.youtube.com/watch?v=bl8jQ2wRh6k">Web development in Emacs with Common Lisp and ClojureSCript</a> -
building <a href="https://github.com/cicakhq/potato">Potato</a>, a Slack-like app.</li>
<li>Shinmera playlists:
<a href="https://www.youtube.com/playlist?list=PLkDl6Irujx9MtJPRRP5KBH40SGCenztPW">Treehouse</a>
(game dev),
<a href="https://www.youtube.com/playlist?list=PLkDl6Irujx9Mh3BWdBmt4JtIrwYgihTWp">Demos</a>
(of small programs).</li>
<li><a href="https://www.youtube.com/watch?v=82o5NeyZtvw">Pushing pixels with Lisp</a>, and by the same author:

<ul>
<li><a href="https://www.youtube.com/watch?v=a2tTpjGOhjw&amp;index=20&amp;list=RDxzTH_ZqaFKI">CEPL demo</a> - working with OpenGL</li>
<li><a href="https://www.youtube.com/channel/UCMV8p6Lb-bd6UZtTc_QD4zA">Baggers&rsquo; channels</a>.</li>
</ul></li>

<li><p><a href="https://www.youtube.com/channel/UCYg6qFXDE5SGT_YXhuJPU0A/videos">Common Lisp Study Group</a> (long videos)</p>

<ul>
<li><a href="https://www.youtube.com/playlist?list=PLbl4KVdl9U3I3MhFWgauT0cz-x7SymZmn&amp;disable_polymer=true">Cando: computational chemistry with Common Lisp on LLVM with Jupyter notebooks</a></li>
</ul></li>

<li><p><a href="https://www.youtube.com/watch?v=XGmo0E_S46I">McClim interactive GUI demos</a>. <a href="https://github.com/robert-strandh/McCLIM/blob/master/Examples/demodemo.lisp">Code examples</a>. Presentation of <a href="https://www.youtube.com/watch?v=kfBmRsPRdGg">Clim listener, Clim debugger, drawing objects into the GUI repl</a>.</p></li>

<li><p><a href="https://www.youtube.com/channel/UC55S8D_44ge2cV10aQmxNVQ">videos of the European Lisp Symposium</a></p></li>
</ul>

<p>and more on <a href="http://www.cliki.net/Lisp%20Videos">Cliki</a>.</p>

<h2 id="some-games">Some games:</h2>

<ul>
<li><a href="https://defungames.com/">Spycursion</a> - &ldquo;a sandbox &ldquo;edutainment&rdquo; MMO centered around hacking and espionage which takes place in a near-future world&rdquo;.</li>
</ul>

<p><img src="https://defungames.com/wp-content/uploads/2019/01/eavesdropping.png" alt="spycursion" width="450"/></p>

<ul>
<li><a href="https://baggers.itch.io/orb">Orb</a></li>
</ul>

<p><img src="https://img.itch.zone/aW1hZ2UvMjUyMTE3LzEyMDYxNDUucG5n/347x500/YEFnGW.png" alt="" /></p>

<ul>
<li><a href="https://github.com/borodust/notalone">Notalone</a></li>
</ul>

<p><img src="https://img.itch.zone/aW1hZ2UvMTg2MzQ1Lzg3MjI2NC5wbmc=/347x500/6WLhIo.png" alt="" /></p>

<ul>
<li><a href="https://sarge.itch.io/moppu">Moppu</a></li>
</ul>

<p><img src="https://img.itch.zone/aW1hZ2UvNTAyMzQ2LzI2MDA1NjUucG5n/347x500/hdXQvV.png" alt="" /></p>

<ul>
<li><a href="https://goofist.itch.io/the-price-of-a-cup-of-coffee">The price of a cup of coffee</a></li>
</ul>

<p><img src="https://img.itch.zone/aW1hZ2UvNTAyNzk3LzI2MDMzNDQucG5n/347x500/0svE3f.png" alt="" /></p>

<ul>
<li><p><a href="http://www.sebity.com/projects.php">http://www.sebity.com/projects.php</a> (Snake, the Invaders,… with OpenGL)</p></li>

<li><p><a href="https://github.com/SahilKang/cl-snake">cl-snake</a> snake in the terminal</p></li>

<li><p><a href="https://github.com/lisp-mirror/fruktorama">Fruktorama</a>, Tetris-like with fruits.</p></li>
</ul>

<p><img src="https://camo.githubusercontent.com/f14f4bd34f1b41942c4dd9fdece3f7ea448e2f94f40fb040c7b03b230d6f3452/68747470733a2f2f6269746275636b65742e6f72672f50617261736974654e6574776f726b2f6672756b746f72616d61332d6c6973702d65646974696f6e2f7261772f306465613761623834326665306638616530336262636564356266316237636633353832343961392f73637265656e73686f74732f73637265656e73686f742d322e706e67" alt="" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Home</h1>
                            <h2 class="article__feed"><a target="_blank" href=""> Lisp journey</a> <span class="article__date">05 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Hi, it&rsquo;s Vincent. I write about my <strong>Common Lisp journey</strong> here. I
started the blog when I was discovering the language and the
ecosystem, wishing more people wrote about CL. Because Common Lisp <del>is</del> was
the most hidden world I know.</p>

<p>I now wrote tools, libraries and software, and I run a web app in
production©.</p>

<hr />

<p>I write intensively about Common Lisp <em>on collaborative resources</em>. <strong>My hidden plan is to make Common Lisp popular again</strong>. For this, I contribute to the <a href="https://github.com/LispCookbook/cl-cookbook/">Common Lisp Cookbook</a> (I am the main contributor, by far). I wrote about: CLOS, data structures, building executables, scripting, web scraping, debugging, error handling, testing, databases, GUI programming, web development, etc, and I added a theme, a sidebar and syntax highlighting. I also take time to maintain the <a href="https://github.com/CodyReichert/awesome-cl/">awesome-cl list</a>, an important resource in my eyes. I dig up, reference and sort Common Lisp libraries (and I still discover hidden gems three years after). I do community stuff for <a href="https://www.reddit.com/r/lispadvocates/">Lisp Advocates</a> (not the creator).</p>

<p>Now a newcomer has far more practical information for getting started than a few years ago. But there&rsquo;s still a lot to do, and I&rsquo;d like to do more. You can thank me and encourage me by donations on the following platforms. As I currently don&rsquo;t have a fixed (nor big) income, that helps. Thanks!</p>

<ul>
<li>ko-fi: <a href="https://ko-fi.com/vindarel">https://ko-fi.com/vindarel</a> (exempt of charges)</li>
<li>liberapay: <a href="https://liberapay.com/vindarel/">https://liberapay.com/vindarel/</a> (exempt of charges)</li>
<li>patreon: <a href="https://www.patreon.com/vindarel">https://www.patreon.com/vindarel</a></li>
</ul>

<div>
<br/>
<script type='text/javascript' src='https://ko-fi.com/widgets/widget_2.js'></script><script type='text/javascript'>kofiwidget2.init('Buy me a coffee!', '#29abe0', 'K3K828W0V');kofiwidget2.draw();</script>
</div>

<p>I also write and maintain tools, libraries, software and project skeletons. Among others:</p>

<p>libraries:</p>

<ul>
<li><a href="https://github.com/vindarel/cl-str/">cl-str</a>, that fixed my first frustration with CL</li>
<li><a href="https://github.com/ciel-lang/CIEL">CIEL</a> (in development)</li>
<li><a href="https://github.com/vindarel/replic/">replic</a>, to help create a readline application in no time</li>
<li><a href="https://github.com/vindarel/fuzzy-match">fuzzy-match</a></li>
<li><a href="https://github.com/vindarel/cl-sendgrid">cl-sendgrid</a>, to send emails easily with the Sendgrid API.</li>
<li><a href="https://github.com/vindarel/progressons">progressons</a> - a progress bar.</li>
<li><a href="https://github.com/vindarel/cl-readline">cl-readline</a> (maintainer)</li>
<li><a href="https://github.com/vindarel/cl-ansi-term">cl-ansi-term</a> (maintainer)</li>
</ul>

<p>software:</p>

<ul>
<li><a href="https://gitlab.com/vindarel/abelujo/">Abelujo</a>, a free software for bookshops (Python)</li>
<li><a href="https://github.com/vindarel/ABStock">ABStock</a>, a catalogue of books (and other products)</li>
<li><a href="https://github.com/OpenBookStore/openbookstore">OpenBookStore</a>, a personal book manager, aiming to replace Abelujo</li>
<li><a href="https://github.com/vindarel/cl-torrents">cl-torrents</a>, with an experimental <a href="https://github.com/vindarel/cl-torrents-web">Weblocks front-end</a></li>
</ul>

<p>tools:</p>

<ul>
<li><a href="https://github.com/vindarel/colisper">colisper</a>, an interface to Comby, for syntactic code checking and refactoring of Lisp code.</li>
<li><a href="https://github.com/vindarel/indent-tools">indent-tools</a> (emacs package)</li>
<li><a href="https://github.com/vindarel/print-licenses">print-licences</a></li>
</ul>

<p>project skeletons and demos:</p>

<ul>
<li><a href="https://github.com/vindarel/lisp-web-template-productlist">lisp-web-template-productlist</a>: Hunchentoot + easy-routes + Djula templates + Bulma CSS + a Makefile to build the project</li>
<li><a href="https://github.com/vindarel/lisp-web-live-reload-example">lisp-web-live-reload-example</a>: an example of how image-based development is useful. Learn to interact with a running website, including with a remote one with Swank.</li>
<li><a href="https://github.com/vindarel/weblocks-todomvc">Weblocks-todomvc</a></li>
</ul>

<p>and others:</p>

<ul>
<li>the <a href="https://github.com/vindarel/lisp-maintainers">lisp-maintainers</a> list.</li>
<li>the funny <a href="https://github.com/vindarel/Hacker-Typer">Hacker Typer in Lisp</a>.</li>
<li>the <a href="https://github.com/vindarel/Hacker-Typer">list of languages implemented in Lisp</a>.</li>
</ul>

<p>I contribute to awesome projects such as:</p>

<ul>
<li><a href="https://github.com/40ants/weblocks/">Weblocks</a>, an <a href="https://github.com/vindarel/awesome-no-js-web-frameworks">isomorphic web framework</a>. I helped write the quickstart, fixed HTML generation in tables, wrote more documentation, raised issues.</li>
<li>the <a href="https://github.com/atlas-engineer/nyxt/">Nyxt browser</a>: I was part of the team in 2019, I am the second contributor of that year.</li>
</ul>

<p>and I fix bugs when I see them (Mito (<a href="https://github.com/fukamachi/mito/graphs/contributors">my contributions!</a>), Djula…).</p>

<p>You can reach me by email at vindarel, mailz dot org. I am <a href="https://www.reddit.com/user/dzecniv/">/u/(reverse (str:concat &ldquo;vince&rdquo; &ldquo;zd&rdquo;))</a> on reddit.</p>

<hr />

<p>This website&rsquo;s sources are on Gitlab: <a href="https://gitlab.com/lisp-journey/lisp-journey.gitlab.io/issues">https://gitlab.com/lisp-journey/lisp-journey.gitlab.io/issues</a></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/11-adlitteram.png" alt="AdLitteram 11">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 11</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">02 02 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/11-adlitteram.png" alt="AdLitteram #11" title="AdLitteram #11" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/images/content/news/2017-01-31/use.jpg" alt="State of Clojure 2016 Results">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">State of Clojure 2016 Results</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">31 01 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Welcome back to the annual State of Clojure survey results. This year we held steady in our response rate as 2,420 of you took the time and effort to weigh in on your experience with Clojure - as always, we appreciate that time and effort very much. And, as always, thanks to Chas Emerick for starting this survey 7 years ago.</p>
</div>
<div class="paragraph">
<p>Clojure (and ClojureScript) were envisioned as tools that could make programming simple, productive, and fun. They were always aimed squarely at the working developer - someone being paid to solve complicated problems who needed to focus more on the solution and less on the unnecessary complexity surrounding it. While we love the academics, open source developers, and hobbyists who have flocked to Clojure, we are always happy to see signs of commercial adoption.</p>
</div>
<div class="paragraph">
<p>Last year, we had an outright majority of users (57%) using Clojure at work. This year, that number accelerates up to 67%.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/use.jpg" alt="Clojure uses">
</div>
</div>
<div class="paragraph">
<p>Within this group of users, several interesting themes emerge:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="state-of-clojure-2016#products">commercial Clojure use is for products, not just internal tooling</a></p>
</li>
<li>
<p><a href="state-of-clojure-2016#cloud">Clojure users are adopting the public cloud</a></p>
</li>
<li>
<p><a href="state-of-clojure-2016#companies">Clojure has penetrated all kinds of companies, not just startups</a></p>
</li>
<li>
<p><a href="state-of-clojure-2016#adoption">one of the biggest barriers to adoption is corporate aversion to new technologies</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>In addition to these themes, we&#8217;ve included <a href="state-of-clojure-2016#details">detailed analysis</a> of the individual questions as well as links to the <a href="state-of-clojure-2016#raw">raw data</a>.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="products"><a class="anchor" href="#products"></a>Commercial Clojure use is for products, not just internal tools</h3>
<div class="paragraph">
<p>A whopping 60% of respondents who use Clojure at work are building applications for people "outside my organization". We changed the wording of the answers to this question from the 2015 survey, so a direct head-to-head comparison isn&#8217;t possible. However, in 2015, fully 70% of respondents said their use was for "personal" projects, while 42% said "company-wide/enterprise". This year, only 5% answered "just me". Even without the direct results comparison, the data shows a dramatic shift towards building products.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/users.jpg" alt="Clojure users">
</div>
</div>
<div class="paragraph">
<p>This year we also introduced a new question, asking what industry or industries people develop for. For commercial users, "Enterprise Software" was the leader (at 22%), followed by "Financial services/fintech", "Retail/ecommerce", "Consumer software", "Media/advertising", and "Healthcare". Everything else was at under 5% reporting. When we dig deeper and look at each of those industries in turn, we find that within each one, "outside my organization" is still the most common answer. In fact, only in "Financial services/fintech" do internal tools come within 15% of "outside my organization".</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/industry.jpg" alt="Industries">
</div>
</div>
</div>
<div class="sect2">
<h3 id="cloud"><a class="anchor" href="#cloud"></a>Clojure users are adopting the public cloud</h3>
<div class="paragraph">
<p>Last year, 51% of respondents said they were deploying into the public cloud. This year, that number is up to 57%, coming almost entirely at the expense of "traditional infrastructure" (private/hybrid cloud was essentially unmoved). Recently, rescale released a report estimating that "we are in fact only at about 6% enterprise cloud penetration today" (<a href="https://blog.rescale.com/cloud-3-0-the-rise-of-big-compute/" class="bare">https://blog.rescale.com/cloud-3-0-the-rise-of-big-compute/</a>). Clojurists in the workforce are considerably ahead of this curve, if true.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/deploy.jpg" alt="Deployment">
</div>
</div>
<div class="paragraph">
<p>There is, unsurprisingly, a heavy correlation between use of the public cloud and developing applications for use "outside my organization". The use of the public cloud also skews heavily towards smaller organizations (companies of fewer than 100 people make up 70% of the public cloud group, while only 55% of the "traditional infrastructure" fell into that category).</p>
</div>
<div class="paragraph">
<p>There were only two industries where traditional infrastructure dramatically beat public cloud: Government/Military (which seems obvious) and Academia (which seems sad, although it could be a reflection of universities' sunk investment in infrastructure).  And only Telecom had a majority of respondents indicating "private/hybrid", which is almost certainly a reflection of the fact that hybrid cloud offerings are, by and large, products from the Telecom sector.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/deploy-private.jpg" alt="Private deployment">
</div>
</div>
</div>
<div class="sect2">
<h3 id="companies"><a class="anchor" href="#companies"></a>Clojure has penetrated all kinds of companies, not just startups</h3>
<div class="paragraph">
<p>If you look at the spread of response for size of organization, while there is a clear winner (11-100), the split is fairly even otherwise. A full 17% of responses were from companies of 1000+ people.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/size.jpg" alt="Organization size">
</div>
</div>
<div class="paragraph">
<p>Web development and open source development are the dominant two domains regardless of company size, but coming in at a strong #3 is "building and delivering commercial services", except when you look at responses from 1000+ companies, in which case "enterprise apps" unsurprisingly moves ahead.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/large-industry.jpg" alt="Large company industries">
</div>
</div>
<div class="paragraph">
<p>"Enterprise software" is the #1 industry regardless of company size. However, #2 is quite distinctly different across sizes&#8201;&#8212;&#8201;in smaller companies (&lt; 100 employees), "consumer software" is the strong #2, whereas for companies &gt; 100 employees, financial services is the dominant #2.</p>
</div>
<div class="paragraph">
<p>(An interesting aside: most industries show a normal bell curve, with most respondents coming from the middle two categories, 11-100 and 101-1000. For example:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/size-per-industry.jpg" alt="Size per industry">
</div>
</div>
<div class="paragraph">
<p>Only two industries show the inverted bell curve, with the most respondents at the edges&#8201;&#8212;&#8201;Academia, and Government/Military.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/size-per-industry-invert.jpg" alt="Size per industry inverted">
</div>
</div>
<div class="paragraph">
<p>You will note that these are the two industries where "traditional infrastructure" also dominates, so the distribution of respondents either being from the largest [most conservative] and smallest [most disruptive] paints an interesting picture of how industries change.)</p>
</div>
</div>
<div class="sect2">
<h3 id="adoption"><a class="anchor" href="#adoption"></a>One of the biggest barriers to adoption is corporate aversion to new technologies</h3>
<div class="paragraph">
<p>As was true the last two years, error messages and "hiring and staffing" are the top 2 reasons given for "What has been most frustrating or has prevented you from using Clojure more than you do now?" though both have fallen several percent since then. Interestingly, "Need docs/tutorials" has jumped from #5 in 2015 to #3 now, which corresponds well with a continuing growth of new entrants into the community.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/prevent.jpg" alt="Prevented from using">
</div>
</div>
<div class="paragraph">
<p>When you break down respondents by size, each category is relatively uniform with one glaring exception: for some reason, companies of 100-1000+ people have a problem with the lack of static typing (it is a strong #3 in that cohort). Everyone else has a carbon copy distribution of the overall answers. When you look by industry, the "enterprise software" crowd would clearly benefit from more tools and a better IDE experience.</p>
</div>
<div class="paragraph">
<p>What we found fascinating was drilling through the free answer portion of the responses to this question. Next year, we&#8217;ll be adding a new possible answer: "corporate aversion to new technologies". If it was captured as one of the main responses, it would come in #2 or #3 overall. We clearly have work to do as a community to arm the technologists who wish to adopt Clojure with the materials and support they need to overcome internal inertia or resistance. That&#8217;s an area we&#8217;d love to both see more people contributing, but also letting us at Cognitect know what else we could provide that would be useful.</p>
</div>
</div>
<div class="sect2">
<h3 id="_summary"><a class="anchor" href="#_summary"></a>Summary</h3>
<div class="paragraph">
<p>When you dig into these numbers, you see a technology that has been accepted as a viable tool for crafting solutions across industries, company types and sizes, and target domains. As you might expect, adoption of Clojure seems closely correlated with the adoption of other new technologies, like the public cloud, and Clojure is beset with some of the same headwinds, like corporate aversion to new things. We are encouraged by the maturation of the community and of the ability of the technology and its adherents to tackle the hard problems of commercial software development.</p>
</div>
</div>
<div class="sect1">
<h2 id="details"><a class="anchor" href="#details"></a>Detailed Results</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In addition to the big themes above, this section highlights a few of the more interesting results for specific questions in the survey. For details on all questions, see the full results.</p>
</div>
<div class="sect2">
<h3 id="_which_dialects_of_clojure_do_you_use"><a class="anchor" href="#_which_dialects_of_clojure_do_you_use"></a>Which dialects of Clojure do you use?</h3>
<div class="paragraph">
<p>The interesting detail here was that the percentage of respondents using ClojureScript rose yet again, such that 2/3 of users are now using both Clojure and ClojureScript together (this has continually risen from about 1/2 3 years ago):</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/dialect.jpg" alt="Clojure dialect">
</div>
</div>
<div class="paragraph">
<p>Clojure increasingly delivers on the promise of a single unified language stack that can be used to cover an entire application.</p>
</div>
</div>
<div class="sect2">
<h3 id="_prior_to_using_clojure_clojurescript_or_clojureclr_what_was_your_primary_development_language"><a class="anchor" href="#_prior_to_using_clojure_clojurescript_or_clojureclr_what_was_your_primary_development_language"></a>Prior to using Clojure, ClojureScript, or ClojureCLR, what was your primary development language?</h3>
<div class="paragraph">
<p>We&#8217;ve changed the way this question is asked and the options provided several times so it&#8217;s difficult to assess trends. However, it&#8217;s clear that developers come to Clojure either from imperative/OO languages (Java, C#, C/C++) or from dynamic languages (Ruby, Python, JavaScript, etc) with only small numbers coming from functional programming languages like Scala, Common Lisp, Haskell, Erlang, etc.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/prior-lang.jpg" alt="Prior language">
</div>
</div>
</div>
<div class="sect2">
<h3 id="_what_is_your_primary_clojure_clojurescript_or_clojureclr_development_environment"><a class="anchor" href="#_what_is_your_primary_clojure_clojurescript_or_clojureclr_development_environment"></a>What is your <strong>primary</strong> Clojure, ClojureScript, or ClojureCLR development environment?</h3>
<div class="paragraph">
<p>Due to the general volatility of tools, it&#8217;s interesting to see how this changes year to year. However, this year things were mostly pretty static with the three most common choices again Emacs/CIDER, Cursive/IntelliJ, and Vim with no major changes in percent use. Sublime, Light Table, and Eclipse/Counterclockwise all became a bit less common. The most interesting development was the rise in the use of Atom which was a new choice and selected by 6% of respondents.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/editor.jpg" alt="Editor">
</div>
</div>
</div>
<div class="sect2">
<h3 id="_what_clojure_clojurescript_or_clojureclr_community_forums_have_you_used_or_attended_in_the_last_year"><a class="anchor" href="#_what_clojure_clojurescript_or_clojureclr_community_forums_have_you_used_or_attended_in_the_last_year"></a>What Clojure, ClojureScript, or ClojureCLR community forums have you used or attended in the last year?</h3>
<div class="paragraph">
<p>This was a new question this year, trying to get a sense of how people are interacting with other members of the community. The Clojurians slack channel was the most frequently used - this is a great place to connect with others and has taken the place of IRC for many. About half of respondents are using the original language mailing lists, and almost that many have looked at the Clojure subreddit.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/community.jpg" alt="Community forum">
</div>
</div>
<div class="paragraph">
<p>Interestingly, most respondents have not attended either local Clojure meetups or Clojure conferences either in-person or remotely. There are many active Clojure meetups and conferences in the world - if you&#8217;d like to talk to other Clojurists, take a look and see if one is near you!</p>
</div>
</div>
<div class="sect2">
<h3 id="_which_versions_of_clojure_do_you_currently_use_in_development_or_production"><a class="anchor" href="#_which_versions_of_clojure_do_you_currently_use_in_development_or_production"></a>Which versions of Clojure do you currently use in development or production?</h3>
<div class="paragraph">
<p>Library maintainers are often interested in how quickly users are migrating to newer versions of Clojure as they decide whether they can use new features. We can see in this year&#8217;s survey that most users are on the latest stable version (1.8.0) - 83%, with a third of respondents already using the 1.9 prereleases prior to final release. Less than 5% are using a Clojure version older than Clojure 1.7, which is good news for those that wish to rely on 1.7 features like cljc files or transducers.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/clojure-versions.jpg" alt="Clojure versions">
</div>
</div>
</div>
<div class="sect2">
<h3 id="_what_versions_of_the_jdk_do_you_target"><a class="anchor" href="#_what_versions_of_the_jdk_do_you_target"></a>What versions of the JDK do you target?</h3>
<div class="paragraph">
<p>Similar to the prior question, it&#8217;s useful to track what versions of the JDK are in use in the community. We saw significant consolidation to Java 1.8 over the past year (with Java 1.9 on the horizon) - 95% of users are using it with only about 2% using a version older than Java 1.7. For the moment, Clojure is still supported on Java 1.6 but eventually that support will be dropped.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/jdk-versions.jpg" alt="JDK versions">
</div>
</div>
</div>
<div class="sect2">
<h3 id="_what_tools_do_you_use_to_compilepackagedeployrelease_your_clojure_projects"><a class="anchor" href="#_what_tools_do_you_use_to_compilepackagedeployrelease_your_clojure_projects"></a>What tools do you use to compile/package/deploy/release your Clojure projects?</h3>
<div class="paragraph">
<p>While Leiningen continues to be ubiquitous, boot made significant advances this year, moving from 13% usage to 22% usage.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/tools.jpg" alt="Tools">
</div>
</div>
</div>
<div class="sect2">
<h3 id="_what_has_been_most_frustrating_or_has_prevented_you_from_using_clojure_more_than_you_do_now"><a class="anchor" href="#_what_has_been_most_frustrating_or_has_prevented_you_from_using_clojure_more_than_you_do_now"></a>What has been most frustrating or has prevented you from using Clojure more than you do now?</h3>
<div class="paragraph">
<p>Error messages continued to be the top frustration for people and we will continue to improve those with the integration of spec in Clojure 1.9. Interestingly, the majority of the other frustrations went down this year compared to last year:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Hiring/staffing - from 33% to 30%</p>
</li>
<li>
<p>Scripting - from 33% to 18% (maybe due to the rise of Planck and Lumo)</p>
</li>
<li>
<p>Docs - from 25% to 22% (hopefully the new Clojure and ClojureScript web sites have helped)</p>
</li>
<li>
<p>Static typing - from 23% to 16% (maybe due to the release of spec)</p>
</li>
<li>
<p>Long-term viability - from 20% to 10%</p>
</li>
<li>
<p>Finding libraries - from 16% to 11%</p>
</li>
<li>
<p>Portability - from 10% to 5% (continued uptake of cljc / reader conditionals)</p>
</li>
</ul>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/prevent-reason.jpg" alt="Prevent reasons">
</div>
</div>
</div>
<div class="sect2">
<h3 id="_which_javascript_environments_do_you_target"><a class="anchor" href="#_which_javascript_environments_do_you_target"></a>Which JavaScript environments do you target?</h3>
<div class="paragraph">
<p>The most interesting story here is the rise in three areas:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>React Native - 18% (new choice this year)</p>
</li>
<li>
<p>Electron - 11% (new choice this year)</p>
</li>
<li>
<p>AWS Lambda - 9% (vs 5% last year)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>As JavaScript continues to seep into every area of computing, ClojureScript is following along with it and seeing new and interesting uses.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/js-env.jpg" alt="JavaScript environments">
</div>
</div>
</div>
<div class="sect2">
<h3 id="_which_tools_do_you_use_to_compilepackagedeployrelease_your_clojurescript_projects"><a class="anchor" href="#_which_tools_do_you_use_to_compilepackagedeployrelease_your_clojurescript_projects"></a>Which tools do you use to compile/package/deploy/release your ClojureScript projects?</h3>
<div class="paragraph">
<p>We saw a small increase in Figwheel this year (after a huge jump after its release) with about 2/3 of ClojureScript users now using it. And as we saw in the prior tools question, there is a big jump in the number of ClojureScript developers using boot (from 15 to 23%).</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/cljs-deploy.jpg" alt="ClojureScript deploy tools">
</div>
</div>
</div>
<div class="sect2">
<h3 id="_which_clojurescript_repl_do_you_use_most_often"><a class="anchor" href="#_which_clojurescript_repl_do_you_use_most_often"></a>Which ClojureScript REPL do you use most often?</h3>
<div class="paragraph">
<p>Again, even more usage of Figwheel here (76%, up from 71% last year). We added Planck this year and it registered at 9%. The Lumo repl was not listed as a choice but did make a showing in the comments.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/cljs-repl.jpg" alt="ClojureScript repl">
</div>
</div>
</div>
<div class="sect2">
<h3 id="_how_are_you_running_your_clojurescript_tests"><a class="anchor" href="#_how_are_you_running_your_clojurescript_tests"></a>How are you running your ClojureScript tests?</h3>
<div class="paragraph">
<p>We added this question to gather some information on what seems like an underserved area of the ecosystem. Of those who responded, we saw:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/cljs-test.jpg" alt="ClojureScript test">
</div>
</div>
<div class="paragraph">
<p>However, there was a lot of information in the "Other" responses as well. At least 60 people (more than replied for the Nashorn choice above) responded that they were either not testing at all or were relying on testing their ClojureScript via cljc tests that ran in Clojure. This is a great area for future improvements with no real consensus and a lot of developers not even doing it at all. Some other choices seen in the comments were Devcards, Karma, Phantom, and doo.</p>
</div>
</div>
<div class="sect2">
<h3 id="_what_has_been_most_frustrating_or_has_prevented_you_from_using_clojurescript_more_than_you_do_now"><a class="anchor" href="#_what_has_been_most_frustrating_or_has_prevented_you_from_using_clojurescript_more_than_you_do_now"></a>What has been most frustrating or has prevented you from using ClojureScript more than you do now?</h3>
<div class="paragraph">
<p>The top answer here was "Using JavaЅcript libs with ClojureScript / Google Closure", which was a new choice we added this year. David Nolen and the ClojureScript community have been working hard on some of the biggest pain points in this area, which culminated in the recent release of a new ClojureScript version with better support for externs and modules.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2017-01-31/cljs-prevent.jpg" alt="ClojureScript prevent reasons">
</div>
</div>
<div class="paragraph">
<p>Some of the other choices fell in importance this year (similar to Clojure):</p>
</div>
<div class="ulist">
<ul>
<li>
<p>"Using ClojureScript REPLs" went from 45% to 34% (rise of Figwheel, Planck, Lumo)</p>
</li>
<li>
<p>"Availability of docs" went from 39% to 31% (new ClojureScript web site)</p>
</li>
<li>
<p>"Long-term viability" went from 15% to 10%</p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="_here_you_can_add_any_final_comments_or_opinions"><a class="anchor" href="#_here_you_can_add_any_final_comments_or_opinions"></a>Here you can add any final comments or opinions&#8230;&#8203;</h3>
<div class="paragraph">
<p>The majority of responses (~62%) here either expressed sentiments of happiness or gratitude (always good to see). Other categories centered around expected themes (many are areas of current or future work): docs/tutorials, error messages, tooling, startup time, etc. One relatively stronger theme this year was the need for better marketing for the purposes of expanding or introducing Clojure within organizations, which is a great area for contribution from the entire community.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="raw"><a class="anchor" href="#raw"></a>The data</h2>
<div class="sectionbody">
<div class="paragraph">
<p>If you&#8217;d like to dig into the results more deeply, you can find the complete set of data from this and former years here:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://www.surveymonkey.com/results/SM-7K6NXJY3/">2016</a></p>
</li>
<li>
<p><a href="http://blog.cognitect.com/blog/2016/1/28/state-of-clojure-2015-survey-results">2015</a></p>
</li>
<li>
<p><a href="http://blog.cognitect.com/blog/2014/10/20/results-of-2014-state-of-clojure-and-clojurescript-survey">2014</a></p>
</li>
<li>
<p><a href="http://cemerick.com/2013/11/18/results-of-the-2013-state-of-clojure-clojurescript-survey/">2013</a></p>
</li>
<li>
<p><a href="http://cemerick.com/2012/08/06/results-of-the-2012-state-of-clojure-survey/">2012</a></p>
</li>
<li>
<p><a href="http://cemerick.com/2011/07/11/results-of-the-2011-state-of-clojure-survey/">2011</a></p>
</li>
<li>
<p><a href="http://cemerick.com/2010/06/07/results-from-the-state-of-clojure-summer-2010-survey/">2010</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Thanks again for providing your responses to help form this picture of our growing community!</p>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/27-technically-not-a-bug.png" alt="Technically not a bug">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Technically not a bug</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">31 01 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/27-technically-not-a-bug.png" alt="Technically not a bug" title="Technically not a bug" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/10-adlitteram.png" alt="AdLitteram 10">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 10</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">27 01 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/10-adlitteram.png" alt="AdLitteram #10" title="AdLitteram #10" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Indentation is the enemy: Writing less complex JavaScript</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">26 01 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I’ve been working a lot with a legacy code-base lately. And this one is particularly troublesome. It has all the hallmarks of a rush job. The code is brittle. There are no tests. Things often seem to break at random. And to my embarrassment, I wrote most of it. So, I've been thinking about how I ended up here. How did the code get so intertwined and brittle? And how do I prevent it in future?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Indentation is the enemy: Writing less complex JavaScript</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">26 01 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I’ve been working a lot with a legacy code-base lately. And this one is particularly troublesome. It has all the hallmarks of a rush job. The code is brittle. There are no tests. Things often seem to break at random. And to my embarrassment, I wrote most of it. So, I've been thinking about how I ended up here. How did the code get so intertwined and brittle? And how do I prevent it in future?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/26-vim-vs-emacs.png" alt="Vim vs Emacs">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Vim vs Emacs</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">24 01 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/26-vim-vs-emacs.png" alt="Vim vs Emacs" title="Vim vs Emacs" /></p>

<p>Special thanks to <strong>Fabian</strong> for suggesting the topic for this comic.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/9-adlitteram.png" alt="AdLitteram 9">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 9</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">20 01 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/9-adlitteram.png" alt="AdLitteram #9" title="AdLitteram #9" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://64.media.tumblr.com/aee5ccc35894471657f9fb949f044a7b/tumblr_inline_ojzyficSRS1tjlbd3_540.png" alt="Introducing the Instapaper Firefox Extension">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Introducing the Instapaper Firefox Extension</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Instapaper</a> <span class="article__date">19 01 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Today we’re launching an official <a href="https://addons.mozilla.org/en-US/firefox/addon/instapaper-official/">Instapaper extension for Firefox</a>!<b><br/></b></p><p>We’ve been getting a lot of requests from Firefox users to build an extension to match the ones we offer for <a href="https://chrome.google.com/webstore/detail/instapaper/ldjkgaaoikpmhmkelcgkgacicjfbofhh?hl=en-GB">Chrome</a>, <a href="https://addons.opera.com/en/extensions/details/instapaper-2/?display=en">Opera</a> and <a href="https://safari-extensions.apple.com/details/?id=com.instapaper.extension-CAM49M58WK">Safari</a>. Now, we’re happy to roll out the same great saving features for Firefox.</p><p>To install the new Firefox extension, open <a href="http://www.instapaper.com/save">www.instapaper.com/save</a> on Firefox or go to Mozilla’s <a href="https://addons.mozilla.org/en-US/firefox/addon/instapaper-official/">Add-on page for Instapaper.<br/><br/></a>Like our other browser extensions, when you find an article or video you want to save, just tap or click once to save it to Instapaper. Other convenient features include:</p><p><b>A keyboard shortcut:</b> A Ctrl+shift+S keyboard shortcut to save the article you’re currently viewing.</p><p><b>A right-click menu option: </b>To save the current page–or any link on the current page–we added an “Instapaper” option to the right-click menu.</p><p><b>More Instapaper save buttons:</b> Now you can “Save to Instapaper” directly from Twitter and Hacker News. Alongside each tweet containing a URL or a Hacker News post, you’ll now see an inline Instapaper save button.</p><p><b>Saving directly to folders:</b> Once your save is confirmed, click the folder icon on the save overlay to direct the article right into one of your folders.</p><p><b>Toggle options:</b> The keyboard shortcut and inline saving options can be toggled on/off.</p><figure data-orig-width="623" data-orig-height="392" class="tmblr-full"><img src="https://64.media.tumblr.com/aee5ccc35894471657f9fb949f044a7b/tumblr_inline_ojzyficSRS1tjlbd3_540.png" alt="image" data-orig-width="623" data-orig-height="392"/></figure><figure data-orig-width="592" data-orig-height="402" class="tmblr-full"><img src="https://64.media.tumblr.com/e6f8e05402928f38a34f4bf8e4ef18ca/tumblr_inline_ojzyg3v9nB1tjlbd3_540.png" alt="image" data-orig-width="592" data-orig-height="402"/></figure><p>If you’ve got any questions or feedback, just let us know via <a href="http://t.umblr.com/redirect?z=mailto%3Asupport%40help.instapaper.com&amp;t=ZDVkNTM5ZjA2NjIzODRiYTc2OWRkZjhkZWFjYjJhOWRmNzRmZWNmZixhc3VpNldtNA%3D%3D&amp;b=t%3AOZjQZ-Pa6uMEdOyfetS5_g&amp;p=http%3A%2F%2Fblog.instapaper.com%2Fpost%2F152600596211&amp;m=1">support@help.instapaper.com</a> or <a href="https://twitter.com/InstapaperHelp">@InstapaperHelp</a> on Twitter.</p><p>– Instapaper Team</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/23-http-status-codes-community.png" alt="HTTP Status Codes - Community Suggestions">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">HTTP Status Codes - Community Suggestions</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">19 01 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/23-http-status-codes-community.png" alt="HTTP Status Codes - Community Suggestions" title="HTTP Status Codes - Community Suggestions" /></p>

<p>var thanks = [‘Jonathan Cary’, ‘Микола Махін’, ‘Maksim Tsvetovat’, ‘Shane Hutter’, ‘/u/GeneReddit123’, ‘Bram Patelski’, ‘Reddit’, ‘Twitter’, ‘Facebook’]</p>

<p>Special thanks to: NixCraft <a href="https://twitter.com/nixcraft"><strong>](https://www.facebook.com/nixcraft/) [</strong></a></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/24-security.png" alt="Security">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Security</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">17 01 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/24-security.png" alt="Security" title="Security" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/8-adlitteram.png" alt="AdLitteram 8">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 8</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">13 01 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/8-adlitteram.png" alt="AdLitteram #8" title="AdLitteram #8" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2017/23-http-status-codes.png" alt="HTTP Status Codes">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">HTTP Status Codes</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">10 01 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2017/23-http-status-codes.png" alt="HTTP Status Codes" title="HTTP Status Codes" /></p>

<p><img src="https://www.monkeyuser.com/assets/images/2017/23-http-status-codes-alt-2.png" alt="HTTP Status Codes - 418" title="HTTP Status Codes - 418" /> Thanks Lionel
<img src="https://www.monkeyuser.com/assets/images/2017/23-http-status-codes-alt-1.png" alt="HTTP Status Codes - 404" title="HTTP Status Codes - 404" /> Thanks /u/spartaboy
<img src="https://www.monkeyuser.com/assets/images/2017/23-http-status-codes-alt-4.png" alt="HTTP Status Codes - 429" title="HTTP Status Codes - 429" /> Thanks @brampatelski
<img src="https://www.monkeyuser.com/assets/images/2017/23-http-status-codes-alt-5.png" alt="HTTP Status Codes - 410" title="HTTP Status Codes - 410" /> Thanks @brampatelski</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Working With APIs the Pythonic Way</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">04 01 2017</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Communication with external services is an integral part of any modern system. Whether it's a payment service, authentication, analytics or an internal one - systems need to talk to each other. In this short article we are going to implement a module for communicating with a made-up payment gateway, step by step.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Using Chrome DevTools with Macchiato</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">26 12 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Chrome DevTools provide a lot of useful features for debugging and profiling applications in the browser. As it happens, you can to connect DevTools to a Node.js process as well. Let's take a look at debugging the <a href='https://github.com/macchiato-framework/examples/tree/master/guestbook'>guestbook project</a> from the examples repository.</p><p>You'll first have to start Figwheel to compile the project by running the following command:</p><pre><code>lein build
</code></pre><p>Once the project is compiled, you have to start Node with the <code>--inspect</code> flag:</p><pre><code>$ node --inspect target/out/guestbook.js

Debugger listening on port 9229.
Warning: This is an experimental feature and could change at any time.
To start debugging, open the following URL in Chrome:
    chrome-devtools://devtools/bundled/inspector.html?experiments=true&amp;v8only=true&amp;ws=127.0.0.1:9229/0dbaef2a-996f-4229-8a52-6c4e50d0bf18
INFO &#91;guestbook.core:19&#93; - guestbook started on 127.0.0.1 : 3000
Figwheel: trying to open cljs reload socket
Figwheel: socket connection established
</code></pre><p>You'll see that there's a URL printed in the console when the app starts. Copy this URL and open it in Chrome to connect DevTools to your Node process. At this point you can use all the tools the same way you would with an application running in the browser. You can debug ClojureScript files, profile the process, and so on.</p><h4 id="gotchas">Gotchas</h4><p>Unfortunately, there's a <a href='http://dev.clojure.org/jira/browse/CLJS-1864'>small bug</a> in the ClojureScript compiler that prevents timestamped source maps from working with Node. The problem is that that the compiler assumes that ClojureScript is running in browser and appends <code>?timestamp</code> at the end of the file name as if it was a URL. Since Node is looking for actual files on disk, it fails to find the source map.</p><p>Currently, the workaround for this is to set <code>:source-map-timestamp false</code> in the compiler options. However, since Node caches the source maps, you have to restart the process any time you make a change in the code to get accurate line numbers.</p><p>The good news is that restarts happen instantaneously, and you can automate this process using Node supervisor as follows:</p><pre><code>npm install supervisor -g
supervisor --inspect target/out/guestbook.js
</code></pre><p>That's all there is to it.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/2016-stats.png" alt="MonkeyUser in 2016">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">MonkeyUser in 2016</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">23 12 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/2016-stats.png" alt="MonkeyUser in 2016" title="MonkeyUser in 2016" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/22-decision-boundary.png" alt="Decision Boundary">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Decision Boundary</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">22 12 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/22-decision-boundary.png" alt="Decision Boundary" title="Decision Boundary" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Macchiato Modules</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">20 12 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                         <p>As I discussed in the last <a href='http://yogthos.net/posts/2016-12-17-MacchiatoProgress.html'>post</a>, Ring middleware stack closely resembles modules in a framework. However, one notable difference is that middleware functions aren't directly aware of one another. When the handler is passed to a middleware function, that function has no way of knowing what other middleware might have been wrapped around the handler by the time it got to it.</p><p>Conversely, these functions can't know what middleware will be wrapped after that they may depend on. Since middleware that was wrapped last will be invoked first, inner middleware ends up being dependent on the outer middleware.</p><p>This presents a number of problems. We can end up with multiple copies of the same middleware wrapped around the handler, middleware could be wrapped in the wrong order, or required middleware might be missing altogether. All of the above cases can lead to unpredictable behaviors, and can be difficult to debug.</p><p>One way to mitigate the problem is by creating a default middleware stack, such as seen in the <a href='https://github.com/ring-clojure/ring-defaults'>ring-defaults</a> library. This takes care of ensuring that all the core middleware is wrapped correctly, but doesn't help with middleware libraries added by the user. Another approach is to wrap the Ring stack in a higher level abstraction as seen with <a href='https://github.com/weavejester/integrant'>Integrant</a>.</p><p>The solution I came up with for Macchiato is to use metadata attached to the handler to track the middleware that's been applied to it. This metadata can be used to inform how the middleware is loaded, and address the problems outlined above.</p><p>Let's take a look at an example of how this works in practice. Let's say we have the default handler such as:</p><pre><code class="clojure">&#40;defn handler &#91;req res raise&#93;
  &#40;res {:body &#40;str &#40;-&gt; req :params :name&#41;&#41;}&#41;&#41;
</code></pre><p>Then, let's say we have two pieces of middleware we wish to wrap the handler with. The first will parse the request params, and the second will keywordize the params. The second middleware function depends on the first in order to work.</p><pre><code class="clojure">&#40;defn parse-params &#91;req&#93;
  ;;parses request parameters into a map
  &#41;

&#40;defn wrap-params &#91;handler&#93;
  &#40;fn &#91;req res raise&#93;
    &#40;handler &#40;parse-params req&#41; res raise&#41;&#41;&#41;

&#40;defn keywordize-params &#91;params&#93;
  ;;keywordizes the params
  &#41;
          
&#40;defn wrap-keyword-params &#91;handler&#93;
  &#40;fn &#91;req res raise&#93;
    &#40;handler &#40;update req :params keywordize-params&#41; res raise&#41;&#41;&#41;
</code></pre><p>We have to make sure that the middleware is chained as follows to get keywordized params:</p><pre><code class="clojure">&#40;def wrapped-handler &#40;-&gt; handler
                         wrap-keyword-params
                         wrap-params&#41;&#41;
</code></pre><p>However, it's not possible to deduce that this actually happened given the resulting handler function. Let's see how we can use metadata to address this problem. We'll update the <code>wrap-params</code> and the <code>wrap-keyword-params</code> functions as follows:</p><pre><code class="clojure">&#40;defn
  &#94;{:macchiato/middleware
    {:id :wrap-params}}    
  wrap-params &#91;handler&#93;
  &#40;fn &#91;req res raise&#93;
    &#40;handler &#40;parse-params req&#41; res raise&#41;&#41;&#41;

&#40;defn
 &#94;{:macchiato/middleware
   {:id :wrap-keyword-params
    :required &#91;:wrap-params&#93;}}
  wrap-keyword-params &#91;handler&#93;
  &#40;fn &#91;req res raise&#93;
    &#40;handler &#40;update req :params keywordize-params&#41; res raise&#41;&#41;&#41;
</code></pre><p>The <code>:id</code> key in the metadata is meant to specify the specific type of middleware as opposed to a concrete implementation. If two pieces of middleware happen to implement the same functionality they should use the same <code>:id</code>. </p><p>The <code>:required</code> key specifies the keys for the <code>:id</code>s that the particular middleware function depends on. In this case, <code>wrap-keyword-params</code> requires <code>wrap-params</code> to be present.</p><p>Next, we can write the code that will update the handler metadata each time it's wrapped with a middleware function.</p><pre><code class="clojure">&#40;defn update-middleware-meta &#91;handler handler-middleware middleware-meta&#93;
  &#40;with-meta
    handler
    {:macchiato/middleware
     &#40;conj handler-middleware middleware-meta&#41;}&#41;&#41;

&#40;defn loaded? &#91;middleware {:keys &#91;id&#93;}&#93;
  &#40;some #{id} &#40;map :id middleware&#41;&#41;&#41;

&#40;defn- middleware-from-handler &#91;handler&#93;
  &#40;-&gt;&gt; handler meta :macchiato/middleware &#40;remove nil?&#41; vec&#41;&#41;

&#40;defn wrap
  &#40;&#91;handler middleware-fn&#93;
   &#40;wrap handler middleware-fn nil&#41;&#41;
  &#40;&#91;handler middleware-fn opts&#93;
   &#40;let &#91;handler-middleware &#40;middleware-from-handler handler&#41;
         middleware-meta    &#40;-&gt; middleware-fn meta :macchiato/middleware&#41;&#93;
     &#40;if &#40;loaded? handler-middleware middleware-meta&#41;
       handler
       &#40;update-middleware-meta
         &#40;if opts
           &#40;middleware-fn handler opts&#41;
           &#40;middleware-fn handler&#41;&#41;
         handler-middleware
         middleware-meta&#41;&#41;&#41;&#41;&#41;
</code></pre><p>The <code>wrap</code> function uses the <code>:macchiato/middleware</code> metadata key to get the currently applied middleware. When a middleware function with the same <code>:id</code> is already present, then the original handler is returned. Otherwise, the handler is wrapped with the middleware and its metadata is updated.</p><p>Let's update the original code that wrapped the handler to use the <code>wrap</code> function:</p><pre><code class="clojure">&#40;def wrapped-handler &#40;-&gt; handler
                         &#40;wrap #'wrap-keyword-params&#41;
                         &#40;wrap #'wrap-params&#41;&#41;&#41;
</code></pre><p>We can now use the <code>meta</code> function to access the metadata that was generated for the handler:</p><pre><code class="clojure">&#40;meta wrapped-handler&#41;

{:macchiato/middleware
 &#91;{:id :wrap-params}
  {:id :wrap-keyword-params
   :required &#91;:wrap-params&#93;}&#93;}
</code></pre><p>This tells us exactly what middleware has been applied to the handler and in what order, allowing us to validate that the middleware chain. This is accomplished as follows:</p><pre><code class="clojure">&#40;defn validate &#91;handler-middleware
   {:keys &#91;id required&#93; :as middleware-meta}&#93;
  &#40;when &#40;not-empty &#40;difference &#40;set required&#41;
                               &#40;set &#40;map :id handler-middleware&#41;&#41;&#41;&#41;
    &#40;throw &#40;js/Error. &#40;str id &quot; is missing required middleware: &quot; required&#41;&#41;&#41;&#41;
  middleware-meta&#41;
  
&#40;defn validate-handler &#91;handler&#93;
  &#40;let &#91;middleware &#40;middleware-from-handler handler&#41;&#93;
    &#40;loop &#91;&#91;middleware-meta &amp; handler-middleware&#93; middleware&#93;
      &#40;when middleware-meta
        &#40;validate handler-middleware middleware-meta&#41;
        &#40;recur handler-middleware&#41;&#41;&#41;
    handler&#41;&#41;  
</code></pre><p>With the above code in place we're now able to ensure that middleware functions are not loaded more than once, and that the order of middleware is correct.</p><p>Finally, Macchiato provides the <code>macchiato.middleware/wrap-middleware</code> convenience function that allows wrapping multiple middleware functions around the handler:</p><pre><code class="clojure">&#40;m/wrap-middleware
  handler
  #'wrap-anti-forgery
  &#91;#'wrap-session {:store &#40;mem/memory-store&#41;}&#93;
  #'wrap-nested-params
  #'wrap-keyword-params
  #'wrap-params&#41;
</code></pre><p>I think that the approach of using metadata provides an elegant view into the state of the middleware chain, while allowing Macchiato to stay compliant with Ring middleware semantics.</p><p>Another advantage of using metadata is that it makes the mechanism user extensible. If you're using a piece of middleware that doesn't have the metadata you need, you can always set it yourself.</p><p>The latest release of Macchiato has all the core middleware tagged with the appropriate metadata, and <a href='https://github.com/macchiato-framework/macchiato-defaults'>macchiato-defaults</a> generates a handler that has the <code>:macchiato/middleware</code> key pointing to the vector of the middleware that was applied.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/21-acquisition.png" alt="Acquisition">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Acquisition</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">20 12 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <div class="center">Thanks <a href="https://twitter.com/i_am_r0by"><i class="ssk ssk-icon ssk-twitter"></i>@i_am_r0by</a></div>

<p><img src="https://www.monkeyuser.com/assets/images/2016/21-acquisition.png" alt="Acquisition" title="Acquisition" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Frameworks, Foundations, and Macchiato</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">17 12 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I've been making steady progress on Macchiato in the past weeks. This post will discuss some of my thought process and design decisions I settled on during this time.</p><p>One of the core questions is what problem the project aims to solve, and how it aims to do that.</p><p>The goal for Macchiato is to provide a way to build Node web applications using CojureScript. Ultimately, I'd like to produce something that's immediately usable and works well out of the box. The best way to accomplish that is to leverage the existing work in this domain.</p><p>The Ring stack is the most popular platform for developing Clojure applications on the JVM, and rightfully so in my opinion. It does an excellent job of abstracting the HTTP protocol, and provides a simple and intuitive API to the user.</p><p>Ring added async handler support in version 1.6, making it possible to implement compatible HTTP handlers on top of Node. This in turn allowed to port the core middleware stack to Macchiato.</p><p>As I was porting <a href='https://github.com/ring-clojure/ring/tree/master/ring-core/'>ring-core</a> on Node, I've come to realize that Ring middleware libraries have a lot in common with framework modules.</p><p>These libraries are meant to be used together in a standard way, they're designed to compose, and they're often built on top of each other.</p><p>However, the Ring stack acts as a foundation rather than a framework. To understand this idea, let's first look at the traditional framework approach.</p><h3 id="frameworks">Frameworks</h3><p>The core problem the frameworks attempt to solve is to provide a standard way to build software where the user can focus on writing the code that's relevant to their application. Meanwhile, the framework attempts to take care of all the incidental details around it.</p><p>The way traditional frameworks, such as Spring, accomplish this is through inversion of control. However, since the connections are no longer expressed directly in code, it makes it difficult to navigate them clouding the logic of the application.</p><p>Another problem with this approach is that the framework necessarily has to make a lot of decisions up front. Yet, a general purpose framework also has to be flexible enough to accommodate many types of application.</p><p>A framework typically turns into an exercise in designing a solution without knowing the problem. My experience is that it's not an effective way to write software in practice.</p><p>However, I think that the problem the frameworks attempt to solve is real. Having to artisanally handcraft each application from ground up is tedious and error prone.</p><h3 id="foundations">Foundations</h3><p>A better way to approach this problem is by addressing the known common needs. The key insight of Ring is that majority of reusable work is centred around processing the incoming HTTP requests and outgoing responses.</p><p>Ring provides a simple core that different middleware can be attached to in order to extend its functionality. We can add middleware that facilitates authentication, sessions, and so on. <a href='https://github.com/funcool/buddy'>Buddy</a>, <a href='https://github.com/metosin/compojure-api'>compojure-api</a>, and <a href='https://github.com/ptaoussanis/sente'>Sente</a> are all great examples of this approach in practice.</p><p>One of the downsides of the library approach is that libraries aren't aware of one another, and the user has to glue them together. However, Ring middleware stack is not just a set of random libraries. Since Ring defines what the request and response must look like, it informs the design of libraries built on top of it. </p><p>The Ring stack is a mature and battle tested foundation for building the rest of the application on top of. At the same time, it doesn't attempt to guess the problems that are specific to your application. You're free to solve them in a way that makes sense to you.</p><h3 id="macchiato">Macchiato</h3><p>Macchiato implements Ring 1.6 async handlers on top of the <code>ClientRequest</code> and the <code>ServerResponse</code> classes exposed by the Node HTTP module. Using the same API provides a consistent experience developing web applications on both platforms, and facilitates code reuse between them.</p><p>One immediate benefit of making Macchiato compatible with Ring was the ability to leverage its test harness. As I port the middleware to Node, I'm able to verify that it still behaves the same as the original. Going forward, it will be possible to write cljc middleware that targets both Ring and Macchiato.</p><p>Alongside the creation of the core libraries, I've been working on the template that packages everything together for the user. This template is informed by my experience working on Luminus and uses many of the same patterns and structure. If you're already familiar with Luminus, then you'll feel right at home with Macchiato.</p><p>As I noted in the last <a href='http://yogthos.net/posts/2016-11-30-Macchiato.html'>post</a>, Macchiato development experience is very similar to working with Clojure on the JVM, and Chrome devtools along with <a href='https://github.com/binaryage/dirac'>Dirac</a> look promising for debugging and profiling apps.</p><p>Meanwhile, the project has already garnered interest from the community. <a href='https://numergent.com/opensource/'>Ricardo J. Méndez</a> has been working on creating a <a href='https://github.com/macchiato-framework/macchiato-sql'>HugSQL style database access library</a>, and <a href='https://github.com/niwinz'>Andrey Antukh</a>, has been working on the <a href='https://github.com/funcool/dost'>dost</a> crypto library.</p><p>It's great to see such prominent members of the community take interest in the project in the early stages. My hope is that as Macchiato matures we'll see many more supporting libraries built around it.</p><p>There's now a <code>#macchiato</code> channel on Clojurians slack. Feel free to drop by and discuss problems and ideas.</p><p>If you're looking to contribute to an open source project, Macchiato is a great opportunity. The project is still in the early days and there are many low hanging fruit. The project needs more tests, libraries, and documentation. This is a great time to make an impact on its future direction.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/7-adlitteram.png" alt="AdLitteram 7">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 7</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">16 12 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/7-adlitteram.png" alt="AdLitteram #7" title="AdLitteram #7" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/20-architecture-2.png" alt="If Buildings Were Built Like Software">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">If Buildings Were Built Like Software</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">15 12 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/20-architecture-2.png" alt="If Buildings Were Built Like Software" title="If Buildings Were Built Like Software" class="visible-xs" /> <img src="https://www.monkeyuser.com/assets/images/2016/20-architecture.png" alt="If Buildings Were Built Like Software" title="If Buildings Were Built Like Software" class="hidden-xs" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/19-development-platforms.png" alt="Development Platforms">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Development Platforms</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">13 12 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/19-development-platforms.png" alt="Development Platforms" title="Development Platforms" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/6-adlitteram.png" alt="AdLitteram 6">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 6</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">09 12 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/6-adlitteram.png" alt="AdLitteram #6" title="AdLitteram #6" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/18-targeted-branding.png" alt="Targeted Branding">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Targeted Branding</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">08 12 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/18-targeted-branding.png" alt="Targeted Branding" title="Targeted Branding" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/17-developer-productivity.png" alt="Developer Productivity">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Developer Productivity</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">06 12 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/17-developer-productivity.png" alt="Developer Productivity" title="Developer Productivity" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Site deployment to S3 and SSL</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">04 12 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Previous Hosting and Deployment Previously, the website was hosted using GitHub Pages, a free static website hosting provided by GitHub. Once Pages is configured, the updated site can be deployed by pushing it to GitHub with git push.
The old website used the Jekyll static site generator. As Jekyll is written by GitHub, GitHub Pages also natively supports Jekyll sites, running the build step for you.
S3 Website Hosting AWS S3 can be configured to host static websites.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/5-adlitteram.png" alt="AdLitteram 5">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 5</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">02 12 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/5-adlitteram.png" alt="AdLitteram #5" title="AdLitteram #5" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Best New Feature in unittest You Didn&#39;t Know You Need</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">01 12 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>From time to time I like to read documentation of modules I think I know well. The python documentation is not a pleasant read but sometimes you strike a gem.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/16-everysoft-inc.png" alt="Everysoft Corporation">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Everysoft Corporation</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">01 12 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/16-everysoft-inc.png" alt="Everysoft Corporation" title="Everysoft Corporation" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Macchiato: ClojureScript Arrives on the Server</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">30 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                         <p> I recently started the <a href='https://github.com/macchiato-framework'>Macchiato</a> project to provide a platform for building ClojureScript based apps on top Node.js.   </p><p>First, let's look at some of the reasons for running ClojureScript on the server. The JVM is an excellent platform, it's mature, performant, and has a large ecosystem around it. This makes it a solid choice for a wide range of applications.</p><p>However, there are situations where the JVM might not be a good fit. It's a complex piece of technology that requires experience to use effectively. It has a fairly large footprint even from small applications. The startup times can be problematic, especially when it comes to loading Clojure runtime.</p><p>Meanwhile, Node.js also happens to be a popular platform with a large ecosystem around it. It requires far less resources for certain types of applications, has very fast startup times, and its ecosystem is familiar to many JavaScript developers.</p><p>Another appeal for Node based servers comes from building full stack ClojureScript single-page applications, since using Node on the server facilitates server-side rendering for any React based libraries.</p><p>While there are a few existing experiments using ClojureScript on Node, such as <a href='https://github.com/whamtet/dogfort'>Dog Fort</a>, none of these appear to be actively maintained. Since ClojureScript and its ecosystem have evolved in the meantime, I wanted to create a fresh stack using the latest tools and best practices.</p><h3 id="overview">Overview</h3><p>My goal for Macchiato is to provide a stack modeled on Ring based around the existing Node ecosystem, and a development environment similar to what's available for Clojure on the JVM.</p><h4 id="the&#95;stack">The Stack</h4><p>I think it makes sense to embrace the Node ecosystem and leverage the existing modules whenever possible. For example, Ring style cookies map directly to the <a href='https://www.npmjs.com/package/cookies'>cookies</a> NPM module. Conversely, there are a number of excellent ClojureScript libraries available as well, such as <a href='https://github.com/ptaoussanis/timbre'>Timbre</a>,  <a href='https://github.com/juxt/bidi/'>Bidi</a>, and <a href='https://github.com/tolitius/mount'>Mount</a>.</p><p>I used a Ring inspired model where I created <a href='https://github.com/macchiato-framework/macchiato-core/blob/master/src/macchiato/http.cljs'>wrappers around Node HTTP request and response objects</a>. This allowed adapting parts of Ring, such as its session store implementation, with minimal changes.</p><p>The <code>ClientRequest</code> object is translated to a Clojure map, and the response map is written to the <code>ServerResponse</code> object. The request handler is implemented as follows:</p><pre><code class="clojure">&#40;defprotocol IHTTPResponseWriter
  &#40;-write-response &#91;data res&#93; &quot;Write data to a http.ServerResponse&quot;&#41;&#41;

&#40;defn response &#91;req res opts&#93;
  &#40;fn &#91;{:keys &#91;cookies headers body status&#93;}&#93;
    &#40;cookies/set-cookies cookies req res &#40;:cookies opts&#41;&#41;
    &#40;.writeHead res status &#40;clj-&gt;js headers&#41;&#41;
    &#40;when &#40;-write-response body res&#41;
      &#40;.end res&#41;&#41;&#41;&#41;

&#40;defn handler &#91;handler-fn &amp; &#91;opts&#93;&#93;
  &#40;let &#91;opts &#40;or opts {}&#41;&#93;
    &#40;fn &#91;req res&#93;
      &#40;handler-fn &#40;req-&gt;map req res opts&#41; &#40;response req res opts&#41;&#41;&#41;&#41;&#41;
</code></pre><p>The <code>handler</code> accepts a <code>handler-fn</code> function that's passed the request map produced by the <code>req-&gt;map</code> helper. The <code>handler-fn</code> is expected to return a request handler function that will be used to generate the response. This function should accept the request map and the <code>response</code> call back function that writes the response map to the <code>ServerResponse</code> object. The <code>IHTTPResponseWriter</code> protocol is used to serialize different kinds of responses.</p><h4 id="concurrent&#95;request&#95;handling">Concurrent Request Handling</h4><p>JVM servers commonly use a listener thread for accepting client requests, the connections are then passed on to a thread pool of request handlers. This allows the listener to continue accepting connections while the requests are being processed.</p><p>Since Node is single threaded, long running request handlers block the server until they finish. While async operations can be used to handle IO in the background, any business logic will end up preventing the server from accepting new connections while it's running.</p><p>One way around this is to use the cluster module that spins up a single listening process that forks child processes and dispatches the requests to them. Setting this up is pretty straight forward: </p><pre><code class="clojure">&#40;defstate env :start &#40;config/env&#41;&#41;

&#40;defstate http :start &#40;js/require &quot;http&quot;&#41;&#41;

&#40;defn app &#91;&#93;
  &#40;mount/start&#41;
  &#40;let &#91;host &#40;or &#40;:host env&#41; &quot;127.0.0.1&quot;&#41;
        port &#40;or &#40;some-&gt; env :port js/parseInt&#41; 3000&#41;&#93;
    &#40;-&gt; @http
        &#40;.createServer
          &#40;handler
            router
            {:cookies {:signed? true}
             :session {:store &#40;mem/memory-store&#41;}}&#41;&#41;
        &#40;.listen port host #&#40;info &quot;{{name}} started on&quot; host &quot;:&quot; port&#41;&#41;&#41;&#41;&#41;

&#40;defn start-workers &#91;os cluster&#93;
  &#40;dotimes &#91;&#95; &#40;-&gt; os .cpus .-length&#41;&#93;
    &#40;.fork cluster&#41;&#41;
  &#40;.on cluster &quot;exit&quot;
       &#40;fn &#91;worker code signal&#93;
         &#40;info &quot;worker terminated&quot; &#40;-&gt; worker .-process .-pid&#41;&#41;&#41;&#41;&#41;

&#40;defn main &#91;&amp; args&#93;
  &#40;let &#91;os      &#40;js/require &quot;os&quot;&#41;
        cluster &#40;js/require &quot;cluster&quot;&#41;&#93;
    &#40;if &#40;.-isMaster cluster&#41;
      &#40;start-workers os cluster&#41;
      &#40;app&#41;&#41;&#41;&#41;
</code></pre><p>However, it's worth noting that unlike threads, processes don't share memory. So, each child that gets spun up will require its own copy of the memory space.</p><h4 id="the&#95;template">The Template</h4><p>I setup a <a href='https://github.com/macchiato-framework/macchiato-template'>template</a> that creates a minimal app with some reasonable defaults. This template is published to Clojars, and you can try it out yourself by running:</p><pre><code>lein new macchiato myapp
</code></pre><p>The template is setup similarly to Luminus. The source code for the project is found in the <code>src</code> folder, and the <code>env</code> folder contains code that's specific for dev and prod environments.</p><p>The <code>project.clj</code> contains <code>dev</code> and <code>release</code> profiles for working with the app in development mode and packaging it for production use. The app can be started in development mode by running:</p><pre><code>lein build
</code></pre><p>This will clean the project, download NPM modules, and start the Figwheel compiler. Once Figwheel compiles the sources, you can run the app with Node in another terminal as follows:</p><pre><code>node target/out/myapp.js
</code></pre><p>The app should now be available at <code>http://localhost:3000</code>.</p><p>Figwheel also starts the nREPL at <code>localhost:7000</code>. You can connect to it from the editor and run <code>&#40;cljs&#41;</code> to load the ClojureScript REPL.</p><p>Packaging the app for production is accomplished by running:</p><pre><code>lein package
</code></pre><p>This will print out <code>package.json</code> for the app and generate the release artifact called <code>target/release/myapp.js</code>.</p><h3 id="looking&#95;forward">Looking Forward</h3><p>Overall, I think that ClojureScript on top of Node is ready for prime time. It opens up server-side Clojure development to a large community of JavaScript developers, and extends the reach of Clojure to any platform that supports Node.</p><p>While the initial results are very promising, there is still much work to be done in order to provide a solid stack such as Luminus. If you think this project is interesting, feel free to ping me via email or on the Clojurians slack. I would love to collaborate on making Macchiato into a solid choice for developing Node based applications.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Updating site CSS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">29 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Old Website The old website&rsquo;s CSS was based on Bootstrap, with some custom styling. Source code can be found here. The code itself was hacked together.
The font is Josefin Slab, which I quite liked for the main page, but I thought it felt too affected for use as the main font for blog posts.
There are issues with the font size of the monospace font used for code blocks.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/15-css-layout.png" alt="CSS Layout">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">CSS Layout</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">29 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/15-css-layout.png" alt="CSS Layout" title="CSS Layout" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/4-adlitteram.png" alt="AdLitteram 4">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 4</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">25 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/4-adlitteram.png" alt="AdLitteram #4" title="AdLitteram #4" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/14-retrospective-accesories.png" alt="Retrospective Accesories">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Retrospective Accesories</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">24 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/14-retrospective-accesories.png" alt="Retrospective Accesories" title="Retrospective Accesories" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Ptolemy: An AWS DMS Table Mapping Generator</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">22 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        This post introduces Ptolemy, a tool for creating AWS DMS mapping tables, recently open sourced by Cloudreach. Ptolemy&rsquo;s source code can be found on GitHub.
Motivation Amazon Web Services provides the Database Migration Service (DMS) tool for migrating data to, from, or between SQL databases. When running DMS, users can supply a table mapping, which allows the user to specify what data is sent from the source database to the target database.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/13-requirements-vs-implementation.png" alt="Requirements vs. Implementation">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Requirements vs. Implementation</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">22 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/13-requirements-vs-implementation.png" alt="Requirements vs. Implementation" title="Requirements vs. Implementation" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://slimbook.es/images/imagetuto/slimbook-essentials/Pantallazo-2016-11-21_13-23-52.png" alt="Solucionar problemas de conexión con la tarjeta de red inalámbrica Asus AC750 en Linux">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Solucionar problemas de conexión con la tarjeta de red inalámbrica Asus AC750 en Linux</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Soporte - SLIMBOOK: ultrabooks, portátiles y ordenadores GNU/Linux</a> <span class="article__date">21 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>En este tutorial se va a explicar como solucionar los problemas ocasionados por la tarjeta de red inalámbrica Asus <span id="productTitle" class="a-size-large">AC750</span> en Linux, que provoca lentitud y cortes en la conexión a Internet.</p>
<p>Lo primero que se tendrá que realizar será abrir la terminal del sistema, que nos servirá para inroducir los comandos necesarios (Puedes utilizar el atajo del teclado <em>Ctr+Alt+T</em>)</p>
<p><img style="display: block; margin-left: auto; margin-right: auto;" alt="Pantallazo 2016 11 21 13 23 52" src="https://slimbook.es/images/imagetuto/slimbook-essentials/Pantallazo-2016-11-21_13-23-52.png" width="487" height="306" /></p>
<p>1- Comprobar la tarjeta de red inalámbrica detectada por el sistema:</p>
<pre>lspci | grep Wireless</pre>
<p>2- Si utilizas Ubuntu será necesario instalar las siguientes herramientas necesarias:</p>
<pre>sudo apt-get install linux-headers-generic build-essential git</pre>
<p>3- Descargar de Git el driver necesario y acceder a su carpeta:</p>
<pre>git clone https://github.com/lwfinger/rtlwifi_new.git</pre>
<pre>cd rtlwifi_new</pre>
<p>4- Se comenzará la instalación del driver:</p>
<pre>make</pre>
<pre>sudo make install</pre>
<pre>sudo modprobe rtl8821ae</pre>
<p>5- Finalmente reinicia el sistema:</p>
<pre>reboot</pre>
<p>&#160;</p>
<p>De esta forma ya debería funcionar correctamente la conexión a Internet inalámbrica, para comprobarlo recomendamos realizar un test de velocidad y comprobar si ya da una velocidad acuerdo a tú conexión a Internet</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://slimbook.es/images/imagetuto/broken-desktop/brokendesktop.jpg" alt="Fixing the broken desktop after resuming from a suspension in Gnome">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Fixing the broken desktop after resuming from a suspension in Gnome</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Soporte - SLIMBOOK: ultrabooks, portátiles y ordenadores GNU/Linux</a> <span class="article__date">21 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>If you use an Nvidia driver with a Gnome desktop and you decide to resume your system from a suspension or hibernation, you will see that your desktop it's broken like in this screenshot.</p>
<p><img src="https://slimbook.es/images/imagetuto/broken-desktop/brokendesktop.jpg" alt="brokendesktop" style="display: block; margin-left: auto; margin-right: auto;" width="500" height="281" />&#160;</p>
<p>To fix this problem we need to refresh the Gnome desktop after this happens. We have created a bash script that refresh Gnome desktop after resuming the system. Follow the steps below to implement it in your system:</p>
<p>&#160;</p>
<ol>
<li>At your terminal you need to go to the path <strong>/lib/systemd/system-sleep/ </strong>and create a new file that will contain the bash script. You can use the text editor that you prefer, we will use nano.</li>
<pre xml:lang="bash" lines="false">[code]sudo nano /lib/systemd/system-sleep/broken-desktop-fix[/code]</pre>
<li>Now you can copy and paste in this new file the follow bash script that we mentioned. This script will refresh Gnome desktop each time you resume after suspension/hibernation.</li>
<pre xml:lang="bash" lines="false">[code]#!/bin/bash<br /> <br />case "$1" in<br />	post)<br />		DISPLAY=:0.0 ; export DISPLAY<br />		STR="$(users)"<br />		echo ${STR}<br />		IFS=' ' read -ra NAMES &#60;&#60;&#60; ${STR}<br /> <br /> 		for i in "${NAMES[@]}"; do<br />		    su $i -c 'dbus-send --type=method_call --dest=org.gnome.Shell /org/gnome/Shell org.gnome.Shell.Eval "string:global.reexec_self()"'<br />		done;;<br />esac[/code]</pre>
<li>After saving the file you will need assign file permissions.</li>
<pre xml:lang="bash" lines="false">[code]sudo chmod 755 /lib/systemd/system-sleep/broken-desktop-fix[/code]</pre>
<li>Finally, the script be working. You can try to suspend to check it's fixed after resume.</li>
</ol>
<p>&#160;</p>
<p>Also we can do it manually each time it happens with <strong>Alt + F2</strong> and then in the text box introduce <strong>r</strong> and finally press <strong>Enter</strong>, and Gnome will refresh to fix it.</p>
<p><img src="https://slimbook.es/images/imagetuto/broken-desktop/manualsolution.jpg" alt="manualsolution" style="display: block; margin-left: auto; margin-right: auto;" width="300" height="164" /></p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Lessons learned after 300 books in 4 years</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Jovica Ilic</a> <span class="article__date">19 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Four years. Three hundred (mostly nonfiction) books. There are a few simple lessons I learned after reading all of those. They might seem too obvious, but aren&#8217;t all the great truths simple? Anyway, here they are: It&#8217;s much better to read the best book on the topic 5 times, than to read 5 different books on... <a class="more-link" href="https://jovicailic.org/2016/11/lessons-learned-300-books-4-years/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a rel="nofollow" href="https://jovicailic.org/2016/11/lessons-learned-300-books-4-years/">Lessons learned after 300 books in 4 years</a> appeared first on <a rel="nofollow" href="https://jovicailic.org">Jovica Ilic</a>.</p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/3-adlitteram.png" alt="AdLitteram 3">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 3</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">18 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/3-adlitteram.png" alt="AdLitteram #3" title="AdLitteram #3" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/12-testing-hammering-nails.png" alt="Testing: Hammering Nails">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Testing: Hammering Nails</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">17 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/12-testing-hammering-nails.png" alt="Testing: Hammering Nails" title="Testing: Hammering Nails" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/11-division.png" alt="Division">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Division</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">15 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/11-division.png" alt="Division" title="Division" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Configuring a Python Development Environment</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Posts on James Routley</a> <span class="article__date">14 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        This article outlines how to set up a Python development environment, and introduces tools to aid development work. This article is intended for those who are unfamiliar with Python, but have experience using a text editor and the command line. The Python language itself is not covered.
Sections  Installation Running Python Code Packages Virtual Environments Linting Debugging  Installation Python can be installed in the following ways:
Mac (assumes Homebrew is installed):
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/2-adlitteram.png" alt="AdLitteram 2">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 2</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">11 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image. (use the commenting section if you think you know the answer)</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/2-adlitteram.png" alt="AdLitteram #2" title="AdLitteram #2" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Timing Tests in Python For Fun and Profit</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">08 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Hunting down slow tests by reporting tests that take longer than a certain threshold (Because the first step to better test performance is awareness!)</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/9-battle-of-js-frameworks.png" alt="Battle of the JS frameworks in 2016">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Battle of the JS frameworks in 2016</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">08 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/9-battle-of-js-frameworks.png" alt="JS Frameworks battle: For recruiters" title="JS Frameworks battle" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/10-expectation-vs-reality-open-source.png" alt="Open Source: Expectation vs. Reality">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Open Source: Expectation vs. Reality</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">08 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/10-expectation-vs-reality-open-source.png" alt="Open Source: Expectation vs. Reality" title="Open Source: Expectation vs. Reality" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">PostgreSQL Async Notifications in Luminus</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">05 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>There are many situations where the application needs to react to changes in the data. The simplest way to handle this requirement is to keep state in the server session. Unfortunately, this makes it difficult to scale applications horizontally, and can incur additional memory requirements.</p><p>A common solution to this problem is to use an external queue service that each instance of the application subscribes to. However, this adds a new component to the architecture that needs to be maintained.</p><p>A less known option is to use Postgres <a href='https://www.postgresql.org/docs/9.5/static/sql-notify.html'>NOTIFY</a> command to send push notifications from the database. This allows multiple instances of the application can subscribe directly to the database to listen for events.</p><p>This post will walk you through configuring a Luminus app to listen for Postgres notification, and broadcast them to the connected clients over a WebSocket.</p><p><em>prerequisites:</em></p><ul><li><a href='http://www.azul.com/downloads/zulu/'>JDK</a></li><li><a href='http://leiningen.org/'>Leiningen</a></li><li><a href='https://www.postgresql.org/'>PostgreSQL</a></li></ul><p>Let's start by creating a new project for our app:</p><pre><code>lein new luminus pg-feed-demo +postgres +re-frame
</code></pre><h3 id="the&#95;database">The database</h3><p>The first step is to create a schema for the app, and set the connection URL in the <code>profiles.clj</code>, e.g:</p><pre><code class="clojure">{:profiles/dev
 {:env
  {:database-url
   &quot;jdbc:pgsql://localhost:5432/feeds&#95;dev?user=feeds&amp;password=feeds&quot;}}
</code></pre><h4 id="migrations">Migrations</h4><p>Once the schema is ready, we can write a migrations script that creates a table called <code>events</code>, and sets up a notification trigger on it. Let's run the following command in the project root folder to create the migration files:</p><pre><code>lein migratus create events-table
</code></pre><p>Next, add the following script as the <code>up</code> migration:</p><pre><code class="sql">CREATE TABLE events
&#40;id SERIAL PRIMARY KEY,
 event TEXT&#41;;
--;;
CREATE FUNCTION notify&#95;trigger&#40;&#41; RETURNS trigger AS $$
DECLARE
BEGIN
 -- TG&#95;TABLE&#95;NAME - name of the table that was triggered
 -- TG&#95;OP - name of the trigger operation
 -- NEW - the new value in the row
 IF TG&#95;OP = 'INSERT' or TG&#95;OP = 'UPDATE' THEN
   execute 'NOTIFY '
   || TG&#95;TABLE&#95;NAME
   || ', '''
   || TG&#95;OP
   || ' '
   || NEW
   || '''';
 ELSE
   execute 'NOTIFY '
   || TG&#95;TABLE&#95;NAME
   || ', '''
   || TG&#95;OP
   || '''';
 END IF;
 return new;
END;
$$ LANGUAGE plpgsql;
--;;
CREATE TRIGGER event&#95;trigger
AFTER INSERT or UPDATE or DELETE ON events
FOR EACH ROW EXECUTE PROCEDURE notify&#95;trigger&#40;&#41;;
</code></pre><p>The<code>notify&#95;trigger</code> function will broadcast a notification with the table name, the operation, and the parameters when available. The <code>event&#95;trigger</code> will run it whenever <code>insert</code>, <code>update</code>, or <code>delete</code> operations are performed on the <code>messages</code> table.</p><p>We'll also add the <code>down</code> migration for posterity:</p><pre><code>DROP FUNCTION notify&#95;trigger&#40;&#41; CASCADE;
DROP TABLE events;
</code></pre><p>We can now run migrations as follows:</p><pre><code>lein run migrate
</code></pre><h4 id="queries">Queries</h4><p>Let's open the <code>resources/sql/queries.sql</code> file and replace the default queries with the following:</p><pre><code class="sql">-- :name event! :! :n
-- :doc insert a new event
INSERT INTO events &#40;event&#41; VALUES &#40;:event&#41;
</code></pre><h3 id="the&#95;server">The server</h3><p>Unfortunately, the official Postgres JDBC driver cannot receive asynchronous notifications, and uses polling to check if any notifications were issued. Instead, we'll use the <a href='http://impossibl.github.io/pgjdbc-ng/'>pgjdbc-ng</a> driver that provides support for many Postgres specific features, including async notifications. Let's update our app to use this driver instead by swapping the dependency in <code>project.clj</code>:</p><pre><code class="clojure">;&#91;org.postgresql/postgresql &quot;9.4.1211&quot;&#93;
&#91;com.impossibl.pgjdbc-ng/pgjdbc-ng &quot;0.6&quot;&#93;
</code></pre>                        <br /><h4 id="notification&#95;listener">Notification listener</h4><p>Let's open up the <code>pg-feed-demo.db.core</code> namespace and update it to fit our purposes. Since we're no longer using the official Postgres driver, we'll need to update the namespace declaration to remove any references to it. We'll also add the import for the <code>PGNotificationListener</code> class that will be used to add listeners to the connection. To keep things simple, we'll also remove any protocol extensions declared there. The resulting namespace should look as follows:</p><pre><code class="clojure">&#40;ns pg-feed-demo.db.core
  &#40;:require
    &#91;cheshire.core :refer &#91;generate-string parse-string&#93;&#93;
    &#91;clojure.java.jdbc :as jdbc&#93;
    &#91;conman.core :as conman&#93;
    &#91;pg-feed-demo.config :refer &#91;env&#93;&#93;
    &#91;mount.core :refer &#91;defstate&#93;&#93;&#41;
  &#40;:import
    com.impossibl.postgres.api.jdbc.PGNotificationListener&#41;&#41;

&#40;defstate &#94;:dynamic &#42;db&#42;
  :start &#40;conman/connect! {:jdbc-url &#40;env :database-url&#41;}&#41;
  :stop &#40;conman/disconnect! &#42;db&#42;&#41;&#41;

&#40;conman/bind-connection &#42;db&#42; &quot;sql/queries.sql&quot;&#41;
</code></pre><p>In order to add a notification listener, we first have to create a connection. Let's create a <a href='https://github.com/tolitius/mount'>Mount</a> <code>defstate</code> called <code>notifications-connection</code> to hold it:</p><pre><code class="clojure">&#40;defstate notifications-connection
  :start &#40;jdbc/get-connection {:connection-uri &#40;env :database-url&#41;}&#41;
  :stop &#40;.close notifications-connection&#41;&#41;
</code></pre><p>Next, we'll add functions that will allow us to add and remove listeners for a given connection:</p><pre><code class="clojure">&#40;defn add-listener &#91;conn id listener-fn&#93;
  &#40;let &#91;listener &#40;proxy &#91;PGNotificationListener&#93; &#91;&#93;
                   &#40;notification &#91;chan-id channel message&#93;
                     &#40;listener-fn chan-id channel message&#41;&#41;&#41;&#93;
    &#40;.addNotificationListener conn listener&#41;
    &#40;jdbc/db-do-commands
      {:connection notifications-connection}
      &#40;str &quot;LISTEN &quot; &#40;name id&#41;&#41;&#41;
    listener&#41;&#41;

&#40;defn remove-listener &#91;conn listener&#93;
  &#40;.removeNotificationListener conn listener&#41;&#41;
</code></pre><p>Let's start the application by running <code>lein run</code> in the terminal. Once it starts, the nREPL will become available at <code>localhost:7000</code>. When the REPL is connected, run the following code in it to start the database connection and register a listener:</p><pre><code class="clojure">&#40;require :reload 'pg-feed-demo.db.core&#41;
&#40;in-ns 'pg-feed-demo.db.core&#41;

&#40;mount.core/start
  #'&#42;db&#42;
  #'notifications-connection&#41;
                  
&#40;add-listener
  notifications-connection
  &quot;events&quot;
  &#40;fn &#91;&amp; args&#93;
    &#40;apply println &quot;got message:&quot; args&#41;&#41;&#41;
</code></pre><p>We can now test that adding a new message produces the notification:</p><pre><code>&#40;event! {:event &quot;hello world&quot;}&#41;
</code></pre><p>One the function runs, we should see something like the following printed in the terminal as the message is added to the database:</p><pre><code>got message: 32427 messages INSERT &#40;0,&quot;hello world&quot;&#41;
</code></pre><h4 id="websocket&#95;connection">WebSocket connection</h4><p>We're now ready to setup the WebSocket connection that will be used to push notifications to the clients. We'll update the <code>pg-feed-demo.routes.home</code>namespace to look as follows:</p><pre><code class="clojure">&#40;ns pg-feed-demo.routes.home
  &#40;:require &#91;pg-feed-demo.layout :as layout&#93;
            &#91;compojure.core :refer &#91;defroutes GET&#93;&#93;
            &#91;pg-feed-demo.db.core :as db&#93;
            &#91;mount.core :refer &#91;defstate&#93;&#93;
            &#91;immutant.web.async :as async&#93;
            &#91;clojure.tools.logging :as log&#93;&#41;&#41;

&#40;defstate channels
  :start &#40;atom #{}&#41;&#41;

&#40;defstate &#94;{:on-reload :noop} event-listener
  :start &#40;db/add-listener
           db/notifications-connection
           :events
           &#40;fn &#91;&#95; &#95; message&#93;
             &#40;doseq &#91;channel @channels&#93;
               &#40;async/send! channel message&#41;&#41;&#41;&#41;
  :stop &#40;db/remove-listener
          db/notifications-connection
          event-listener&#41;&#41;

&#40;defn persist-event! &#91;&#95; event&#93;
  &#40;db/event! {:event event}&#41;&#41;

&#40;defn connect! &#91;channel&#93;
  &#40;log/info &quot;channel open&quot;&#41;
  &#40;swap! channels conj channel&#41;&#41;

&#40;defn disconnect! &#91;channel {:keys &#91;code reason&#93;}&#93;
  &#40;log/info &quot;close code:&quot; code &quot;reason:&quot; reason&#41;
  &#40;swap! channels #&#40;remove #{channel} %&#41;&#41;&#41;

&#40;defn home-page &#91;&#93;
  &#40;layout/render &quot;home.html&quot;&#41;&#41;

&#40;defroutes home-routes
  &#40;GET &quot;/&quot; &#91;&#93;
    &#40;home-page&#41;&#41;
  &#40;GET &quot;/events&quot; request
    &#40;async/as-channel
      request
      {:on-open    connect!
       :on-close   disconnect!
       :on-message persist-event}&#41;&#41;&#41;

</code></pre><p>The <code>channels</code> state will contain a set of all the channels for the currently connected clients.</p><p>The <code>event-listener</code> will create a new listener that's triggered when events are stored in the database. The handler function will broadcast each event to all the connected clients. Note that we need <code>&#94;{:on-reload :noop}</code> metadata on the listener to prevent it being registered multiple times in case the namespace is reloaded during development.</p><p>Whenever the server receives a message from a client, the message will be persisted to the database by the <code>persist-event!</code> function.</p><p>Finally, we'll create the <code>/events</code> route that will be used to manage WebSocket communication with the clients.</p><h3 id="the&#95;client">The client</h3><p>The client will need to track the currently available messages, allow the user to send new messages to the server, and update the available messages based on server WebSocket notifications.</p><p>Let's run Figwheel to start the ClojureScript compiler before we start working on the client-side code by running the following command:</p><pre><code>lein figwheel
</code></pre>Once Figwheel compiler starts, navigate to <a href='http://localhost:3000'>http://localhost:3000</a> in the browser to load the client-side of the application.<h4 id="re-frame&#95;events">Re-frame events</h4><p>We'll start by adding a handler for adding messages in the <code>pg-feed-demo.handlers</code> namespace:</p><pre><code class="clojure">&#40;reg-event-db
  :event
  &#40;fn &#91;db &#91;&#95; event&#93;&#93;
    &#40;update db :events &#40;fnil conj &#91;&#93;&#41; event&#41;&#41;&#41;
</code></pre><p>Next, we'll add a corresponding subscription to see the current messages in the <code>pg-feed-demo.subscriptions</code> namespace:</p><pre><code class="clojure">&#40;reg-sub
  :events
  &#40;fn &#91;db &#95;&#93;
    &#40;:events db&#41;&#41;&#41;
</code></pre><h4 id="websocket&#95;connection">WebSocket connection</h4><p>We can now add a <code>pg-feed-demo.ws</code> namespace to manage the client-side of the WebSocket connection:</p><pre><code class="clojure">&#40;ns pg-feed-demo.ws&#41;

&#40;defonce ws-chan &#40;atom nil&#41;&#41;

&#40;defn send
  &#91;message&#93;
  &#40;if @ws-chan
    &#40;.send @ws-chan message&#41;
    &#40;throw &#40;js/Error. &quot;Websocket is not available!&quot;&#41;&#41;&#41;&#41;

&#40;defn connect-ws &#91;url handler&#93;
  &#40;if-let &#91;chan &#40;js/WebSocket. url&#41;&#93;
    &#40;do
      &#40;set! &#40;.-onmessage chan&#41; #&#40;-&gt; % .-data handler&#41;&#41;
      &#40;reset! ws-chan chan&#41;&#41;
    &#40;throw &#40;js/Error. &quot;Websocket connection failed!&quot;&#41;&#41;&#41;&#41;
</code></pre><h4 id="user&#95;interface">User interface</h4><p>Finally, we'll update the <code>pg-feed-demo.core</code> namespace to list incoming events and allow the user to generate an event. To do that, We'll update the namespace to look as follows:</p><pre><code class="clojure">&#40;ns pg-feed-demo.core
  &#40;:require &#91;reagent.core :as r&#93;
            &#91;re-frame.core :as rf&#93;
            &#91;pg-feed-demo.handlers&#93;
            &#91;pg-feed-demo.subscriptions&#93;
            &#91;pg-feed-demo.ws :as ws&#93;&#41;&#41;

&#40;defn home-page &#91;&#93;
  &#91;:div.container
   &#91;:div.navbar&#93;
   &#91;:div.row&gt;div.col-sm-12&gt;div.card
    &#91;:div.card-header&gt;h4 &quot;Events&quot;&#93;
    &#91;:div.card-block&gt;ul
     &#40;for &#91;event @&#40;rf/subscribe &#91;:events&#93;&#41;&#93;
       &#94;{:key event}
       &#91;:li event&#93;&#41;&#93;&#93;
   &#91;:hr&#93;
   &#91;:div.row&gt;div.col-sm-12&gt;span.btn-primary.input-group-addon
    {:on-click #&#40;ws/send &#40;str &quot;user event &quot; &#40;js/Date.&#41;&#41;&#41;}
    &quot;generate event&quot;&#93;&#93;&#41;

&#40;defn mount-components &#91;&#93;
  &#40;r/render &#91;#'home-page&#93; &#40;.getElementById js/document &quot;app&quot;&#41;&#41;&#41;

&#40;defn init! &#91;&#93;
  &#40;rf/dispatch-sync &#91;:initialize-db&#93;&#41;
  &#40;ws/connect-ws
    &#40;str &quot;ws://&quot; &#40;.-host js/location&#41; &quot;/events&quot;&#41;
    #&#40;rf/dispatch &#91;:event %&#93;&#41;&#41;
  &#40;mount-components&#41;&#41;
</code></pre><p>That's all there is to it. We should now be able to send events to the server and see the notifications in the browser. We should also be able to generate events by running queries directly in the database, or in another instance of the application.</p><p>The complete source for the project is available <a href='https://github.com/yogthos/pg-feed-demo'>here</a>.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/adlitteram/1-adlitteram.png" alt="AdLitteram 1">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">AdLitteram 1</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">04 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Welcome to AdLitteram. The challenge is to guess the programming term that is represented in the image.</p>

<p><img src="https://www.monkeyuser.com/assets/images/adlitteram/1-adlitteram.png" alt="AdLitteram #1" title="AdLitteram #1" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/8-java-vs-javascript-recruiters.png" alt="Java vs. Javascript: For recruiters">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Java vs. Javascript: For recruiters</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">03 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/8-java-vs-javascript-recruiters.png" alt="Java vs Javascript: For recruiters" title="Java vs Javascript: For recruiters" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to Add Custom Action Buttons to Django Admin</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">01 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The built-in admin actions, operate on a queryset and are hidden in a dropbox menu. They are not suitable for most use cases. In this article we are going to add custom action buttons for each row in a Django Admin list view.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Instapaper Premium is now free for everyone</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Instapaper</a> <span class="article__date">01 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Today we&rsquo;re making <a href="https://www.instapaper.com/premium">Instapaper Premium</a> available to all Instapaper users, free of charge. Instapaper Premium is the best way to experience all that Instapaper has to offer, and we&rsquo;re excited to open it up to everyone. <br/></p><p>Before, some of our greatest features were limited to Instapaper Premium subscribers. Now that we&rsquo;re <a href="http://blog.instapaper.com/post/149374303661">better resourced</a>, we&rsquo;re able to offer everyone the best version of Instapaper. Starting today, all users will have access to:</p><p><b></b></p><ul><li>An ad-free Instapaper website</li><li>Full-text search for all articles</li><li>Unlimited Notes</li><li>Text-to-speech playlists</li><li>Unlimited speed reading</li><li>“Send to Kindle” via bookmarklet and mobile apps</li><li>Kindle Digests of up to 50 articles</li></ul><p>For existing Instapaper Premium users, we’ll offer prorated refunds for your current subscription, and you’ll no longer be billed for Instapaper Premium. Thanks for your support throughout the years, we appreciate it.</p><p>All users will continue to have an ad-free Instapaper app experience, and we’re eliminating ads on the web entirely.<br/></p><p>Opening Instapaper Premium is something we’ve always wanted to do, and we’re thrilled to give everyone the very best Instapaper experience. If you’ve got any questions or feedback, just let us know via <a href="mailto:support@help.instapaper.com">support@help.instapaper.com</a> or <a href="https://twitter.com/InstapaperHelp">@InstapaperHelp</a> on Twitter.</p><p>– Instapaper Team</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/6-npe.png" alt="Null Pointer">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Null Pointer</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">01 11 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/6-npe.png" alt="Null Pointer" title="Null Pointer" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://www.monstruosfelices.es/legiondelespacio/wp-content/uploads/2016/10/cropped-banner-32x32.jpg" alt="Películas de terror para Halloween">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Películas de terror para Halloween</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Legión del Espacio</a> <span class="article__date">31 10 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        En el caso de que hayas decidido no disfrazarte de Harley Quinn y pasar esta noche de terror en casa con unas pizzas, cervezas, amigos y pelis de terror, desde la Legión del Espacio vamos a recomendaros algunos de los títulos que más nos han gustado de los últimos años. Babadook (2014) es una película [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://www.monstruosfelices.es/legiondelespacio/wp-content/uploads/2016/10/cropped-banner-32x32.jpg" alt="El Doctor Extraño y las pastillas antimareo">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">El Doctor Extraño y las pastillas antimareo</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Legión del Espacio</a> <span class="article__date">31 10 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        El viernes acudió la legión del espacio en pleno para ver el estreno de Doctor Extraño, la última de las adaptaciones de la Marvel. Nos encontramos, como es normal, en la típica historia de orígenes del personaje, algo necesario, pero que acaba por ser un montón de clichés que se repiten una y otra vez [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Why Christians should write Fantasy Stories</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">26 10 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Is it OK for a Christian to write fantasy stories? The bible is pretty clear that people should not use magic. Why would it be OK to write about magic? And isn't the whole idea of writing fantasy stories frivolous anyway? Wouldn't our time be better spent serving the poor and telling people about Jesus, or even reading the bible? I would argue that not only is it OK, but if you are a Christian with the inclination to write fantasy stories, it’s helpful if you do.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Bullet Proofing Django Models</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">25 10 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>We recently added a bank account like functionality into one of our products. During the development we encountered some textbook problems and I thought it can be a good opportunity to go over some of the patterns we use in our Django models.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://www.monstruosfelices.es/legiondelespacio/wp-content/uploads/2016/10/cropped-banner-32x32.jpg" alt="Walking Dead 7×01 Sin Spoilers: Cásate conmigo, Negan">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Walking Dead 7×01 Sin Spoilers: Cásate conmigo, Negan</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Legión del Espacio</a> <span class="article__date">25 10 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Es difícil entender cómo seguimos viendo The Walking Dead. Se pasa por el forro lo mejor de los cómics, imprime un ritmo demencialmente lento a algunos episodios y se aprovecha de los cliffhangers como un cabrón con los últimos dos o tres capítulos de cada temporada. Y sin embargo, con la cantidad de cosas que [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/5-heisenbug.png" alt="Heisenbug">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Heisenbug</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">25 10 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/5-heisenbug.png" alt="Heisenbug" title="Heisenbug" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/7-project-managers.png" alt="How Project Managers Are Seen By">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">How Project Managers Are Seen By</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">25 10 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/7-project-managers.png" alt="ProjectManagers" title="ProjectManagers" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://www.monstruosfelices.es/legiondelespacio/wp-content/uploads/2016/10/cropped-banner-32x32.jpg" alt="Discos clásicos con portada de Star Wars">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Discos clásicos con portada de Star Wars</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Legión del Espacio</a> <span class="article__date">24 10 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Hay gente que además de tener mucho tiempo libre son unas verdaderas máquinas del diseño gráfico. Ese parece ser el caso de Why the Longplay Face, que se dedica a retocar algunas de las portadas de discos más conocidos de los últimos cincuenta años, en los que coloca personajes de Star Wars. A mí me [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://www.monstruosfelices.es/legiondelespacio/wp-content/uploads/2016/10/cropped-banner-32x32.jpg" alt="Doctor, te extraño">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Doctor, te extraño</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Legión del Espacio</a> <span class="article__date">24 10 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        El viernes 28 de octubre llega una de las películas Marvel más esperadas por toda la tropa legionaria. Después de que la segunda de los Vengadores nos dejara algo fríos con tanta pelea absurda y carreras para arriba y para abajo, y que la Civil War se quedara en Pupita War, esperamos que Doctor Extraño [&#8230;]
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/1-minor-bug.png" alt="Bugfixing - for developers">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Bugfixing - for developers</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">20 10 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/1-minor-bug.png" alt="Bugfixing for developers" title="Bugfixing for developers" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/2-diesaster-scale.png" alt="disaster Scale">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">disaster Scale</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">17 10 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/2-diesaster-scale.png" alt="disaster scale" title="disaster scale" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/img/atom/atom-nrepl.png" alt="Configuring Atom for Luminus">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Configuring Atom for Luminus</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">15 10 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>There are many editors and IDEs available for Clojure today. The most popular ones are Emacs with <a href='https://github.com/clojure-emacs/cider'>CIDER</a> and IntelliJ with <a href='https://cursive-ide.com/'>Cursive</a>. While both of these options provide excellent development environments, they also require a bit of learning to become productive in.</p><p>Good news is that you don't have to learn a complex environment to get started. This post will walk you through the steps of configuring <a href='https://atom.io/'>Atom editor</a> editor to work with a <a href='http://www.luminusweb.net/'>Luminus</a> project. We'll see how to configure Atom for editing Clojure code and how to connect it to the remote REPL started by the Luminus app for interactive development.</p><h3 id="prerequisites">Prerequisites</h3><p>You'll need the following installed to follow along with this post:</p><ul><li><a href='http://www.azul.com/downloads/zulu/'>OpenJDK</a></li><li><a href='http://leiningen.org/'>Leiningen</a></li><li><a href='https://atom.io/'>Atom</a></li></ul><h3 id="configuring&#95;atom">Configuring Atom</h3><p>Let's take a look at the bare minimum Atom configuration for working with Clojure. Once you're up and running, you may with to look <a href='https://gist.github.com/jasongilman/d1f70507bed021b48625'>here</a> for a more advanced configuration. We'll start by installing the following packages:</p><ul><li><a href='https://atom.io/packages/parinfer'>parinfer</a> or <a href='https://atom.io/packages/lisp-paredit'>lisp-paredit</a> package for structural editing</li><li><a href='https://atom.io/packages/proto-repl'>proto-repl</a> to connect to a Clojure REPL</li></ul><h3 id="structural&#95;editing">Structural Editing</h3><p>A structural editor understands the structure of Clojure code and provides shortcuts for manipulating s-expressions instead of lines of text. It also eliminates the need to manually balance the parens. This takes a bit of getting used to, but it will make working with Clojure a lot more pleasant in the long run.</p><h4 id="parinfer">Parinfer</h4><p>The <code>parinfer</code> mode will attempt to automatically infer the necessary parens based on the indentation. This mode has a gentle learning curve and attempts to get our of your way as much as possible. You can read more about how it works <a href='https://shaunlebron.github.io/parinfer/#introduction'>here</a>.</p><h4 id="paredit">Paredit</h4><p>The <code>paredit</code> mode takes a bit more getting used to, but provides you with precise control over code structure. Whenever you add a peren, a matching closing paren will be inserted automatically. Paredit will also prevent you you from deleting parens unless you have an empty pair. </p><p>The package also provides a handy <code>ctrl-w</code> shortcut that will extend the selection by s-expression. This is the recommended way to select code as you don't have to manually match the start and end of an expression when selecting.</p><h3 id="the&#95;repl">The REPL</h3><p>The REPL is an essential tool for working with Clojure. When integrated with the editor, it allows running any code that you write directly in the application.</p><h4 id="connecting&#95;the&#95;repl">Connecting the REPL</h4><p>We'll create a new Luminus project with SQLite database support by running the following command:</p><pre><code>lein new luminus myapp +sqlite</code></pre><p>Once the project is created, we can go to the project folder and run the migrations:</p><pre><code>cd myapp 
lein run migrate
</code></pre>We're now ready to start the app in development mode:  <br /><pre><code>lein run</code></pre><p>The app will start the nREPL server on <code>localhost:7000</code> once it loads. Let's open the project in Atom and connect to the nREPL instance.</p><p>The default keybinding for connecting to the nREPL is <code>ctrl-alt-, y</code> on Windows/Linux and <code>cmd-alt-, y</code> on OS X. This should pop up a dialog asking for the host and the port.</p><p><img src="/img/atom/atom-nrepl.png" alt="" /></p><p>Enter <code>7000</code> as the port and hit <code>enter</code>. If everything went well the REPL should now be connected to your project.</p><p>Once the REPL is connected we can try to evaluate some code in it. For example, let's check what namespace we're currently in by typing <code>&#42;ns&#42;</code> in the REPL and then hitting <code>shift-enter</code>. The result should look something like the following:</p><p><img src="/img/atom/atom-repl-ns.png" alt="" /></p><p>Let's navigate to the <code>myapp.routes.home</code> namespace and try to run some of the database query functions from there. We'll first need to require the database namespace:</p><pre><code class="clojure">&#40;ns myapp.routes.home
  &#40;:require &#91;myapp.layout :as layout&#93;
            &#91;compojure.core :refer &#91;defroutes GET&#93;&#93;
            &#91;ring.util.http-response :as response&#93;
            &#91;clojure.java.io :as io&#93;
            ;; add a reference to the db namespace
            &#91;myapp.db.core :as db&#93;&#41;&#41;
</code></pre><p>Once we've done that, we'll need to reload <code>myapp.routes.home</code> namespace. To do that we'll need to send the code from the editor to the REPL for evaluation.</p><p>There are a few commands for doing this. I recommend starting by using the <code>ctrl-alt-, B</code> shortcut that sends the top-level block of code to the REPL for execution. Place the cursor inside the <code>ns</code> declaration and hit <code>ctrl-alt-, B</code> to send it to the REPL. We can see that the REPL displays the code that was sent to it along with the result:</p><p><img src="/img/atom/send-to-repl.png" alt="" /></p><p>Now that we have the <code>db</code> namespace required, we can start the database connection state by typing the following command in the REPL:</p><pre><code class="clojure">&#40;mount.core/start #'db/&#42;db&#42;&#41;
</code></pre><p>The result should look as follows:</p><p><img src="/img/atom/atom-start-db.png" alt="" /></p><p>With the database is started, let's add a user to it by running the following code in the REPL:</p><pre><code class="clojure">&#40;db/create-user!
 {:id &quot;foo&quot;
  :first&#95;name &quot;Bob&quot;
  :last&#95;name &quot;Bobberton&quot;
  :email &quot;bob@foo.bar&quot;
  :pass &quot;secret&quot;}&#41;
</code></pre><p>We can also test that the user was added successfully by running:</p><pre><code class="clojure">&#40;db/get-user {:id &quot;foo&quot;}&#41;
</code></pre><p>We can see that the user record exists in the database:</p><pre><code class="clojure">{:id &quot;foo&quot;
 :admin nil
 :is&#95;active nil
 :last&#95;login nil
 :first&#95;name &quot;Bob&quot;
 :last&#95;name &quot;Bobberton&quot;
 :email &quot;bob@foo.bar&quot;
 :pass &quot;secret&quot;}
</code></pre><p>As you can see, the code that we run in the REPL executes in the context of the application and has access to all the resources and the application state. Let's take a closer look at how this helps us during development.</p><p>You might have noticed that the records we get back from the database use the <code>&#95;</code> character as word separator. Meanwhile, idiomatic Clojure code uses the <code>-</code> character. Let's write a couple of functions to transform the key names in the results.</p><p>A Clojure map represents its entities as vectors containing key-value pairs. We'll start by writing a function to rename underscores to dashes in map entries:</p><pre><code class="clojure">&#40;defn clojurize &#91;&#91;k v&#93;&#93;
  &#91;&#40;-&gt; k name &#40;.replaceAll &quot;&#95;&quot; &quot;-&quot;&#41; keyword&#41; v&#93;&#41;
</code></pre><p>We'll load the function in the namespace by placing the cursor anywhere inside it and hitting <code>ctrl-alt-, B</code> to load it. Let's run this function in the REPL to see that it works:</p><pre><code class="clojure">&#40;clojurize &#91;:first&#95;name &quot;Bob&quot;&#93;&#41;
=&gt;&#91;:first-name &quot;Bob&quot;&#93;
</code></pre><p>We can see that the result is what we expect. Next, let's write a function to rename the keys in a map:</p><pre><code class="clojure">&#40;defn clojurize-keys &#91;m&#93;
  &#40;-&gt;&gt; m &#40;map clojurize&#41; &#40;into {}&#41;&#41;&#41;
</code></pre><p>We'll load the new function and test that this works as expected in the REPL:</p><pre><code class="clojure">&#40;clojurize-keys &#40;db/get-user {:id &quot;foo&quot;}&#41;&#41;
</code></pre><p>We see that the result is the translated map that we want:</p><pre><code class="clojure">{:id &quot;foo&quot;
 :admin nil
 :is-active nil
 :last-login nil
 :first-name &quot;Bob&quot;
 :last-name &quot;Bobberton&quot;
 :email &quot;bob@foo.bar&quot;
 :pass &quot;secret&quot;}
</code></pre><p>Now that we have a nicely formatted result, let's add a route to query it in the browser:</p><pre><code class="clojure">&#40;defroutes home-routes
  &#40;GET &quot;/&quot; &#91;&#93; &#40;home-page&#41;&#41;
  &#40;GET &quot;/user/:id&quot; &#91;id&#93;
       &#40;-&gt; &#40;db/get-user {:id id}&#41;
           &#40;clojurize-keys&#41;
           &#40;response/ok&#41;&#41;&#41;
  &#40;GET &quot;/about&quot; &#91;&#93; &#40;about-page&#41;&#41;&#41;
</code></pre><p>We can now navigate to <code>http://localhost:3000/user/foo</code> and see the user data.</p><h3 id="conclusion">Conclusion</h3><p>That's all there is to it. While this setup is fairly minimal, it will let you play with a lot of Clojure features without having to spend practically any time learning and configuring an editor. </p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/3-do-not-disturb.png" alt="Universal Do Not Disturb Indicator">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Universal Do Not Disturb Indicator</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">13 10 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/3-do-not-disturb.png" alt="Do Not Disturb" title="Universal Do Not Disturb Indicator" /></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.monkeyuser.com/assets/images/2016/4-project-lifecycle.png" alt="Project Lifecycle">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Project Lifecycle</h1>
                            <h2 class="article__feed"><a target="_blank" href="">MonkeyUser</a> <span class="article__date">11 10 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><img src="https://www.monkeyuser.com/assets/images/2016/4-project-lifecycle.png" alt="Project Lifecycle" title="Project Lifecycle" />
<script>"A2RBOncYCusW"</script></p>

                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Running a node.js app in a low-memory environment</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">01 10 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Running a node.js app in a low-memory environment requires some additional work to ensure that the v8 garbage collector is aware of the memory ceiling. This post outlines an approach to achieve this.
Background Out of the box, a 64-bit installation of node.js assumes a memory ceiling of 1.5GB per node process. If you are running your node app in a memory constrained environment, e.g. a low-cost VPS server or PaaS instance, it&rsquo;s necessary to inform the v8 runtime that you have a reduced memory ceiling.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Running a node.js app in a low-memory environment</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">01 10 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Running a node.js app in a low-memory environment requires some additional work to ensure that the v8 garbage collector is aware of the memory ceiling. This post outlines an approach to achieve this.
Background Out of the box, a 64-bit installation of node.js assumes a memory ceiling of 1.5GB per node process. If you are running your node app in a memory constrained environment, e.g. a low-cost VPS server or PaaS instance, it&rsquo;s necessary to inform the v8 runtime that you have a reduced memory ceiling.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/search_post1.png" alt="Introducing a new search experience for iOS">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Introducing a new search experience for iOS</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Instapaper</a> <span class="article__date">28 09 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Earlier this year, we <a href="http://blog.instapaper.com/post/143899635741">rebuilt our search backend</a> as a first step in making search on Instapaper faster and easier to scale. Today, we’re launching a completely overhauled search experience on iOS, which is now available to all users on <a href="https://itunes.apple.com/us/app/instapaper/id288545208?mt=8">Instapaper version 7.2</a>.<b><br/></b></p><p><b>Search in half the taps </b></p><p>The new search comes with big improvements and is accessible directly at the top of your article list (without having to go through the side menu). Just scroll up on the article list to reveal the search bar.</p><p><figure class="tmblr-full" data-orig-height="416" data-orig-width="600" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/search_post1.png"><img src="https://64.media.tumblr.com/b605a8ad38adf32e9d7bee722c2fd6e5/tumblr_inline_p7gifbBOtr1rof3ra_540.png" data-orig-height="416" data-orig-width="600" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/search_post1.png"/></figure></p><p><b>Local search for everyone</b><br/></p><p>Once you tap the search bar, you’ll see an option to search either your current section (e.g. Home) or All Articles. Everyone can search by title in the current section, regardless of connectivity. If you’re an Instapaper Premium subscriber, the All Articles tab provides you access to full-text search.</p><p><figure class="tmblr-full" data-orig-height="416" data-orig-width="600" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/search_post2.png"><img src="https://64.media.tumblr.com/6b9da09099e59f0ff5af3039c2608dc5/tumblr_inline_p7gifbstiY1rof3ra_540.png" data-orig-height="416" data-orig-width="600" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/search_post2.png"/></figure></p><p><b>Manage articles in search results<br/></b></p><p>In addition to filtering results by section, you can also manage your articles in search results. Swipe across any article entry in search for options including  “move to a folder”, “archive”, “delete” or “share”.</p><p><b>Open search results in reader view</b></p><p>Previously, articles in search results would open within the in-app browser. Now, if you open an article from search results, you’ll stay in the Instapaper app–even if the article isn’t stored on your device–and have access to all Instapaper reader features.<b><br/></b></p><p><b>Other improvements</b><br/></p><p>This release also has several fixes and improvements based on your feedback, including support for iOS10. If you have any questions, feature requests or issues you’d like us to sort out, please reach out to <a href="http://t.umblr.com/redirect?z=mailto%3Asupport%40help.instapaper.com&amp;t=YTNkYjg1YzkxNWNmZTNjNDU1NTMzNjBlN2I1NGU3MDRhODdhM2NlZCxZV1FjTElQRQ%3D%3D&amp;m=1&amp;b=t%3AOZjQZ-Pa6uMEdOyfetS5_g">support@help.instapaper.com</a> or <a href="https://twitter.com/@InstapaperHelp">@InstapaperHelp</a> on Twitter. We love hearing from our users, and we thank you for choosing Instapaper!</p><p>– Instapaper Team</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Reusable Components</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">25 09 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>One of the projects my team works is a clinical documentation platform. The goal of the project is to facilitate the implementation of different kinds of workflows for the clinics at our hospital.</p><h2 id="requirements">Requirements</h2><p>One major requirement for the platform is support for multiple concurrent users working on the same document. For example, both a physician and a pharmacist may have to enter the prescribed medications for a patient. Both users have to be able to complete their work concurrently and to be aware of the changes made by the other.</p><p>Another requirement is to visualize the data differently depending on the discipline. Patient lab results may need to be shown as a table in one place, but as a trending chart in another. A physician may call a piece of data by one name, while the pharmacist calls it by another.</p><p>In other words, the data model needs to have different views associated with it. Furthermore, some information may not be shown in a particular view at all, but it would still need to be updated when a field in the view changes.</p><p>Consider an example where you're collecting patient height and weight, then the BMI is calculated based on that. The user may only be interested in seeing height and weight in their workflow, but once that data changes the BMI still needs to be recalculated even if it's not displayed in that view.</p><p>Finally, we have a large data model based on the <a href='https://www.hl7.org/fhir/'>Hl7 FHIR</a> standard. This standard specifies resources for describing different kinds clinical data, such as patient demographics, medications, allergies and so on. An example of a resource definition can be seen in the <a href='https://www.hl7.org/fhir/resourcelist.html'>Resources</a> section.</p><h2 id="architecture">Architecture</h2><p>The concurrent user requirement means that the changes made by different users have to be kept in sync. Meanwhile, business rules have to be applied transactionally for each change.</p><p>The easiest way to address the above requirements is to keep the master document on the server. Any time a client makes a change, a request is sent to the server over a WebSocket. The server updates the field in the document and runs the business rules. It will then notify the clients viewing a particular document of all the fields that were updated in the transaction.</p><p>The clients simply reflect the state of the document managed by the server and never make local updates to the model. This ensures that all the changes are handled centrally, and that the business rules are applied regardless of what is displayed on the client.</p><p>The second problem is the creation of views for the data. Since we have many distinct fields, but only a small number of types of fields, it made sense for us to create widgets to represent specific data types. The widgets are bound to the fields in the data model using the path as a unique identifier.</p><p>Let's take a look at a <a href='https://github.com/yogthos/components-example'>sample project</a> that illustrates the above architecture to see how this works in practice.</p><h2 id="server-side&#95;state&#95;management">Server-Side State Management</h2><p>We'll start by examining the server-side implementation of the architecture starting with the <a href='https://github.com/yogthos/components-example/blob/master/src/clj/components_example/document.clj'>components-example.document</a> namespace. The server in our example keeps its state in a <code>ref</code>, and updates it transactionally whenever it receives an update from the client.</p><pre><code class="clojure">&#40;defonce document &#40;ref {}&#41;&#41;

&#40;defn bmi &#91;weight height&#93;
  &#40;when &#40;and weight height &#40;pos? height&#41;&#41;
    &#40;/ weight &#40;&#42; height height&#41;&#41;&#41;&#41;

&#40;defn bmi-rule &#91;doc&#93;
  &#40;let &#91;weight &#40;get-in doc &#91;:vitals :weight&#93;&#41;
        height &#40;get-in doc &#91;:vitals :height&#93;&#41;&#93;
    &#91;{:path  &#91;:vitals :bmi&#93;
      :value &#40;bmi weight height&#41;}&#93;&#41;&#41;

&#40;def rules
  {&#91;:vitals :weight&#93; bmi-rule
   &#91;:vitals :height&#93; bmi-rule}&#41;

&#40;defn run-rules &#91;doc {:keys &#91;path&#93;}&#93;
  &#40;when-let &#91;rule &#40;rules path&#41;&#93;
    &#40;rule doc&#41;&#41;&#41;

&#40;defn update-document! &#91;{:keys &#91;path value&#93; :as path-value}&#93;
  &#40;dosync
    &#40;let &#91;current-document &#40;alter document assoc-in path value&#41;
          updated-paths    &#40;run-rules current-document path-value&#41;&#93;
      &#40;doseq &#91;{:keys &#91;path value&#93;} updated-paths&#93;
        &#40;alter document assoc-in path value&#41;&#41;
      &#40;into &#91;path-value&#93; updated-paths&#41;&#41;&#41;&#41;
</code></pre><p>Note the use of the <code>dosync</code> block in the <code>update-document!</code> function to update the document and run the business rules as a transaction.</p><p>Each rule can in turn create additional changes in the document. A vector of updated <code>path-value</code> pairs is returned as the result of the update. Our setup has a single rule that calculates the BMI. This rule is triggered whenever the weight or height fields are changed.</p><p>While the example keeps the document in memory, there's nothing stopping us from keeping it in the database and running the updates using a transaction against it. This is especially easy to do with PostgreSQL as it supports working with individual JSON fields directly.</p><h2 id="client-server&#95;communication">Client-Server Communication</h2><p>When the client loads, it establishes a WebSocket connection with the server. This connection is used to notify the server of the user actions and to push the changes back to the clients.</p><p>Server side of the connection can be found in the <a href='https://github.com/yogthos/components-example/blob/master/src/clj/components_example/routes/ws.clj'>components-example.routes.ws</a> namespace. The part that's of most interest to us is the <code>handle-message</code> multimethod that's keyed on the <code>:document/update</code> event:</p><pre><code class="clojure">&#40;defmethod handle-message :document/update &#91;{:keys &#91;?data&#93;}&#93;
  &#40;let &#91;updated-paths &#40;update-document! ?data&#41;&#93;
    &#40;doseq &#91;uid &#40;-&gt; @socket :connected-uids deref :any&#41;&#93;
      &#40;&#40;:send-fn @socket&#41; uid &#91;:document/update updated-paths&#93;&#41;&#41;&#41;&#41;
</code></pre><p>The multimethod calls the <code>update-document!</code> function we just saw and then notifies the connected clients with its result.</p><p>Conversely, the client portion of the WebSocket connection is found in the <a href='https://github.com/yogthos/components-example/blob/master/src/cljs/components_example/ws.cljs'>components-example.ws</a> namespace. Here we have the <code>update-value</code> function that sends the update event to the server, and the <code>handle-message</code> multimethod that handles incoming update messages:</p><pre><code class="clojure">&#40;defn update-value &#91;path-value&#93;
  &#40;&#40;:send-fn @socket&#41; &#91;:document/update path-value&#93;&#41;&#41;

&#40;defmethod handle-message :document/update &#91;&#91;&#95; updated-paths&#93;&#93;
  &#40;doseq &#91;{:keys &#91;path value&#93;} updated-paths&#93;
    &#40;dispatch &#91;:set-doc-value path value&#93;&#41;&#41;&#41;
</code></pre><p>The multimethod dispatches a re-frame event for each path/value pair in the message. Let's take a look at the re-frame handlers and subscriptions next.</p><h2 id="client-side&#95;state&#95;management">Client-Side State Management</h2><p>Re-frame handlers are found in the <a href='https://github.com/yogthos/components-example/blob/master/src/cljs/components_example/handlers.cljs'>components-example.handlers</a> namespace, where the document state is updated using the following handlers:</p><pre><code class="clojure">&#40;reg-event-db
  :set-doc-value
  &#40;fn &#91;db &#91;&#95; path value&#93;&#93;
    &#40;assoc-in db &#40;into &#91;:document&#93; path&#41; value&#41;&#41;&#41;

&#40;reg-event-db
  :save
  &#40;fn &#91;db &#91;&#95; path value&#93;&#93;
    &#40;ws/update-value {:path path :value value}&#41;
    db&#41;&#41;
</code></pre><p>The <code>:save</code> event creates a WebSocket call to notify the server of the change. Meanwhile, the <code>:set-doc-value</code> event is used to update the client state with the set of changes. This event will be triggered by a WebSocket message from the server, whenever the master document is updated.</p><p>We also need to have a corresponding subscription to view the state of the document. This subscription is found in the <a href='https://github.com/yogthos/components-example/blob/master/src/cljs/components_example/subscriptions.cljs'>components-example.subscriptions</a> namespace:</p><pre><code class="clojure">&#40;reg-sub
  :document
  &#40;fn &#91;db &#91;&#95; path&#93;&#93;
    &#40;let &#91;doc &#40;:document db&#41;&#93;
      &#40;if path &#40;get-in doc path&#41; doc&#41;&#41;&#41;&#41;
</code></pre><p>Next, let's take a look at how the UI components are defined and associated with the data model.</p><h2 id="application&#95;components">Application Components</h2><p>The UI for the application consists of widgets representing individual data types. When a widget is instantiated it's associated with a particular path in the document. The widgets are found in the <a href='https://github.com/yogthos/components-example/blob/master/src/cljs/components_example/widgets.cljs'>components-example.widgets</a> namespace.</p><p>The set of all valid paths is contained in the <a href='https://github.com/yogthos/components-example/blob/master/src/cljc/components_example/model.cljc'>components-example.model</a> namespace. This namespace is written using CLJC, and provides a single schema for both the client and the server portions of the application.</p><p>The widgets are associated with the model using the <a href='https://github.com/yogthos/components-example/blob/master/src/cljs/components_example/model_view.cljs'>components-example.model-view</a> namespace. Each of the paths found in the model can have multiple views associated with it. In our example, we have the form for entering the data and a preview for displaying it.</p><p>Finally, we have the <a href='https://github.com/yogthos/components-example/blob/master/src/cljs/components_example/view.cljs'>components-example.view</a> namespace that provides the layout for the page. This namespace instantiates the widgets defined in the <code>model-view</code> namespace and lays them out as needed for a particular page in the application.</p><p>Let's explore each of these namespaces in detail below.</p><h3 id="model">Model</h3><p>The data model in our application consists of a map that's keyed on the element path where each key points to the type of data found in that element. Let's take a look at a simple demographics model below:</p><pre><code class="clojure">&#40;def Name
  {:first s/Str
   :last  s/Str}&#41;

&#40;def demographics
  {&#91;:demographics :mrn&#93;
   s/Str
   
   &#91;:demographics :name&#93;
   Name

   &#91;:demographics :name :dob&#93;
   #?&#40;:clj java.util.Date
      :cljs js/Date&#41;

   &#91;:demographics :address :province&#93;
   &#40;s/enum &quot;AB&quot; &quot;BC&quot; &quot;MB&quot; &quot;NB&quot; &quot;NL&quot; &quot;NS&quot; &quot;NT&quot; &quot;NU&quot; &quot;ON&quot; &quot;PE&quot; &quot;QC&quot; &quot;SK&quot; &quot;YT&quot;&#41;}&#41;
</code></pre><p>We can see that the demographics model contains the name, the date of birth, and the province for the patient.</p><p>The paths can point to any type of data structure. For example, the <code>&#91;:demographics :name&#93;</code> path points to a map containing the first and the last name.</p><p>Meanwhile, the <code>&#91;:demographics :name :dob&#93;</code> path leverages CLJC to provide different validators for Clojure and ClojureScript.</p><h3 id="widgets">Widgets</h3><p>Now, let's take a look at the approach we took to map the FHIR data model to the UI in the application.</p><p>At the lowest level we have widgets that represent a particular type of element. These would include text fields, datepickers, dropdowns, tables, and so on. The way we chose to represent the widgets was to use multimethods. The widgets are initialized using a map containing the <code>:type</code> key:</p><pre><code class="clojure">&#40;defmulti widget :type&#41;
</code></pre><p>Given the multimethod definition above, a text input widget might look as follows:</p><pre><code class="clojure">&#40;defmethod widget :text-input &#91;{:keys &#91;label path&#93;}&#93;
  &#40;r/with-let &#91;value    &#40;r/atom nil&#41;
               focused? &#40;r/atom false&#41;&#93;
    &#91;:div.form-group
     &#91;:label label&#93;
     &#91;:input.form-control
      {:type      :text
       :on-focus  #&#40;do
                    &#40;reset! value @&#40;rf/subscribe &#91;:document path&#93;&#41;&#41;
                    &#40;reset! focused? true&#41;&#41;
       :on-blur   #&#40;do
                    &#40;rf/dispatch
                      &#91;:save path @value&#93;&#41;
                    &#40;reset! focused? false&#41;&#41;
       :value     &#40;if @focused? @value @&#40;subscribe-doc path&#41;&#41;
       :on-change #&#40;reset! value &#40;-&gt; % .-target .-value&#41;&#41;}&#93;&#93;&#41;&#41;
</code></pre><p>The text input widget subscribes to the given path in the document as its value. Since we don't want to generate unnecessary WebSocket events while the user is typing, the input keeps a local state while it's focused.</p><p>When the user focuses the input, its local state is set to the current document state, and when the focus is lost, the update event is generated with the new value.</p><p>Each widget is a reusable component that is associated with a path in the document to create a concrete instance:</p><pre><code class="clojure">&#91;widget {:type :text-input
         :lable &quot;first name&quot;
         :path &#91;:patient :name :first&#93;}&#93;
</code></pre><p>Since the widgets are mapped to the data elements via the path when instantiated, they can easily be composed into larger components. For example, we'll create a patient name component using two <code>:text-input</code> widgets:</p><pre><code class="clojure">&#40;defmethod widget :name &#91;{:keys &#91;first-name last-name path&#93;}&#93;
  &#91;:div
   &#91;widget {:label first-name
            :type :text-input
            :path &#40;conj path :first&#41;}&#93;
   &#91;widget {:label last-name
            :type :text-input
            :path &#40;conj path :last&#41;}&#93;&#93;&#41;
</code></pre><p>Composite widgets provide us with the ability to describe complex data elements that are common among different resources.</p><h3 id="model-view">Model-View</h3><p>The widgets are associated with the concrete paths using a model-view map. This map is keyed on the same paths as the model map, but points to widget declarations instead of the types. We can represent the MRN and name fields as follows:</p><pre><code class="clojure">&#40;def demographics-form
  {&#91;:demographics :mrn&#93;
   {:label &quot;medical record number&quot;
    :type  :text-input}
    
   &#91;:demographics :name&#93;
   {:first-name &quot;first name&quot;
    :last-name  &quot;last name&quot;
    :type       :name}}&#41;
</code></pre><p>The model/view map contains a set of UI elements for representing the data model. Note that this approach allows us to create multiple view definitions for any particular data element.</p><p>This is useful as we may wish to present the data differently depending on the use case. For example, some users may manipulate the data, while others will simply want to view it.</p><h3 id="view">View</h3><p>This brings us to the view portion of the architecture. The view aggregates the widgets defined in the model-view map into a particular layout. The demographics view could look as follows:</p><pre><code class="clojure">&#40;defn create-widget &#91;view path&#93;
  &#40;let &#91;opts &#40;view path&#41;&#93;
    &#91;widget &#40;assoc opts :path path&#41;&#93;&#41;&#41;

&#40;defn form-row &#91;view path&#93;
  &#91;:div.row&gt;div.col-md-12
   &#40;create-widget view path&#41;&#93;&#41;
   
&#40;defn demographics &#91;view&#93;
  &#91;:div
   &#40;form-row demographics-form &#91;:demographics :mrn&#93;&#41;
   &#40;form-row demographics-form &#91;:demographics :name&#93;&#41;&#93;&#41;
</code></pre><p>Here we use a <code>create-widget</code> helper function that looks up the options for a widget in the view and instantiate it with the given path.</p><p>The widgets are then wrapped in the layout tags in the <code>form-row</code> and inserted in the the <code>div</code> that represents the demographics view.</p><p>Once the widgets are defined, it becomes trivial to create different kinds of interfaces using them. This is perfect for our use case where we have a large common data model with many different views into it.</p><h2 id="conclusion">Conclusion</h2><p>I hope this provides a bit of an insight into building large UIs with reusable components using Reagent and re-frame. My team has found that this approach scales very nicely and allows us to quickly build different kinds of UIs against a common data model.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Static Typing vs WebSockets</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">06 09 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                         <p>A <a href='https://hashrocket.com/blog/posts/websocket-shootout'>recent post</a> compared WebSocket server performance in Clojure, C++, Elixir, Go, NodeJS, and Ruby. Chris Allen wrote a <a href='http://bitemyapp.com//posts/2016-09-03-websocket-shootout-haskell.html'>nice follow-up post</a> where he implemented the benchmark using Haskell.</p><p>The initial results looked extremely favorable for Haskell. However, it turned out that the Haskell implementation failed to deliver messages reliably, <a href='https://github.com/hashrocket/websocket-shootout/pull/14'>dropping 98% of the messages it received</a>. What's interesting is that this is exactly the kind of behavior we would expect Haskell type system to prevent from happening. So, how did the fact that messages were being dropped slip by completely undetected?</p><h4 id="update">update</h4><p>As a couple of people helpfully pointed out, the problem was not in fact caused by using unsafe functions. It's simply a type of error that would not be caught by the Haskell type system in general.</p><p>While the problems I outline with the unsafe operations are still present, it's clearly possible for serious problems to slip by even when you're not using them.</p><p>If anything, I think this bolsters the argument for the importance of a mature ecosystem and specification testing.</p><p><hr></p><h3 id="type&#95;system&#95;escape&#95;hatches">Type system escape hatches</h3><p>Haskell provides escape hatches from its type system, and these are often used in practice to achieve reasonable performance. When we look at code in the <a href='https://github.com/jberryman/unagi-chan'>unagi-chan</a> library used in the Haskell implementation, we can see that it uses <code>unsafeInterleaveIO</code> to get the channel contents.</p><p>This is an example of an escape hatch that bypasses the type checker entirely. While Haskell is conceptually a pure language, the internal GHC implementation is imperative in nature. GHC runtime evaluates impure functions that produce side effects making the order of evaluation important. Functions like <code>unsafeInterleaveIO</code> expose the impure runtime to the user, and open the gate for all the types of errors we're familiar with from imperative languages.</p><p>The way GHC implements Haskell inherently precludes safety guarantees by its type system. The purity is effectively an honor system, and cannot be proved by the compiler. In other words, once we use a library that happens to use unsafe operations any guarantees that we get from the type system go out of the window.</p><h3 id="types&#95;are&#95;not&#95;a&#95;specification">Types are not a specification</h3><p>While Haskell type system can help ensure that our code is self-consistent, it clearly can't provide any guarantees regarding the behavior of third party code. Since most real world applications tend to rely on many third party libraries, it means that unless we know what each library is doing we can't ever be certain that our code will work as expected.</p><p>The developer can't possibly be expected to audit every library they use in their project to ensure that it behaves safely. Since most applications rely on large amounts of third party code, availability of mature and reliable libraries is a major factor when it comes to building robust applications.</p><p>While the benchmark in this example is trivial, it's a good example of real world problems many projects have to deal with. Most applications have to interact with the external resources such as queues, databases, and other services. Therefore, we need mature and tested libraries in order to accomplish these tasks effectively.</p><p>I think this is one of the major reasons why hosted languages have been gaining popularity in recent years. When the language relies on a mature ecosystem, such as the JVM, it inherits a lot of battle tested code along with it.</p><p>However, this problem exists in every language. Ultimately, we need to know what the code is doing, and clearly types don't provide us with enough information to really be sure the code is doing what was intended.</p><h3 id="achieving&#95;correctness">Achieving correctness</h3><p>The only way to know that the code is doing what was intended is to have a specification, and test the code against it. This is true pretty much for any language in use today. Tests allow us to validate complex properties that are difficult or even impossible to encode using most type systems.</p><p>Consider the trivial case of validating a user generated password. We need to check its length, combinations of characters it contains, and whether it matches the retyped password. All most type systems can tell us is that we have to pass the function a couple of strings and it will return a boolean.</p><p>To check any of the properties that prove that the function does what was intended, we need to come up with a specification and test the code against it. While the tests do not provide an exhaustive proof of correctness, they provide proof that the code satisfies the intended use cases.</p><p>An argument can be made that types save time in finding bugs when the tests fail. However, my experience is that it's often trivial to track down the actual problem once you're aware of it.</p><p>I think this is where the trade-off between static and dynamic languages lies. The former forces us to describe the types up front, and makes it easier to track down potential errors. Meanwhile, the latter approach allows us to skip this step at the cost of potentially having to do more work to find bugs later.</p><p>To the best of my knowledge nobody knows whether one approach is strictly more efficient than the other.  The overall amount of work appears to be comparable with both approaches. However, the nature of work is different, therefore each approach appeals to a different mindset.</p><p>One interesting approach is to generate types from tests <a href='https://github.com/typedclojure/auto-annotation'>as seen in recent version of Typed Clojure</a>. Using tests to drive type generation has the potential to offer the best of both worlds. We can work with a dynamic language, and offload the work of figuring out the type relationships to a library. As long as we're diligent about writing tests, we get the types for free.</p><p>Another powerful tool for writing robust code is the REPL. When it's integrated with the editor, testing code as you write it becomes very natural. It's quite common for me to test functions as I develop them, then extract the REPL session into a test suite for the feature I'm working on.</p><h3 id="takeaways">Takeaways</h3><p>Even a strong type system, such as one found in Haskell, provides a very weak specification in practice. Just because the code compiles doesn't mean it's actually doing what was intended.</p><p>The type system does not help debugging many real world problems. The code in this benchmark worked as expected under small load, and started exhibiting errors when it was stress tested.</p><p>The ecosystem around the language is an important factor when it comes to productivity. When we use mature and battle tested libraries, we're much less likely to be surprised by their behavior.</p><p>Tests are ultimately the only practical way to provide a specification for the application. Behaviors that are easily tested can be difficult or impossible to encode using a type system.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Instapaper is joining Pinterest</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Instapaper</a> <span class="article__date">23 08 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Today, we’re excited to announce that Instapaper is joining <a href="http://pinterest.com">Pinterest</a>. In the three years since betaworks acquired Instapaper from Marco Arment, we’ve completely rewritten our backend, overhauled our mobile and web clients, improved parsing and search, and introduced tons of great features like highlights, text-to-speech, and speed reading to the product.</p><p>All of these features and developments revolved around the core mission of Instapaper, which is allowing our users to discover, save, and experience interesting web content. In that respect, there is a lot of overlap between Pinterest and Instapaper. Joining Pinterest provides us with the additional resources and experience necessary to achieve that shared mission on a much larger scale.</p><p>Instapaper provides a compelling source for news-based content, and we&rsquo;re excited to take those learnings to Pinterest&rsquo;s discovery products. We’ll also be experimenting with using our parsing technology for certain Rich Pin types.</p><p>For you, the Instapaper end user and customer, nothing changes. The Instapaper team will be moving from betaworks in New York City to Pinterest’s headquarters in San Francisco, and we’ll continue to make Instapaper a great place to save and read articles.</p><p>As we focus on the future of the user experience, we’ll be sunsetting our developer product, Instaparser. Starting today, we will cease signups for Instaparser and halt billing for existing customers. In order to ensure a smooth transition for current users, we will keep Instaparser running until November 1, 2016. </p><p>Lastly, and most importantly, we want to thank all of our readers for your support throughout the years. Whether you supported us back when Marco built and ran Instapaper, from the betaworks acquisition, or just found out about us recently, we truly appreciate your continued support and look forward to bringing you the same great product at Pinterest.</p><p><b></b></p><p>If you have any questions at all, please reach out to us at <a href="mailto:support@help.instapaper.com">support@help.instapaper.com</a> </p><p><b></b></p><p>- Instapaper Team</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Keeping Tests DRY with Class Based Tests In Python</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">19 08 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Tests can be a bummer to write but even a bigger nightmare to maintain. When we noticed we are putting off simple tasks just because we were afraid to update some monster test case, we started looking for more creative ways to simplify the process of writing and maintaining tests. In this article I will describe a class based approach to writing tests.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Marvellously Mysterious JavaScript Maybe Monad</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">06 08 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Monads have a bad reputation in the JavaScript community. Douglas Crockford even said that monads are cursed: Once you reach enlightenment and finally understand monads, you immediately lose the ability to explain them to others. Even amongst experienced functional programmers, monads are treated with respect. But, if you can understand Promises then you can understand monads.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Marvellously Mysterious JavaScript Maybe Monad</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">06 08 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Monads have a bad reputation in the JavaScript community. Douglas Crockford even said that monads are cursed: Once you reach enlightenment and finally understand monads, you immediately lose the ability to explain them to others. Even amongst experienced functional programmers, monads are treated with respect. But, if you can understand Promises then you can understand monads.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Things You Must Know About Django Admin As Your App Gets Bigger</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Haki Benita</a> <span class="article__date">04 08 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The Django admin is a very powerful tool. We use it for day to day operations, browsing data and support. As we grew some of our projects from zero to 100K+ users we started experiencing some of Django's admin pain points - long response times and heavy load on the database.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Web Development with Clojure, Second Edition</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">23 07 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                         <p>I'm glad to announce that the <a href='https://pragprog.com/book/dswdcloj2/web-development-with-clojure-second-edition'>second edition of Web Development with Clojure</a> is finally finished. The book took longer to put together than I anticipated, and I ended up missing the original release target by a few months.</p><p>However, all the delays resulted in a much better book in the end. Having a long beta period allowed me to collect a lot of feedback from the readers and address any concerns that came up. This process helped ensure that the material is clear and easy to follow, while keeping a good pace. I discussed the specifics of what the book covers an earlier post <a href='http://yogthos.net/posts/2016-01-01-ClojureWebDev2.html'>here</a>.</p><p>It's my sincere hope that the book will provide the readers with a smooth path into the wonderful world of Clojure web development.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://http.cat/200" alt="Working around the Java SSL trust store">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Working around the Java SSL trust store</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">15 07 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The Java standard library provides a rich networking API. For example, the <code>java.net.URL</code> class provides a simple way to access resources using a URL location pattern. We can do fun stuff like this using it:</p><pre><code class="clojure">&#40;-&gt; &quot;https://gist.githubusercontent.com/yogthos/f432e5ba0bb9d70dc479/raw/768050c7fae45767b277a2ce834f4d4f00158887/names.clj&quot;
    &#40;java.net.URL.&#41;
    &#40;slurp&#41;
    &#40;load-string&#41;&#41;

&#40;gen-name 11 6&#41;    
</code></pre><p>Unfortunately, the SSL certificates bundled with the default Java runtime aren't comprehensive. For example, the <a href='https://http.cat/'>https://http.cat/</a> site has a valid certificate that's not part of the default Java trust store.</p><p>Let's write a function to read an image from the site using <code>java.net.URL</code>, then save it to a file to see what happens.</p><pre><code class="clojure">&#40;defn read-image &#91;url&#93;
  &#40;let &#91;conn &#40;.openConnection &#40;java.net.URL. url&#41;&#41;&#93;    
    &#40;.getInputStream conn&#41;&#41;&#41;
    
&#40;clojure.java.io/copy
  &#40;read-image &quot;https://http.cat/200&quot;&#41;
  &#40;java.io.FileOutputStream. &quot;200.jpg&quot;&#41;&#41;
</code></pre><p>When we try to access the resource, we end up with a security exception because the default trust store does not contain the right certificate.</p><pre><code>javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException:
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target
...
</code></pre><p>One way we could work around this problem would be to add the certificate to the local store. This is the proper solution that should be used in the vast majority of cases.</p><p>However, there are situations where this approach isn't possible. I've run into many situations working in the enterprise where SSL was misconfigured, and the application would need to connect to an intranet service over such a connection. At the same time I had no control over the deployment environment and wasn't able to manage the keystore there.</p><p>An alternative approach is to replace the default certificate check for a specific connection with a custom one. Let's take a look at how this can be accomplished.</p><p>We'll first have to create a proxy <code>TrustManager</code>, then use it to create a socket factory for our connection as seen in the following code:</p><pre><code class="clojure">&#40;defn set-socket-factory &#91;conn&#93;
  &#40;let &#91;cert-manager &#40;make-array X509TrustManager 1&#41;
        sc           &#40;SSLContext/getInstance &quot;SSL&quot;&#41;&#93;
    &#40;aset cert-manager 0
          &#40;proxy &#91;X509TrustManager&#93;&#91;&#93;
            &#40;getAcceptedIssuers &#91;&#93;&#41;
            &#40;checkClientTrusted &#91;&#95; &#95;&#93;&#41;
            &#40;checkServerTrusted &#91;&#95; &#95;&#93;&#41;&#41;&#41;
    &#40;.init sc nil cert-manager &#40;java.security.SecureRandom.&#41;&#41;
    &#40;.setSSLSocketFactory conn &#40;.getSocketFactory sc&#41;&#41;&#41;&#41;
</code></pre><p>The custom socket factory will use the <code>X509TrustManager</code> proxy that we provide and rely on it for validation. We can simply return <code>nil</code> from each of the validation methods to skip the certificate validation.</p><p>Note that while we're skipping validation entirely in the above example, we'd likely want to supply a custom validator that validates against an actual certificate in practice.</p><p>Next, let's update the <code>read-image</code> function to set the custom socket factory for the connection before trying to read from it:</p><pre><code class="clojure">&#40;defn read-image &#91;url&#93;
  &#40;let &#91;conn &#40;.openConnection &#40;java.net.URL. url&#41;&#41;&#93;
    &#40;set-socket-factory conn&#41;
    &#40;.getInputStream conn&#41;&#41;&#41;

&#40;clojure.java.io/copy
  &#40;read-image &quot;https://http.cat/200&quot;&#41;
  &#40;java.io.FileOutputStream. &quot;200.jpg&quot;&#41;&#41;    
</code></pre><p>We should now have a <code>200.jpg</code> file on our file system with the following content:</p><p><img src="https://http.cat/200" alt="cat" /></p><p>That's all there is to it. We can now enjoy consuming cat HTTP status pictures using the <code>java.net.URL</code> and even make some silly <a href='https://github.com/yogthos/ring-http-cat-status'>Ring middleware</a> using it. :)</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://www.monstruosfelices.es/legiondelespacio/wp-content/uploads/2016/10/cropped-banner-32x32.jpg" alt="Beach Games">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Beach Games</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Legión del Espacio</a> <span class="article__date">01 07 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://www.monstruosfelices.es/legiondelespacio/wp-content/uploads/2016/10/cropped-banner-32x32.jpg" alt="Amor de verano">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Amor de verano</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Legión del Espacio</a> <span class="article__date">30 06 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://www.monstruosfelices.es/legiondelespacio/wp-content/uploads/2016/10/cropped-banner-32x32.jpg" alt="Tinta de veranooooo">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Tinta de veranooooo</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Legión del Espacio</a> <span class="article__date">29 06 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Motivation, Self-control and Good News</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">29 06 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        How to you make yourself do things that you don’t feel like doing? When it’s a cold winter morning and you have to get up in the dark to go to work, how do you make yourself leave the warm bed? If you’ve just started a diet, how do you resist the doughnuts your work colleague decided to share? How do you make yourself strap on the running shoes and go jogging? Doing things you don’t feel like doing is hard work---it takes willpower. But where do you get the motivation?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://www.monstruosfelices.es/legiondelespacio/wp-content/uploads/2016/10/cropped-banner-32x32.jpg" alt="#BudSpencer NO #RIP">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">#BudSpencer NO #RIP</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Legión del Espacio</a> <span class="article__date">28 06 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">One weird trick that will change the way you code forever: JavaScript TDD</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">15 06 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ‘One weird trick’ is a cheesy title, I know. Originally I was using it as a draft placeholder title for a joke. But the more I thought about it, the more it seemed appropriate because it's true. Test Driven Development is one weird trick that will change the way you code forever. It will make you a more badass developer.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">One weird trick that will change the way you code forever: JavaScript TDD</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">15 06 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ‘One weird trick’ is a cheesy title, I know. Originally I was using it as a draft placeholder title for a joke. But the more I thought about it, the more it seemed appropriate because it's true. Test Driven Development is one weird trick that will change the way you code forever. It will make you a more badass developer.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Consider Hoplon</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">06 06 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>A <a href='https://dl.dropboxusercontent.com/u/12379861/micha_on_hoplon_vs_react/index.html'>recent discussion of Hoplon vs React</a> has been making rounds. While I don't necessarily agree that using React is as difficult as Micha makes it sound, I do think that Hoplon provides an interesting alternative to React that has a number of benefits.</p><p>The main selling point for Hoplon is that it's simple. Hoplon doesn't use a virtual DOM, and thus it doesn't have a component lifecycle. One major benefit of this approach is in making it natural to use with existing Js libraries that expect to work with the browser DOM.</p><p>An example of this would be something like using a <a href='https://github.com/cljsjs/packages/tree/master/jquery-daterange-picker'>jQuery date picker widget</a>. With Reagent, we'd have to use the lifecycle hooks, and make sure that the component is mounted in the browser DOM before the library is called. Conversely, we may need to consider the case of the component updating separately. While, it's not difficult to reason about in most cases, it does introduce some mental overhead. Using the same date picker in Hoplon can be seen <a href='https://github.com/hoplon/jquery.daterangepicker/blob/master/src/hoplon/jquery/daterangepicker.cljs.hl'>here</a>.</p><p>However, while I found the idea of Hoplon interesting, I've never gave it a serious look due to the fact that it looked to be a monolithic stack. When you read Hoplon documentation, it's easy to get the impression that it has to be used with Boot, you have to use special <code>.hl</code> files to define ClojureScript, and you're expected to work with its server implementation.</p><p>This all can be appealing if you're looking for a full-stack solution where decisions have been made for you, but it's a bit of a deterrent for somebody who already has a preferred workflow and uses other tools such as Figwheel and Leiningen.</p><p>After having a discussion with Micha <a href='https://www.reddit.com/r/Clojure/comments/4mi64q/hoplon_vs_react/'>on Reddit</a>, I realized that this wasn't the case and decided to give Hoplon another shot.</p><h3 id="the&#95;setup">The Setup</h3><p>I used the <a href='https://github.com/reagent-project/reagent-template'>reagent-template</a> that I maintain as the base for he project by running the following command in the terminal:</p><pre><code>lein new reagent hoplon-app
</code></pre><p>Next, I updated the dependencies in <code>project.clj</code> to remove the references to Reagent, and add the Hoplon dependency instead:</p><pre><code class="clojure">  :dependencies &#91;&#91;org.clojure/clojure &quot;1.8.0&quot;&#93;
                 &#91;ring-server &quot;0.4.0&quot;&#93;
                 &#91;hoplon &quot;6.0.0-alpha15&quot;&#93;
                 &#91;ring &quot;1.4.0&quot;&#93;
                 &#91;ring/ring-defaults &quot;0.2.0&quot;&#93;
                 &#91;compojure &quot;1.5.0&quot;&#93;
                 &#91;hiccup &quot;1.0.5&quot;&#93;
                 &#91;yogthos/config &quot;0.8&quot;&#93;
                 &#91;org.clojure/clojurescript &quot;1.9.36&quot;
                  :scope &quot;provided&quot;&#93;
                 &#91;secretary &quot;1.2.3&quot;&#93;&#93;
</code></pre><p>That's all the changes I had to do in order to switch to using Hoplon in the project.</p><p>The next step was to open up the ClojureScript source in the <code>src/cljs/hoplon&#95;app/core.cljs</code> file and replace the references to Reagent with Hoplon:</p><pre><code class="clojure">&#40;ns hoplon-app.core
  &#40;:require
    &#91;hoplon.core
     :as h
     :include-macros true&#93;
    &#91;javelin.core
     :refer &#91;cell&#93;
     :refer-macros &#91;cell= dosync&#93;&#93;&#41;&#41;

&#40;h/defelem home &#91;&#93;
  &#40;h/div
    :id &quot;app&quot;
    &#40;h/h3 &quot;Welcome to Hoplon&quot;&#41;&#41;&#41;

&#40;defn mount-root &#91;&#93;
  &#40;js/jQuery #&#40;.replaceWith &#40;js/jQuery &quot;#app&quot;&#41; &#40;home&#41;&#41;&#41;&#41;

&#40;defn init! &#91;&#93;
  &#40;mount-root&#41;&#41;    
</code></pre><p>At this point I could start Figwheel and see the page load in the browser by running:</p><pre><code>lein figwheel
</code></pre><p>As you can see the main difference so far is that we mount the Hoplon DOM using plain jQuery call, and the elements are defined using Hoplon helper macros.</p><p>Let's see how we can add a bit of state to our Hoplon app. Hoplon state management is handled by the <a href='https://github.com/hoplon/javelin'>Javelin</a> library. It uses a similar concept to the Reagent atom where we can define cells, and then whenever the state of the cells changes any elements that are looking at its value will be notified.</p><p>We'll create a simple to-do list to illustrate how this works. First, we need to create a cell to hold the data. We'll add the following code at the top of the namespace to do that:</p><pre><code class="clojure">&#40;def todo-items &#40;cell &#91;&quot;foo&quot;&#93;&#41;&#41;
</code></pre><p>The above code will define a Javelin cell that contains a vector with the string <code>&quot;foo&quot;</code> in it. We can now render the value of the cell as follows the the <code>home</code> element:</p><pre><code class="clojure">&#40;h/defelem home &#91;&#93;
  &#40;h/div
    :id &quot;app&quot;
    &#40;h/h3 &quot;Welcome to Hoplon&quot;&#41;
    &#40;h/p &#40;cell= todo-items&#41;&#41;&#41;&#41;
</code></pre><p>The <code>cell=</code> call is reactive and whenever the state of the cell changes the paragraph will be repainted to with its current value. We can now add some code to add new items to the to-do list:</p><pre><code class="clojure">&#40;h/defelem add-todo &#91;&#93;
  &#40;let &#91;new-item &#40;cell &quot;&quot;&#41;&#93;
    &#40;h/div
      &#40;h/input :type &quot;text&quot;
               :value new-item
               :change #&#40;reset! new-item @%&#41;&#41;
      &#40;h/button :click #&#40;dosync
                          &#40;swap! todo-items conj @new-item&#41;
                          &#40;reset! new-item &quot;&quot;&#41;&#41;
                &#40;h/text &quot;Add #&#126;{&#40;inc &#40;count todo-items&#41;&#41;}&quot;&#41;&#41;&#41;&#41;&#41;
</code></pre><p>The above code should be fairly familiar to anybody who's used Reagent. We define a local state in a <code>let</code> binding and create a <code>div</code> that contains an <code>input</code> and a <code>button</code>. The <code>input</code> displays the value of the <code>new-item</code> cell and updates it in its <code>:change</code> event. Meanwhile, the button will swap the <code>todo-items</code> cell and add the value of the new item, then reset it to an empty string.</p><p>Notice that the button text displays the current item count. This is accomplished by Hoplon <code>#&#126;</code> helper that allows us to easily display cell values within strings.</p><p>We should now be able to update our <code>home</code> element as follows to have the <code>add-todo</code> component show up on the page:</p><pre><code class="clojure">&#40;h/defelem home &#91;&#93;
  &#40;h/div
    :id &quot;app&quot;
    &#40;h/h3 &quot;Welcome to Hoplon&quot;&#41;
    &#40;h/p &#40;cell= todo-items&#41;&#41;
    &#40;add-todo&#41;&#41;&#41;
</code></pre><p>When we add to-do items, they should be showing up in the list. So far everything looks nearly identical to working with Reagent.</p><p>Now, let's update the items to be rendered in the list a bit nicer. We'll write the following element to render the list:</p><pre><code class="clojure">&#40;h/defelem todo-list &#91;{:keys &#91;title&#93;}&#93;
  &#40;h/div
      &#40;h/h4 &#40;or title &quot;TODO&quot;&#41;&#41;
      &#40;h/ul
        &#40;h/for-tpl &#91;todo todo-items&#93;
          &#40;h/li todo&#41;&#41;&#41;&#41;&#41;
</code></pre><p>The element uses the Hoplon <code>for-tpl</code> macro to run through the elements in the list. The macro is used to map dynamically sized collections to DOM nodes. With the element in place, we can update our <code>home</code> element to display a nice HTML list:</p><pre><code class="clojure">&#40;h/defelem home &#91;&#93;
  &#40;h/div
    :id &quot;app&quot;
    &#40;h/h3 &quot;Welcome to Hoplon&quot;&#41;
    &#40;todo-list {:title &quot;TODO List&quot;}&#41;
    &#40;add-todo&#41;&#41;&#41;
</code></pre><p>We should now see a list of items displayed that will get updated as we add items using the <code>add-todo</code> element. That's all there's to it. While it's a trivial app, I hope it gives you a taste of what working with Hoplon is like. The full source for the project can be seen <a href='https://github.com/yogthos/hoplon-app'>here</a>.</p><h3 id="conclusion">Conclusion</h3><p>I was very pleasantly surprised by how easy it was to use Hoplon in a project setup with Leiningen and Figwheel. The semantics that Hoplon provides are very similar to Reagent, and are arguably simpler since there's no need to worry about the component lifecycle.</p><p>The one aspect of Reagent that I prefer is that the UI is defined declaratively using the Hiccup syntax. This makes it possible to manipulate UI elements as plain data. However, I don't think that using functions to define the UI is a deal breaker.</p><p>Overall, I think that Hoplon is often overlooked when ClojureScript UI libraries are considered, and this is very unfortunate. It's a solid library that provides clean and simple semantics to the user.</p><p>If, like me, you've been avoiding Hoplon because you were under the impression that you have to use it in a specific way, then I strongly urge you to give it another look.</p><h4 id="update">Update</h4><p>Luminus now provides a Hoplon profile using the <code>+hoplon</code> flag.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to fight like a man</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">01 06 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A friend of mine asked me for some advice before he got married. This was my response.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Introducing clojure.spec</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">23 05 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>I&#8217;m happy to introduce today <strong>clojure.spec</strong>, a new core library and support for data and function specifications in Clojure.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_better_communication"><a class="anchor" href="#_better_communication"></a>Better Communication</h3>
<div class="paragraph">
<p>Clojure is a dynamic language, and thus far we have relied on documentation or external libraries to explain the use and behavior of functions and libraries. But documentation is difficult to produce, is frequently not maintained, cannot be automatically checked and varies greatly in quality. Specs are expressive and precise. Including <strong>spec</strong> in Clojure creates a lingua franca with which we can state how our programs work and how to use them.</p>
</div>
</div>
<div class="sect2">
<h3 id="_more_leverage_and_power"><a class="anchor" href="#_more_leverage_and_power"></a>More Leverage and Power</h3>
<div class="paragraph">
<p>A key advantage of specifications over documentation is the leverage they provide. In particular, specs can be utilized by programs in ways that docs cannot. Defining specs takes effort, and <strong>spec</strong> aims to maximize the return you get from making that effort. <strong>spec</strong> gives you tools for leveraging specs in documentation, validation, error reporting, destructuring, instrumentation, test-data generation and generative testing.</p>
</div>
</div>
<div class="sect2">
<h3 id="_improved_developer_experience"><a class="anchor" href="#_improved_developer_experience"></a>Improved Developer Experience</h3>
<div class="paragraph">
<p>Error messages from macros are a perennial challenge for new (and experienced) users of Clojure. Specs can be used to conform data in macros instead of using a custom parser. And Clojure&#8217;s macro expansion will automatically use specs, when present, to explain errors to users. This should result in a greatly improved experience for users when errors occur.</p>
</div>
</div>
<div class="sect2">
<h3 id="_more_robust_software"><a class="anchor" href="#_more_robust_software"></a>More Robust Software</h3>
<div class="paragraph">
<p>Clojure has always been about simplifying the development of robust software. In all languages, dynamic or not, tests are essential to quality - too many critical properties are not captured by common type systems. <strong>spec</strong> has been designed from the ground up to directly support generative testing via <a href="https://github.com/clojure/test.check">test.check</a>. When you use <strong>spec</strong> you get generative tests for free.</p>
</div>
<div class="paragraph">
<p>Taken together, I think the features of <strong>spec</strong> demonstrate the ongoing advantages of a powerful dynamic language like Clojure for building robust software - superior expressivity, instrumentation-enhanced REPL-driven development, sophisticated testing and more flexible systems. I encourage you to read the <strong>spec</strong> <a href="https://clojure.org/about/spec">rationale and overview</a>. Look for spec&#8217;s inclusion in the next alpha release of Clojure, within a day or so.</p>
</div>
<div class="paragraph">
<p>I hope you find <strong>spec</strong> useful and powerful.</p>
</div>
<div class="paragraph">
<p>Rich</p>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Writing an expandable widget with Reagent</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">20 05 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I recently needed to create an expandable widget and I wanted to be able to close it by clicking elsewhere on the screen. An example would be an input field and an associated component to select the input value such as a date picker.</p><p>We'll define an example component to look as follows:</p><pre><code class="clojure">&#40;defn expandable-component &#91;&#93;
  &#91;:div
   &#91;:input
    {:type :text}&#93;
   &#91;:table&gt;tbody      
    &#40;for &#91;row &#40;range 5&#41;&#93;
      &#91;:tr
       &#40;for &#91;n &#40;range 5&#41;&#93;
         &#91;:td&gt;button.btn
          {:on-click
           #&#40;do
              &#40;reset! value n&#41;
              &#40;reset! expanded? false&#41;&#41;} n&#93;&#41;&#93;&#41;&#93;&#93;&#41;
</code></pre><p>Next, we'll use the <code>with-let</code> statement to define some state for the component.</p><pre><code class="clojure">&#40;defn expandable-component1 &#91;&#93;
  &#40;r/with-let
    &#91;expanded? &#40;r/atom false&#41;
     value     &#40;r/atom nil&#41;&#93;
    &#91;:div
     &#91;:input
      {:type :text
       :value @value
       :on-click #&#40;swap! expanded? not&#41;}&#93;
     &#91;:table&gt;tbody
      {:style &#40;if @expanded?
                {:position :absolute}
                {:display &quot;none&quot;}&#41;}
      &#40;for &#91;row &#40;range 5&#41;&#93;
        &#91;:tr
         &#40;for &#91;n &#40;range 5&#41;&#93;
           &#91;:td&gt;button.btn.btn-secondary
            {:on-click
             #&#40;do
                &#40;reset! value n&#41;
                &#40;reset! expanded? false&#41;&#41;} n&#93;&#41;&#93;&#41;&#93;&#93;&#41;&#41;
</code></pre><p>The table is now hidden by default, and it's displayed when the user clicks the input. The table contains cells with numbers. When the user clicks a number, then the table is hidden and the input is reset to the value selected.</p><p>This works fine. However, the only way we can hide the table is by either picking a number or clicking on the input itself. It's not terrible, but it would be nicer if we could simply click off the table to have it go away.</p><p>The problem is that there is no local event the widget can use to detect that the user clicked elsewhere. So, what can we do here?</p><p>The solution I ended up using was to use a combination of events to detect the state of the widget. Let's see how this works below.</p><p>First, I added the <code>:on-blur</code> event to the input. When the input loses focus, the table is hidden. Now if I click elsewhere on the screen the table will disappear as intended.</p><p>Unfortunately, this breaks the interaction with the table itself. Since now the focus goes away and I'm no longer able to select the number I want.</p><p>In order to get around that problem we can use the <code>:on-mouse-enter</code> and <code>:on-mouse-leave</code> events on the table. This way we can check if the mouse is in the table before changing the visibility.</p><pre><code class="clojure">&#40;defn expandable-component &#91;&#93;
  &#40;r/with-let
    &#91;expanded? &#40;r/atom false&#41;
     value     &#40;r/atom nil&#41;
     mounse-on-table? &#40;r/atom false&#41;&#93;
    &#91;:div
     &#91;:input
      {:type :text
       :value @value
       :on-click #&#40;swap! expanded? not&#41;
       :on-blur #&#40;when-not @mounse-on-table? &#40;reset! expanded? false&#41;&#41;}&#93;
     &#91;:table&gt;tbody
      {:style &#40;if @expanded? {:position :absolute} {:display &quot;none&quot;}&#41;
       :on-mouse-enter #&#40;reset! mounse-on-table? true&#41;
       :on-mouse-leave #&#40;reset! mounse-on-table? false&#41;}
      &#40;for &#91;row &#40;range 5&#41;&#93;
        &#91;:tr
         &#40;for &#91;n &#40;range 5&#41;&#93;
           &#91;:td&gt;button.btn.btn-secondary
            {:on-click
             #&#40;do
                &#40;reset! value n&#41;
                &#40;reset! expanded? false&#41;&#41;} n&#93;&#41;&#93;&#41;&#93;&#93;&#41;&#41;
</code></pre><p>The new approach works as intended. The table will now close whenever the user clicks outside it. You can see this in action <a href='http://cljsfiddle.com/#gist=639bcbe8d328da071713729a714b7f65'>here</a>.</p><p>Hopefully this trick will save you some time creating these types of components in Reagent.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">TDD Should be Fun</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">07 05 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Sometimes TDD can seem like a drag. Are you writing mocks that are several times more complicated than the code you will test? Does your test suite take minutes (or hours) to run? Does refactoring your code fill you with dread because of all the tests to rewrite? If any of this sounds familiar then it may be time to try a new strategy.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">TDD Should be Fun</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">07 05 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Sometimes TDD can seem like a drag. Are you writing mocks that are several times more complicated than the code you will test? Does your test suite take minutes (or hours) to run? Does refactoring your code fill you with dread because of all the tests to rewrite? If any of this sounds familiar then it may be time to try a new strategy.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">New and Improved Search</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Instapaper</a> <span class="article__date">05 05 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>For a while now, some of the most consistent feature requests we’ve gotten from users have involved improvements to Instapaper’s full-text search engine. For months now, the existing search infrastructure had been stretched to its current limits. In order to continue scaling and implement a lot of the features you’ve been requesting, we needed to completely rebuild our search infrastructure.</p><p>Today, we’re very excited to launch the new search infrastructure, which is the first of several steps in what we intend to be a complete overhaul of Instapaper’s search feature. For <a href="https://www.instapaper.com/premium">Instapaper Premium</a> customers, the most noticeable difference will be query speed. We’ve improved the speed of search queries by 6x on average, and far better on certain cases. Additionally, we’ve implemented a handful of new features in the search engine.</p><ul><li><b>Sorting Options</b>: The previous search engine only returned results sorted by most recent. The new search engine defaults to a “Relevance” sort, with the options to sort by “Newest” and “Oldest” as well.<br/></li><li><b>Title Searches</b>: The new full-text search automatically searches article titles, along with the complete text of the article.</li><li><b>Exact Matches</b>: By putting a search query around quotes, you can search for an exact phrase.</li><li><b>Site and Author Filtering</b>: We’ve implemented an “Advanced Search” option that allows you to filter by domain name (e.g., nytimes.com) and author.</li><li><b>Paged Results</b>: Previously, searches were limited to only the 50 most-recent matching results. With the new search, you can page through all of the search results.</li><li><b>Multi-Language Support</b>: Instapaper has users from all over the world, however, the previous search only supported queries with English characters. The new search engine supports queries in all languages.<br/></li></ul><p>Rebuilding the backend for Instapaper’s full-text search is the first (and most complicated) step in our overhaul for search. Some of the features listed above like paged results, sorting options, and advanced search options are only available on instapaper.com at launch. However, we will also be reimplementing search on iOS and Android, which will bring the full functionality to those platforms.</p><p>If you have any feedback on the new search or have any particular features you’d like us to keep in mind as we continue our revamp of search, we’d love to hear from you <a href="https://twitter.com/InstapaperHelp">@InstapaperHelp</a> on Twitter or via email at <a href="mailto:support@help.instapaper.com">support@help.instapaper.com</a>. Thanks, as always, for using Instapaper!</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Luminus Workflow</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">28 04 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I recently presented at the <a href='http://2016.phillyemergingtech.com/'>Philly ETE conference</a>, and it was a really great experience. The conference was well organized, there were lots of great talks, and I got to meet a bunch of interesting people.</p><p>My <a href='http://chariotsolutions.com/screencast/philly-ete-2016-2-dmitri-sotnikov-transforming-enterprise-development-clojure/'>talk</a> focused on the workflow using Luminus and Reagent. During the talk I built a simple app from scratch. The app illustrates how to work with a relational database, create a documented service API, and build a UI for it using Reagent. The live demo portion stats around the 11 minute mark.</p><p>If you're interested in my workflow using Luminus and Cursive, then I definitely recommend watching the talk.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A Gentle Introduction to Javascript Test Driven Development: Part 3</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">18 04 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        This is part three of a three-part series outlining my personal approach to JavaScript TDD. Testing code that creates HTML and manipulates the DOM can be tricky—especially when testing without a browser. In this article I outline one approach to this, and finish off the sample application we have been building through the series.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A Gentle Introduction to Javascript Test Driven Development: Part 3</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">18 04 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        This is part three of a three-part series outlining my personal approach to JavaScript TDD. Testing code that creates HTML and manipulates the DOM can be tricky—especially when testing without a browser. In this article I outline one approach to this, and finish off the sample application we have been building through the series.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A Gentle Introduction to Javascript Test Driven Development: Part 2</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">17 04 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Working with JavaScript network calls can be tricky when practicing Test Driven Development. This article gives an example of how to use stubs and Promises to make testing network calls easier. This is part two of a three-part series outlining my personal approach to JavaScript TDD.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A Gentle Introduction to Javascript Test Driven Development: Part 2</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">17 04 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Working with JavaScript network calls can be tricky when practicing Test Driven Development. This article gives an example of how to use stubs and Promises to make testing network calls easier. This is part two of a three-part series outlining my personal approach to JavaScript TDD.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The State of Clojure Web Development</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">17 04 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The Kickstarter for the <a href='https://www.kickstarter.com/projects/1346708779/arachne-rapid-web-development-for-clojure'>Arachne</a> framework was just announced. I think this is very exciting, and I sincerely hope that it will be successful. There is plenty of room for frameworks in the Clojure web application domain. However, I also think that the pitch in the video severely misrepresents the current state of Clojure web development.</p><h3 id="is&#95;it&#95;hard&#95;to&#95;make&#95;an&#95;app?">Is it hard to make an app?</h3><p>Luke says that the motivation for the project is that there is no simple way to put a Clojure web app together. You want to make a website quickly, but unfortunately Clojure is not well suited for this task because the lead time is just too long.</p><p>Luke goes as far as to say that starting a new Clojure web application with all the parts together, that's actually deployable is a one to three months process.</p><p>Simplifying this process is precisely the <a href='https://www.youtube.com/watch?v=JKoaG4kSyxs&t=14m53s'>motivation</a> behind <a href='http://www.luminusweb.net/'>Luminus</a>. In fact, Luminus, and other frameworks such as <a href='https://hoplon.io/'>Hoplon</a>, have been filling this exact niche for years now. While I’m not as familiar with Hoplon, I will focus on contrasting the stated goals behind Arachne and the goals for Luminus.</p><p>First thing I’d like to address is the claim that it takes a long time to create a web application following best practices. Creating a new Luminus app is as easy as running <code>lein new luminus myapp</code> in the terminal. Perhaps what Luke meant was that creating an application using his preferred stack and defaults takes a long time.</p><p>Luminus is based on over a decade of experience working in the enterprise environment and building real world applications. It's built on top of mature libraries that are known to work well together. These are wrapped up in a template that follows the best practices, and makes it easy to create a working application that's ready for deployment out of the box.</p><p>Some of the things Luke lists are:</p><ul><li>Overall structure</li><li>Resource lifecycle management</li><li>Routing</li><li>Content negotiation</li><li>HTML rendering</li><li>Authentication & authorization</li><li>Validation</li><li>Logging</li><li>Testing</li></ul><p>All of these are supported out of the box in Luminus.</p><h3 id="what&#95;about&#95;beginners?">What about beginners?</h3><p>Another problem Luke identifies is that there needs to be a tool for beginners, or people new to the Clojure language. Once again, this is precisely the target demographic for Luminus.</p><p>I've literally spent years working with existing libraries, <a href='https://github.com/yogthos/Selmer'>creating my own</a> when necessary, <a href='http://www.luminusweb.net/docs'>writing documentation</a>, and putting things together for that express purpose. I've even written <a href='https://pragprog.com/book/dswdcloj2/web-development-with-clojure-second-edition'>a couple of books</a> on this topic now.</p><p>Arachne aims to experiment with creating an easy to start with solution that will scale. Luminus is designed to scale, and it’s currently being used in production in the enterprise. It's not experimental in any way, it's an actual proven solution that exists today.</p><p>Luminus allows you to start fast and deploy out of the box, but it is also designed to be built on as you go. Like Arachne aims to do, Luminus already embraces modular design. It's built on top of battle tested libraries such as Ring and Compojure, but it doesn't lock you into doing things a particular way.</p><p>Luminus makes it trivial to swap things like the underlying HTTP server, templating engine, the database you're using, and so on. The core template provides a minimal skeleton app. This template can then be extended using hints to provide additional functionality.</p><h3 id="but&#95;is&#95;it&#95;modular?">But is it modular?</h3><p>Arachne has an ambitious goal to provide a way to specify the application using a data driven approach. The idea being that this makes it easier to swap different components in the existing project.</p><p>I’ve considered similar approaches for Luminus, but ultimately decided against that. First, I think that Ring middleware already provides an extremely powerful mechanism for injecting functionality in the request handling pipeline. This is where most of the changes will happen in your project. You might decide to swap out or change things like session handling middleware as your project evolves.</p><p>However, my experience is that in most cases it’s not possible to simply swap a component such as the database for a different one without having to change some code in the application.</p><p>For example, if I switch the templating engine, then I have to update my HTML templates. When I switch a database from SQL to Datomic, I have to rewrite the queries and the business logic. That’s where the most of effort will end up being spent. </p><p>That said, the code that deals with any particular component in Luminus is minimal by design. So, the vast majority of the code you’d have to change would be the code that you’ve written yourself.</p><p>The one place I found it to be possible to provide swappable components is the underlying HTTP server. Luminus provides wrapper libraries for all the popular servers, and it’s possible to swap them out by simply changing the dependency in the project.</p><p>I think it would be possible to build things like authentication and authorization modules that are swappable. However, a generic solution is necessarily more complex than a focused one. A component that can be used in many different situations will always be more complex than one that solves a specific problem.</p><p>For this reason, I firmly believe that such design decisions should be left up to the user. The libraries should provide focused functionality, while the user decides how to put them together in a way that makes sense for their project.</p><h3 id="conclusion">Conclusion</h3><p>At the end of the day, Luminus isn’t based just on my experience, but also that of the contributors and the users over the years. Arachne will be informed by Luke’s experience and that necessarily means that it will provide a new and interesting way to put together Clojure web applications.</p><p>Overall, I think it will be great to see a new web framework for Clojure. There is plenty of room for alternatives to Luminus, and Arachne could explore many areas that aren't the focus for Luminus at the moment. Therefore, I wholeheartedly urge you to support the Kickstarter so that we can have more choices for Clojure web development.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/sponsor_weekly%402x.png" alt="Instapaper Weekly Sponsorship">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Instapaper Weekly Sponsorship</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Instapaper</a> <span class="article__date">11 04 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><i><strong>Update 8/29/2016</strong>: Since <a href="http://blog.instapaper.com/post/149374303661" target="_blank">Instapaper is now a Pinterest product</a> we no longer offer sponsorships for Instapaper Weekly. Thanks to all of our previous sponsors!</i></p>
<p>We’re excited to announce that we’ll be opening up sponsorship slots for our Instapaper Weekly email.</p><p><b>About Instapaper Weekly</b></p><p>Instapaper Weekly is an algorithmically-generated newsletter delivered every Sunday. The email contains the most popular highlight created by all Instapaper users for the week, and a list of the most popular articles saved to Instapaper for each day of the past week.</p><p>The Weekly is currently delivered to about 1.5 million Instapaper users. The open rate for the weekly email is 17% and the click-through rate is about 2.7%.</p><p><b>Why Sponsorships?</b></p><p>By design, the Instapaper Weekly is a reflection of what our readers consider to be the most important and noteworthy topics for a given week. Sponsoring the Weekly places your content amongst the best content Instapaper has to offer and provides access to a large, engaged audience of tech-oriented and well-read professionals.</p><p><b>Sponsoring</b><br/></p><p>As the Weekly compiles content our users found most compelling, we will be holding our sponsorship choices to the same standards of high quality. Your sponsored content should fit within our existing format for Instapaper Weekly and consist of a link, title, description, and thumbnail image. Ideally, the link would be something that our mobile-centric users can save to Instapaper for later reading.</p><p>We will run the sponsorship between the “Top Highlight” and “Most Popular” sections of the weekly email:</p><p><figure class="tmblr-full" data-orig-height="1354" data-orig-width="1200" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/sponsor_weekly%402x.png"><img src="https://64.media.tumblr.com/802af88008a4a03321d838deca4f1c51/tumblr_inline_p7mho7gMnq1rof3ra_540.png" alt="image" data-orig-height="1354" data-orig-width="1200" data-orig-src="https://s3-us-west-2.amazonaws.com/staticinstapaper/blog/sponsor_weekly%402x.png"/></figure></p><p>If you’d like to sponsor Instapaper Weekly, please send us an email to <a href="mailto:sponsors@instapaper.com?subject=Instapaper+Weekly+Sponsorship">sponsors@instapaper.com</a>.<br/></p><p>Thanks,<br/>Instapaper Team</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A Gentle Introduction to Javascript Test Driven Development: Part 1</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">11 04 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Getting started with test driven development (TDD) can be daunting. It sounds tedious, boring and hard. There’s also a confusing array of frameworks and libraries out there. Some work on the server; some work in the browser; some do both... it can be hard to know where to start. This is part one of a three-part series outlining my personal approach to JavaScript TDD.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A Gentle Introduction to Javascript Test Driven Development: Part 1</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">11 04 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Getting started with test driven development (TDD) can be daunting. It sounds tedious, boring and hard. There’s also a confusing array of frameworks and libraries out there. Some work on the server; some work in the browser; some do both... it can be hard to know where to start. This is part one of a three-part series outlining my personal approach to JavaScript TDD.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Star Wars: The Force Awakens—Philosophy, passion and Jesus</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">27 02 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I really like Star Wars, and I enjoyed <em>The Force Awakens</em>. I think that when you dig below the surface, the ways in which it agrees and disagrees with Christianity are different from what you might expect. In the end, the Star Wars movies are just that: a bunch of movies. But, as I've said before, if we watch in the right way, movies can point us to something deeper and more meaningful—a new <em>and better</em> hope.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Building a simple message queue with Redis</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">24 02 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        There are lots of options when it comes to choosing a message queue for your application. The guys at queues.io have a very comprehensive summary of the options.
There are some times, however, where you don&rsquo;t need something as heavyweight as RabbitMQ or Amazon SQS. A popular alternative is to build a queue using Redis. A simple implementation will use LPUSH to push messages onto the queue, and BRPOP pull them off, respectively.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Building a simple message queue with Redis</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">24 02 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        There are lots of options when it comes to choosing a message queue for your application. The guys at queues.io have a very comprehensive summary of the options.
There are some times, however, where you don&rsquo;t need something as heavyweight as RabbitMQ or Amazon SQS. A popular alternative is to build a queue using Redis. A simple implementation will use LPUSH to push messages onto the queue, and BRPOP pull them off, respectively.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Luminus embraces HugSQL</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">22 02 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>There are lots of Clojure libraries available for working with SQL. The core libraries that provide the low level functionality are <a href='https://github.com/clojure/java.jdbc'>clojure.java.jdbc</a> and the more recent <a href='https://github.com/funcool/clojure.jdbc'>clojure.jdbc</a>. Some of the more popular libraries built on top of them are <a href='https://github.com/korma/Korma'>Korma</a>, <a href='https://github.com/jkk/honeysql'>Honey SQL</a>, and <a href='https://github.com/krisajenkins/yesql'>Yesql</a>.   </p><p>I've been a huge fan of the approach that Yesql takes since it was released. Every time I've worked with a DSL for SQL, I've found that I'd always run into cases where I knew exactly what to do if I was writing plain SQL, but I couldn't find a clean way to express using the abstraction on top of it. Since Yesql approach lets you keeps your SQL as SQL the problem largely goes away.</p><p>Luminus has been using Yesql since it came out and I think it made the framework much more approachable. Unfortunately, Yesql doesn't appear to be actively developed, and I found myself falling back to using clojure.java.jdbc directly for things like <a href='https://github.com/krisajenkins/yesql/issues/51'>batch inserts</a>.</p><p>Another problem from Luminus perspective is that Yesql API defines query functions directly. Luminus uses <a href='https://github.com/luminus-framework/conman'>conman</a> for connection management, and it creates its own connection-aware functions. This required an ugly hack of using a shadow namespace for interning the functions generated by Yesql.</p><p>I recently learned about the <a href='http://www.hugsql.org/'>HugSQL</a> library that is inspired by Yesql, and addresses all the issues I've run into using it. The official site does a good job enumerating the <a href='http://www.hugsql.org/#faq-yesql'>major differences</a> from Yesql. Some of the highlights for HugSQL are:</p><ul><li><a href='http://www.hugsql.org/#using-snippets'>snippets</a> that facilitate composable queries</li><li>support for <a href='http://www.hugsql.org/#using-insert'>multi-row inserts</a></li><li>supports <a href='http://www.hugsql.org/#adapter'>multiple backends</a> such as clojure.java.jdbc and clojure.jdbc</li><li>great documentation</li></ul><p>The latest version of HugSQL provides an API that returns a map of query functions keyed on their names as well as the ability to define the functions directly.</p><p>I think this is a very useful feature even if you're not using conman or Luminus. Having a map of the query functions allows the user to decide what they want to do with them explicitly. For example, you're able to do things like the following:</p><pre><code class="clojure">&#40;def queries &#40;hugsql.core/map-of-db-fns &quot;queries.sql&quot;&#41;

&#40;defn get-user &#91;db opts&#93;
  &#40;&#40;-&gt; queries :get-user :fn&#41; db opts&#41;&#41;
</code></pre><h2 id="yesql&#95;vs&#95;hugsql">Yesql vs HugSQL</h2><p>Let's take a look at the basic usage of HugSQL and differences from Yesql.</p><p>The core syntax in HugSQL is quite similar to Yesql. Both Yesql and HugSQL use comments with a special format to provide the metadata for generating the functions to work with queries.</p><h4 id="yesql">Yesql</h4><pre><code class="sql">-- name: create-user!
-- creates a new user record
INSERT INTO users
&#40;id, pass&#41;
VALUES &#40;:id, :pass&#41;

-- name: get-users
-- retrieve all users
SELECT &#42; FROM users

-- name: get-user
-- retrieve a user given the id.
SELECT &#42; FROM users
WHERE id = :id
</code></pre><p>Yesql uses the <code>-- name: fn-name</code> syntax to specify the function name, the comment below the function name is implicitly used as the doc for the function. The <code>!</code> at the end of the function name is used as a convention to indicate that it mutates the data. The query parameter placeholders are identified using the <code>:</code> prefix.</p><h4 id="hugsql">HugSQL</h4><pre><code class="sql">-- :name create-user! :! :n
-- :doc creates a new user record
INSERT INTO users
&#40;id, pass&#41;
VALUES &#40;:id, :pass&#41;

-- :name get-users :? :&#42;
-- :doc retrieve all users
SELECT &#42; FROM users

-- :name get-user :? :1
-- :doc retrieve a user given the id
SELECT &#42; FROM users
WHERE id = :id
</code></pre><p>The HugSQL version uses the <code>-- :name</code> syntax instead that mirrors the Clojure keyword syntax. The function name is followed by two additional flags. The first flag indicates the SQL command type and the second indicates the result.</p><p>This provides more flexibility for handling the results. For example, the <code>get-users</code> query indicates that it selects multiple records, while the <code>get-user</code> indicates that it selects exactly one record. This helps document the intent of the query and cuts down on boilerplate, as you'd have to write a wrapper otherwise that gets the first result from the query.</p><h4 id="command&#95;flags">command flags</h4><ul><li><code>:query</code> or <code>:?</code> - query with a result-set (default)</li><li><code>:execute</code> or <code>:!</code> - any statement</li><li><code>:returning-execute</code> or <code>:&lt;!</code> - support for <code>INSERT ... RETURNING</code></li><li><code>:insert</code> or <code>:i!</code> - support for insert and jdbc <code>.getGeneratedKeys</code></li></ul><h4 id="result&#95;flags">result flags</h4><ul><li><code>:one</code> or <code>:1</code> - one row as a hash-map</li><li><code>:many</code> or <code>:&#42;</code> - many rows as a vector of hash-maps</li><li><code>:affected</code> or <code>:n</code> - number of rows affected (inserted/updated/deleted)</li><li><code>:raw</code> - passthrough an untouched result (default)</li></ul><p>In HugSQL, all the comments that represent metadata start with a key describing the type of metadata. In the examples above, the doc string is explicitly specified using the <code>-- :doc</code> prefix.</p><p>HugSQL also supports additional syntax within its queries. For example, if we wanted to insert multiple records using a single query, then we could use a vector of records as follows:</p><pre><code class="sql">-- :name add-users! :! :n
-- :doc add multiple users
INSERT INTO users
&#40;id, pass&#41;
VALUES :t&#42;:users
</code></pre><pre><code class="clojure">&#40;add-users! db {:users
                &#91;&#91;&quot;bob&quot; &quot;Bob&quot;&#93;
                 &#91;&quot;alice&quot; &quot;Alice&quot;&#93;&#93;}&#41;
</code></pre><p>The syntax for for in-list queries is also a bit different from Yesql. The SQL query uses the <code>:v&#42;</code> flag to indicate the value list parameter.</p><pre><code class="sql">-- :name find-users :? :&#42;
-- :doc find users with a matching ID
SELECT &#42;
FROM users
WHERE id IN &#40;:v&#42;:ids&#41;
</code></pre><p>The function parameters will now consist of a map with the key <code>:ids</code> that points to a vector of ids that we would like to match on.</p><pre><code class="clojure">&#40;find-users db {:ids &#91;&quot;foo&quot; &quot;bar&quot; &quot;baz&quot;&#93;}&#41;
</code></pre><p>As you can see, the syntactic differences for basic queries are very minor. I've migrated a number of projects to HugSQL already, and found the process to be completely painless.</p><p>I haven't covered the advanced features of HugSQL, but I highly recommend looking over the official documentation to see what's available.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Animating the Unanimatable</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Josh Comeau&#39;s blog</a> <span class="article__date">15 02 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        An in-depth look at the surprisingly complicated problem of animating the transition when two items in a list swap positions.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A Gentle Introduction to Functional JavaScript: Part&amp;nbsp;4</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">11 02 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        In the last article of our four-part introduction to functional programming in JavaScript, we looked at higher-order functions. In this article we discuss how to use these new tools with style.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A Gentle Introduction to Functional JavaScript: Part&amp;nbsp;4</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">11 02 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        In the last article of our four-part introduction to functional programming in JavaScript, we looked at higher-order functions. In this article we discuss how to use these new tools with style.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A Gentle Introduction to Functional JavaScript: Part&amp;nbsp;3</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">06 02 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        In the last article, we saw how functional programming can be used with arrays. In this article we examine higher-order functions—functions for making functions.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A Gentle Introduction to Functional JavaScript: Part&amp;nbsp;3</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">06 02 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        In the last article, we saw how functional programming can be used with arrays. In this article we examine higher-order functions—functions for making functions.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A Gentle Introduction to Functional JavaScript: Part&amp;nbsp;2</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">30 01 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        In the previous article, we saw how functions can be used to make certain code abstractions easier. In this article we apply these techniques to arrays and lists.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A Gentle Introduction to Functional JavaScript: Part&amp;nbsp;2</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">30 01 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        In the previous article, we saw how functions can be used to make certain code abstractions easier. In this article we apply these techniques to arrays and lists.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A Gentle Introduction to Functional JavaScript: Part&amp;nbsp;1</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">29 01 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        What is all the hype about Functional JavaScript? And why is it called <em>functional?</em> It’s not as though anyone sets out to write <em>dys</em>functional Javascript. What is it good for? Why would you bother?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A Gentle Introduction to Functional JavaScript: Part&amp;nbsp;1</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">29 01 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        What is all the hype about Functional JavaScript? And why is it called <em>functional?</em> It’s not as though anyone sets out to write <em>dys</em>functional Javascript. What is it good for? Why would you bother?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">State of Clojure 2015 survey results</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">28 01 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div class="paragraph">
<p>Check out the State of Clojure 2015 survey results here:</p>
</div>
<div class="paragraph">
<p><a href="http://blog.cognitect.com/blog/2016/1/28/state-of-clojure-2015-survey-results" class="bare">http://blog.cognitect.com/blog/2016/1/28/state-of-clojure-2015-survey-results</a></p>
</div>
<div class="paragraph">
<p>Thanks for responding - it&#8217;s great to see the community growing and doing great things!</p>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure 1.8 is now available</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">19 01 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Some of the new features for 1.8 are:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>More string functions in <a href="https://clojure.github.io/clojure/clojure.string-api.html">clojure.string</a> (portable to ClojureScript): index-of, last-index-of, starts-with?, ends-with?, includes?</p>
</li>
<li>
<p>Compiler <a href="xref/../../../../../reference/compilation#directlinking">direct linking</a> - improves performance and startup time</p>
</li>
<li>
<p><a href="xref/../../../../../reference/repl_and_main#_launching_a_socket_server">Socket server</a> and socket server REPL - adds the ability to allow remote Clojure REPL connections</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>For more information, see the <a href="https://github.com/clojure/clojure/blob/master/changes.md">complete list</a> of all changes since Clojure 1.7 for more details.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_contributors"><a class="anchor" href="#_contributors"></a>Contributors</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Thanks to all of those who contributed to Clojure 1.8 (first time contributors in bold):</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Alexander Yakushev</strong></p>
</li>
<li>
<p>Alex Miller</p>
</li>
<li>
<p>Alex Redington</p>
</li>
<li>
<p>Alf Kristian Stoyle</p>
</li>
<li>
<p>Ambrose Bonnaire-Sergeant</p>
</li>
<li>
<p><strong>Andrew Rosa</strong></p>
</li>
<li>
<p>Andy Fingerhut</p>
</li>
<li>
<p><strong>Andy Sheldon</strong></p>
</li>
<li>
<p><strong>Aspasia Beneti</strong></p>
</li>
<li>
<p><strong>Blake West</strong></p>
</li>
<li>
<p>Bozhidar Batsov</p>
</li>
<li>
<p><strong>Daniel Compton</strong></p>
</li>
<li>
<p><strong>Erik Assum</strong></p>
</li>
<li>
<p>Gary Fredericks</p>
</li>
<li>
<p>Ghadi Shayban</p>
</li>
<li>
<p><strong>Gordon Syme</strong></p>
</li>
<li>
<p>Howard Lewis Ship</p>
</li>
<li>
<p><strong>Jean Niklas L&#8217;orange</strong></p>
</li>
<li>
<p><strong>Jeremy Heiler</strong></p>
</li>
<li>
<p><strong>Jonas Enlund</strong></p>
</li>
<li>
<p>Jozef Wagner</p>
</li>
<li>
<p>Karsten Schmidt</p>
</li>
<li>
<p>Kevin Downey</p>
</li>
<li>
<p><strong>Mark Simpson</strong></p>
</li>
<li>
<p>Michael Blume</p>
</li>
<li>
<p><strong>Nahuel Greco</strong></p>
</li>
<li>
<p>Nicola Mometto</p>
</li>
<li>
<p><strong>Nikita Prokopov</strong></p>
</li>
<li>
<p><strong>Nola Stowe</strong></p>
</li>
<li>
<p><strong>Ragnar Dahlén</strong></p>
</li>
<li>
<p><strong>Ralf Schmitt</strong></p>
</li>
<li>
<p>Rich Hickey</p>
</li>
<li>
<p><strong>Russ Olsen</strong></p>
</li>
<li>
<p><strong>Shogo Ohta</strong></p>
</li>
<li>
<p>Steve Miner</p>
</li>
<li>
<p>Stuart Halloway</p>
</li>
<li>
<p>Timothy Baldridge</p>
</li>
<li>
<p><strong>Tsutomu Yano</strong></p>
</li>
<li>
<p><strong>Yanxiang Lou</strong></p>
</li>
</ul>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Contrasting Component and Mount</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">19 01 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                         <p>There was a recent wave of discussions on pros and cons of using Component and Mount approaches to state management. Both libraries aim to provide a clean way to manage stateful resources in the application. However, each one takes a very different approach.</p><p>Component is the currently accepted way to manage state, and it works well when you structure your application around it. However, it does require certain trade-offs in order to make the most of it. Let's take a look at some of the reasons you may wish to choose Mount over Component for your project.</p><h3 id="managing&#95;the&#95;state&#95;with&#95;component">Managing the State with Component</h3><p>Component uses the dependency injection approach to managing stateful resources in the application. A system map is used to track all the components and their relationships. This map is then passed around the application explicitly, and used to provide access to the resources.</p><p>This approach encourages coupling between the code managing the resources and the business logic. A common pattern is to pass the component system around the application. The system is injected from the top level, and then functions pick parts of the system to pass down until they're eventually used by a function that relies on a particular resource.</p><p>One side-effect of this design is that it becomes impossible to test any part of the application without having the resources available. Therefore, if we wish to run tests in the REPL, then we need to instantiate a separate system map using the test resources. This problem makes it important to be able to create multiple instances of the components at runtime.</p><h3 id="component&#95;and&#95;the&#95;repl">Component and the REPL</h3><p>Since Component is based on protocols it doesn't play well with the REPL workflow, as changes to <code>defrecord</code> do not affect the instances that have already been created. The whole app needs to be restarted in order to make sure that the REPL is still in a good state.</p><p>This problem is discussed in detail by Stuart Sierra in his post on the <a href='http://thinkrelevance.com/blog/2013/06/04/clojure-workflow-reloaded'>reloaded workflow</a>. I find that the reloaded workflow used with Component is much closer to TDD than the traditional Lisp style REPL driven workflow.</p><p>However, one of the advantages of working with a language like Clojure is that we shouldn't need to run tests all that often. Since development is primarily done using the REPL, we should have a good idea of what the code is doing while we're working on it.</p><p>RDD provides a very tight feedback loop. I can develop the features interactively, then create the tests based on the REPL session once the code is doing what I need.</p><p>There are only a handful of situations where I find it necessary to run the full test suite. I run tests before I commit code, I run tests on the CI server, but I don't find it necessary to rerun tests any time I write a bit of code during development. I certainly shouldn't have to reload the whole app for changes to take effect.</p><p>I like the guard rail metaphor Rich Hickey used in his <a href='http://www.infoq.com/presentations/Simple-Made-Easy'>Simple Made Easy</a> talk:</p><blockquote><p>"I can make changes 'cause I have tests!  Who does that?!  Who drives their car around banging against the guard rails saying, "Whoa!  I'm glad I've got these guard rails!" </p></blockquote><p>This is a good reminder that the tests are primarily a sanity check. We should have confidence in our code because we understand it and are able to reason about it.</p><p>To facilitate understanding, most code in the application should be pure, and we shouldn't have to rely on any external resources to test such code. I think that it helps to treat core business logic as you would a library. It should be completely agnostic about where the data is coming from and where it's going.</p><p>However, Component encourages a different kind of design where business logic ends up being reliant on the resources. In this situation, it's no longer possible to test the business logic in isolation.</p><p>Finally, any functions that takes the system map as a parameter are invariably tied to it. This is at odds with treating functions as core reusable building blocks.</p><h3 id="the&#95;mount&#95;approach">The Mount Approach</h3><p>Mount takes the approach of encapsulating stateful resources using namespaces. This leads to a natural separation between the code that deals with state from the pure core of the application logic.</p><p>When the core is kept pure, then it can be safely tested in isolation without having to provide any mock resources to it. This also makes the code reusable out of the box.</p><p>Mount makes it trivial to integrate into existing applications. The app doesn't need to be designed up front to take advantage of it, as it does with Component.</p><p>Since Mount doesn't rely on protocols, it doesn't impact the REPL driven workflow. There's no need for an elaborate setup to facilitate reloading the whole application any time a change is made.</p><p>The primary disadvantages of Mount are that it's not possible to create multiple instances of a resource, and that we have to be mindful not to couple namespaces representing resources to the business logic.</p><p>Conceptually, most resources in the application are singletons by their very nature. When we have a database connection or a queue, there is precisely one external resource that we're working with.</p><p>As I illustrated earlier, the primary reason for having multiple instances of a resource is testing. Mount provides a simple solution for running tests with alternate implementations as described in its <a href='https://github.com/tolitius/mount#swapping-alternate-implementations'>documentation</a>. This facilitates practically the same workflow as Component, where an instance of the resource can be swapped out with another for testing. However, the bigger advantage is that we no longer need to have resources available to test majority of the code in the first place.</p><p>Another argument is that you may have different instances of the same type of resource. For example, an application might use multiple queues that all have the same API. In this case, we can use <code>defrecord</code> to define the class representing the API for the queue. We'll then manage the lifecycle of each instance using <code>defstate</code>.</p><p>While we do have to be mindful of our design when using Mount, the same is true for Component as well. For example, nothing stops us from putting the Component system in a var that's referenced directly. The same reasoning we use to avoid doing that should be used when working with Mount as well.</p><p>In general, I see very few downsides to using Mount and I see a lot of practical benefits, some of which I've outlined above.</p><h3 id="conclusion">Conclusion</h3><p>I think that both Component and Mount have their own sets of trade-offs. Component is a framework that requires the application to be structured around it. Conversely, it necessitates a TDD style workflow to work with it effectively.</p><p>On the other hand, Mount is not prescriptive about the workflow or application structure. I think this makes it a more flexible solution that's a great fit for many kinds of applications. The flip side is that we have to be more careful about how we structure the application as Mount is agnostic regarding the architecture.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Welcome to the new clojure.org!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">14 01 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div class="paragraph">
<p>You are reading this on the newly updated Clojure web site! The first thing you will notice is that everything got a fresh coat of paint and the design is a big step forward. Essentially all of the old page content has been moved over to the new site, however some things are in new locations - in virtually all of those cases, you should find redirects taking you to the new location.</p>
</div>
<div class="paragraph">
<p>There are also several new things on the site:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="xref/../../../../news">News</a> - periodically we will post topical news here about new features, releases, or other things of note - these also appear as links on the home page</p>
</li>
<li>
<p><a href="xref/../../../../../community/events">Events</a> - there is now a page for each upcoming Clojure event, also with links on the home page</p>
</li>
<li>
<p><a href="xref/../../../../../guides">Guides</a> - a new section for building out community guides and tutorials</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Most importantly, all of the site content is stored in a <a href="https://github.com/clojure/clojure-site">repository</a> and open for pull requests from contributors with a signed contributor agreement. If you are interested in adding or changing content, please check out the page on <a href="xref/../../../../../community/contributing_site">site contributions</a> and the current <a href="https://github.com/clojure/clojure-site/issues">issues</a> list.</p>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Web Development with Clojure 2nd Edition</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">01 01 2016</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <h3 id="beta&#95;release&#95;update">Beta Release Update</h3><p>Unfortunately, it looks like there's been a bit of editorial delay and we missed the 13th release date. The new date is set for the second of February. Apologies to everybody who's waiting for the release. </p><hr/><p>I'm glad to report that the second edition of Web Development with Clojure is just around the corner. The beta release is planned for January the 13th, and then I'm hoping to have the final release shortly after. The second edition took a bit longer than I anticipated, but I think the wait will be worth it.</p><h3 id="what&#95;to&#95;expect">What to Expect</h3><p>The primary goal of the book is to provide a solid introduction to the world of Clojure web development. Clojure community is growing rapidly and most new users come from languages such as Java, Ruby, and Python.</p><p>My aim is to illustrate how to build typical web applications using Clojure in a style that's friendly to those who come from using a mainstream language. In order to keep the material accessible, I deliberately chose to focus on the core concepts and avoid some of the more advanced topics. Conversely, if you're already familiar with Clojure and would like to get into web development then the book will serve as a great introduction.</p><p>The first edition of my book came out at the time when Clojure web stack was in a great deal of flux. <a href='http://www.webnoir.org/'>Noir</a> micro-framework just got deprecated, Cognitect announced <a href='https://github.com/pedestal/pedestal'>Pedestal</a>, and ClojureScript was in its infancy. It was hard to predict where things would go from there.</p><p>Much has changed in the past year in Clojure web ecosystem, and the second edition of the book reflects that. While the first edition was fairly unopinionated and gave a broad overview of different libraries, the new version primarily focuses on the <a href='http://www.luminusweb.net/'>Luminus</a> stack.</p><p>Majority of the tools and libraries I cover are the ones I've used professionally to build real world applications. This naturally means that there is an inherent bias towards my workflow and the way I like to build applications. On the other hand, if you're new to building Clojure web applications it's helpful to learn using a particular workflow that you can adjust to your needs as you get comfortable.</p><p>Just like the first edition, the book is based around projects that illustrate how to accomplish different tasks in a typical web app. Each chapter introduces a particular concept and gets the reader to work through it by building a project from scratch. By the end of the book the reader should be comfortable writing many typical web applications using Clojure and have the background to explore further on their own.</p><h3 id="topics&#95;covered">Topics Covered</h3><p>The book will consist of the following chapter:</p><ul><li><h4>Getting Your Feet Wet</h4><ul><li>takes the reader through setting up the environment and building a simple application using Luminus</li></ul></li><li><h4>Clojure Web Stack</h4><ul><li>takes a step back and looks at Ring and Compojure in detail</li></ul></li><li><h4>Luminus Architecture</h4><ul><li>provides an overview of the Luminus template and ways to organize your projects</li></ul></li><li><h4>Add ClojureScript</h4><ul><li>illustrates how to convert the applications from the first chapter to a SPA style app using Reagent</li></ul></li><li><h4>Real-time Messaging With Websockets</h4><ul><li>illustrates how to use Websockets in a Clojure/Script application using Sente</li></ul></li><li><h4>Writing RESTful Web Services</h4><ul><li>covers the basics of using the <a href='https://github.com/metosin/compojure-api'>compojure-api</a> library to provide <a href='http://swagger.io/'>Swagger</a> style service API</li></ul></li><li><h4>Database Access</h4><ul><li>introduces clojure.java.jdbc and Yesql, and how to use these libraries to work with a relational database</li></ul></li><li><h4>Picture Gallery</h4><ul><li>ties all the above concepts together by working through a picture gallery application</li></ul></li><li><h4>Finishing Touches</h4><ul><li>covers testing and packaging the application for deployment</li></ul></li></ul><p>The book will also contain a number of appendices that deal with topics such as NoSQL databases.</p><h3 id="what's&#95;not&#95;covered">What's Not Covered</h3><p>As Clojure web ecosystem continues to evolve, many new tools and libraries, such as the <a href='https://github.com/juxt'>JUXT stack</a>, have appeared just this year. While I would love to cover them all, that simply wouldn't fit the goals I set for this project.</p><p>One notable omission from the book is <a href='https://github.com/omcljs/om'>Om Next</a>. First, I'd like to say that it's a fantastic library and I think very highly of it as well as the ideas behind it. However, I simply haven't used it in anger as I have Reagent. I also think that Reagent is the simpler of the two libraries and therefore more suitable for beginners. I hope that the book will provide a solid foundation for the reader to explore libraries like Om on their own.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Trouble with AOT</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">26 12 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                         <p>I recently ran into an interesting issue when I added the <a href='https://github.com/fzakaria/slf4j-timbre'>slf4j-timbre</a> dependency to a project. As soon as the dependency was added the project would fail to build and I'd see the following error:</p><pre><code>Caused by: java.io.FileNotFoundException: Could not locate clojure/tools/reader/impl/ExceptionInfo&#95;&#95;init.class or clojure/tools/reader/impl/ExceptionInfo.clj on classpath.
</code></pre><p>The <code>slf4j-timbre</code> library does not depend on <code>clojure.tools.reader</code>, and at first glance there's nothing in it that should've caused problems. I did notice that the library depends on <code>com.taoensso/timbre 4.1.4</code> that in turn depends on <code>com.taoensso/encore 2.18.0</code>, and it uses on an older version of <code>clojure.tools.reader</code>.</p><p>At this point I thought the solution would be simple. I'd just include the latest version of <code>encore</code> and everything should work fine. However that didn't turn out to be the case.</p><p>I decided to take another look at <code>slf4j-timbre</code> to see what else might be happening. At this point I noticed that it uses <code>:aot :all</code> in the project configuration. This causes the library to be compiled to Java classes as opposed to being distributed at source. This is necessary since the library has to implement the SLF4J interface and has to provide a Java class in its implementation.</p><p>When the namespace that references <code>Timbre</code> is compiled then any namespaces it depends on are also compiled and packaged in the <code>jar</code>. These compiled classes will take precedence over the source dependencies when the library is included in the project.</p><p>So, even though I was explicitly including the version of <code>encore</code> that uses the latest <code>clojure.tools.reader</code>, the compiled version packaged in <code>slf4j-timbre</code> would end up being used causing the exception above. As far as I can tell there's no way to overwrite these in the project configuration.</p><h3 id="implications&#95;for&#95;luminus">Implications for Luminus</h3><p>Unfortunately, Luminus dependencies require both a SLF4J compliant logger and the latest <code>clojure.tools.reader</code>. While I think <code>Timbre</code> is an excellent library, it's just not the right fit at the moment.</p><p>Luckily, <a href='https://github.com/clojure/tools.logging'>clojure.tools.logging</a> provides a SLF4J compliant API for Clojure logging. The latest release of Luminus uses <code>clojure.tools.logging</code> along with the <a href='https://logging.apache.org/log4j/2.x/'>log4j</a> library as the default logging implementation. It's a mature library that has excellent performance and provides a <a href='https://logging.apache.org/log4j/2.x/manual/appenders.html'>plethora of logging appenders</a>.</p><p>Since <code>log4j</code> can be configured using a properties file, it fits the Luminus approach of using 12 factor style configuration. The library will look for a file called <code>log4j.properties</code> on the classpath to get its default configuration. Luminus packages this file in the <code>resources</code> folder with the following configuration:</p><pre><code>### stdout appender
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=&#91;%d&#93;&#91;%p&#93;&#91;%c&#93; %m%n

### rolling file appender
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=./log/app-name.log

log4j.appender.R.MaxFileSize=100KB
log4j.appender.R.MaxBackupIndex=20

log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=&#91;%d&#93;&#91;%p&#93;&#91;%c&#93; %m%n

### root logger sets the minimum logging level
### and aggregates the appenders
log4j.rootLogger=DEBUG, stdout, R
</code></pre><p>As you can see the configuration is very straight forward, it's also <a href='https://logging.apache.org/log4j/2.x/manual/configuration.html#Properties'>well documented</a>. The default configuration can be overridden at runtime by setting the <code>:log-config</code> environment variable. You can now create a custom logging configuration on the target system and then set an environment variable to point to it as seen below:</p><pre><code>export LOG&#95;CONFIG=prod-log.properties
</code></pre><p>I think that the new approach provides a solid solution for most situations with minimal changes from the existing behavior.</p><h3 id="final&#95;thoughts">Final Thoughts</h3><p>The moral of the story is that you want to be very careful when using AOT in libraries. Whenever possible it is best to avoid it, and if you do have to use it then try to find the minimal subset of the namespaces that absolutely have to be compiled.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Creating a demo page for your npm module</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">17 12 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        So, you&rsquo;ve created a super-awesome npm module, and you want to share it with the world. You&rsquo;ve seen other modules include handy demo sites, where you can play around with the functionality directly in your browser, before even downloading the module yourself. So, just how do you create a demo page?
In the past, if you created server-side code, you&rsquo;d need to run a server so that a demo could be created.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Creating a demo page for your npm module</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">17 12 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        So, you&rsquo;ve created a super-awesome npm module, and you want to share it with the world. You&rsquo;ve seen other modules include handy demo sites, where you can play around with the functionality directly in your browser, before even downloading the module yourself. So, just how do you create a demo page?
In the past, if you created server-side code, you&rsquo;d need to run a server so that a demo could be created.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Managing State in Luminus</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">05 12 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <h3 id="the&#95;problem&#95;of&#95;state">The problem of State</h3><p>Most real-world applications will interact with external resources such as databases. Typically, in order to interact with a database we have to initialize a connection when our application starts, use this connection to access the database, and then tear it down when the application shuts down. </p><p>In some cases these resources may even depend on one another. We may be getting configuration from one resource and then using it to initialize another. A large application may have a number of different resources that are interdependent and have to be coordinated.</p><h4 id="using&#95;component">Using Component</h4><p>One popular approach to addressing this problem is to use the <a href='https://github.com/stuartsierra/component'>component</a> library. Component creates a graph that describes all the resources and then we pass it around to any functions that rely on them. This library was originally developed to support the <a href='http://thinkrelevance.com/blog/2013/06/04/clojure-workflow-reloaded'>reloaded workflow</a> advocated by Stuart Sierra.</p><p>The advantage of this approach is that it allows us to keep the application code completely stateless and lets us inject the stateful resources at runtime. The two main benefits are that the core application logic remains pure and we can easily provide mock resources to it for testing. If you're interested in learning more about building applications based on component I recommend checking out the <a href='https://github.com/weavejester/duct'>Duct</a> framework by James Reeves that I covered in an earlier <a href='http://yogthos.net/posts/2015-10-01-Compojure-API.html'>post</a>.</p><p>I think that's a fine approach for building applications, but I also think that there are tradeoffs that one has to buy into when using component.</p><p>Component introduces simplicity by providing a formal separation between pure and impure code, but also adds complexity in terms of the structure of the application.</p><p>The application has to keep a global component graph that tracks the relationships between the resources and pass it explicitly to any code that needs to interact with them. My experience is that this introduces boilerplate and indirection making the overall application structure more complex. Component also requires the developer to adopt a specific workflow to take full advantage of it.</p><p>Component can also be rather confusing for beginners and I have avoided using it in Luminus for that reason. However, the problems that component addresses are real and if we're not using component we still need a way to address them. For this reason Luminus uses the <a href='https://github.com/tolitius/mount'>mount</a> library to orchestrate the stateful resources in the application.</p><h4 id="using&#95;mount">Using Mount</h4><p>Unlike component, mount does not require us to structure the application in a specific way or to adopt a particular workflow to use it.</p><p>The library leverages the existing namespace hierarchy to resolve the resource dependencies. This approach obviates the need to keep a separate component graph and pass it all over the application.</p><p>Mount uses the <code>defstate</code> macro to define stateful resources. The macro allows specifying the code to initialize and tear down the resource by associating it with the <code>:start</code> and <code>:stop</code> keys. In case of a connection we would associate the code that initializes the connection in the <code>:start</code> key and the code that tears it down with the <code>:stop</code> key respectively.</p><p>Mount will look for any namespaces that define states with <code>defstate</code> and and compile a set of stateful resources based on that. The resources are started and stopped based on the order of reference of their namespaces.</p><p>Mount system is started by calling <code>mount.core/start</code> and stopped using <code>mount.core/stop</code>. This ensures that the lifecycle of the resources is managed in automated fashion and their relationships are all accounted for.</p><p>Like component, mount <a href='https://github.com/tolitius/mount#the-importance-of-being-reloadable'>supports the reloaded workflow</a> and even provides ways to restart parts of the application. Mount also supports <a href='https://github.com/tolitius/mount#swapping-alternate-implementations'>swapping in alternate implementations</a> for the resources. This provides a simple way to run tests with mock resources without having to restart the REPL.</p><h3 id="structuring&#95;the&#95;application">Structuring the Application</h3><p>While mount provides us with a solution for managing the lifecycle of the components, we still need a way to ensure that our application is easy to reason about. Since mount does not enforce the separation between pure and impure code, we have to structure the application in such a way that side effects aren't mixed into the core application logic.</p><h4 id="encapsulating&#95;resources">Encapsulating Resources</h4><p>The approach I like to take in my applications is to keep the code that interacts with external resources at the edges of the application. The core business logic should be pure and testable, while anything that deals with side effects and external resources should be pushed to a thin layer around it.</p><p>I also find it useful to localize resource management in order to reduce coupling between components. For example, when I'm dealing with a database resource I'll create a namespace to manage it. This namespace will be responsible for handling the connection lifecycle internally and providing the connection to the functions defined in it.</p><p>Such a namespace provides an API for interacting with the resource for the rest of the application. Any functions calling this API do not have to be aware of its internal implementation.</p><p>My experience is that this approach allows compartmentalizing the application into self-contained components that can be reasoned about individually. When I update the internal implementation of a particular component the rest of the application does not need to be aware of the change.</p><p>An example of this would be changing the underlying resource. We may start writing the application by using a database directly, then realize that the functionality can be extracted into a shared service. When the mechanics of communicating with an external resource are internal to the component we can safely update it to use the new type of resource without affecting the rest of the application.</p><h4 id="organizing&#95;the&#95;components">Organizing the Components</h4><p>The workflows in web applications are typically driven by the client requests. Since requests will often require interaction with a resource, such as a database, we will generally have to access that resource from the route handling the request. In order to isolate the stateful code we should have our top level functions deal with managing the side effects.</p><p>Consider a concrete example. Let's say we have a route that facilitates user authentication. The client will supply the username and the password in the request. The route will have to pull the user credentials from the database and compare these to the ones supplied by the client. Then a decision is made whether the user logged in successfully or not and its outcome communicated back to the client.</p><p>In this workflow, the code that deals with the external resources should be localized to the namespace that provides the route and the namespace that handles the database access.</p><p>The route handler function will be responsible for calling the function that fetches the credentials from the database. The code that determines whether the password and username match represents the core business logic. This code should be pure and accept the supplied credentials along with those found in the database explicitly. This structure can be seen in the diagram below.</p><pre><code>            pure code
+----------+
| business |
|  logic   |
|          |
+-----+----+
      |
------|---------------------
      |     stateful code
+-----+----+   +-----------+
|  route   |   |           |
| handlers +---+  database |
|          |   |           |
+----------+   +-----------+
</code></pre><p>Keeping the business logic pure ensures that we can reason about it and test it without considering the external resources. Meanwhile the code that deals with side effects is pushed to the top making it easy for us to manage it.</p><h3 id="conclusion">Conclusion</h3><p>Clojure makes it easy to structure the application in such a way that the core of the application logic is kept pure. Doing this is a very good practice and will help you keep your applications manageable as they continue to grow. While it's possible to formalize the handling of stateful resources, using libraries such as component, I personally have not found this to be necessary in my applications.</p><p>I hope this post provides a bit of an insight into how Luminus based applications should be structured for long term maintainability.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Sky Is not Falling</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">28 11 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>A recent post by Elben Shira boldy proclaims <a href='http://elbenshira.com/blog/the-end-of-dynamic-languages/'>the end of dynamic languages</a>. There was <a href='http://pointersgonewild.com/2015/11/25/have-static-languages-won/'>a great followup</a> by Maxime Chevalier-Boisvert that I'd like to expand on a bit in this post.</p><p>I think that people often forget that programming is a human endeavor. When all is said and done what really matters is whether you enjoy working with a particular language or not. Of course, different people like different things and hence the plethora of languages available today.</p><p>I would not presume to tell people that the way I develop is the one true way. I've found an approach that works for me, I know I'm productive with it, and most importantly I enjoy it.</p><p>The truth is that this is the case for everybody else out there as well. Anybody who tells you that they found the one true way is frankly deluded. There's no empirical evidence to show that the typing discipline is the deciding factor of code quality, and everybody out there is using their own anecdotal experience to find the workflow that works for them.</p><p>Proponents of static typing accept its benefits as axiomatic. However, I think that's a case of putting the cart before the horse. Let's take a look at the claims from the perspective of a dynamic language user.</p><h3 id="the&#95;case&#95;for&#95;static&#95;typing">The Case for Static Typing</h3><p>Static typing provides a way to formally track relationships in code and thus allows catching a certain class of errors at compile time. The advantage of this approach is that it becomes possible to guarantee that these types of errors cannot occur at runtime.</p><p>Many proponents of static typing argue that this is a common source of errors in dynamic languages and that it's not possible to write and maintain large codebases in absence of static types. It's common to see assertions such as the following:</p><p><a href='http://conf.researchr.org/event/POPL-2016/popl-2016-papers-is-sound-gradual-typing-dead-'>Programmers have come to embrace dynamically typed languages for prototyping and delivering large and complex systems. When it comes to maintaining and evolving these systems, the lack of explicit static typing becomes a bottleneck.</a></p><p>In practice, very little research has been done to determine whether this is a major source of errors for applications written in dynamic languages, and the few studies that are available don’t show anything conclusive in this regard.</p><p>Furthermore, there’s no evidence that real world projects written in statically typed languages produce superior results to their dynamic counterparts. In fact, some of the largest and most robust systems out there are written in dynamic languages such as Erlang:</p><p><a href='https://pragprog.com/articles/erlang'>Erlang is used all over the world in high-tech projects where reliability counts. The Erlang flagship project (built by Ericsson, the Swedish telecom company) is the AXD301. This has over 2 million lines of Erlang.</a></p><p><a href='https://pragprog.com/articles/erlang'>The AXD301 has achieved a NINE nines reliability (yes, you read that right, 99.9999999%). Let’s put this in context: 5 nines is reckoned to be good (5.2 minutes of downtime/year). 7 nines almost unachievable ... but we did 9.</a></p><p>Erlang is a poster child for robust and fault tolerant systems. However, plenty of large projects have been written in other dynamic languages as well. There's a good chance that a piece of software you rely on daily is written using a dynamic language and it works just fine.</p><h3 id="complexity&#95;inherent&#95;in&#95;static&#95;typing">Complexity inherent in static typing</h3><p>Since static typing sounds like a net win on paper, the obvious questions are why many people prefer dynamic languages and why hasn't static typing been decisively shown to be more effective.</p><p>The main drawback of static typing is that you're required to prove what you're stating to the compiler. Anybody who has done proofs knows that stating something is always simpler than proving it. In fact, many things are very simple to state, but are notoriously difficult to prove. Fermat's last theorem is a famous example of this.</p><p>Baking a proof into the solution leads to incidental complexity. Once you run into limits of what the type system can easily express then you end up having to write increasingly more convoluted code to satisfy it.</p><p>This results in code that’s harder to understand because it compounds the complexity of the problem being solved with the complexity of expressing it using the type system. Effectively, any statement we make in our program has to be accompanied by a proof of correctness to make it possible for the compiler to verify it. The requirement of proving that the code is self-consistent is often at odds with making it simple.</p><p>A concrete example of this would be the use of state monad to formally represent mutation in a language like Haskell. Here's what Timothy Baldridge has to say about his experience trying to apply this pattern in Clojure when working on the <a href='https://github.com/clojure/core.async'>core.async</a> library:</p><blockquote><p><a href='https://groups.google.com/d/msg/clojure/wccacRJIXvg/tFAxZBuO0wMJ'>When I first wrote the core.async go macro I based it on the state monad. It seemed like a good idea; keep everything purely functional. However, over time I've realized that this actually introduces a lot of incidental complexity. And let me explain that thought.</a> </p></blockquote><blockquote><p><a href='https://groups.google.com/d/msg/clojure/wccacRJIXvg/tFAxZBuO0wMJ'>What are we concerned about when we use the state monad, we are shunning mutability. Where do the problems surface with mutability? Mostly around backtracking (getting old data or getting back to an old state), and concurrency.</a> </p></blockquote><blockquote><p><a href='https://groups.google.com/d/msg/clojure/wccacRJIXvg/tFAxZBuO0wMJ'>In the go macro transformation, I never need old state, and the transformer isn't concurrent. So what's the point? Recently I did an experiment that ripped out the state monad and replaced it with mutable lists and lots of atoms. The end result was code that was about 1/3rd the size of the original code, and much more readable.</a> </p></blockquote><blockquote><p><a href='https://groups.google.com/d/msg/clojure/wccacRJIXvg/tFAxZBuO0wMJ'>So more and more, I'm trying to see mutability through those eyes: I should reach for immutable data first, but if that makes the code less readable and harder to reason about, why am I using it?</a> </p></blockquote><p>In a language that forces us to use a particular formalism to represent this problem there would be no alternative solution. While the resulting code would be provably correct, it would be harder for the developer to reason about its intent. Therefore, it's difficult to say whether it's correct in any meaningful sense.</p><p>Ultimately, a human needs to be able to understand what the code is doing and why. The more complexity is layered on top of the original problem the more difficult it becomes to tell what purpose the code serves.</p><p>As another example, let’s consider what we would need to understand to read an HTTP request using a Haskell web framework such as <a href='https://github.com/scotty-web/scotty'>Scotty</a>. We'll quickly run into <code>ScottyM</code> type that's defined as <code>type ScottyM = ScottyT Text IO</code>. To use it effectively we need to understand the <code>ScottyT</code>. It in turn requires understanding the <code>ReaderT</code>.</p><p>Understanding <code>ReaderT</code> relies on understanding of monads, monad transformers and the <code>Reader</code> monad. Meanwhile, to understand the <code>Reader</code> we have to know about functors and applicatives. To understand these we have to understand higher kinded types and constructor classes. This leads us to type classes, type constructors, algebraic datatypes, and so forth.</p><p>All of this is needed to satisfy the formalisms of the Haskell type system and is completely tangential to the problem of reading HTTP requests from a client.</p><p>Of course, one might argue that Haskell is at the far end of the formal spectrum. In a language with a more relaxed type system you have escape hatches such as casting and unchecked side effects.</p><p>However, once you go down that road then it's only a matter of degrees with how relaxed a system you're comfortable with. At this point you've already accepted that working around the type system can make your life easier.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Rendering Reagent on the Server using Hiccup</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">24 11 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I recently watched a great talk titled <a href='https://www.youtube.com/watch?v=fICC26GGBpg'>Optimizing ClojureScript Apps For Speed</a>, where Allen Rohner discusses the benefits and hurdles of server-side rendering.</p><p>React supports hooking in to server generated HTML at runtime. However, since React is a JavaScript library it becomes problematic to leverage this functionality from Clojure. While the JVM provides a Js runtime with Nashorn, it's extremely slow and requires a lot of twiddling to work for even basic examples.</p><p>Another approach is to run an instance of Node.js and farm out React rendering to it. This avoids the limitations of Nashorn, but introduces a host of new problems described in the talk.</p><p>Allen then proposes an alternative approach where he implements parts of the Om API and cross-compiles the components that way. You can see how this works in his <a href='https://github.com/arohner/foam'>Foam</a> library.</p><p>The main difficulty identified in the talk is in implementing a sufficient amount of Om API in order to generate HTML on the server.</p><p>This got me thinking about what it would take to leverage this approach using Reagent. Unlike Om, Reagent has a tiny API and the only part of it used to create components is the Reagent atom implementation. The components themselves are written using plain Hiccup syntax.</p><p>Let's see how this could work. We'll start by creating a new Reagent project:</p><pre><code>lein new reagent reagent-serverside
</code></pre><p>Next, we'll add a new namespace in called <code>reagent-serverside.home</code> <code>src/cljc/reagent&#95;serverside/home.cljc</code>. This namespace will house the home page component that we'll pre-render on the server.</p><p>All we have to do now is to use a reader conditional to only require the Reagent atom during ClojureScript compilation:</p><pre><code class="clojure">&#40;ns reagent-serverside.home
  #?&#40;:cljs
     &#40;:require &#91;reagent.core :as reagent :refer &#91;atom&#93;&#93;&#41;&#41;&#41;
</code></pre><p>We can now write our components as we would normally:</p><pre><code class="clojure">&#40;ns reagent-serverside.home
  #?&#40;:cljs
     &#40;:require &#91;reagent.core :as reagent :refer &#91;atom&#93;&#93;&#41;&#41;&#41;

&#40;def items &#40;atom nil&#41;&#41;

&#40;defn item-list &#91;items&#93;
  &#91;:ul
   &#40;for &#91;item items&#93;
     &#94;{:key item}
     &#91;:li item&#93;&#41;&#93;&#41;

&#40;defn add-item-button &#91;items&#93;
  &#91;:button
   {:on-click #&#40;swap! items conj &#40;count @items&#41;&#41;}
   &quot;add item&quot;&#93;&#41;

&#40;defn home-page &#91;&#93;
  &#91;:div &#91;:h2 &quot;Welcome to reagent-serverside&quot;&#93;
   &#91;add-item-button items&#93;
   &#91;item-list @items&#93;&#93;&#41;
</code></pre><p>We'll have the <code>items</code> atom to house a collection of items, an <code>item-list</code> function to render it, and the <code>home-page</code> function that will use the <code>item-list</code> component. We also have a button that lets the user add new items with an <code>:on-click</code> event. This is all standard Reagent code.</p><h3 id="rendering&#95;on&#95;the&#95;server">Rendering on the Server</h3><p>Now, let's navigate to the <code>reagent-serverside.handler</code> namespace and reference the <code>reagent-serverside.home</code> we just created.</p><pre><code class="clojure">&#40;ns reagent-serverside.handler
  &#40;:require ...
            &#91;reagent-serverside.home :refer &#91;items home-page&#93;&#93;&#41;&#41;
</code></pre><p>We'll now have to write the functions that will traverse the components and render them as appropriate. We'll attach a <code>:data-reactid</code> key to each one to give it an identifier that React looks for, and inject the result into our Hiccup markup.</p><pre><code class="clojure">&#40;defn react-id-str &#91;react-id&#93;
  &#40;assert &#40;vector? react-id&#41;&#41;
  &#40;str &quot;.&quot; &#40;clojure.string/join &quot;.&quot; react-id&#41;&#41;&#41;

&#40;defn set-react-id &#91;react-id element&#93;
  &#40;update element 1 merge {:data-reactid &#40;react-id-str react-id&#41;}&#41;&#41;

&#40;defn normalize &#91;component&#93;
  &#40;if &#40;map? &#40;second component&#41;&#41;
    component
    &#40;into &#91;&#40;first component&#41; {}&#93; &#40;rest component&#41;&#41;&#41;&#41;

&#40;defn render
  &#40;&#91;component&#93; &#40;render &#91;0&#93; component&#41;&#41;  
  &#40;&#91;id component&#93;
   &#40;cond
    &#40;fn? component&#41;
    &#40;render &#40;component&#41;&#41;    

    &#40;not &#40;coll? component&#41;&#41;
    component
    
    &#40;coll? &#40;first component&#41;&#41;
    &#40;map-indexed #&#40;render &#40;conj id %1&#41; %2&#41; component&#41;
    
    &#40;keyword? &#40;first component&#41;&#41;
    &#40;let &#91;&#91;tag opts &amp; body&#93; &#40;normalize component&#41;&#93;
      &#40;-&gt;&gt; body
           &#40;map-indexed #&#40;render &#40;conj id %1&#41; %2&#41;&#41;
           &#40;into &#91;tag opts&#93;&#41;
           &#40;set-react-id id&#41;&#41;&#41;
    
    &#40;fn? &#40;first component&#41;&#41;
    &#40;render id &#40;apply &#40;first component&#41; &#40;rest component&#41;&#41;&#41;&#41;&#41;&#41;

&#40;reset! items &#40;range 10&#41;&#41;

&#40;def mount-target
  &#91;:div#app &#40;render home-page&#41;&#93;&#41;
</code></pre><p>The <code>render</code> function will recursively walk the components evaluating any functions it finds and assigning the React id to each element.</p><p>Next, we'll set the <code>items</code> atom to a range of numbers, and then call <code>render</code> inside the <code>mount-target</code> to generate the markup.</p><h3 id="rendering&#95;on&#95;the&#95;client">Rendering on the Client</h3><p>Finally, let's navigate to the <code>reagent-serverside.core</code> namespace in the <code>src/cljs</code> source path. We'll update it to reference the <code>home</code> namespace we created and render the <code>home-page</code> component on load.</p><pre><code class="clojure">&#40;ns reagent-serverside.core
    &#40;:require &#91;reagent.core :as reagent :refer &#91;atom&#93;&#93;
              &#91;reagent-serverside.home :refer &#91;items home-page&#93;&#93;&#41;&#41;

&#40;defn mount-root &#91;&#93;
  &#40;reagent/render &#91;home-page&#93; &#40;.getElementById js/document &quot;app&quot;&#41;&#41;&#41;

&#40;defn init! &#91;&#93;
  &#40;reset! items &#40;range 20&#41;&#41;
  &#40;mount-root&#41;&#41;
</code></pre><p>When we load the page we'll immediately see the server generated markup and then it will be updated by Reagent when ClojureScript is loaded. There are a few caveats here that you should be aware of.</p><p>Any components you wish to render on the server have to be written in <code>cljc</code>, so you may end up having to add some shims for things like Ajax calls.</p><p>The component syntax has to work with both Reagent and Hiccup, so you have to be mindful to use the common subset.</p><p>React is fairly picky about the structure and the <code>data-reactid</code> tags. So, it can be tricky to generate a DOM tree that it likes. The example in the post will give a React warning about the DOM being different. Some more work is needed around this.</p><p>However, even in the case that React doesn't reuse the DOM, the user will see the page immediately and you'll get the benefits of SEO for your site.</p><p>Full source is available on <a href='https://github.com/yogthos/reagent-serverside'>GitHub</a>.</p><h3 id="conclusions">Conclusions</h3><p>Overall, I'm very happy with the results and it looks like it would be fairly easy to wrap this up into a library. The data focused approach is a huge win for Reagent here in my opinion. Since the components are laid out using regular Clojure data structures there's no need to implement any special API and things just work out of the box.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Evaluating ClojureScript in the Browser</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">12 11 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>ClojureScript can now <a href='https://swannodette.github.io/2015/07/29/clojurescript-17/'>compile itself without relying on the Google Closure compiler</a>, and it's now possible to evaluate code straight in the browser. In this post we'll look at how that's accomplished by creating a code editor using <a href='https://codemirror.net/'>CodeMirror</a>, <a href='https://highlightjs.org/'>highlight.js</a>, and <a href='https://reagent-project.github.io/'>Reagent</a>. The code entered in the editor will be sent for evaluation and the result displayed to the user.</p><p>Let's start by creating a new Reagent project by running the following command:</p><pre><code>lein new reagent cljs-eval-example +figwheel
</code></pre><p>Next, we'll navigate to the project folder and start Figwheel by running:</p><pre><code>lein figwheel
</code></pre><p>Let's open the browser at <code>http://localhost:3449</code> and navigate to the <code>cljs-eval-example.core</code> namespace in the <code>src/cljs</code> folder. We'll first need to reference <code>cljs.js</code> namespace:</p><pre><code class="clojure">&#40;ns cljs-eval-example.core
  &#40;:require
   ...
   &#91;cljs.js :refer &#91;empty-state eval-str js-eval&#93;&#93;&#41;&#41;
</code></pre><p>We'll create <code>evaluate</code> function that will accept a string and a callback. This function calls <a href='https://cljs.github.io/api/cljs.js/eval-str'>cljs.js/eval-str</a> as follows:</p><pre><code class="clojure">&#40;defn evaluate &#91;s cb&#93;
  &#40;eval-str
     &#40;empty-state&#41;
     s
     nil
     {:eval       js-eval    
      :source-map true
      :context    :expr}
     cb&#41;&#41;
</code></pre><p>The <code>eval-str</code> function accepts an initial state, followed by the string representing the form to evaluate, a name, a map with the options, and a callback function for handling the result of the evaluation. We can create an initial state by calling <code>cljs.js/empty-state</code> function. We can now test that our code works by adding a button to our <code>home-page</code> component:</p><pre><code class="clojure">&#40;defn home-page &#91;&#93;
  &#91;:div
   &#91;:button
    {:on-click #&#40;evaluate &quot;&#40;println \&quot;hello world!\&quot;&#41;&quot; &#40;fn &#91;&#95;&#93;&#41;&#41;}
    &quot;let's compile!&quot;&#93;&#93;&#41;
</code></pre><p>When we click the button we should see <code>&quot;hello world!&quot;</code> printed in the browser console. Next, let's add a <code>:textarea</code> to allow entering some text and then send it for evaluation.</p><pre><code class="clojure">&#40;defn home-page &#91;&#93;
  &#40;let &#91;input &#40;atom nil&#41;
        output &#40;atom nil&#41;&#93;
    &#40;fn &#91;&#93;
      &#91;:div
       &#91;:textarea
        {:value @input
         :on-change #&#40;reset! input &#40;-&gt; % .-target .-value&#41;&#41;}&#93;       
       &#91;:div&gt;button
        {:on-click #&#40;evaluate @input &#40;fn &#91;result&#93; &#40;reset! output result&#41;&#41;&#41;}
        &quot;let's compile!&quot;&#93;
       &#91;:p @output&#93;&#93;&#41;&#41;&#41;
</code></pre><p>At this point we can type some code in our input box, click the button to evaluate it, and see the result. So far so good, now let's make the editor look a bit nicer by replacing it with the CodeMirror version.</p><p>We'll open up the <code>cljs-eval-example.handler</code> namespace in the <code>src/clj</code> folder. There, we'll update the <code>include-css</code> and <code>include-js</code> portions of the <code>head</code> to add the respective CSS and Js files for running CodeMirror.</p><pre><code class="clojure">&#40;defn head &#91;&#93;
  &#91;:head
   &#91;:meta {:charset &quot;utf-8&quot;}&#93;
   &#91;:meta {:name &quot;viewport&quot;
           :content &quot;width=device-width, initial-scale=1&quot;}&#93;
   &#40;include-css
    &#40;if &#40;env :dev&#41; &quot;/css/site.css&quot; &quot;/css/site.min.css&quot;&#41;
    &quot;//cdnjs.cloudflare.com/ajax/libs/codemirror/5.8.0/codemirror.min.css&quot;
    &#40;if &#40;env :dev&#41; &quot;css/site.css&quot; &quot;css/site.min.css&quot;&#41;&#41;
   &#40;include-js
    &quot;//cdnjs.cloudflare.com/ajax/libs/codemirror/5.8.0/codemirror.min.js&quot;
    &quot;//cdnjs.cloudflare.com/ajax/libs/codemirror/5.8.0/mode/clojure/clojure.min.js&quot;&#41;&#93;&#41;
</code></pre><p>With that in place we'll need to reload the page for the new assets to become available. Since we're using external JavaScript that modifies the DOM, we'll need to use the <code>reagent.core/create-class</code> function to create the editor component.</p><p>The <code>create-class</code> function accepts a map keyed on the <a href='https://facebook.github.io/react/docs/component-specs.html'>React lifecycle methods</a>. The methods that we wish to implement are <code>:render</code> and <code>:component-did-mount</code>:</p><pre><code class="clojure">&#40;defn editor &#91;input&#93;
  &#40;reagent/create-class
   {:render &#40;fn &#91;&#93; &#91;:textarea 
                     {:default-value &quot;&quot;
                      :auto-complete &quot;off&quot;}&#93;&#41;
    :component-did-mount &#40;editor-did-mount input&#41;}&#41;&#41;
</code></pre><p>The <code>editor</code> component will accept the <code>input</code> atom as the parameter and pass it to the <code>editor-did-mount</code> function. This function will look as follows:</p><pre><code class="clojure">&#40;defn editor-did-mount &#91;input&#93;
  &#40;fn &#91;this&#93;
    &#40;let &#91;cm &#40;.fromTextArea  js/CodeMirror
                             &#40;reagent/dom-node this&#41;
                             #js {:mode &quot;clojure&quot;
                                  :lineNumbers true}&#41;&#93;
      &#40;.on cm &quot;change&quot; #&#40;reset! input &#40;.getValue %&#41;&#41;&#41;&#41;&#41;&#41;
</code></pre><p>The <code>editor-did-mount</code> is a closure that returns a function that accepts the mounted React component, it then calls <code>reagent/dom-node</code> on it to get the actual DOM node mounted in the browser. We'll then call <code>.fromTextArea</code> method on <code>js/CodeMirror</code> and pass it the node along with a map of rendering hints.</p><p>Calling <code>.fromTextArea</code> returns an instance of the CodeMirror. As a last step we'll add the <code>change</code> event to this instance to reset the <code>input</code> atom with the updated text whenever the text in the editor is changed.</p><p>We can now update the <code>home-page</code> component to use the <code>editor</code> component instead of a plain <code>textarea</code>:</p><pre><code class="clojure">&#40;defn home-page &#91;&#93;
  &#40;let &#91;input &#40;atom nil&#41;
        output &#40;atom nil&#41;&#93;
    &#40;fn &#91;&#93;
      &#91;:div
       &#91;editor input&#93;
       &#91;:div
        &#91;:button
         {:on-click #&#40;evaluate @input &#40;fn &#91;{:keys &#91;value&#93;}&#93; &#40;reset! output value&#41;&#41;&#41;}
         &quot;run&quot;&#93;&#93;
       &#91;:p @output&#93;&#93;&#41;&#41;&#41;
</code></pre><p>The editor looks a lot nicer now, but the output doesn't have any highlighting. Let's fix that by running it through highlight.js to generate nicely formatted results.</p><p>Once again, we'll need to add the additional CSS and Js files in the <code>cljs-eval-example.handler</code> namespace:</p><pre><code class="clojure">&#40;defn head &#91;&#93;
  &#91;:head
   &#91;:meta {:charset &quot;utf-8&quot;}&#93;
   &#91;:meta {:name &quot;viewport&quot;
           :content &quot;width=device-width, initial-scale=1&quot;}&#93;
   &#40;include-css
    &#40;if &#40;env :dev&#41; &quot;/css/site.css&quot; &quot;/css/site.min.css&quot;&#41;
    &quot;//cdnjs.cloudflare.com/ajax/libs/codemirror/5.8.0/codemirror.min.css&quot;
    &quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.9.1/styles/default.min.css&quot;
    &#40;if &#40;env :dev&#41; &quot;css/site.css&quot; &quot;css/site.min.css&quot;&#41;&#41;
   &#40;include-js
    &quot;//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.9.1/highlight.min.js&quot;
    &quot;//cdnjs.cloudflare.com/ajax/libs/codemirror/5.8.0/codemirror.min.js&quot;
    &quot;//cdnjs.cloudflare.com/ajax/libs/codemirror/5.8.0/mode/clojure/clojure.min.js&quot;&#41;&#93;&#41;
</code></pre><p>Back in the <code>cljs-eval-example.core</code> namespace we'll add a reference for <code>&#91;cljs.pprint :refer &#91;pprint&#93;&#93;</code> and write the <code>result-view</code> component that will take care of highlighting the output.</p><pre><code class="clojure">&#40;ns cljs-eval-example.core
  &#40;:require ...
            &#91;cljs.pprint :refer &#91;pprint&#93;&#93;&#41;&#41;

...
            
&#40;defn result-view &#91;output&#93;
  &#40;reagent/create-class
   {:render &#40;fn &#91;&#93;
              &#91;:pre&gt;code.clj
               &#40;with-out-str &#40;pprint @output&#41;&#41;&#93;&#41;
    :component-did-update render-code}&#41;&#41;
</code></pre><p>Highlight.js defaults to using <code>&lt;pre&gt;&lt;code&gt;...&lt;/pre&gt;&lt;/code&gt;</code> blocks, so we'll generate one in the <code>:render</code> function. Then we'll call the <code>render-code</code> function when the <code>:component-did-update</code> state is triggered. This function will simply pass the node to the <code>.highlightBlock</code> function provided by highlight.js:</p><pre><code class="clojure">&#40;defn render-code &#91;this&#93;
  &#40;-&gt;&gt; this reagent/dom-node &#40;.highlightBlock js/hljs&#41;&#41;&#41;
</code></pre><p>Finally, we'll have to update the <code>home-page</code> component to use the <code>result-view</code> component we just wrote:</p><pre><code class="clojure">&#40;defn home-page &#91;&#93;
  &#40;let &#91;input &#40;atom nil&#41;
        output &#40;atom nil&#41;&#93;
    &#40;fn &#91;&#93;
      &#91;:div
       &#91;editor input&#93;
       &#91;:div
        &#91;:button
         {:on-click #&#40;evaluate @input &#40;fn &#91;{:keys &#91;value&#93;}&#93; &#40;reset! output value&#41;&#41;&#41;}
         &quot;run&quot;&#93;&#93;
       &#91;:div
        &#91;result-view output&#93;&#93;&#93;&#41;&#41;&#41;
</code></pre><p>Now both the editor and the output should look nicely highlighted, and the output will be formatted as a bonus. The entire code listing is as follows:</p><pre><code class="clojure">&#40;ns cljs-eval-example.core
  &#40;:require
   &#91;reagent.dom :as dom&#93;
   &#91;reagent.core :as reagent :refer &#91;atom&#93;&#93;
   &#91;cljs.js :refer &#91;empty-state eval-str js-eval&#93;&#93;
   &#91;cljs.pprint :refer &#91;pprint&#93;&#93;&#41;&#41;

&#40;defn evaluate &#91;s cb&#93;
  &#40;eval-str
     &#40;empty-state&#41;
     s
     nil
     {:eval       js-eval    
      :source-map true
      :context    :expr}
     cb&#41;&#41;

&#40;defn editor-did-mount &#91;input&#93;
  &#40;fn &#91;this&#93;
    &#40;let &#91;cm &#40;.fromTextArea  js/CodeMirror
                             &#40;dom/dom-node this&#41;
                             #js {:mode &quot;clojure&quot;
                                  :lineNumbers true}&#41;&#93;
      &#40;.on cm &quot;change&quot; #&#40;reset! input &#40;.getValue %&#41;&#41;&#41;&#41;&#41;&#41;

&#40;defn editor &#91;input&#93;
  &#40;reagent/create-class
   {:render &#40;fn &#91;&#93; &#91;:textarea
                    {:default-value &quot;&quot;
                     :auto-complete &quot;off&quot;}&#93;&#41;
    :component-did-mount &#40;editor-did-mount input&#41;}&#41;&#41;

&#40;defn render-code &#91;this&#93;
  &#40;-&gt;&gt; this dom/dom-node &#40;.highlightBlock js/hljs&#41;&#41;&#41;

&#40;defn result-view &#91;output&#93;
  &#40;reagent/create-class
   {:render &#40;fn &#91;&#93;
              &#91;:pre&gt;code.clj
               &#40;with-out-str &#40;pprint @output&#41;&#41;&#93;&#41;
    :component-did-update render-code}&#41;&#41;

&#40;defn home-page &#91;&#93;
  &#40;let &#91;input &#40;atom nil&#41;
        output &#40;atom nil&#41;&#93;
    &#40;fn &#91;&#93;
      &#91;:div
       &#91;editor input&#93;
       &#91;:div
        &#91;:button
         {:on-click #&#40;evaluate @input &#40;fn &#91;{:keys &#91;value&#93;}&#93; &#40;reset! output value&#41;&#41;&#41;}
         &quot;run&quot;&#93;&#93;
       &#91;:div
        &#91;result-view output&#93;&#93;&#93;&#41;&#41;&#41;

&#40;defn mount-root &#91;&#93;
  &#40;dom/render &#91;home-page&#93; &#40;.getElementById js/document &quot;app&quot;&#41;&#41;&#41;

&#40;defn init! &#91;&#93;
  &#40;mount-root&#41;&#41;
</code></pre><p>A complete example project is available on <a href='https://github.com/yogthos/cljs-eval-example'>GitHub</a>.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/files/jconsole-default-screen.png" alt="Troubleshooting With JConsole">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Troubleshooting With JConsole</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">08 10 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>It's often useful to be able to tell how much resources your app happens to be using. I've previously discussed how <a href='/posts/2012-08-21-Reflecting-on-performance.html'>JVisualVM</a> can be used to do some basic profiling for the application. In this post we'll look at how to use another great tool called <code>jconsole</code> that also comes with the JVM. First, let's create and run a new Luminus web app as follows:</p><pre><code>lein new luminus guestbook
cd guestbook
lein uberjar
java -jar target/guestbook.jar
</code></pre><p>We'll run the following command in a separate terminal:</p><pre><code>jconsole
</code></pre><p>We should be greeted by a screen that looks something like the following:</p><p><img src="/files/jconsole-default-screen.png" alt="jconsole" /></p><p>We'll select guestbook and connect to it. Once the connection is established we'll see an overview screen detailing memory, class instances, threads, and CPU usage.</p><p><img src="/files/jconsole-summary-screen.png" alt="jconsole summary" /></p><p>We can also select tabs to drill down into details about each of these as well as the VM summary. The <code>Memory</code> tab is the one of most interest to start. This screen will let us see a graph of memory usage over time and allow us to initiate garbage collection. It also shows the details about application memory usage and how it compares to the overall memory allocated by the JVM. </p><p><img src="/files/jconsole-memory-screen.png" alt="jconsole summary" /></p><p>Let's run the <a href='https://httpd.apache.org/docs/2.2/programs/ab.html'>Apache HTTP server benchmarking tool</a>, that comes bundled by default on OS X, and see how that affects our application.</p><pre><code>ab -c 10 -n 1000 http://127.0.0.1:3000/
This is ApacheBench, Version 2.3 &lt;$Revision: 1663405 $&gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 &#40;be patient&#41;
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        undertow
Server Hostname:        127.0.0.1
Server Port:            3000

Document Path:          /
Document Length:        3918 bytes

Concurrency Level:      10
Time taken for tests:   3.544 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      4251000 bytes
HTML transferred:       3918000 bytes
Requests per second:    282.14 &#91;#/sec&#93; &#40;mean&#41;
Time per request:       35.444 &#91;ms&#93; &#40;mean&#41;
Time per request:       3.544 &#91;ms&#93; &#40;mean, across all concurrent requests&#41;
Transfer rate:          1171.26 &#91;Kbytes/sec&#93; received

Connection Times &#40;ms&#41;
              min  mean&#91;+/-sd&#93; median   max
Connect:        0    0   0.1      0       3
Processing:    15   35  27.4     26     252
Waiting:       15   35  26.3     26     226
Total:         15   35  27.5     26     252

Percentage of the requests served within a certain time &#40;ms&#41;
  50%     26
  66%     31
  75%     37
  80%     41
  90%     54
  95%     75
  98%    110
  99%    227
 100%    252 &#40;longest request&#41;
</code></pre><ul><li>note that 282 req/sec number is running without any warmup while being instrumented</li></ul><p>We can see that as the server is getting hammered by requests the memory usage spikes from roughly a 100 megs to about 275. However, once GC is performed the memory usage goes right back down.</p><p><img src="/files/jconsole-gc.png" alt="jconsole summary" /></p><p>This tells us that the application starts using more resources as it serves multiple concurrent requests, but then releases these as the GC runs indicating that no memory leaks are happening. We can also confirm that the threads and class instances are not getting out of hand as the application continues to run using the the respective tabs.</p><p><img src="/files/jconsole-threads.png" alt="jconsole summary" /></p><p><img src="/files/jconsole-classes.png" alt="jconsole summary" /></p><p>As you can see <code>jconsole</code> is a handy tool that can be used to quickly diagnose the behavior of a Clojure application. Should we find anything that warrants further investigation then it would be time to run a profiler such as <code>jvisualvm</code> to see where specifically the resources are being used.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Building services with Duct and compojure-api</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">01 10 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>In this post we'll look at writing a RESTful service using <a href='https://github.com/weavejester/duct'>Duct</a> and <a href='https://github.com/metosin/compojure-api'>compojure-api</a>. Our service will use a SQLite database and illustrate how to do operations such as adding, remove, and authenticating users.</p><h3 id="prerequisites">Prerequisites</h3><ul><li><a href='http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html'>JDK</a></li><li><a href='http://leiningen.org/'>Leiningen</a></li></ul><h3 id="creating&#95;the&#95;project">Creating the Project</h3><p>Duct is a minimal web framework with emphasis on using <a href='https://github.com/stuartsierra/component'>component</a> to manage stateful resources such as database connections. We can create a new Duct application by running the following command:</p><pre><code>lein new duct swagger-service +example
</code></pre><p>This will generate a fresh application and add an example route component to it. Once the application is created we'll have to run the <code>setup</code> task to generate local assets in the root folder of the application:</p><pre><code>cd swagger-service
lein setup
</code></pre><p>We can now test that our application works as follows:</p><pre><code>lein run
</code></pre><p>If everything went well then we should be able to navigate to <code>localhost:3000</code> and see <code>Hello World</code> displayed on the page. We're now ready to start working on creating our service.</p><h4 id="adding&#95;dependencies">Adding Dependencies</h4><p>We'll start by adding some dependencies in <code>project.clj</code> that we'll need in order to create our service:</p><pre><code class="clojure">:dependencies
&#91;...
 &#91;crypto-password &quot;0.1.3&quot;&#93;
 &#91;metosin/compojure-api &quot;0.23.1&quot;&#93;
 &#91;org.xerial/sqlite-jdbc &quot;3.8.11.1&quot;&#93;
 &#91;yesql &quot;0.5.0&quot;&#93;
 &#91;migratus &quot;0.8.4&quot;&#93;&#93;
</code></pre><p>We'll use <code>crypto-password</code> to handle password hashing when we create user accounts and checking passwords during authentication. The <code>compojure-api</code> library will be used to generate the service endpoints. The <code>sqlite-jdbc</code> driver will be used as our data store, we'll access it using <code>yesql</code>, and we'll generate the database using <code>migratus</code>.</p><h4 id="configuring&#95;migrations">Configuring Migrations</h4><p>Let's add the <code>migratus</code> plugin along with its configuration to our project:</p><pre><code class="clojure">:plugins &#91;&#91;lein-environ &quot;1.0.1&quot;&#93;
          &#91;lein-gen &quot;0.2.2&quot;&#93;
          &#91;migratus-lein &quot;0.1.7&quot;&#93;&#93;

:migratus {:store :database             
           :db {:classname &quot;org.sqlite.JDBC&quot;
                :connection-uri &quot;jdbc:sqlite:service-store.db&quot;}}          
</code></pre><p>We can now run the following commands to generate the migration files for the <code>users</code> table:</p><pre><code>mkdir resources/migrations
lein migratus create users
</code></pre><p>This will produce files for <code>up</code> and <code>down</code> migrations such as:</p><pre><code class="sql">20151001145313-users.down.sql
20151001145313-users.up.sql
</code></pre><p>The <code>up</code> migrations file will create the table:</p><pre><code class="sql">CREATE TABLE users
&#40;id VARCHAR&#40;20&#41; PRIMARY KEY,
 first&#95;name VARCHAR&#40;30&#41;,
 last&#95;name VARCHAR&#40;30&#41;,
 email VARCHAR&#40;30&#41;,
 admin BOOLEAN,
 last&#95;login TIME,
 is&#95;active BOOLEAN,
 pass VARCHAR&#40;100&#41;&#41;;
</code></pre><p>Conversely, the <code>down</code> migrations file will delete it:</p><pre><code class="sql">DROP TABLE users;
</code></pre><p>We can now run the following command to create the database:</p><pre><code>lein migratus migrate
</code></pre><h4 id="adding&#95;database&#95;queries">Adding Database Queries</h4><p>With the database created, we'll need to add some queries to access the database. We'll create a new file called <code>resources/sql/queries.sql</code> and put the following SQL queries in it:</p><pre><code class="sql">-- name: create-user!
-- creates a new user record
INSERT INTO users
&#40;id, first&#95;name, last&#95;name, email, pass&#41;
VALUES &#40;:id, :first&#95;name, :last&#95;name, :email, :pass&#41;

-- name: get-user
-- retrieve a user given the id.
SELECT &#42; FROM users
WHERE id = :id

-- name: get-users
-- retrieve a user given the id.
SELECT id, first&#95;name, last&#95;name, email FROM users

-- name: delete-user!
-- delete a user given the id
DELETE FROM users
WHERE id = :id
</code></pre><h3 id="creating&#95;the&#95;database&#95;component">Creating the Database Component</h3><p>Now, let's create a component that will be used to access it. We'll create a new namespace called <code>swagger-service.component.db</code> then put the following code there:</p><pre><code class="clojure">&#40;ns swagger-service.component.db
  &#40;:require &#91;yesql.core :refer &#91;defqueries&#93;&#93;
            &#91;com.stuartsierra.component :as component&#93;
            &#91;crypto.password.bcrypt :as password&#93;
            &#91;environ.core :refer &#91;env&#93;&#93;&#41;&#41;

&#40;defqueries &quot;sql/queries.sql&quot;&#41;

&#40;defn create-user-account! &#91;user db&#93;
  &#40;create-user! &#40;update user :pass password/encrypt&#41; db&#41;&#41;

&#40;defn authenticate &#91;user db&#93;
  &#40;boolean
   &#40;when-let &#91;db-user &#40;-&gt; user &#40;get-user db&#41; first&#41;&#93;
     &#40;password/check &#40;:pass user&#41; &#40;:pass db-user&#41;&#41;&#41;&#41;&#41;

&#40;defrecord DbComponent &#91;connection&#93;
  component/Lifecycle
  &#40;start &#91;component&#93;
         &#40;assoc component :connection connection&#41;&#41;
  &#40;stop &#91;component&#93;
        &#40;dissoc component :connection&#41;&#41;&#41;

&#40;defn db-component &#91;connection&#93;
  &#40;-&gt;DbComponent connection&#41;&#41;
</code></pre><p>The namespace will define query functions by calling the <code>defqueries</code> macro and giving it the path to the <code>queries.sql</code> file we just created.</p><p>Then we'll add a couple of helper functions to create a user account with a hashed password and to check whether the user and the password match the stored credentials.</p><p>Next, we define the <code>DbComponent</code> record that will manage the lifecycle of the database. The <code>start</code> function in the component will associate the given connection settings with the <code>:connection</code> key in the component, and the <code>stop</code> function will remove the connection.</p><p>The connection is specified in the <code>swagger-service.config</code> namespace and points to the <code>connection-uri</code> key that is expected to be found in the environment.</p><pre><code class="clojure">&#40;def environ
  {:http {:port &#40;some-&gt; env :port Integer.&#41;}
   :db   {:connection-uri &#40;:connection-uri env&#41;}}&#41;
</code></pre><p>We'll add the actual connection information under the <code>:env</code> key in <code>profiles.clj</code>:</p><pre><code class="clojure">;; Local profile overrides

{:profiles/dev  {:env {:connection-uri &quot;jdbc:sqlite:service-store.db&quot;}}
 :profiles/test {}}
</code></pre><p>Finally, we have a helper function to instantiate the component called <code>db-component</code>.</p><h4 id="adding&#95;a&#95;new&#95;component&#95;to&#95;the&#95;system">Adding a New Component to the System</h4><p>With the component created we can now add it to the system found in the <code>swagger-service.system</code> namespace:</p><pre><code class="clojure">&#40;ns swagger-service.system
 &#40;:require ...
           &#91;swagger-service.component.db :refer &#91;db-component&#93;&#93;&#41;&#41;

...
           
&#40;defn new-system &#91;config&#93;
 &#40;let &#91;config &#40;meta-merge base-config config&#41;&#93;
   &#40;-&gt; &#40;component/system-map
        :db      &#40;db-component &#40;:db config&#41;&#41;
        :app     &#40;handler-component &#40;:app config&#41;&#41;
        :http    &#40;jetty-server &#40;:http config&#41;&#41;
        :example &#40;endpoint-component example-endpoint&#41;&#41;
       &#40;component/system-using
        {:http &#91;:app&#93;
         :app  &#91;:example&#93;
         :example &#91;&#93;          
         :db &#91;&#93;}&#41;&#41;&#41;&#41;            
</code></pre><h3 id="creating&#95;an&#95;http&#95;endpoint&#95;component">Creating an HTTP Endpoint Component</h3><p>The final step is to add the service endpoint that will provide the RESTful interface to the database. We'll create a new namespace called <code>swagger-service.endpoint.service</code>. The namespace will use the <code>compojure-api</code> library to define the service operations. The library requires us to declare the types of request parameters and responses for each endpoint using the <a href='https://github.com/Prismatic/schema'>schema</a> library.</p><p>Let's start by creating the namespace declaration with the following references:</p><pre><code class="clojure">&#40;ns swagger-service.endpoint.service
 &#40;:require &#91;clojure.java.io :as io&#93;
           &#91;ring.util.http-response :refer :all&#93;
           &#91;compojure.api.sweet :refer :all&#93;
           &#91;schema.core :as s&#93;
           &#91;swagger-service.component.db :as db&#93;&#41;&#41;
</code></pre><p>Then we'll create the schema for the User type that matches the user table in our database:</p><pre><code class="clojure">&#40;s/defschema User
 {:id String
  &#40;s/optional-key :first&#95;name&#41; String
  &#40;s/optional-key :last&#95;name&#41; String
  &#40;s/optional-key :email&#41; String
  &#40;s/optional-key :pass&#41; String}&#41;
</code></pre><p>Finally, let's create the <code>service-endpoint</code> component that will define the service routes. The component accepts the <code>config</code> as its parameter. The config will contain the <code>:db</code> key that we added to our system earlier with the database connection.</p><p>The routes are created by calling the <code>api</code> macro from <code>compojure-api</code>:</p><pre><code class="clojure">&#40;defn service-endpoint &#91;config&#93;
 &#40;api
   &#40;ring.swagger.ui/swagger-ui
    &quot;/swagger-ui&quot;&#41;
   &#40;swagger-docs
    {:info {:title &quot;User API&quot;}}&#41;
   &#40;context&#42; &quot;/api&quot; &#91;&#93;
             :tags &#91;&quot;users&quot;&#93;

             &#40;GET&#42; &quot;/users&quot; &#91;&#93;
                   :return  &#91;User&#93;
                   :summary &quot;returns the list of users&quot;
                   &#40;ok &#40;db/get-users {} &#40;:db config&#41;&#41;&#41;&#41;
             
             &#40;GET&#42; &quot;/user/:id&quot;  &#91;&#93;
                   :return      User
                   :path-params &#91;id :- String&#93;
                   :summary     &quot;returns the user with a given id&quot;
                   &#40;ok &#40;db/get-users {:id id} &#40;:db config&#41;&#41;&#41;&#41;

             &#40;POST&#42; &quot;/authenticate&quot; &#91;&#93;
                    :return         Boolean
                    :body-params    &#91;user :- User&#93;
                    :summary        &quot;authenticates the user using the id and pass.&quot;
                    &#40;ok &#40;db/authenticate user &#40;:db config&#41;&#41;&#41;&#41;
             
             &#40;POST&#42; &quot;/user&quot;      &#91;&#93;
                    :return      Long
                    :body-params &#91;user :- User&#93;
                    :summary     &quot;creates a new user record.&quot;
                    &#40;ok &#40;db/create-user-account! user &#40;:db config&#41;&#41;&#41;&#41;
             
             &#40;DELETE&#42; &quot;/user&quot;    &#91;&#93;
                    :return      Long
                    :body-params &#91;id :- String&#93;
                    :summary     &quot;deletes the user record with the given id.&quot;
                    &#40;ok &#40;db/delete-user! {:id id} &#40;:db config&#41;&#41;&#41;&#41;&#41;&#41;&#41;
</code></pre><p>Notice that we call <code>ring.swagger.ui/swagger-ui</code> and <code>swagger-docs</code> at the beginning of the definition of <code>api</code>. This will automatically produce the API documentation for the service operations defined within it. Once our service is hooked up, we'll be able to navigate to <code>localhost:3000/swagger-ui</code> and see an interactive page for testing the API endpoints.</p><p>As you may have noticed, <code>compojure-api</code> mimics Compojure route definitions with the difference that the route method name has a <code>&#42;</code> after it. The route definition also has some additional keys associated with it.</p><ul><li>the <code>:return</code> key specifies the return type for the service operation</li><li>the <code>:summary</code> key provides the documentation about the purpose of the operation</li><li>the parameters are specified using different keys depending on the parameter type, such as <code>:path-params</code> and <code>:body-params</code>.</li></ul><p>Finally, each route will return a response type with the result of calling the handler associated with it.</p><p>If we look at the <code>&quot;/users&quot;</code> route we see that it calls the <code>get-users</code> function from the database and passes it the value of the <code>:db</code> key from the config. This will be used to resolve the database connection at runtime.</p><h3 id="adding&#95;the&#95;endpoint&#95;to&#95;the&#95;system">Adding the Endpoint to the System</h3><p>With the route added we can now navigate back to the <code>swagger-service.system</code> namespace and add the component there:</p><pre><code class="clojure">&#40;ns swagger-service.system
 &#40;:require ...
           &#91;swagger-service.component.db :refer &#91;db-component&#93;&#93;
           &#91;swagger-service.endpoint.service :refer &#91;service-endpoint&#93;&#93;&#41;&#41;
           
...

&#40;defn new-system &#91;config&#93;
 &#40;let &#91;config &#40;meta-merge base-config config&#41;&#93;
   &#40;-&gt; &#40;component/system-map
        :db      &#40;db-component &#40;:db config&#41;&#41;
        :app     &#40;handler-component &#40;:app config&#41;&#41;
        :http    &#40;jetty-server &#40;:http config&#41;&#41;
        :example &#40;endpoint-component example-endpoint&#41;
        :service &#40;endpoint-component service-endpoint&#41;&#41;
       &#40;component/system-using
        {:http &#91;:app&#93;
         :app  &#91;:example :service&#93;
         :service &#91;:db&#93;
         :example &#91;&#93;          
         :db &#91;&#93;}&#41;&#41;&#41;&#41;            
</code></pre><p>The service component is initialized using the <code>endpoint-component</code> Duct helper. Next, the component relationships have to be described explicitly. We can see that the <code>:service</code> component depends on the <code>:db</code> component, and the <code>:app</code> in turn depends on both the <code>:example</code> and the <code>:service</code>.</p><p>We can now restart our app and navigate to <code>localhost:3000/swagger-ui</code> to see the service test page. Using this page we can test all the service operations that we defined such as creating new users, authenticating, and listing users.</p><p>The full source for this tutorial is available on <a href='https://github.com/yogthos/swagger-service'>GitHub</a>.</p><h3 id="conclusion">Conclusion</h3><p>As you can see, <code>compojure-api</code> allows us to easily define RESTful services with type assertions, documentation, and a helpful test page. I've found this approach to be extremely effective when creating service APIs as it documents what each endpoint is doing and makes it easy to collaborate with consumers of the service. Meanwhile, Duct provides an excellent base for building services using the component pattern.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Setting up a Docker-based MEAN development environment</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">25 07 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A common problem for any developer is setting up your development environment for working on multiple projects. By nature, different projects will run different software stacks, and so each piece of the stack needs to be installed and managed. This can get messy when the number of projects increases, and especially when revisiting older projects that were coded against an older version of the stack.
For this reason, it&rsquo;s a good idea to try and segregate your dev environment for each project.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Setting up a Docker-based MEAN development environment</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">25 07 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A common problem for any developer is setting up your development environment for working on multiple projects. By nature, different projects will run different software stacks, and so each piece of the stack needs to be installed and managed. This can get messy when the number of projects increases, and especially when revisiting older projects that were coded against an older version of the stack.
For this reason, it&rsquo;s a good idea to try and segregate your dev environment for each project.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Luminus is Moving -&gt; HTTP Kit -&gt; Immutant</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">11 07 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                         <h2 id="update">Update</h2><p>After having some discussions with the author of HTTP Kit and doing a deeper evaluation of Immutant I'm switching to it as the default.</p><p>It turns out that Immutant addresses all of the concerns as well as HTTP Kit while having the benefit of a larger team maintaining it.</p><p>The version 2 of Immutant is modular and provides a minimal runtime that has low overhead. The websocket support works similarly to HTTP Kit and is now documented as well. Unlike Jetty 9 adapters with websocket support, Immutant builds do not require JRE 8 to run.</p><p>Finally, Immutant provides many useful pluggable libraries for caching, message queues, and scheduling.</p><h2 id="end&#95;update">End Update</h2> <p>One of the guiding principles for Luminus has been to provide a great user experience out of the box. Having to go through a tedious setup before you can focus on the problem you actually want to solve should be unnecessary.</p><p>Luminus removes the burden or having to find the libraries, configure middleware, and add the common boilerplate. The application generated by the template is ready for  deployment out of the box. The only part that's missing is the domain logic for your application.</p><p>As the project evolves I'm always looking for new ways to streamline user experience. Clojure web ecosystem is rapidly evolving along with the best practices and tools. Luminus aims to keep abreast of these changes and to provide a reference implementation for Ring based applications.</p><p>Recently, Luminus moved to using <a href='https://github.com/yogthos/migratus'>Migratus</a> for handling database migrations for reasons discussed in <a href='http://yogthos.net/posts/2015-06-29-Luminus-Migratus.html'>this</a> post. This time we'll look at the reasons for moving to HTTP Kit as the default server.</p><p>Up to now, Luminus applications would use the version of Jetty packaged by the Ring dependency. The major drawback of the default Jetty adapter is its lack of support for websockets. After evaluating the alternatives I settled on HTTP Kit as the default server for Luminus.</p><p>HTTP Kit is built on top of <a href='https://en.wikipedia.org/wiki/Non-blocking_I/O_(Java&#41;'>NIO</a>. It combines <a href='https://github.com/ptaoussanis/clojure-web-server-benchmarks'>high performance</a> when handling a large number of connections with <a href='http://www.http-kit.org/600k-concurrent-connection-http-kit.html'>low memory overhead</a> per connection. Finally, it provides a Ring/Compojure compatible API for working with <a href='https://en.wikipedia.org/wiki/WebSocket'>websockets</a> that's now <a href='http://www.luminusweb.net/docs/websockets.md'>part</a> of the official Luminus documentation.</p><p>While HTTP Kit is the default, all the major HTTP servers are supported via their respective flags:</p><ul><li><code>+alpeh</code> - <a href='https://github.com/ztellman/aleph'>Aleph</a> is a stream based server built on top of Netty</li><li><code>+immutant</code> - <a href='http://immutant.org/'>Immutant</a> is a <a href='http://www.jboss.org/'>JBoss</a> based server with many built in features such as messaging, scheduling and caching</li><li><code>+jetty</code> - <a href='https://github.com/mpenet/jet'>Jet</a> is the Ring Jetty adapter with websocket support</li></ul><p>Another major change is that the <a href='https://github.com/weavejester/lein-ring'>lein-ring</a> plugin is no longer used by default. Since the plugin is based on the Jetty based <a href='https://github.com/weavejester/ring-server'>ring-server</a> library, a separate workflow was required for the alternative HTTP servers.</p><p>Instead, the template now provides its own <code>core</code> namespace that manages the server lifecycle. This provides a consistent experience regardless of the server being used. The <code>lein-ring</code> plugin is now part of the <code>+war</code> profile used to generate server independent WAR archives for deployment to application servers such as <a href='http://tomcat.apache.org/'>Apache Tomcat</a>.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Data Focused</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">07 07 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>One interesting part I noticed about working with Clojure is that I practically never look for solutions to problems on Google or StackOverflow. I might google to see if a library exists for accomplishing a particular task, but I rarely end up having to google how to do a specific task.</p><p>This got me thinking about why that may be since I used to do that commonly back when I worked with Java. I think the key reason is that Clojure encourages writing code that operates on plain data.</p><h3 id="object&#95;oriented&#95;approach">Object Oriented Approach</h3><p>Object oriented languages, such as Java, encourage encapsulating the data in domain specific abstractions. Rich Hickey discusses this in detail in his excellent <a href='https://www.youtube.com/watch?v=VSdnJDO-xdg'>Clojure, Made Simple</a> talk. The OO approach ultimately leads to creation of frameworks that provide formalized ways to tie all the different domain abstractions together.</p><p>The problem with frameworks is that they impose a particular workflow on the user. However, in most cases there are many valid ways to solve a particular problem. The approach that the framework takes is just one way to do things and not necessarily the best way. If you happen to think about a problem differently from the authors of the framework then using it will not feel intuitive.</p><p>When you encounter a problem then you either have to spend the time to understand the internals of the framework and its design or simply memorize how different tasks are accomplished.</p><p>Understanding the internals of a complex piece of software is an arduous process that can take a long time and it's often time that you do not have. Conversely, having to understand the internals typically indicates that the abstraction you're working with is a leaky one.</p><p>This is where googling comes in. You know what your problem is, you know how you would solve it given the time, but you don't know how the authors of the framework expect you to solve it using their approach.</p><p>Since the choice of the solution completely arbitrary, there's no way for you to logically deduce what it is. In many cases the only realistic option is to hope that someone else ran into a similar problem already and see how they solved it within the context of the framework.</p><h3 id="data&#95;centric&#95;approach">Data Centric Approach</h3><p>Clojure takes the approach of keeping the data and logic separate. Instead of building local abstractions for each domain as we do with objects, all the functions operate on a common set of data structures. When a function is called its output can be used in a new context without any additional ceremony.</p><p>Since all Clojure libraries use the same core data structures, it's trivial to take the output of one library and pass it as input to another. Using the REPL we can quickly see how a particular library behaves and what output it generates.</p><p>This approach allows the user to find the libraries that fit the problem they're solving and then compose them in the way that makes sense in their particular scenario. The same core pattern of composing data transformations can be applied at different resolutions within a project.</p><p>At the lowest level we have functions as our building blocks. We combine these in different ways to transform the data on the small scale.</p><p>Once we have a number of related functions that represent a particular domain we combine them into a namespace, and then we pass the data between the namespaces to move data from one domain to another.</p><p>Libraries are simply collections of namespaces, and we use the same pattern when  transform the data by combining them. A great example of this would be the <a href='https://github.com/ring-clojure/ring-defaults/blob/3dca3756a33892f607c45bc4eb582796e4997dd9/src/ring/middleware/defaults.clj#L90'>ring-defaults</a> library that chains a number libraries to achieve complex transformations of HTTP requests and responses.</p><p>Finally, at the top level we may have multiple projects passing data between each other in form of services. This approach is becoming increasingly popular in the industry as seen with the micro-services movement.</p><p>With Clojure, the focus is always on the data. When solving a problem, all we have to do is figure out how we need to transform the data and then find the appropriate building blocks for our problem.</p><p>Focusing on the data helps keep code simple and reusable without introducing unnecessary indirection into the process. I think this is the key reason why it's possible to work with Clojure without having to constantly memorize new patterns to solve different kinds problems.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure 1.7 is now available</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">30 06 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>We are pleased to announce the release of Clojure 1.7. The two headline features for 1.7 are transducers and reader conditionals. Also see the <a href="https://github.com/clojure/clojure/blob/master/changes.md">complete list</a> of all changes since Clojure 1.6 for more details.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_transducers"><a class="anchor" href="#_transducers"></a>Transducers</h2>
<div class="sectionbody">
<div class="paragraph">
<p><a href="xref/../../../../../../reference/transducers">Transducers</a> are composable algorithmic transformations. They are independent from the context of their input and output sources and specify only the essence of the transformation in terms of an individual element. Because transducers are decoupled from input or output sources, they can be used in many different processes - collections, streams, channels, observables, etc. Transducers compose directly, without awareness of input or creation of intermediate aggregates.</p>
</div>
<div class="paragraph">
<p>Many existing sequence functions now have a new arity (one fewer argument than before). This arity will return a transducer that represents the same logic but is independent of lazy sequence processing. Functions included are: map, mapcat, filter, remove, take, take-while, drop, drop-while, take-nth, replace, partition-by, partition-all, keep, keep-indexed, map-indexed, distinct, and interpose. Additionally some new transducer functions have been added: cat, dedupe, and random-sample.</p>
</div>
<div class="paragraph">
<p>Transducers can be used in several new or existing contexts:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>into - to collect the results of applying a transducer</p>
</li>
<li>
<p>sequence - to incrementally compute the result of a transducer</p>
</li>
<li>
<p>transduce - to immediately compute the result of a transducer</p>
</li>
<li>
<p>eduction - to delay computation and recompute each time</p>
</li>
<li>
<p>core.async - to apply a transducer while values traverse a channel</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_portable_clojure_and_reader_conditionals"><a class="anchor" href="#_portable_clojure_and_reader_conditionals"></a>Portable Clojure and Reader Conditionals</h2>
<div class="sectionbody">
<div class="paragraph">
<p>It is now common to see a library or application targeting multiple Clojure platforms with a single codebase. Clojure 1.7 introduces a new extension (.cljc) for files that can be loaded by Clojure and ClojureScript (and other Clojure platforms).</p>
</div>
<div class="paragraph">
<p>There will often be some parts of the code that vary between platforms. The primary mechanism for dealing with platform-specific code is to isolate that code into a minimal set of namespaces and then provide platform-specific versions (.clj/.class or .cljs) of those namespaces.</p>
</div>
<div class="paragraph">
<p>To support cases where is not feasible to isolate the varying parts of the code, or where the code is mostly portable with only small platform-specific parts, 1.7 provides <a href="xref/../../../../../../reference/reader#_reader_conditionals">Reader Conditionals</a>.</p>
</div>
<div class="paragraph">
<p>Reader conditionals are a new reader form that is only allowed in portable cljc files. A reader conditional expression is similar to a cond in that it specifies alternating platform identifiers and expressions. Each platform is checked in turn until a match is found and the expression is read. All expressions not selected are read but skipped. A final :default fallthrough can be provided. If no expressions are matched, the reader conditional will read nothing. The reader conditional splicing form takes a sequential expression and splices the result into the surrounding code.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_contributors"><a class="anchor" href="#_contributors"></a>Contributors</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Thanks to all of those who contributed patches to Clojure 1.7:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Timothy Baldridge</p>
</li>
<li>
<p>Bozhidar Batsov</p>
</li>
<li>
<p>Brandon Bloom</p>
</li>
<li>
<p>Michael Blume</p>
</li>
<li>
<p>Ambrose Bonnaire-Sergeant</p>
</li>
<li>
<p>Aaron Cohen</p>
</li>
<li>
<p>Pepijn de Vos</p>
</li>
<li>
<p>Andy Fingerhut</p>
</li>
<li>
<p>Gary Fredricks</p>
</li>
<li>
<p>Daniel Solano Gómez</p>
</li>
<li>
<p>Stuart Halloway</p>
</li>
<li>
<p>Rich Hickey</p>
</li>
<li>
<p>Immo Heikkinen</p>
</li>
<li>
<p>Andrei Kleschinsky</p>
</li>
<li>
<p>Howard Lewis Ship</p>
</li>
<li>
<p>Alex Miller</p>
</li>
<li>
<p>Steve Miner</p>
</li>
<li>
<p>Nicola Mometto</p>
</li>
<li>
<p>Tomasz Nurkiewicz</p>
</li>
<li>
<p>Ghadi Shayban</p>
</li>
<li>
<p>Paul Stadig</p>
</li>
<li>
<p>Zach Tellman</p>
</li>
<li>
<p>Luke VanderHart</p>
</li>
<li>
<p>Jozef Wagner</p>
</li>
<li>
<p>Devin Walters</p>
</li>
<li>
<p>Jason Wolfe</p>
</li>
<li>
<p>Steven Yi</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Also, continued thanks to the total list of contributors from all releases.</p>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Luminus is Migrating to Migratus</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">29 06 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                         <p>There was a recent discussion on <a href='https://groups.google.com/forum/#!topic/luminusweb/rRJYbyUOKAY'>google groups</a> regarding migrations and handling of database credentials in Luminus. Up to now, Luminus would generate a template where the database credentials were hardcoded in the <code>&lt;app&gt;.db.core</code> namespace and migrations were handled by the <a href='https://github.com/weavejester/ragtime/tree/0.3/ragtime.lein'>ragtime.lein</a> plugin.</p><p>This was not ideal for a couple of reasons. First, the hardcoded credentials aren't great for any serious applications. The credentials end up being checked in the code repository and have to be manually updated for each environment the application runs in. Second, you end up with separate sets of database configuration for the application and for the plugin. This is error prone as it puts the burden on the user to keep the credentials in sync.</p><p>The proposed approach was to use the <code>profiles.clj</code> instead to keep a single set of credentials for development. The production credentials would then be supplied using environment variables. This is a much cleaner approach to handling credentials as they're no longer part of the code and can be configured in a single place.  </p><p>In the meantime, Ragtime had a new major version release <a href='https://github.com/weavejester/ragtime'>0.4.0</a> that introduces a number of changes. Ragtime is moving away from using a Leiningen plugin, and instead recommends <a href='https://github.com/weavejester/ragtime/wiki/Leiningen-Integration'>running the commands from the REPL</a>. The other major change is that it<a href='https://github.com/weavejester/ragtime/wiki/SQL-Migrations#sql'> no longer allows multiple statements  in a single migrations file</a>.  </p><p> The rationale here is that different SQL databases have different restrictions on the commands that can be sent in a single message. Therefore using a heuristic to split up migrations isn't guaranteed to work correctly across different database engines.  </p><p> While this is true, in my view it also results in subpar user experience. While it's ok for trivial migrations, such as the ones seen in the examples, it doesn't scale well for larger ones. I think that there is a lot of value in being able to see the entirety of a migration in a single place without having to jump across multiple files.  </p><p> <strong>update:</strong> Since the writing of the post, Ragtime has <a href='https://github.com/weavejester/ragtime/commit/eea75fcfc1a6d51c28bfb9dc58540a842f2111d5'>added</a> the ability to use a custom separator, so it should be available in the next release.  </p><p>At this point I decided to see what other migrations libraries were available and to evaluate if any of them would be a good fit for the workflow that Luminus aims to provide. The one I settled on was <a href='https://github.com/pjstadig/migratus'>Migratus</a>. It provides a workflow that's nearly identical to the original Ragtime based one that Luminus used.</p><p>Migrtus elegantly addresses the problem of splitting up statements by using a custom separator <code>--;;</code> to identify individual statements within the file. This removes the ambiguity of having to infer where one statement ends and another begins without forcing the user to split their migrations into multiple files.</p><p>Unfortunately, Migratus has not been maintained for the past two years and relied on a deprecated version of the <code>clojure.java.jdbc</code> library. Since Migratus already works well and it's a relatively simple library I decided to see if I could bring it up to date.</p><p>This turned out to be a relatively painless process and I ended up making some minor changes and improvements along the way. I contacted Paul Stadig, who is the author of the library, and he graciously agreed to transfer the ownership as he's no longer planning on developing it himself. I've released the updated library to Clojars and the latest version of Luminus uses Migratus to handle migrations.</p><p>As I mentioned earlier, using a Leiningen plugin to handle dev migrations requires dupliction of credentials. Instead, Luminus now provides an <code>&lt;app&gt;.db.migrations</code> namespace that manages migrations. This namespace is invoked from the <code>&lt;app&gt;.core/-main</code> when it's passed in <code>migrate</code> or <code>rollback</code> arguments. These arguments can be optionally followed by the migration ids in order to apply specific migrations. So, when previously you would run <code>lein ragtime migrate</code>, you'd now run <code>lein run migrate</code> to apply migrations.</p><p>Since this code is now part of the project it can now be run from the packaged <code>uberjar</code> as well. This allows the application to run its migrations on the server without necessitating a separate process for migrating the production database. Complete migrations documentation is available on <a href='http://www.luminusweb.net/docs/migrations.md'>the offical Luminus site</a>.</p><p>Having a straight forward way to run migrations and store credentials securely, taking into account production environments, is an important aspect of providing a solid base for developing web applications.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Using Pulsar</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">17 06 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>In this post, we'll take a look at a basic usage example for Pulsar and see how to package it for production.</p><h3 id="what&#95;is&#95;pulsar?">What is Pulsar?</h3><p><a href='http://docs.paralleluniverse.co/pulsar/'>Pulsar</a> is the official Clojure API for the <a href='http://www.paralleluniverse.co/quasar/'>Quasar</a> library that provides lightweight green threads and Erlang style actors for the JVM.</p><p>Quasar has a lot of similarities to the popular <a href='http://akka.io/'>Akka framewok</a>, but has the advantage of being a library as opposed to a framework that imposes its own workflow. For those interested, a detailed comparison of Quasar and Akka is availble <a href='http://blog.paralleluniverse.co/2015/05/21/quasar-vs-akka/'>here</a>.</p><p>Using Pulsar is very straight forward, however there are a few caveats to be aware of when it comes to packaging it for production. Quasar requires bytecode instrumentation in order to provide suspendanble functions, and this means that the <code>project.clj</code> needs to have additional hints to facilitate it. </p><h3 id="creating&#95;the&#95;project">Creating the Project</h3><p>Let's start by creating a new project called <code>pulsar-example</code>:</p><pre><code>lein new pulsar-example
</code></pre><p>Next, we'll add the following dependencies to the <code>project.clj</code> file:</p><pre><code class="clojure">&#91;co.paralleluniverse/pulsar &quot;0.7.2&quot;&#93;
&#91;co.paralleluniverse/quasar-core &quot;0.7.2&quot;&#93;
</code></pre><p>We'll also have to add a <code>:java-agents</code> key that will invoke the Quasar agent responsible for the instrumentation:</p><pre><code class="clojure">:java-agents &#91;&#91;co.paralleluniverse/quasar-core &quot;0.7.2&quot;&#93;&#93;
</code></pre><h3 id="adding&#95;actors">Adding Actors</h3><p>Let's open up the <code>pulsar-example.core</code> namespace and update the <code>ns</code> declaration as follows:</p><pre><code class="clojure">&#40;ns pulsar-example.core
  &#40;:require
   &#91;co.paralleluniverse.pulsar
    &#91;core :refer :all&#93;
    &#91;actors :refer :all&#93;&#93;&#41;
  &#40;:refer-clojure :exclude &#91;promise await&#93;&#41;
  &#40;:gen-class&#41;&#41;
</code></pre><p>We'll implement <a href='https://github.com/puniverse/pulsar/blob/master/src/test/clojure/co/paralleluniverse/pulsar/examples/pingpong.clj'>one of the official examples</a> where two actors send messages to one another. In the example we have two functions called <code>ping</code> and <code>pong</code>. These are defined using the <code>defsfn</code> macro as opposed to regular <code>defn</code>. This is necessary in order for these functions to be suspendable.</p><p>The <code>ping</code> function will accept two parameters consisting of the number representing remaining iterations and the actor to send messages to.</p><p>The function checks if there are remaining iterations and notfies <code>pong</code> that the conversation is complete when <code>n</code> is zero. Otherwise, it sends a ping message to the <code>pong</code> actor and waits to receive an acknowledgement before recurring. As you may have guessed, the <code>receive</code> call will block until a message is received.</p><p>The <code>@self</code> notation is used to access the actor itself. This is needed to pass it to the other actor as part of the message in order to receive a response.</p><pre><code class="clojure">&#40;defsfn ping &#91;n pong&#93;
  &#40;if &#40;== n 0&#41;
    &#40;do
      &#40;! pong :finished&#41;
      &#40;println &quot;ping finished&quot;&#41;&#41;
    &#40;do
      &#40;! pong &#91;:ping @self&#93;&#41;
      &#40;receive
        :pong &#40;println &quot;Ping received pong&quot;&#41;&#41;
      &#40;recur &#40;dec n&#41; pong&#41;&#41;&#41;&#41;
</code></pre><p>Meanwhile, the <code>pong</code> function will wait to receive a message, if the message is <code>:finished</code> then it finishes its run, and if it matches <code>&#91;:ping ping&#93;</code> then it will return the message <code>:ping</code> to the caller and recur:</p><pre><code class="clojure">&#40;defsfn pong &#91;&#93;
  &#40;receive
    :finished &#40;println &quot;Pong finished&quot;&#41;
    &#91;:ping ping&#93; &#40;do
                   &#40;println &quot;Pong received ping&quot;&#41;
                   &#40;! ping :pong&#41;
                   &#40;recur&#41;&#41;&#41;&#41;
</code></pre><p>Note that the message can either be a keyword or a vector containing the parameters we wish to pass to the actor. Finally, we'll add a <code>-main</code> function as the entry point to our program. Note that we <code>join</code> our actors to ensure that the application keeps running until the actors exit.</p><pre><code class="clojure">&#40;defn -main &#91;&#93;
  &#40;let &#91;a1 &#40;spawn pong&#41;
        b1 &#40;spawn ping 3 a1&#41;&#93;
    &#40;join a1&#41;
    &#40;join b1&#41;
    :ok&#41;&#41;
</code></pre><p>We can now test that everything is working by running it from the REPL or using <code>lein run</code>.</p><h3 id="packaging&#95;for&#95;deployment">Packaging for Deployment</h3><p>Once we're ready to package our app for deployment we need to make sure that the Quasar agent can be run to instrument our suspendable functions. To do that we'll have to add a <code>:manifest</code> key to our project that points to the following configuration:</p><pre><code class="clojure">:manifest
 {&quot;Premain-Class&quot; &quot;co.paralleluniverse.fibers.instrument.JavaAgent&quot;
  &quot;Agent-Class&quot; &quot;co.paralleluniverse.fibers.instrument.JavaAgent&quot;
  &quot;Can-Retransform-Classes&quot; &quot;true&quot;
  &quot;Can-Redefine-Classes&quot; &quot;true&quot;}
</code></pre><p>This will be written out to the <code>META-INF/MANIFEST.MF</code> file in the jar and provide the necessary information about the agent. The project can now be packaged by running <code>lein uberjar</code>. One final thing to be aware of is that the resulting jar must be run with the <code>-javaagent</code> flag as follows:</p><pre><code>java -javaagent:target/pulsar-example.jar -jar target/pulsar-example.jar
</code></pre><p>This is all that needs to be done in order to package and run Pulsar projects using Leiningen. As always, the complete source for the example is available <a href='https://github.com/yogthos/pulsar-example'>on GitHub</a>.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">ClojureScript REPL with Figwheel</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">16 06 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <h4 id="update:&#95;figwheel&#95;changed&#95;recently&#95;and&#95;the&#95;new&#95;process&#95;of&#95;starting&#95;the&#95;repl&#95;is&#95;documented&#95;on&#95;the&#95;<a href='https://github.com/bhauman/lein-figwheel/wiki'>official Wiki</a>.">update: Figwheel changed recently and the new process of starting the REPL is documented on the <a href='https://github.com/bhauman/lein-figwheel/wiki'>official Wiki</a>.</h4><p>Figwheel provides a fantastic developer experience and if you're not using it already I highly encourage you to give it a shot. I found that in most cases live code reloading is sufficient for my workflow, but there are occasions where I do want to have an actual REPL available.</p><p>This mostly comes up when I'm working with code that's not directly tied to rendering UI components and it can quickly devolve into <code>println</code> debugging.</p><p>You probably noticed that Figwheel starts a REPL in the terminal when it runs. However, this REPL is not terribly useful in practice. What would be better is to have a REPL that's connected to the editor, such as Cursive or Emacs, so that you can evaluate the code you're working on the same way you would with Clojure.</p><p>Luckily, getting this to work turns out to be a pretty simple affair. First thing we need to do is to make sure that the Figwheel config in <code>project.clj</code> has the <code>:nrepl-port</code> key set as seen below:</p><pre><code class="clojure">:figwheel
{:http-server-root &quot;public&quot;
 :server-port 3449
 :nrepl-port 7002 ;;start nREPL on port 7002
 :css-dirs &#91;&quot;resources/public/css&quot;&#93;
 :ring-handler yourapp/handler}
</code></pre><p>When you run <code>lein figwheel</code> the nREPL server will become available and you can connect your editor to it at <code>localhost:7002</code>, or whatever port you've specifcied. Once the nREPL is connected you'll have to run the following commands there:</p><pre><code class="clojure">user&gt; &#40;use 'figwheel-sidecar.repl-api&#41;
user&gt; &#40;cljs-repl&#41;
</code></pre><p>You should see the Figwheel REPL start up the same way it did when you ran <code>lein figwheel</code> in the terminal. You should now be able to send any code from the editor to the REPL for evaluation.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Websockets with HTTP Kit</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">11 06 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>In this post we'll look at working with websocks using Reagent and HTTP Kit. We'll see how to create a multi-user chat server that allows multiple clients to communicate with one another.</p><p>First thing to mention is that there are a couple of Clojure/Script libraries for working with websockets, such as <a href='https://github.com/ptaoussanis/sente'>Sente</a> and <a href='https://github.com/james-henderson/chord'>Chord</a>. However, what I'd like to illustrate is that using websockets directly from ClojureScript is extremely straight forward. Let's start by creating a new Luminus project that we'll use as the base for our example. We'll create the project using the <code>+http-kit</code> profile:</p><pre><code>lein new luminus multi-client-ws +http-kit +cljs
</code></pre><p>Once the application is created we'll need to startup the server and Figwheel. To do that, we'll need to run the following commands in separate terminals.</p><pre><code>lein run
</code></pre><pre><code>lein figwheel
</code></pre><h3 id="the&#95;server">The Server</h3><p>Let's create a new namespace called <code>multi-client-ws.routes.websockets</code> and add the following references there:</p><pre><code>
&#40;ns multi-client-ws.routes.websockets
 &#40;:require &#91;compojure.core :refer &#91;GET defroutes&#93;&#93;
           &#91;org.httpkit.server
            :refer &#91;send! with-channel on-close on-receive&#93;&#93;
           &#91;cognitect.transit :as t&#93;
           &#91;taoensso.timbre :as timbre&#93;&#41;&#41;
</code></pre><p>Next, we'll create a Compojure route for our websocket handler:</p><pre><code class="clojure">&#40;defroutes websocket-routes
 &#40;GET &quot;/ws&quot; request &#40;ws-handler request&#41;&#41;&#41;
</code></pre><p>Where the <code>ws-handler</code> function will look as follows:</p><pre><code class="clojure">&#40;defn ws-handler &#91;request&#93;
 &#40;with-channel request channel
               &#40;connect! channel&#41;
               &#40;on-close channel &#40;partial disconnect! channel&#41;&#41;
               &#40;on-receive channel #&#40;notify-clients %&#41;&#41;&#41;&#41;
</code></pre><p>The function accepts the request and passes it to the <code>org.httpkit.server/with-channel</code> macro provided by the HTTP Kit API. The macro creates accepts the request as its argument and binds the value of the <code>:async-channel</code> key to the second paramets representing the name of the channel. The statement following the channel name will be called once when the channel is created. In our case we'll call the <code>connect!</code> function defined below any time a new client connects:</p><pre><code class="clojure">&#40;defonce channels &#40;atom #{}&#41;&#41;

&#40;defn connect! &#91;channel&#93;
 &#40;timbre/info &quot;channel open&quot;&#41;
 &#40;swap! channels conj channel&#41;&#41;
</code></pre><p>The function will log that a new channel was opened and add the channel to the set of open channels defined above.</p><p>When the client disconnects the <code>on-close</code> function will be called. This function accepts the channel along with a handler. The handler should accept the channel and the disconnect status. Our handler will log that the channel disconnected and remove it from the set of open channels.</p><pre><code class="clojure">&#40;defn disconnect! &#91;channel status&#93;
 &#40;timbre/info &quot;channel closed:&quot; status&#41;
 &#40;swap! channels #&#40;remove #{channel} %&#41;&#41;&#41;
</code></pre><p>Finally, we have the <code>on-receive</code> function that's called any time a client message is received. We'll pass it the <code>notify-clients</code> function as the handler. This function will broadcast the message to all the connected clients.</p><pre><code class="clojure">&#40;defn notify-clients &#91;msg&#93;
 &#40;doseq &#91;channel @channels&#93;
     &#40;send! channel msg&#41;&#41;&#41;
</code></pre><p>That's all we need to do to manage the lifecycle of the websocket connections and to handle client communication.</p><p>Next, We'll need to add the routes in our <code>multi-client-ws.handler</code> namespace:</p><pre><code class="clojure">&#40;def app
 &#40;-&gt; &#40;routes
       websocket-routes
       &#40;wrap-routes home-routes middleware/wrap-csrf&#41;
       base-routes&#41;
     middleware/wrap-base&#41;&#41;
</code></pre><p>We will also have to update our <code>multi-client-ws.middleware/wrap-base</code> middleware wrapper to remove the <code>wrap-formats</code> middleware as it conflicts with handling websocket requests.</p><h3 id="the&#95;client">The Client</h3><p>We'll start by creating a <code>multi-client-ws.websockets</code> in the <code>src-cljs/multi&#95;client&#95;ws</code> folder. The namespace will require the transit library:</p><pre><code class="clojure">&#40;ns multi-client-ws.websockets
 &#40;:require &#91;cognitect.transit :as t&#93;&#41;&#41;
</code></pre><p>Next, we'll define an atom to hold our websocket channel and a couple of helpers for reading and writing the JSON encoded transit messages.</p><pre><code class="clojure">&#40;defonce ws-chan &#40;atom nil&#41;&#41;
&#40;def json-reader &#40;t/reader :json&#41;&#41;
&#40;def json-writer &#40;t/writer :json&#41;&#41;
</code></pre><p>We'll now create a function to handle received messages. The function will accept the callback handler and return a function that decodes the transit message and passes it to the handler:</p><pre><code class="clojure">&#40;defn receive-transit-msg!
 &#91;update-fn&#93;
 &#40;fn &#91;msg&#93;
   &#40;update-fn
     &#40;-&gt;&gt; msg .-data &#40;t/read json-reader&#41;&#41;&#41;&#41;&#41;
</code></pre><p>We'll also create a function that sends messages to the socket if it's open:</p><pre><code class="clojure">&#40;defn send-transit-msg!
 &#91;msg&#93;
 &#40;if @ws-chan
   &#40;.send @ws-chan &#40;t/write json-writer msg&#41;&#41;
   &#40;throw &#40;js/Error. &quot;Websocket is not available!&quot;&#41;&#41;&#41;&#41;
</code></pre><p>Finally, we'll add a function to create a new websocket given the URL and the received message handler:</p><pre><code class="clojure">&#40;defn make-websocket! &#91;url receive-handler&#93;
 &#40;println &quot;attempting to connect websocket&quot;&#41;
 &#40;if-let &#91;chan &#40;js/WebSocket. url&#41;&#93;
   &#40;do
     &#40;set! &#40;.-onmessage chan&#41; &#40;receive-transit-msg! receive-handler&#41;&#41;
     &#40;reset! ws-chan chan&#41;
     &#40;println &quot;Websocket connection established with: &quot; url&#41;&#41;
   &#40;throw &#40;js/Error. &quot;Websocket connection failed!&quot;&#41;&#41;&#41;&#41;
</code></pre><h3 id="the&#95;ui">The UI</h3><p>We'll now navigate to the <code>multi-client-ws.core</code> namespace and remove the code that's already there. We'll set the <code>ns</code> definition to the following:</p><pre><code class="clojure">&#40;ns multi-client-ws.core
 &#40;:require &#91;reagent.core :as reagent :refer &#91;atom&#93;&#93;
           &#91;multi-client-ws.websockets :as ws&#93;&#41;&#41;
</code></pre><p>Next, we'll create an atom to keep a list of messages and a Reagent component that renders it:</p><pre><code class="clojure">&#40;defonce messages &#40;atom &#91;&#93;&#41;&#41;

&#40;defn message-list &#91;&#93;
 &#91;:ul
  &#40;for &#91;&#91;i message&#93; &#40;map-indexed vector @messages&#41;&#93;
    &#94;{:key i}
    &#91;:li message&#93;&#41;&#93;&#41;
</code></pre><p>We'll now create a <code>message-input</code> component that will allow us to type in a message and send it to the server. This component creates a local atom to keep track of the message being typed in and sends the message to the server when the <code>enter</code> key is pressed.</p><pre><code class="clojure">&#40;defn message-input &#91;&#93;
 &#40;let &#91;value &#40;atom nil&#41;&#93;
   &#40;fn &#91;&#93;
     &#91;:input.form-control
      {:type :text
       :placeholder &quot;type in a message and press enter&quot;
       :value @value
       :on-change #&#40;reset! value &#40;-&gt; % .-target .-value&#41;&#41;
       :on-key-down
       #&#40;when &#40;= &#40;.-keyCode %&#41; 13&#41;
          &#40;ws/send-transit-msg!
           {:message @value}&#41;
          &#40;reset! value nil&#41;&#41;}&#93;&#41;&#41;&#41;
</code></pre><p>We can now create the <code>home-page</code> component that looks as follows:</p><pre><code class="clojure">&#40;defn home-page &#91;&#93;
 &#91;:div.container
  &#91;:div.row
   &#91;:div.col-md-12
    &#91;:h2 &quot;Welcome to chat&quot;&#93;&#93;&#93;
  &#91;:div.row
   &#91;:div.col-sm-6
    &#91;message-list&#93;&#93;&#93;
  &#91;:div.row
   &#91;:div.col-sm-6
    &#91;message-input&#93;&#93;&#93;&#93;&#41;
</code></pre><p>We'll also create an <code>update-messages!</code> function that will be used as the handler for the received messages. This function will append the new message and keep a buffer of 10 last received messages.</p><p>All that's left to do is mount the <code>home-page</code> component and create the websocket in the <code>init!</code> function:</p><pre><code class="clojure">&#40;defn mount-components &#91;&#93;
 &#40;reagent/render-component &#91;#'home-page&#93; &#40;.getElementById js/document &quot;app&quot;&#41;&#41;&#41;

&#40;defn init! &#91;&#93;
 &#40;ws/make-websocket! &#40;str &quot;ws://&quot; &#40;.-host js/location&#41; &quot;/ws&quot;&#41; update-messages!&#41;
 &#40;mount-components&#41;&#41;
</code></pre><p>We should now be able to open multiple browser windows and any messages typed in one window should show up in all the open windows.</p><h3 id="conclusion">Conclusion</h3><p>As you can see, it's very easy to setup basic client-server communication between HTTP Kit and ClojureScript. While you may wish to use one of the libraries mentioned earlier for more sophisticated apps, it's certainly not necessary in many cases. The complete source for the example can be found on <a href='https://github.com/luminus-framework/examples/tree/master/multi-client-ws-http-kit'>GitHub</a>.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">An Alternative to npm Private Modules</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">20 05 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Note: this article was written in May 2015. Much has changed since then, so the below may no longer be relevant. I will look to publish a revised post soon.
npm has recently unleashed private modules to world. This allows you to publish a node module to your own private registry, and install it via npm install as normal. I think this is a good move from npm, and with a price of only $7/user/month, it doesn&rsquo;t break the bank.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">An Alternative to npm Private Modules</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">20 05 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Note: this article was written in May 2015. Much has changed since then, so the below may no longer be relevant. I will look to publish a revised post soon.
npm has recently unleashed private modules to world. This allows you to publish a node module to your own private registry, and install it via npm install as normal. I think this is a good move from npm, and with a price of only $7/user/month, it doesn&rsquo;t break the bank.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Web Development with Clojure 2</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">14 04 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>First, I'd like to thank all those who purchased the first edition of the book. I was overwhelmed by the response from the readers, and exhilirated to learn that it helped many start developing their web applications using Clojure. I'm excited to announce that I'm working on the second edition of <a href='https://pragprog.com/book/dswdcloj/web-development-with-clojure'>Web Development with Clojure</a> and that I'm expecting to publish it sometime this summer.</p><h2 id="what&#95;to&#95;expect">What to Expect</h2><p>The main goal of the book is to provide a no-nonsense introduction to web development using Clojure. As such, I chose to cover tools and libraries that I consider to be beginner friendly.</p><p>Clojure web ecosystem has been steadily maturing since the release of the first edition. Last time I illustrated a number of approaches for putting applications together without recommending any one in particular over the others. This time around I'm primarily focusing on building application based on the  <a href='http://www.luminusweb.net/'>Luminus</a> stack. Luminus has recently seen <a href='http://yogthos.net/posts/2015-02-28-Luminus-2.0.html'>a major update</a> and continues to provide a solid foundation for building Clojure web applications according to best practices.</p><p>Clojure community favors using composable libraries over monolithic frameworks. This approach offers a number of advantages by giving the developer full control over the structure of the application the components used in it.</p><p>However, this approach works best for experienced developers who have a good understanding of the ecosystem and the available libraries. Having to develop this experience presents a significant barrier for newcomers. Luminus mitigates this issue by providing a batteries included template coupled with centralized documentation. This makes it a perfect foundation for a book aimed at beginners.</p><p>If you're familiar with the Clojure basics and you're looking to apply it for building web applications then this book is for you. The book aims to provide the reader with the understanding of the core ecosystem and the available tooling.</p><h2 id="what's&#95;new">What's New</h2><p>Those who are familiar with the first edition will find a number of changes and a number of new topics covered this time around.</p><p>At the time of writing of the first edition I felt that ClojureScript was not quite ready for general consumption. While some companies were already using it in production, the tooling around it was often challenging to use. As such, the book only gave it a very brief introduction and focused on traditional server side templating instead.</p><p>ClojureScript has matured greatly in the past year and the tooling is rapidly improving, while libraries such as Om and Reagent provide a clear benefit over using plain JavaScript. This time around ClojureScript is front and center with a primary focus on building single page apps using the Reagent library. I chose Reagent over Om for reasons I've discussed <a href='http://yogthos.net/posts/2014-07-15-Building-Single-Page-Apps-with-Reagent.html'>here</a>. In short, I find that it's much easier to learn and apply effectively. The main project in the book that guides the reader through developing a multi-user picture gallery application is now developed as a single page application using Reagent.</p><p>Another major change is that I no longer recommend using <a href='https://github.com/noir-clojure/lib-noir'>lib-noir</a> for developing new applications. While the library provides a number of helpers for achieving many common tasks found in typical web applications, it also introduces some problems inherent in its design. I've discussed some of these  in my <a href='http://yogthos.net/posts/2015-02-28-Luminus-2.0.html'>last post</a>. Today, there are excellent standalone libraries available for each of the tasks that <code>lib-noir</code> was used for and I recommend using these instead.</p><p>The database chapter has been updated to introduce the excellent <a href='https://github.com/krisajenkins/yesql'>Yesql</a> library and use the syntax of the latest version of <a href='https://github.com/clojure/java.jdbc'>clojure.java.jdbc</a>.</p><p>I’m now covering the use of the <a href='https://github.com/metosin/compojure-api'>compojure-api</a> library along side <a href='http://clojure-liberator.github.io/liberator/'>Liberator</a>. I’ve had an excellent experience using this library and I highly recommend trying it out if you haven’t already. The library uses <a href='https://github.com/Prismatic/schema'>Prismatic/schema</a>  to define the service API and allows automatic generation of interactive <a href='http://swagger.io/'>Swagger</a> documentation such as seen <a href='http://petstore.swagger.io/'>here</a>.</p><p>Finally, the book will provide more information on topics such as database migrations and deployment as part of addressing some of the feedback from the previous edition.</p><p>My hope is that the book will be useful to both new readers as well as those who purchased the first edition.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Announcing Luminus 2.0</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">28 02 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I'm excited to announce the release of Luminus 2.0. This release is a major update and introduces a number of changes to the framework. These changes reflect the evolution of the Clojure web stack and best practices over the past year.</p><p>The biggest change is that Luminus is no longer using <a href='https://github.com/noir-clojure/lib-noir'>lib-noir</a>, nor will I be actively developing the library going forward. I intend to continue maintaining it and to provide bug fixes, but I will not be working on additional features. If anybody is interested in taking it over then please leave a comment on GitHub in that regard.</p><p>I believe that lib-noir has served an important role providing many useful features such as input validation, access rules, session handling and so on. However, today there are great standalone libraries available for accomplishing each of these tasks. I believe that using simple and focused libraries leads to better overall user experience. The libraries that Luminus currently defaults to are as follows:</p><ul><li>access rules - <a href='https://github.com/funcool/buddy'>Buddy</a></li><li>cache  - <a href='https://github.com/clojure/core.cache'>core.cache</a></li><li>crypto - <a href='https://github.com/funcool/buddy'>Buddy</a></li><li>database - <a href='https://github.com/krisajenkins/yesql'>Yesql</a></li><li>sessions/cookies - <a href='https://github.com/ring-clojure/ring/wiki/Sessions'>Ring</a></li><li>validation - <a href='https://github.com/leonardoborges/bouncer'>Bouncer</a></li></ul><p>Session management is the biggest change from the user perspective. While lib-noir uses a request bound session that can be manipulated anywhere within the scope of the request, Ring requires sessions to be associated with the response explicitly by the handler.</p><p>While lib-noir approach is unquestionably convenient it introduces a subtle problem. Since the session is bound to a thread-local variable it's possible to run into race conditions with the in-memory session store. I feel that the Ring approach results in simpler design that’s more explicit about what it’s doing.</p><p>The new middleware stack is now based on  <a href='https://github.com/ring-clojure/ring-defaults'>ring-defaults</a> instead of the <code>app-handler</code> from lib-noir as Noir specific middleware is no longer required.</p><p>The move from Korma to Yesql is another major change. While Korma provides a nice DLS for working with SQL, I feel that the sheer simplicity of Yesql is preferable in the long run.</p><p>Meanwhile, Buddy is an exciting set of libraries for handling authorization, authentication, and access rules. It has an intuitive API and excellent documentation.</p><p>Bouncer is an excellent validation library that works with both Clojure and ClojureScript allowing for shared validation logic between the server and the client.</p><p>Some other changes include the <code>+cljs</code> profile updates for <a href='https://github.com/bhauman/lein-figwheel'>Figwheel</a> support and the deprecation of the <code>+site</code> profile. It's been replaced with the <code>+auth</code> profile  that sets up Buddy middleware for session based authentication instead.</p><p>As always, the framework primarily strives to remove the boilerplate from typical web projects and provide reasonable defaults. If you don’t agree with any of the library choices that it makes it’s trivial to swap them out with your own. The base profile is intentionally kept minimal to provide an unopinionated default.</p><p>The <a href='https://github.com/yogthos/luminus-template'>template project</a> for Luminus has been completely rewritten as well. The new template cleanly separates different profiles making it much easier to maintain and add new features.</p><p>Finally, all the documentation has been updated to reflect the changes with the original made available on <a href='https://github.com/yogthos/luminus/tree/master/resources/docs-1.x'>GitHub</a>.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Freelancing: Taking the Plunge</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">24 01 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        You&rsquo;re working as a full-time employee, slaving away for 40 hours per week. The job is secure, your pay is pretty decent and the work is moderately interesting, but you don&rsquo;t have much flexibility or freedom. All your friends are freelancers, regaling tales of £400 per day rates with the freedom to work when and where they please. Could you do it too? Could you forsake the good job, good pay and security for a life altogether more risky?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Freelancing: Taking the Plunge</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">24 01 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        You&rsquo;re working as a full-time employee, slaving away for 40 hours per week. The job is secure, your pay is pretty decent and the work is moderately interesting, but you don&rsquo;t have much flexibility or freedom. All your friends are freelancers, regaling tales of £400 per day rates with the freedom to work when and where they please. Could you do it too? Could you forsake the good job, good pay and security for a life altogether more risky?
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A simple plugin system in Clojure</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">15 01 2015</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>In this post we’ll see how to create a simplistic plugin system where plugins can be supplied as Leiningen dependencies and automatically initialized without any additional code change in the application.</p><p>Let’s take a look at Cryogen for a concrete example of how this can be useful. Cryogen started out using Markdown for content encoding, and we recently got a pull request that adds <a href='https://github.com/cryogen-project/cryogen/pull/43'>AsciiDoc support</a>.</p><p>It’s always great to get additional features, but sometimes features also carry an undesirable cost. It turns out that AsciiDoc support relies on <a href='https://github.com/asciidoctor/asciidoctorj'>AsciidoctorJ</a>, that in turn relies on JRuby and pulls in a huge amount of additional dependencies. This has a significant impact on the startup time of the application.</p><p>For anybody who isn’t using AsciiDoc the new feature simply degrades the user experience. So, ideally we’d like to keep AsciiDoc as a feature, but also avoid impacting users who aren’t using it. The ideal scenario is to be able to split out the parsers into standalone libraries and include the ones we need. This also has the benefit of people being able to write their own custom plugins that add the features they need without having to update the core project.</p><p>The approach I took here was to create an <code>init</code> function for each plugin that will take care of any initialization that the plugin needs to do and register it with the system.</p><p>All the available parsers are stored in an atom called <code>markup-registry</code> in <a href='https://github.com/cryogen-project/cryogen-core'>cryogen-core</a>, and each plugin simply updates the registry when it loads:</p><pre><code class="clojure">&#40;defn init &#91;&#93;
  &#40;swap! markup-registry conj &#40;markdown&#41;&#41;&#41;
</code></pre><p>The full code for the Markdown plugin can be seen <a href='https://github.com/cryogen-project/cryogen-markdown/blob/master/src/cryogen_markdown/core.clj'>here</a>.</p><p>Next, we need to make our plugins discoverable so that they can be loaded when the application starts. This can be done using a configuration file that can be found on a classpath. Cryogen plugin configuration is stored in <code>resources/plugin.edn</code> using the following format:</p><pre><code class="clojure">{:description &quot;Markdown parser&quot;
 :init cryogen-markdown.core/init}
</code></pre><p>Using the above information we can load the appropriate namespace and run the initializer function for the plugin.</p><p>First, we need to grab all the resources with the name <code>plugin.edn</code> which can done as follows:</p><pre><code class="clojure">&#40;defn load-plugins &#91;&#93;
  &#40;let &#91;plugins &#40;.getResources &#40;ClassLoader/getSystemClassLoader&#41; &quot;plugin.edn&quot;&#41;&#93;
    &#40;loop &#91;&#93;
      &#40;load-plugin &#40;.. plugins nextElement openStream&#41;&#41;
      &#40;when &#40;.hasMoreElements plugins&#41;
        &#40;recur&#41;&#41;&#41;&#41;&#41;
</code></pre><p>Next, we read the configuration for each resource, require its namespace and then run the initializer functions as seen below:</p><pre><code class="clojure">&#40;defn load-plugin &#91;url&#93;
  &#40;let &#91;{:keys &#91;description init&#93;} &#40;edn/read-string &#40;slurp url&#41;&#41;&#93;
    &#40;println &#40;green &#40;str &quot;loading module: &quot; description&#41;&#41;&#41;
    &#40;-&gt; init str &#40;s/split #&quot;/&quot;&#41; first symbol require&#41;
    &#40;&#40;resolve init&#41;&#41;&#41;&#41;
</code></pre><p>With that in place we simply run <code>load-plugins</code> when the applicatin starts and any plugins found on the classpath will be initialized. All the user has to do is select what plugins they want to include in their dependencies to get the functionality they need.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The State of Reagent</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">01 12 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I'm happy to report that Dan Holmsand has graciously agreed to move <a href='https://github.com/reagent-project/reagent'>Reagent</a> to a GitHub Organization called the <a href='https://github.com/reagent-project'>reagent-project</a>. The organization will help spread the work as well as provide a hub for all the related projects. There has been a lot of recent interest in the org and several projects have already migrated under the umbrella.</p><p>First, I'd like to mention the <a href='https://github.com/reagent-project/reagent-cookbook'>reagent-cookbook</a> project that provides many recipes for accomplishing common tasks, such as Js library integration, using Reagent. The project provides clear and simple guidelines for contributing to help ensure that all recipes have a common format that's easy to follow. Next addition is the <a href='https://github.com/reagent-project/historian'>Historian</a> project that provides drop-in undo/redo functionality for Reagent. World Singles has recently <a href='https://groups.google.com/forum/#!msg/clojurescript/r9B1k4MoTXA/J5gdZBa-BwUJ'>switched from Om to Reagent</a> and Sean Corfield has added <a href='https://github.com/reagent-project/reagent-cursor'>reagent-cursor</a> library for Om-like cursor support in the process. Finally, there is my own <a href='https://github.com/reagent-project/reagent-forms'>reagent-forms</a> library for creating data bindings using Reagent.</p><p>New Reagent projects can now be easily created and run using the <a href='https://github.com/reagent-project/reagent-template'>reagent-template</a> as follows:</p><pre><code>lein new reagent my-app
cd my-app
lein cljsbuild auto &amp;
lein ring server
</code></pre><p>The template will generate a Clojure/Clojurescript web app that's designed to get you up and running without any tedious setup. The resulting project is setup to use <a href='https://github.com/bhauman/lein-figwheel'>Figwheel</a> for live code reloading and <a href='https://github.com/tomjakubowski/weasel'>weasel</a> for the REPL enabling smooth development out of the box.</p><p>The template uses sane library and configuration choices across the stack with Reagent for the UI, <a href='https://github.com/gf3/secretary'>Secretary</a> for client side routing, and the Ring/Compojure stack on the backend.</p><p>The dev server and packaging are handled by <a href='https://github.com/weavejester/lein-ring'>lein-ring</a> that will take care of reloading changes during development and producing either an uberjar or an uberwar for running standalone or deploying to a container respectively. The project also contains a <code>Procfile</code> for instant Heroku deployment. For more details, please visit the project page <a href='https://github.com/reagent-project/reagent-template'>here</a>.</p><p>As you can see, much has happened with Reagent in the past month and the future is looking very bright. If you haven't tried Reagent yet, there's never been a better time than now. :)</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Moving to Cryogen</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">26 11 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The blog has officially been moved over to <a href='https://github.com/lacarmen/cryogen'>Cryogen</a>. While, all the content has been migrated over, the links for the posts have changed and the original comments are no longer available since I'm now using Disqus.</p><p><a href='https://github.com/yogthos/yuggoth'>Yuggoth</a> was a fun experment and it held up to most traffic storms over the years, but at the end of the day it's hard to beat the simplicity of a static site.</p><p>Porting the content from my old blog turned out to be a simple affair. I used Postgres to store all the blog content in Yuggoth. The database contains tables for the posts, the comments, the tags, and the files. All I had to do was extract the data and write it back out using the Cryogen format. First, I extracted the binary data for the files as seen below.</p><pre><code class="clojure">&#40;defn write-file &#91;{:keys &#91;data name&#93;}&#93;
   &#40;with-open &#91;w &#40;clojure.java.io/output-stream
                   &#40;str &quot;resources/templates/files/&quot; name&#41;&#41;&#93;
     &#40;.write w data&#41;&#41;&#41;

&#40;defn extract-files &#91;&#93;
  &#40;doseq &#91;file &#40;sql/query db &#91;&quot;select &#42; from file&quot;&#93;&#41;&#93;
    &#40;write-file file&#41;&#41;&#41;

</code></pre><p>The posts table contains the content, while the tags are stored in a separate table. The tags can be aggregated by post using the handy <code>array&#95;agg</code> function. This function will produce a <code>Jdbc4Array</code> as the result, and its contents can then be extracted to a vector.</p><pre><code class="clojure">&#40;defn extract-tags &#91;post&#93;
  &#40;update-in post &#91;:tags&#93; #&#40;vec &#40;.getArray %&#41;&#41;&#41;&#41;

&#40;defn get-posts &#91;&#93;
  &#40;map extract-tags
       &#40;sql/query db
         &#91;&quot;select array&#95;agg&#40;t.tag&#41; as tags,
                  b.id, b.time, b.title, b.content from blog b, tag&#95;map t
           where t.blogid = b.id
           group by b.id, b.time, b.title, b.content&quot;&#93;&#41;&#41;&#41;

</code></pre><p>Now, all that's left to do is to generate the post metadata and the file name. Since each post contains a publication date and a title, these can be used to produce a filename in the format expected by Cryogen.</p><pre><code class="clojure">&#40;defn format-post-date &#91;date&#93;
  &#40;let &#91;fmt &#40;java.text.SimpleDateFormat. &quot;dd-MM-yyyy&quot;&#41;&#93;
    &#40;.format fmt date&#41;&#41;&#41;

&#40;defn format-post-filename &#91;time title&#93;
  &#40;str
    &#40;-&gt;&gt; &#40;re-seq #&quot;&#91;a-zA-Z0-9&#93;+&quot; title&#41;
         &#40;clojure.string/join &quot;-&quot;&#41;
         &#40;str &quot;resources/templates/md/posts/&quot; &#40;format-post-date time&#41; &quot;-&quot;&#41;&#41;
   &quot;.md&quot;&#41;&#41;
</code></pre><p>With that in place we can simply run through all the posts and extract them into appropriate files.</p><pre><code class="clojure">&#40;defn write-post &#91;{:keys &#91;id time tags content title&#93;}&#93;
  &#40;with-open &#91;wrt &#40;clojure.java.io/writer &#40;format-post-filename time title&#41;&#41;&#93;
    &#40;.write wrt
            &#40;with-out-str
              &#40;clojure.pprint/pprint
                {:title title
                 :layout :post
                 :tags &#40;vec &#40;.split tags &quot; &quot;&#41;&#41;}&#41;&#41;&#41;
    &#40;.write wrt &quot;\n&quot;&#41;
    &#40;.write wrt content&#41;&#41;&#41;

&#40;defn extract-posts &#91;&#93;
  &#40;doseq &#91;post &#40;get-posts&#41;&#93;
    &#40;write-post post&#41;&#41;&#41;

</code></pre><p>And that's all there is to it. Moral of the story is that we should always keep the data separate from its representation as you never know when you will need it down the road.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Short ID Generation in JavaScript</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">16 11 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A &lsquo;short&rsquo; or &lsquo;hash&rsquo; ID is a seemingly random sets of characters, popularised by services which need unique but readable (and typeable) URLs. For example, YouTube use short IDs for their video URLs:
http://www.youtube.com/watch?v=IfeyUGZt8nk I found myself needing to generate short IDs for URLs in a recent project. These were the requirements:
Be short enough to type Be easy enough to speak (e.g. over the phone in support situations) Be unique (or close to unique as feasible) Not contain any rude words I wasn&rsquo;t looking at generating millions of IDs per day, all I needed was something simple.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Short ID Generation in JavaScript</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">16 11 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A &lsquo;short&rsquo; or &lsquo;hash&rsquo; ID is a seemingly random sets of characters, popularised by services which need unique but readable (and typeable) URLs. For example, YouTube use short IDs for their video URLs:
http://www.youtube.com/watch?v=IfeyUGZt8nk I found myself needing to generate short IDs for URLs in a recent project. These were the requirements:
Be short enough to type Be easy enough to speak (e.g. over the phone in support situations) Be unique (or close to unique as feasible) Not contain any rude words I wasn&rsquo;t looking at generating millions of IDs per day, all I needed was something simple.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Cryogen: static site generation made easy</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">13 11 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><a href='https://github.com/lacarmen/cryogen'>Cryogen</a> is a new Clojure static site generator by <a href='https://github.com/lacarmen'>Carmen La</a>. Since there are already many popular site generators such as Jekyll, let's take a look at what makes Cryogen interesting.</p><p>In my opinion, the main feature of this project is its simplicity. Cryogen is shipped as a Leiningen template and all you have to do to create a site is run:</p><pre><code>lein new cryogen my-blog
</code></pre><p>This will create an instance of the project with a template site initialized. The site can be run in dev mode using:</p><pre><code>lein ring server
</code></pre><p> Once started, a helpful readme is shown on what to do next, which is a really nice touch.</p><p>The server will watch for changes in the <code>resources/templates</code> folder and recompile the site whenever updates are detected. The compiled site is served from <code>resources/public</code>. The static assets generated there can now be copied to over to be served by Nginx or Apache in production.</p><p>The layout is handled using <a href='https://github.com/yogthos/Selmer'>Selmer</a> templates, while the content of the posts and the pages is written using Markdown with the help of <a href='https://github.com/yogthos/markdown-clj'>markdown-clj</a>.</p><p>The generator handles all the common things like linking up pages, creating tags, syntax highlighting, sitemap, and RSS our of the box.</p><p>While most site generators take the approach of providing numerous configuration options for customization, Cryogen simply gives you the code to customize any way you see fit. You can simply go to the <code>cryogen.compiler</code> namespace and easily change its behaviour to fit whatever it is you're doing. The compiler code is very clean and easy to follow, making it easy to customize.</p><p>I definitely recommend taking a look at this project if you're looking to make a static site in the future.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure Cup Results</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">08 10 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Clojure Cup results are in and you can see the winning entries <a href='https://clojurecup.com/'>here</a>. Kudos to all the teams who participated in the event!</p><p>It was exciting to see a wide variety of ideas explored during the event as well as the number of projects that were taken to completion. It's extremely impressive to see the kinds of Clojure apps that can be built from scratch in just a couple of days.</p><p>The scope of the competition clearly grew from last year, the prizes were bigger, the teams were larger, and the projects were more ambitious. One major change that I noticed was that a lot more projects were using ClojureScript and many of these used Om and Reagent to build the UI. It's great to see ClojureScript taking off and bringing some sanity to the world of front-end development.</p><p>Overall, I think it was an exciting event and I highly recommend browsing through the <a href='https://clojurecup.com/#/apps'>apps</a>. Many of the projects are <a href='https://github.com/clojurecup2014'>hosted on GitHub</a> and it's worth exploring the code to learn some new tricks. :)</p><p>I can't wait to see what Clojure Cup 2015 will bring.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Parsing and rendering templates in Clojure &amp; Haskell</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">03 10 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>A little while back <a href='https://github.com/bitemyapp'>Chris Allen</a> discovered the joys of Haskell. We had a few discussions regarding the merits of static typing and whether Haskell would be a more productive language than Clojure.</p><p>Haskell was my first foray into functional programming, and it's the language that made me fall in love with it. However, I also found that non-trivial type relationships would often require a lot of mental gymnastics. Eventually, I ended up moving to Clojure as I realized that I was simply more productive in it.</p><p>Chris would have none of this, and repeatedly told me that I was simply lying about having tried Haskell, since nobody could possibly enjoy using a dynamic language after seeing the glory of HM type inference.</p><p>These sorts of debates are rather tiring, so instead I proposed that Chris would translate a small piece of Clojure code to Haskell. Then we could discuss the merits of each approach using a concrete example.</p><p>On December of 2013, I posted <a href='https://gist.github.com/yogthos/8025281'>this gist</a> and while it's not trivial, it weighs in at about 70 lines of code. It's a minimal example where I find Haskell starts making things unnecessarily difficult.</p><p>The code runs through a stream and looks for either <code>{{...}}</code> or <code>{% if ... %}</code> tags. It is intentionally kept short to limit noise, so it simply reads the tag names and prints them out. Since the code is a dumbed down version of <a href='https://github.com/yogthos/Selmer'>Selmer</a>, which Chris participated on writing, I assumed he would have little difficulty reading and translating it.</p><p>To my surprise he started making excuses that if he did translate it then it would give me ammunition to complain about Haskell being difficult. I think that's a rather strange argument to make for somebody making the case that Haskell makes things simpler.</p><p>Then he said he'd do it using the <a href='http://www.haskell.org/haskellwiki/Parsec'>Parsec</a> library, which obviously defeats the point. The question is not whether you can figure out a library API in Haskell, but how would you translate specific piece of Clojure code to Haskell.</p><p>The power of Clojure is that it allows me to solve hard problems instead of having to rely on somebody else to write libraries that do the hard stuff and then glue them together.</p><p>At this point Chris proceeded to ignore the request for over half a year, until he suddenly decided to start <a href='https://twitter.com/bitemyapp/status/517829996975370240'>messaging me about it on Twitter</a> last night. All of a sudden he couldn't wait a second more and what's more apparently my code was broken! As he so eloquently put it <a href='https://twitter.com/bitemyapp/status/517830192509624320'>"@yogthos broken software in a unityped language...whodathunkit..."</a>. He proceeded to berate me and insisted that the code does not work, that <a href='https://twitter.com/bitemyapp/status/517833301801721856'>I'm a liar</a> for suggesting that it does, and he must make a blog post regarding this situation immediately.</p><p>I was surprised to hear this as I clearly recall the parser example working last I touched it. Since there was no reason to change it, I was fairly confident that it would be in working order. However, not having access to a computer at the time I could not check it myself.</p><p>Normally, if an individual contacts me respectfully I would be glad to help and work with them to figure out what the problem is. I make mistakes, we all do, and it's conceivable that there might've been a problem with my code. The approach Chris chosen was frankly insulting.</p><p>I explained to Chris that I was not at a computer and I can't look at the code, but evidently the blog post simply could not wait. You can read it in full <a href='http://bitemyapp.com/posts/2014-10-02-parsing-and-rendering-templates-in-haskell.html'>here</a>.</p><p>The problem turned out to be that Chris is apparently incapable of reading code. The parser gets initialized with the <code>render-file</code> function:</p><pre><code class="clojure">&#40;defn render-file &#91;filename args&#93;
  &#40;render &#40;parse filename&#41; args&#41;&#41;
</code></pre><p>This function calls the <code>parse</code> function on the <code>filename</code> and then passes the parsed content to <code>render</code>. Chris tried to call <code>render</code> with:</p><pre><code class="clojure">&#40;parser/render &quot;Hello {{name}}!&quot; {:name &quot;Yogthos&quot;}&#41;
</code></pre><p>Shockingly enough he got an error doing that, at this point he evidently was incapable figuring out on his own what was causing the error and proceeded to throw a tantrum on Twitter.</p><p>Of course, if the goal was to actually figure out what the problem was then one would at least look at what parse is doing:</p><pre><code class="clojure">&#40;defn parse &#91;file&#93;
  &#40;with-open &#91;rdr &#40;clojure.java.io/reader file&#41;&#93;
</code></pre><p>Then it would immediately become obvious that we must pass in something that can be read by <code>clojure.java.io/reader</code>, such as <code>java.io.StringBufferInputStream</code>, and then pass the result of <code>parse</code> to <code>render</code>. Naturally, when called correctly the code does exactly what it's supposed to:</p><pre><code class="clojure">&#40;render
  &#40;parse
    &#40;java.io.StringBufferInputStream. &quot;Hello {{name}}&quot;&#41;&#41;
    {:name &quot;Yogthos&quot;}&#41;
=&gt;&quot;Hello filter tag value: name&quot;
</code></pre><p>Since Chris managed to run the <code>render-file</code> function as seen in one the snippets in his blog post, he doesn't seem to understand that I asked him to translate that code to Haskell. For whatever reason, he includes a screenshot of Selmer documentation, which is <em>not</em> the behavior of the parser and was never intended to be. The spec that Chris was asked to translate to Haskell is the code in the gist.</p><p>In his post, Chris went ahead and answered the question he would like to have been asked as opposed to the one he was actually asked. I suppose making a straw man is a lot easier than answering the original question.</p><p>What I learned from this experience is that some Haskell users like to talk a lot about their favorite language, but when asked to solve a simple problem they will do anything but that. I don't find that to be terribly convincing myself.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Yet Another Clojure Intro Guide</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">27 09 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>There are already lots of guides introducing Clojure syntax and many of its features, but these guides tend to focus on individual examples as opposed to the broad concepts behind the language.</p><p>In my experience, the difficulty in learning Clojure doesn't stem from the syntax, but from having to approach problems with a new mindset. The goal of this guide is to impart such a mindset on the reader. How badly I fail at this task remains to be seen. :P</p><p>Without further ado, <a href='http://yogthos.github.io/ClojureDistilled.html'>here's</a> the guide itself, and I hope you'll find it useful if you're starting out with Clojure.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Using ClojureScript REPL from Light Table</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">20 09 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I recently discovered that <a href='http://www.lighttable.com/'>Light Table</a> REPL works with ClojureScript without the need for any specific setup in your project.  All you need is the <a href='https://github.com/emezeske/lein-cljsbuild'>lein-cljsbuild</a> plugin to run the incremental compiler and follow the steps below:</p><ol><li>start the ClojureScript compiler using <code>lein cljsbuild auto</code></li><li>start the server using <code>lein ring server</code></li><li>open the Light Table browser connection to the server</li><li>navigate to a ClojureScript namespace in your project and start evaluating expressions</li></ol><p>I tried other ClojureScript REPL setups before and I always found the process extremely fiddly, with Light Table everything just worked out of the box. I definitely recommend giving it a shot if you haven't yet, especially if you're working with ClojureScript.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">No REST for the whippet</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">16 09 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Over the past few days I have had the pleasure of standing up and talking about RESTful APIs.
On Saturday I opened CodeHub&rsquo;s JavaScript workshop with a quick introduction to developing a RESTful API with Mongoose, Node and Express. It was my first attempt at live coding in front of an audience, I apologise to anybody who attended and thought I was going too fast. It&rsquo;s amazing how quickly the time can fly by!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">No REST for the whippet</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">16 09 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Over the past few days I have had the pleasure of standing up and talking about RESTful APIs.
On Saturday I opened CodeHub&rsquo;s JavaScript workshop with a quick introduction to developing a RESTful API with Mongoose, Node and Express. It was my first attempt at live coding in front of an audience, I apologise to anybody who attended and thought I was going too fast. It&rsquo;s amazing how quickly the time can fly by!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Introducing reagent-forms</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">31 08 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>One thing I’ve always found to be particularly tedious is having to create data bindings for form elements. Reagent makes this much more palatable than most libraries I’ve used. All you need to do is create an atom and use it to track the state of the components.</p><p>However, creating the components and binding them to the state atom is still a manual affair. I decided to see if I could roll this into a library that would provide a simple abstraction for tracking the state of the fields in forms.</p><p>The usual way to bind inputs to atoms as illustrated in the <a href='http://holmsand.github.io/reagent/'>official Reagent docs</a> can be seen below:</p><pre><code class="clojure">&#40;ns example
  &#40;:require &#91;reagent.core :as reagent :refer &#91;atom&#93;&#93;&#41;&#41;

&#40;defn atom-input &#91;value&#93;
  &#91;:input {:type &quot;text&quot;
           :value @value
           :on-change #&#40;reset! value &#40;-&gt; % .-target .-value&#41;&#41;}&#93;&#41;

&#40;defn shared-state &#91;&#93;
  &#40;let &#91;val &#40;atom &quot;foo&quot;&#41;&#93;
    &#40;fn &#91;&#93;
      &#91;:div
       &#91;:p &quot;The value is now: &quot; @val&#93;
       &#91;:p &quot;Change it here: &quot; &#91;atom-input val&#93;&#93;&#93;&#41;&#41;&#41;
</code></pre><p>We create an atom with some state and then pass it to our input component. The component will display the current value and update the state when its <code>:on-change</code> event is triggered.</p><p>Normally, we’d have to go through each field in the form and pass the state to it so that it can bind itself to the document we’re generating.</p><p>I wanted to be able to specify a template for a form and then pass the entire template to a function that would take care of binding all the fields to an atom representing the document.</p><p>This function would need to know what parts of the form need to be bound, how to bind each type of element, and how to uniquely identify it in the document.</p><p>My solution was to introduce the <code>:field</code> attribute that would identify the component as a form field, and to use the <code>:id</code> attribute as the unique key for the element.</p><p>The binding function would then walk the form and check for any component that contain the <code>:field</code> key in its attribute map. The key would point to the type of component such as text, numeric, list, and so on.</p><p>Then it could pass the component to a specific binding function that would be responsible for linking the field with the document and return a bound component. Let’s take a look at how this all works with an example.<br /></p><p>We’ll first need to include the library in our project `[reagent-forms "0.1.3"] <code>, then we’ll require the </code>reagent-forms.core/bind-fields` function in our namespace:</p><pre><code class="clojure">&#40;ns myform.core
  &#40;:require &#91;reagent-forms.core :refer &#91;bind-fields&#93;&#93;&#41;
</code></pre><p>Next, we need to create a form template to represent our form:</p><pre><code class="clojure">&#40;defn row &#91;label input&#93;
  &#91;:div.row
    &#91;:div.col-md-2 &#91;:label label&#93;&#93;
    &#91;:div.col-md-5 input&#93;&#93;&#41;

&#40;def form-template
  &#91;:div
   &#40;row &quot;first name&quot; &#91;:input {:field :text :id :person.first-name}&#93;&#41;
   &#40;row &quot;last name&quot; &#91;:input {:field :text :id :person.last-name}&#93;&#41;
   &#40;row &quot;age&quot; &#91;:input {:field :numeric :id :person.age}&#93;&#41;
   &#40;row &quot;email&quot; &#91;:input {:field :email :id :person.email}&#93;&#41;
   &#40;row &quot;comments&quot; &#91;:textarea {:field :textarea :id :comments}&#93;&#41;&#93;&#41;
</code></pre><p>Note that we call helper functions, such as <code>row</code>, eagerly. The <code>bind-fields</code>  function will walk the template to construct the actual components that will be used by Reagent.</p><p>The <code>.</code> in the <code>:id</code> key indicates nested structure. When we have a key like <code>:person.first-name</code>, then its value will be stored under <code>{:person {:first-name &lt;field-value&gt;}}</code>.</p><p>Our form component will then create an atom to represent the document and bind it to the template to produce the actual form:</p><pre><code class="clojure">&#40;defn form &#91;&#93;
  &#40;let &#91;doc &#40;atom {}&#41;&#93;
    &#40;fn &#91;&#93;
      &#91;:div
       &#91;:div.page-header &#91;:h1 &quot;Reagent Form&quot;&#93;&#93;
       &#91;bind-fields form-template doc&#93;
       &#91;:label &#40;str @doc&#41;&#93;&#93;&#41;&#41;&#41;
</code></pre><p>That’s all there is to it. Whenever the state of any of the components changes the <code>doc</code> atom will be updated and vice versa.</p><p>The <code>bind-fields</code> function also accepts optional events. Events are triggered whenever the document is updated, and will be executed in order they are listed. Each event sees the document modified by its predecessor. The event must take 3 parameters, which are the id, the value, and the document.</p><p>The id and the value represent the value that was changed to trigger the event, and the document is the atom that contains the state of the form. Note that the id is in form of a vector representing the path in the document. The event can either return an updated document or <code>nil</code>, when <code>nil</code> is returned then the state of the document is unmodified. The following is an example of an event to calculate the value of the <code>:bmi</code> key when the <code>:weight</code> and <code>:height</code> keys are populated:</p><pre><code class="clojure">&#40;defn row &#91;label input&#93;
  &#91;:div.row
    &#91;:div.col-md-2 &#91;:label label&#93;&#93;
    &#91;:div.col-md-5 input&#93;&#93;&#41;

&#40;def form-template
 &#91;:div
   &#91;:h3 &quot;BMI Calculator&quot;&#93;
   &#40;row &quot;Height&quot; &#91;:input {:field :numeric :id :height}&#93;&#41;
   &#40;row &quot;Weight&quot; &#91;:input {:field :numeric :id :weight}&#93;&#41;
   &#40;row &quot;BMI&quot; &#91;:input {:field :numeric :id :bmi :disabled true}&#93;&#41;&#93;&#41;

&#91;w/bind-fields
  form-template
  doc
  &#40;fn &#91;&#91;id&#93; value {:keys &#91;weight height&#93; :as doc}&#93;
    &#40;when &#40;and &#40;some #{id} &#91;:height :weight&#93;&#41; weight height&#41;
      &#40;assoc-in doc &#91;:bmi&#93; &#40;/ weight &#40;&#42; height height&#41;&#41;&#41;&#41;&#41;&#93;
</code></pre><p>The library provides support for a number of common fields such as inputs, checkboxes, radio buttons, lists, and multi-selects. However, it also makes it easy to add your own custom fields by implementing the <code>reagent-forms.core/init-field</code> multimethod.</p><p>The method must take two parameters, where the first parameter is the field component and the second is the options map. The options contain two keys called  <code>get</code> and <code>save!</code>. The <code>get</code> key points to a function that accepts an id and returns the document value associated with it. The <code>save!</code> function accepts an id and a value that will be associated with it. Let’s take a look at the <code>:radio</code> field implementation as an example:<pre><code class="clojure">&#40;defmethod init-field :radio
  &#91;&#91;type {:keys &#91;field id value&#93; :as attrs} &amp; body&#93;
   {:keys &#91;get save!&#93;}&#93;
  &#40;let &#91;state &#40;atom &#40;= value &#40;get id&#41;&#41;&#41;&#93;
    &#40;fn &#91;&#93;
      &#40;into
        &#91;type
         &#40;merge {:type :radio
                 :checked @state
                 :class &quot;form-control&quot;
                 :on-change
                 #&#40;do
                    &#40;save! id value&#41;
                    &#40;reset! state &#40;= value &#40;get id&#41;&#41;&#41;&#41;}
                attrs&#41;&#93;
         body&#41;&#41;&#41;&#41;
</code></pre></p><p>As you can see, the method simply returns a new component that’s bound to the supplied id in the document. For more details please see the <a href='https://github.com/yogthos/reagent-forms'>documentation</a> on the project page.</p><p>The library is still rather new and as such has some rough edges, such as poor error reporting. However, I already find it to be quite useful in my own projects.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">File Snooping</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">17 08 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I recently needed to watch files for changes and had a chance to play around with using the <code>WatchService</code> functionality in JDK 7. As is generally the case with Java, the API requires you to jump through a number of hoops to do anything, but turns out that it’s possible to wrap it up into something reasonable in the end.</p><p>The <code>WatchService</code> can be used to watch directories and provides different types of events, such as create, modify, delete, and overflow. The first three are self-explanatory and the last is a special event that’s triggered when an event might have been discarded or lost.</p><p>What we’d like to do is create a function called <code>watch</code> that accepts an input path along with event handlers for each of the above events.</p><p>To create a watcher we first need to get an instance of a <code>Path</code>. To do that we have to call <code>&#40;-&gt; path &#40;file&#41; &#40;.toURI&#41; &#40;Paths/get&#41;&#41;</code>. Next, we can get an instance of the <code>WatchService</code> by calling <code>&#40;.newWatchService &#40;FileSystems/getDefault&#41;&#41;</code></p><p>Now that we have a <code>Path</code> and a <code>WatchService</code>, we can register the service with the path to listen for the events we specify.</p><p>To handle this, I ended up creating a map with the keys representing the events and the values being the event handling functions.</p><pre><code class="clojure">{:create event-handler
 :modify event-handler}
</code></pre><p>When the event is triggered we will receive an instance of the  <code>WatchEvent</code>. So, the handler functions should accept it as the parameter.</p><pre><code class="clojure">&#40;defn event-handler &#91;event&#93;
  &#40;println &#40;.kind event&#41; &#40;.context event&#41;&#41;&#41;
</code></pre><p>Next, I created a couple of helpers to map the keywords to the appropriate events:</p><pre><code class="clojure">&#40;defn register-events! &#91;dir watch-service opts&#93;
  &#40;.register dir watch-service
    &#40;-&gt; opts
       &#40;select-keys &#91;StandardWatchEventKinds/ENTRY&#95;CREATE
                     StandardWatchEventKinds/ENTRY&#95;MODIFY
                     StandardWatchEventKinds/ENTRY&#95;DELETE
                     StandardWatchEventKinds/OVERFLOW&#93;&#41;
       &#40;keys&#41;
       &#40;into-array&#41;&#41;&#41;&#41;

&#40;defn rename-event-keys &#91;opts&#93;
  &#40;rename-keys opts
    {:create StandardWatchEventKinds/ENTRY&#95;CREATE
     :modify StandardWatchEventKinds/ENTRY&#95;MODIFY
     :delete StandardWatchEventKinds/ENTRY&#95;DELETE
     :overflow StandardWatchEventKinds/OVERFLOW}&#41;&#41;
</code></pre><p>The transformed map is now ready for use. The <code>WatchService</code> implements closeable, so we can use the <code>with-open</code> macro to manage it:</p><pre><code class="clojure">&#40;defn watch &#91;path opts&#93;
  &#40;let &#91;dir &#40;-&gt; path &#40;file&#41; &#40;.toURI&#41; &#40;Paths/get&#41;&#41;
        opts &#40;rename-event-keys opts&#41;&#93;
    &#40;with-open &#91;watch-service
                &#40;.newWatchService &#40;FileSystems/getDefault&#41;&#41;&#93;
      &#40;register-events! dir watch-service opts&#41;
      &#40;watch-loop watch-service opts&#41;&#41;&#41;&#41;
</code></pre><p>The <code>watch</code> function will register the events we passed in, open the watch service and then call the <code>watch-loop</code> function to do the actual watching.</p><pre><code class="clojure">&#40;defn watch-loop &#91;watch-service opts&#93;
  &#40;loop &#91;&#93;
    &#40;let &#91;k &#40;.take watch-service&#41;&#93;      
      &#40;doseq &#91;event &#40;.pollEvents k&#41;&#93;
        &#40;if-let &#91;handler &#40;get opts &#40;.kind event&#41;&#41;&#93;
          &#40;handler event&#41;&#41;&#41;
      &#40;when &#40;.reset k&#41; &#40;recur&#41;&#41;&#41;&#41;&#41;
</code></pre><p>The <code>watch-loop</code> starts each iteration by calling <code>take</code> on the watch service. This method blocks until it receives an event, the service is closed or it’s interrupted.</p><p>Once we receive an event we can look it up in our options map and call the handler for the event. Finally, we need to call <code>reset</code> on the key before we start the next iteration.</p><p>Since the <code>take</code> function blocks, we probably want to run it in a thread:</p><pre><code class="clojure">&#40;defn start-watcher! &#91;path opts&#93;
  &#40;doto &#40;Thread. #&#40;watch path opts&#41;&#41;
    &#40;.setDaemon true&#41;
    &#40;.start&#41;&#41;&#41;
</code></pre><p>The above will start a background watcher thread and return it. The thread is daemonized, so that it doesn’t prevent the application from exiting. Example usage for the above can be to track when files are created or modified in the directory:</p><pre><code class="clojure">&#40;start-watcher! “&#126;/downlads”
  {:create #&#40;println “file created” &#40;-&gt; % &#40;.context&#41; &#40;.toString&#41;&#41;&#41;
   :modify #&#40;println “file modified” &#40;-&gt; % &#40;.context&#41; &#40;.toString&#41;&#41;&#41;}&#41;
</code></pre><p>That’s all there is to it and the full source for the example can be seen <a href='https://gist.github.com/yogthos/911e6aba9802ceacd83c'>here</a>.</p><h3 id="update">Update</h3><p>As one of the comments points out, JDK will poll on OS X and the default poll interval is quite large. In order to get around this we can force high sensitivity when we register the <code>WatchService</code> as follows:</p><pre><code class="clojure">&#40;defn register-events! &#91;dir watch-service&#93;
  &#40;.register dir
    watch-service
    &#40;into-array
      &#91;StandardWatchEventKinds/ENTRY&#95;CREATE
       StandardWatchEventKinds/ENTRY&#95;MODIFY
       StandardWatchEventKinds/ENTRY&#95;DELETE
       StandardWatchEventKinds/OVERFLOW&#93;&#41;
    &#40;into-array
      &#91;&#40;com.sun.nio.file.SensitivityWatchEventModifier/HIGH&#41;&#93;&#41;&#41;&#41;
</code></pre> 
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Routing With Secretary</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">14 08 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>In the last post, we looked at using Reagent for building single page apps. The <a href='https://github.com/yogthos/reagent-example'>example</a> app contained a single page with a form in it, which isn't terribly exciting as far as single page apps go.</p><p>In this post we’ll see see how to create an app with multiple pages and how we can route between them using the <a href='https://github.com/gf3/secretary'>secretary</a> library.</p><p>The app will be a guestbook with a page that shows a list of users and another page that allows new users to sign in. We’ll use the project from the last post as the base for this tutorial.</p><p><b><i>update</i></b> the tutorial has been updated to the latest version of Luminus, you'll need to create a new project to follow along using <code>lein new luminus guestbook +cljs</code></p><p>First thing that we have to do is to add the <code>&#91;secretary &quot;1.2.3&quot;&#93;</code> dependency to our <code>project.clj</code>. Next, let’s refactor our namespaces in <code>src/cljs</code> as follows:</p><pre><code>src
  └ cljs
    └ guestbook
      └ core.cljs
      └ pages
        └ guest.cljs
        └ guest&#95;list.cljs
</code></pre><ul><li>The <code>core</code> namespace will act as the entry point for the client.</li><li>The <code>session</code> will house the global state of the application.</li><li>The <code>guest</code> namespace will house the sign-in form.</li><li>The <code>guest-list</code> namespace will display the guests.</li></ul><p>Since we refactored the namespaces we’ll also need to update our <code>app.html</code> template to reflect that.</p><pre><code class="xml">&lt;script type=&quot;text/javascript&quot;&gt;goog.require&#40;&quot;guestbook.core&quot;&#41;;&lt;/script&gt;
</code></pre><h3 id="session&#95;management">Session Management</h3><p>In our example, the session will track the currently selected page and the saved documents.</p><p>We’ll use the <a href='https://github.com/reagent-project/reagent-utils/blob/master/src/reagent/session.cljs'>reagent-utils</a> session. The session is simply a Ragent atom with some helper functions around it.</p><h3 id="listing&#95;guests">Listing Guests</h3><p>Let’s open up the <code>guest-list</code> namespace and add the following code there.</p><pre><code class="clojure">&#40;ns guestbook.pages.guest-list
  &#40;:require &#91;reagent.session :as session&#93;
            &#91;clojure.string :as s&#93;
            &#91;reagent.core :as reagent :refer &#91;atom&#93;&#93;
            &#91;secretary.core :refer &#91;dispatch!&#93;&#93;&#41;&#41;

&#40;defn guest-list-page &#91;&#93;
  &#91;:div
   &#91;:div.page-header &#91;:h2 &quot;Guests&quot;&#93;&#93;
   &#40;for &#91;{:keys &#91;first-name last-name&#93;}
         &#40;session/get :guests&#41;&#93;
     &#91;:div.row
      &#91;:p first-name &quot; &quot; last-name&#93;&#93;&#41;
   &#91;:button {:type &quot;submit&quot;
             :class &quot;btn btn-default&quot;
             :on-click #&#40;dispatch! &quot;/sign-in&quot;&#41;}
    &quot;sign in&quot;&#93;&#93;&#41;
</code></pre><p>The namespace will contain a page that lists the guests that are currently in the session. The <code>“sign in”</code> button on the page uses the <code>dispatch!</code> function in order to route to the <code>“/sign-in”</code> page.</p><h3 id="adding&#95;routes">Adding Routes</h3><p>The <code>core</code> namespace will specify the list of routes and provide an <code>init!</code> function to set the current page and render it when the application loads.</p><pre><code class="clojure">&#40;ns guestbook.core
  &#40;:require &#91;reagent.core :as r&#93;
            &#91;reagent.session :as session&#93;
            &#91;secretary.core :as secretary :include-macros true&#93;
            &#91;goog.events :as events&#93;
            &#91;goog.history.EventType :as HistoryEventType&#93;
            &#91;guestbook.ajax :refer &#91;load-interceptors!&#93;&#93;
            &#91;guestbook.pages.guest-list
            :refer &#91;guest-list-page&#93;&#93;
           &#91;guestbook.pages.guest :refer &#91;guest-page&#93;&#93;&#41;
  &#40;:import goog.History&#41;&#41;

&#40;defn page &#91;&#93;
  &#91;&#40;session/get :current-page&#41;&#93;&#41;

;; -------------------------
;; Routes
&#40;secretary/set-config! :prefix &quot;#&quot;&#41;

&#40;secretary/defroute &quot;/&quot; &#91;&#93;
  &#40;session/put! :current-page guest-list-page&#41;&#41;

&#40;secretary/defroute &quot;/sign-in&quot; &#91;&#93;
  &#40;session/put! :current-page guest-page&#41;&#41;

;; -------------------------
;; History
;; must be called after routes have been defined
&#40;defn hook-browser-navigation! &#91;&#93;
  &#40;doto &#40;History.&#41;
        &#40;events/listen
          HistoryEventType/NAVIGATE
          &#40;fn &#91;event&#93;
              &#40;secretary/dispatch! &#40;.-token event&#41;&#41;&#41;&#41;
        &#40;.setEnabled true&#41;&#41;&#41;

;; -------------------------
;; Initialize app
&#40;defn mount-components &#91;&#93;
  &#40;r/render &#91;#'page&#93; &#40;.getElementById js/document &quot;app&quot;&#41;&#41;&#41;

&#40;defn init! &#91;&#93;
  &#40;load-interceptors!&#41;
  &#40;hook-browser-navigation!&#41;
  &#40;mount-components&#41;&#41;
</code></pre><p>As we can see above, <code>secretary</code> uses Compojure inspired syntax that should look very familiar to anybody who's dabbled in Clojure web development.</p><p>In our case the routes will simply set the appropriate page in the session when called. The <code>render</code> function will then be triggered by the atom update and render the page for us.</p><h3 id="signing&#95;in">Signing In</h3><p>Finally, we’ll add the sign-in form in the <code>guest</code> namespace. The page will keep its local state in an atom and update the session using the callback handler in the <code>save-doc</code> function.</p><p>Note that we don’t have to do anything else to update the list of guests once the callback completes. Since the session atom has been updated, it will trigger the guest list to repaint with the new elements.</p><p>I found that this behavior largely obviates the need to use <code>core.async</code> since the Reagent atom can act as a sync point between the view and the model. It also makes it trivial to implements the <a href='http://facebook.github.io/react/docs/flux-overview.html'>React Flux</a> pattern.</p><pre><code>Views---&gt;&#40;actions&#41; --&gt; Dispatcher--&gt;&#40;callback&#41;--&gt; Stores---+
Ʌ                                                          |
|                                                          V
+--&#40;event handlers update&#41;--&#40;Stores emit &quot;change&quot; events&#41;--+
</code></pre><p>Our view components dispatch updates to the atoms, which represent the stores. The atoms in turn notify any components that dereference them when their state changes.</p><p>Using <code>get/set!</code> functions to access the atoms, as we’re doing in this example, allows us to easily listen for changes and hook in event handlers.</p><pre><code class="clojure">&#40;ns guestbook.pages.guest
  &#40;:refer-clojure :exclude &#91;get&#93;&#41;
  &#40;:require &#91;reagent.session :as session&#93;
            &#91;reagent.core :as reagent :refer &#91;atom&#93;&#93;
            &#91;secretary.core :refer &#91;dispatch!&#93;&#93;
            &#91;ajax.core :refer &#91;POST&#93;&#93;&#41;&#41;

&#40;defn put! &#91;doc id value&#93;
  &#40;swap! doc assoc :saved? false id value&#41;&#41;

&#40;defn get &#91;doc id&#93;
  &#40;id @doc&#41;&#41;

&#40;defn row &#91;label &amp; body&#93;
  &#91;:div.row
   &#91;:div.col-md-2 &#91;:span label&#93;&#93;
   &#91;:div.col-md-3 body&#93;&#93;&#41;

&#40;defn text-input &#91;doc id label&#93;
  &#91;row label
   &#91;:input {:type &quot;text&quot;
            :class &quot;form-control&quot;
            :value &#40;get doc id&#41;
            :onChange #&#40;put! doc id &#40;-&gt; % .-target .-value&#41;&#41;}&#93;&#93;&#41;

&#40;defn save-doc &#91;doc&#93;
  &#40;POST &quot;/save&quot;
        {:params &#40;dissoc @doc :saved?&#41;
         :handler
         &#40;fn &#91;&#95;&#93;
           &#40;put! doc :saved? true&#41;
           &#40;session/update-in! &#91;:guests&#93; conj @doc&#41;
           &#40;dispatch! &quot;/&quot;&#41;&#41;}&#41;&#41;

&#40;defn guest-page &#91;&#93;
  &#40;let &#91;doc &#40;atom {}&#41;&#93;
    &#40;fn &#91;&#93;
      &#91;:div
       &#91;:div.page-header &#91;:h1 &quot;Sign In&quot;&#93;&#93;

       &#91;text-input doc :first-name &quot;First name&quot;&#93;
       &#91;text-input doc :last-name &quot;Last name&quot;&#93;

       &#40;if &#40;get doc :saved?&#41;
         &#91;:p &quot;Saved&quot;&#93;
         &#91;:button {:type &quot;submit&quot;
                   :class &quot;btn btn-default&quot;
                   :on-click #&#40;save-doc doc&#41;}
          &quot;Submit&quot;&#93;&#41;
       &#91;:button {:type &quot;submit&quot;
                 :class &quot;btn btn-default&quot;
                 :on-click #&#40;dispatch! &quot;/&quot;&#41;} &quot;back&quot;&#93;&#93;&#41;&#41;&#41;
</code></pre><p>The form code on this page is based on the <a href='http://yogthos.net/#/blog/54'>previous tutorial</a> and should hopefully be self explanatory at this point.</p><h3 id="hooking&#95;in&#95;browser&#95;navigation">Hooking in Browser Navigation</h3><p>As a final touch, we can add support for managing history using <code>goog.events</code> to enable more intelligent navigation using the browser.</p><pre><code class="clojure">&#40;ns guestbook.core
 &#40;:require &#91;reagent.session :as session&#93;
           &#91;guestbook.pages.guest-list
            :refer &#91;guest-list-page&#93;&#93;
           &#91;guestbook.pages.guest :refer &#91;guest-page&#93;&#93;
           &#91;reagent.core :as reagent :refer &#91;atom&#93;&#93;
           &#91;secretary.core :as secretary
             :include-macros true :refer &#91;defroute&#93;&#93;
           &#91;goog.events :as events&#93;
           &#91;goog.history.EventType :as EventType&#93;&#41;&#41;

&#40;defn hook-browser-navigation! &#91;&#93;
  &#40;doto &#40;History.&#41;
    &#40;events/listen
      EventType/NAVIGATE
      &#40;fn &#91;event&#93;
        &#40;secretary/dispatch! &#40;.-token event&#41;&#41;&#41;&#41;
    &#40;.setEnabled true&#41;&#41;&#41;

</code></pre><p>The function is then run by the <code>init!</code> function when the app loads:</p><pre><code class="clojure">&#40;defn init! &#91;&#93;
  &#40;load-interceptors!&#41;
  &#40;hook-browser-navigation!&#41;
  &#40;mount-components&#41;&#41;
</code></pre><p>As usual, the source for the project can be found <a href='https://github.com/yogthos/reagent-secretary-example'>here</a>.</p><h3 id="final&#95;thoughts">Final Thoughts</h3><p>The example in this post is intentionally kept trivial, but hopefully it illustrates a simple way to hook up multiple pages and navigate between them using Reagent and secretary.</p><p>I recently rewrote this blog engine to use Reagent and I found that it made the code much cleaner and easier to maintain. I think one of the main benefits of the single page approach is that it enforces a clear separation between the server and the client portions of the application.</p><p>If you’d like to see a complete application built using the approach discussed here, don’t hesitate to take a look at the <a href='https://github.com/yogthos/yuggoth'>code</a> behind this blog.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Transducers are Coming</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">06 08 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Transducers are a powerful and composable way to build algorithmic transformations that you can reuse in many contexts, and they&#8217;re coming to Clojure core and core.async.</p>
</div>
<div class="paragraph">
<p>Two years ago, in a <a href="https://clojure.org/news/2012/05/15/anatomy-of-reducer">blog post describing how reducers work</a>, I described the reducing function transformers on which they were based, and provided explicit examples like <code>mapping</code>, <code>filtering</code> and <code>mapcatting</code>. Because the reducers library intends to deliver an API with the same 'shape' as existing sequence function APIs, these transformers were never exposed a la carte, instead being encapsulated by the macrology of reducers.</p>
</div>
<div class="paragraph">
<p>In working recently on providing algorithmic combinators for core.async, I became more and more convinced of the superiority of reducing function transformers over channel&#8594;channel functions for algorithmic transformation. In fact, I think they are a better way to do many things for which we normally create bespoke replicas of map, filter etc.</p>
</div>
<div class="paragraph">
<p>So, reducing function transformers are getting a name - <strong>transducers</strong>, and first-class support in Clojure core and core.async.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_whats_a_transducer"><a class="anchor" href="#_whats_a_transducer"></a>What&#8217;s a Transducer?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>To recap that earlier post:</p>
</div>
<div class="paragraph">
<p>A reducing function is just the kind of function you&#8217;d pass to <code>reduce</code> - it takes a result so far and a new input and returns the next result-so-far. In the context of transducers it&#8217;s best to think about this most generally:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code>;;reducing function signature
whatever, input -&gt; whatever</code></pre>
</div>
</div>
<div class="paragraph">
<p>and a transducer is a function that takes one reducing function and returns another:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">;;transducer signature
(whatever, input -&gt; whatever) -&gt; (whatever, input -&gt; whatever)</code></pre>
</div>
</div>
<div class="paragraph">
<p>The primary power of transducers comes from their fundamental decoupling - they don&#8217;t care (or know about):</p>
</div>
<div class="ulist">
<ul>
<li>
<p>the 'job' being done (what the reducing function does)</p>
</li>
<li>
<p>the context of use (what 'whatever' is)</p>
</li>
<li>
<p>the source of inputs (where input comes from).</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The other source of power comes from the fact that transducers compose using ordinary function composition.</p>
</div>
<div class="paragraph">
<p>The reducers library leverages transducers' decoupling from the job, the representation, and the source of inputs to accomplish parallel reduction. But transducers can also be used for:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>a la carte laziness</p>
</li>
<li>
<p>transformations during collection building</p>
</li>
<li>
<p>collection/iteration/laziness-free transforming reductions</p>
</li>
<li>
<p>channel transformations, event notifications and more.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>All of this is coming to Clojure core and core.async.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_new_stuff"><a class="anchor" href="#_new_stuff"></a>New stuff</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Concretely, most of the core sequence functions are gaining a new arity, one shorter than their current shortest, which elides the final collection source argument. This arity will return a transducer that represents the same logic, independent of lazy sequence processing.</p>
</div>
<div class="paragraph">
<p>Thus:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">;;look Ma, no collection!
(map f)</code></pre>
</div>
</div>
<div class="paragraph">
<p>returns a 'mapping' transducer. filter et al get similar support.</p>
</div>
<div class="paragraph">
<p>You can build a 'stack' of transducers using ordinary function composition (comp):</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">(def xform (comp (map inc) (filter even?)))</code></pre>
</div>
</div>
<div class="paragraph">
<p>You might notice the similarity between the above comp and a call to &#8594;&gt;:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">(-&gt;&gt; aseq (map inc) (filter even?))</code></pre>
</div>
</div>
<div class="paragraph">
<p>One way to think of transducers is like &#8594;&gt; but independent of the job (lazy sequence creation) and the source of inputs (aseq).</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_transducers_in_action"><a class="anchor" href="#_transducers_in_action"></a>Transducers in action</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Once you&#8217;ve got a transducer, what can you do with it? <em><strong>An open set of things.</strong></em></p>
</div>
<div class="paragraph">
<p>For instance, given the above transducer and some data in a vector, you can:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>lazily transform the data (one lazy sequence, not three as with composed sequence functions)<br></p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="content">
<pre>(sequence xform data)</pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>reduce with a transformation (no laziness, just a loop)<br></p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="content">
<pre>(transduce xform + 0 data)</pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>build one collection from a transformation of another, again no laziness<br></p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="content">
<pre>(into [] xform data)</pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>create a recipe for a transformation, which can be subsequently sequenced, iterated or reduced<br></p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="content">
<pre>(iteration xform data)</pre>
</div>
</div>
<div class="ulist">
<ul>
<li>
<p>or use the same transducer to transform everything that goes through a channel<br></p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="content">
<pre>(chan 1 xform)</pre>
</div>
</div>
<div class="paragraph">
<p>The latter demonstrates the corresponding new capability of core.async channels - they can take transducers.</p>
</div>
<div class="paragraph">
<p>This post is just to serve as a heads up on what the ongoing work is about. There will be more explanations, tutorials and derivations to follow, here and elsewhere.</p>
</div>
<div class="paragraph">
<p>I&#8217;m excited about transducers and the power they bring, and I hope you are too!</p>
</div>
<div class="paragraph">
<p>Rich</p>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Building Single Page Apps with Reagent</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">15 07 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <h2 id="background">Background</h2><p>I recently started working on a new project that has a significant UI component. I decided that this was a good opportunity to take a look at Angular and React for building the client as a single page application.</p><p>After a bit of evaluation, I decided that React was a better fit for the project. Specifically, I found the idea of the virtual DOM very appealing and its component based approach to be a good way to manage the application state.</p><p>Once I got a bit deeper into using React I found it lacking in many areas. For example, it doesn't provide an adequate solution for complex data binding and while there are a few libraries such as <a href='https://github.com/prometheusresearch/react-forms'>react-forms</a>, I didn't find them to be a good fit for my needs.</p><p>Having heard lots of great things about Om, I decided that this might be a good time to revisit ClojureScript. While I've done some projects in ClojureScript <a href='http://yogthos.net/blog/43-Introducing+cljs-ajax'>previously</a>, I always ended up going back to JavaScript in the end.</p><p>For me, the benefits were not enough to outweigh the maturity of JavaScript and the tooling available for it. One of the things I found to be particularly painful was debugging generated JavaScript. This problem has now been addressed by the addition of source maps.</p><h2 id="trying&#95;om">Trying Om</h2><p>As I went through Om tutorials, I found that it exposes a lot of the incidental details to the user. Having to pass <code>nil</code> arguments, reify protocols, and manually convert to Js using <code>#js</code> hints are a but a few warts that I ran into. Although, it's worth noting that the <a href='https://github.com/Prismatic/om-tools'>om-tools</a> library from Prismatic address some of these issues.</p><p>Overall, I feel that Om requires a significant time investment in order to become productive. I found myself wanting a higher level of abstraction for creating UI components and tracking state between them. This led me to trying <a href='http://holmsand.github.io/reagent/'>Reagent</a>. This library provides a very intuitive model for assembling UI components and tracking their state, and you have to learn very few concepts to start using it efficiently.</p><h2 id="differences&#95;between&#95;om&#95;and&#95;reagent">Differences between Om and Reagent</h2><p>Om and Reagent make different design decisions that result in different tradeoffs, each with its own strength and weaknesses. Which of these libraries is better primarily depends on the problem you're solving.</p><p>The biggest difference between Om and Reagent is that Om is highly prescriptive in regards to state management in order to ensure that components are reusable. It's an anti-pattern for Om components to manipulate the global state directly or by calling functions to do so. Instead, components are expected to communicate using <a href='https://github.com/clojure/core.async'>core.async</a> channels. This is done to ensure high modularity of the components. Reagent leaves this part of the design up to you and allows using a combination of global and local states as you see fit.</p><p>Om takes a data centric view of the world by being agnostic about how the data is rendered. It treats the React DOM and Om components as implementation details. This decision often results in code that's verbose and exposes incidental details to the user. These can obviously be abstracted, but Om does not aim to provide such an abstraction and you'd have to write your own helpers as seen with Prismatic and om-tools.</p><p>On the other hand, Reagent provides a standard way to define UI components using <a href='https://github.com/weavejester/hiccup'>Hiccup</a> style syntax for DOM representation. Each UI component is a data structure that represents a particular DOM element. By taking a DOM centric view of the UI, Reagent makes writing composable UI components simple and intuitive. The resulting code is extremely succinct and highly readable. It's worth noting that nothing in the design prevents you from swapping in custom components. The only constraint is that the component must return something that is renderable.</p><h2 id="using&#95;reagent">Using Reagent</h2><p>The rest of this post will walk through building a trivial Reagent app where I hope to illustrate what makes Reagent such an excellent library. Different variations of CRUD apps are probably the most common types of web applications nowadays. Let's take a look at creating a simple form with some fields that we'll want to collect and send to the server.</p><p>I won't go into details of setting up a ClojureScript project in this post, but you can use the <a href='https://github.com/yogthos/reagent-example'>reagent-example</a> project to follow along. The project requires <a href='http://leiningen.org/'>Leiningen</a> build tool and you will need to have it installed before continuing.</p><p>Once you check out the project, you will need to start the ClojureScript compiler by running <code>lein cljsbuild auto</code> and run the server using <code>lein ring server</code>.</p><p>The app consists of UI components that are tied to a model. Whenever the user changes a value of a component, the change is reflected in our model. When the user clicks the submit button then the current state is sent to the server.</p><p>The ClojureScript code is found in the <code>main.core</code> under the <code>src-cljs</code> source directory. Let's delete its contents and start writing our application from scratch. As the first step, we'll need to reference <code>reagent</code> in our namespace definition.</p><pre><code class="clojure">&#40;ns main.core
 &#40;:require &#91;reagent.core :as reagent :refer &#91;atom&#93;&#93;&#41;&#41;
</code></pre><p>Next, let's create a Reagent component to represent the container for our page.</p><pre><code class="clojure">&#40;defn home &#91;&#93;
  &#91;:div
    &#91;:div.page-header &#91;:h1 &quot;Reagent Form&quot;&#93;&#93;&#93;&#41;
</code></pre><p>We can now render this component on the page by calling the <code>render-component</code> function.</p><pre><code class="clojure">&#40;reagent/render-component &#91;home&#93;
  &#40;.getElementById js/document &quot;app&quot;&#41;&#41;
</code></pre><p>As I mentioned above, the components can be nested inside one another. To add a text field to our form we'll write a function to represent it and add it to our <code>home</code> component.</p><pre><code class="clojure">&#40;defn text-input &#91;label&#93;
  &#91;:div.row
    &#91;:div.col-md-2
      &#91;:span label&#93;&#93;
    &#91;:div.col-md-3
      &#91;:input {:type &quot;text&quot; :class &quot;form-control&quot;}&#93;&#93;&#93;&#41;

&#40;defn home &#91;&#93;
  &#91;:div
    &#91;:div.page-header &#91;:h1 &quot;Reagent Form&quot;&#93;&#93;
    &#91;text-input &quot;First name&quot;&#93;&#93;&#41;
</code></pre><p>Notice that even though <code>text-input</code> is a function we're not calling it, but instead we're putting it in a vector. The reason for this is that we're specifying the component hierarchy. The components will be run by Reagent when they need to be rendered.</p><p>We can also easily extract the row into a separate component. Once again, we won't need to call the <code>row</code> function directly, but can treat the component as data and leave it up to Reagent when it should be evaluated.</p><pre><code class="clojure">&#40;defn row &#91;label &amp; body&#93;
  &#91;:div.row
   &#91;:div.col-md-2 &#91;:span label&#93;&#93;
   &#91;:div.col-md-3 body&#93;&#93;&#41;

&#40;defn text-input &#91;label&#93;
  &#91;row label &#91;:input {:type &quot;text&quot; :class &quot;form-control&quot;}&#93;&#93;&#41;

</code></pre><p>We now have an input field that we can display. Next, we need to create a model and bind our component to it. Reagent allows us to do this using its <code>atom</code> abstraction over the React state. The Reagent atoms behave just like standard Clojure atoms. The main difference is that a change in the value of the atom causes any components that dereference it to be repainted.</p><p>Any time we wish to create a local or global state we create an atom to hold it. This allows for a simple model where we can create variables for the state and observe them as they change over time. Let's add an atom to hold the state for our application and a couple of handler functions for accessing and updating it.</p><pre><code class="clojure">&#40;def state &#40;atom {:doc {} :saved? false}&#41;&#41;

&#40;defn set-value! &#91;id value&#93;
  &#40;swap! state assoc :saved? false&#41;
  &#40;swap! state assoc-in &#91;:doc id&#93; value&#41;&#41;

&#40;defn get-value &#91;id&#93;
  &#40;get-in @state &#91;:doc id&#93;&#41;&#41;

</code></pre><p>We can now update our <code>text-input</code> component to set the state when the <code>onChange</code> event is called and display the current state as its <code>value</code>.</p><pre><code class="clojure">&#40;defn text-input &#91;id label&#93;
  &#91;row label
   &#91;:input
     {:type &quot;text&quot;
       :class &quot;form-control&quot;
       :value &#40;get-value id&#41;
       :on-change #&#40;set-value! id &#40;-&gt; % .-target .-value&#41;&#41;}&#93;&#93;&#41;

&#40;defn home &#91;&#93;
  &#91;:div
    &#91;:div.page-header &#91;:h1 &quot;Reagent Form&quot;&#93;&#93;
    &#91;text-input :first-name &quot;First name&quot;&#93;&#93;&#41;
</code></pre><p>Let's add a save button to our form so that we can persist the state. For now, we'll simply log the current state to the console.</p><pre><code class="clojure">&#40;defn home &#91;&#93;
  &#91;:div
    &#91;:div.page-header &#91;:h1 &quot;Reagent Form&quot;&#93;&#93;
    &#91;text-input :first-name &quot;First name&quot;&#93;    
    &#91;:button {:type &quot;submit&quot;
              :class &quot;btn btn-default&quot;
              :on-click #&#40;.log js/console &#40;clj-&gt;js @state&#41;&#41;}
     &quot;Submit&quot;&#93;&#93;&#41;
</code></pre><p>If we open the console, then we should see the current value of the <code>:first-name</code> key populated in our document whenever we click submit. We can now easily add a second component for the last name and see that it gets bound to our model in exactly the same way.</p><pre><code class="clojure">&#40;defn home &#91;&#93;
  &#91;:div
    &#91;:div.page-header &#91;:h1 &quot;Reagent Form&quot;&#93;&#93;

    &#91;text-input :first-name &quot;First name&quot;&#93;
    &#91;text-input :last-name &quot;First name&quot;&#93;

    &#91;:button {:type &quot;submit&quot;
              :class &quot;btn btn-default&quot;
              :onClick #&#40;.log js/console &#40;clj-&gt;js @state&#41;&#41;}
     &quot;Submit&quot;&#93;&#93;&#41;
</code></pre><p>So far we've been using a global variable to hold all our state, while it's convenient for small applications this approach doesn't scale well. Fortunately, Reagent allows us to have localized states in our components. Let's take a look at implementing a multi-select component to see how this works.</p><p>When the user clicks on an item in the list, we'd like to mark it as selected. Obviously, this is something that's only relevant to the list component and shouldn't be tracked globally. All we have to do to create a local state is to initialize it in a closure.</p><p>We'll implement the multi-select by creating a component to represent the list and another to represent each selection item. The list component will accept an id and a label followed by the selection items.</p><p>Each item will be represented by a vector containing the id and the value of the item, eg: <code>&#91;:beer &quot;Beer&quot;&#93;</code>. The value of the list will be represented by a collection of the ids of the currently selected items.</p><p>We will use a <code>let</code> binding to initialize an atom with a map keyed on the item ids to represent the state of each item.</p><pre><code class="clojure">&#40;defn selection-list &#91;id label &amp; items&#93;
  &#40;let &#91;selections &#40;-&gt;&gt; items &#40;map &#40;fn &#91;&#91;k&#93;&#93; &#91;k false&#93;&#41;&#41; &#40;into {}&#41; atom&#41;&#93;    
    &#40;fn &#91;&#93;
      &#91;:div.row
       &#91;:div.col-md-2 &#91;:span label&#93;&#93;
       &#91;:div.col-md-5
        &#91;:div.row
         &#40;for &#91;&#91;k v&#93; items&#93;
          &#91;list-item id k v selections&#93;&#41;&#93;&#93;&#93;&#41;&#41;&#41;
</code></pre><p>The item component will be responsible for updating its state when clicked and persisting the new value of the list in the document.</p><pre><code class="clojure">&#40;defn list-item &#91;id k v selections&#93;
  &#40;letfn &#91;&#40;handle-click! &#91;&#93;
            &#40;swap! selections update-in &#91;k&#93; not&#41;
            &#40;set-value! id &#40;-&gt;&gt; @selections
                                &#40;filter second&#41;
                                &#40;map first&#41;&#41;&#41;&#41;&#93;
    &#91;:li {:class &#40;str &quot;list-group-item&quot;
                      &#40;if &#40;k @selections&#41; &quot; active&quot;&#41;&#41;
          :on-click handle-click!}
      v&#93;&#41;&#41;
</code></pre><p>Let's add an instance of the <code>selection-list</code> component to our form and see how it looks.</p><pre><code class="clojure">&#40;defn home &#91;&#93;
  &#91;:div
    &#91;:div.page-header &#91;:h1 &quot;Reagent Form&quot;&#93;&#93;

    &#91;text-input :first-name &quot;First name&quot;&#93;
    &#91;text-input :last-name &quot;First name&quot;&#93;

    &#91;selection-list :favorite-drinks &quot;Favorite drinks&quot;
     &#91;:coffee &quot;Coffee&quot;&#93;
     &#91;:beer &quot;Beer&quot;&#93;
     &#91;:crab-juice &quot;Crab juice&quot;&#93;&#93;

    &#91;:button {:type &quot;submit&quot;
              :class &quot;btn btn-default&quot;
              :onClick #&#40;.log js/console &#40;clj-&gt;js @state&#41;&#41;}
     &quot;Submit&quot;&#93;&#93;&#41;
</code></pre><p>Finally, let's update our submit button to actually send the data to the server. We'll use the <a href='https://github.com/JulianBirch/cljs-ajax'>cljs-ajax</a> library to handle our Ajax calls. Let's add the following dependency <code>&#91;cljs-ajax &quot;0.2.6&quot;&#93;</code> to our <code>project.clj</code> and update our namespace to reference it.</p><pre><code class="clojure">&#40;ns main.core
 &#40;:require &#91;reagent.core :as reagent :refer &#91;atom&#93;&#93;
           &#91;ajax.core :refer &#91;POST&#93;&#93;&#41;&#41;
</code></pre><p>With that in place we can write a <code>save-doc</code> function that will send the current state of the document to the server and set the state to saved on success.</p><pre><code class="clojure">&#40;defn save-doc &#91;&#93;
  &#40;POST &#40;str js/context &quot;/save&quot;&#41;
        {:params &#40;:doc @state&#41;
         :handler &#40;fn &#91;&#95;&#93; &#40;swap! state assoc :saved? true&#41;&#41;}&#41;&#41;
</code></pre><p>We can now update our form to either display a message indicating that the document has been saved or the submit button based on the value of the <code>:saved?</code> key in our state atom.</p><pre><code class="clojure">&#40;defn home &#91;&#93;
  &#91;:div
    &#91;:div.page-header &#91;:h1 &quot;Reagent Form&quot;&#93;&#93;

    &#91;text-input :first-name &quot;First name&quot;&#93;
    &#91;text-input :last-name &quot;Last name&quot;&#93;
    &#91;selection-list :favorite-drinks &quot;Favorite drinks&quot;
     &#91;:coffee &quot;Coffee&quot;&#93;
     &#91;:beer &quot;Beer&quot;&#93;
     &#91;:crab-juice &quot;Crab juice&quot;&#93;&#93;

   &#40;if &#40;:saved? @state&#41;
     &#91;:p &quot;Saved&quot;&#93;
     &#91;:button {:type &quot;submit&quot;
              :class &quot;btn btn-default&quot;
              :onClick save-doc}
     &quot;Submit&quot;&#93;&#41;&#93;&#41;
</code></pre><p>On the server side we'll simply log the value submitted by the client and return "ok".</p><pre><code class="clojure">&#40;ns reagent-example.routes.services
  &#40;:use compojure.core&#41;
  &#40;:require &#91;reagent-example.layout :as layout&#93;
            &#91;noir.response :refer &#91;edn&#93;&#93;
            &#91;clojure.pprint :refer &#91;pprint&#93;&#93;&#41;&#41;

&#40;defn save-document &#91;doc&#93;
  &#40;pprint doc&#41;
  {:status &quot;ok&quot;}&#41;

&#40;defroutes service-routes
  &#40;POST &quot;/save&quot; {:keys &#91;body-params&#93;}
        &#40;edn &#40;save-document body-params&#41;&#41;&#41;&#41;
</code></pre><p>With the route hooked up in our handler we should see something like the following whenever we submit a message from our client:</p><pre><code class="clojure">{:first-name &quot;Jasper&quot;, :last-name &quot;Beardly&quot;, :favorite-drinks &#40;:coffee :beer&#41;}
</code></pre><p>As you can see, getting started with Reagent is extremely easy and it requires very little code to create a working application. You could say that single page Reagent apps actually fit on a single page. :) In the next installment we'll take a look at using the <a href='https://github.com/gf3/secretary'>secretary</a> library to add client side routing to the application.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Pattern Libraries</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">08 07 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I&rsquo;ve recently been working on a web app from the ground up. Bootstrap 3 was a good choice to get started - it is super easy to get a site up and running without having to worry too much about styling. In essence, it allowed me to build out some of the requirements with a wireframe-y front-end.
After a while, the designs for the app were ready and it was time to apply the styles to make the app look good.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Pattern Libraries</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">08 07 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        I&rsquo;ve recently been working on a web app from the ground up. Bootstrap 3 was a good choice to get started - it is super easy to get a site up and running without having to worry too much about styling. In essence, it allowed me to build out some of the requirements with a wireframe-y front-end.
After a while, the designs for the app were ready and it was time to apply the styles to make the app look good.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">From Backbone To React: Our Experience Scaling a Web Application</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Murilo Pereira</a> <span class="article__date">22 06 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        At Sonian we have a small team building interactive visualizations where companies can better understand their massive amounts of email data. Building this kind of program is non-trivial: data needs to be synchronized between servers and complex interfaces through user interactions or otherwise while at the same time having the user perceive it as &ldquo;feeling right&rdquo;. Like other software disciplines it&rsquo;s a combination of engineering and art.
As engineers we want to write our programs so that they have as few bugs as possible and are easily extendable, and as a company delivering value to customers we want stable features delivered quickly.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Angular Boilerplate</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">15 05 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        It&rsquo;s important in this era of web application development to have a strong toolset at your disposal. Growing complexity with &lsquo;fat&rsquo; client apps can lead to a maintenance nightmare if not properly planned and thought out.
Luckily there are a number of projects out there that can help. One such project is Yeoman, which is &lsquo;The Web&rsquo;s Scaffolding Tool for Modern Webapps&rsquo;. Yeoman essentially bundles together a few of the web&rsquo;s most important front-end tools:
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Angular Boilerplate</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">15 05 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        It&rsquo;s important in this era of web application development to have a strong toolset at your disposal. Growing complexity with &lsquo;fat&rsquo; client apps can lead to a maintenance nightmare if not properly planned and thought out.
Luckily there are a number of projects out there that can help. One such project is Yeoman, which is &lsquo;The Web&rsquo;s Scaffolding Tool for Modern Webapps&rsquo;. Yeoman essentially bundles together a few of the web&rsquo;s most important front-end tools:
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Righteousness</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">14 05 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Over Easter, our pastor challenged us to live like Jesus is actually risen. Someone I know (quite rightly) asked the question “but what does that look like?” My response is that part of the answer is <em>righteousness</em>, but that might need some explaining.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Case for React.js and ClojureScript</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Murilo Pereira</a> <span class="article__date">01 05 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        This presentation is a comparison of MVC web frameworks with React.js and ClojureScript. It was given to the engineering team at Sonian in May 2014.
Discussion on Hacker News: link.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Mongoose Validations</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">23 04 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A few years ago, I was involved in building a product using Hibernate. This was the first exposure I had to auto-validation of data models according to their schemas, and I soon learned how powerful and time-saving this was.
One of the great advantages of using Mongoose over plain MongoDB is its built-in support for data schemas, and hence automatic validation of data when it is persisted. I&rsquo;ve jotted down some notes here on how to configure validators in the latest version of Mongoose (3.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Mongoose Validations</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">23 04 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        A few years ago, I was involved in building a product using Hibernate. This was the first exposure I had to auto-validation of data models according to their schemas, and I soon learned how powerful and time-saving this was.
One of the great advantages of using Mongoose over plain MongoDB is its built-in support for data schemas, and hence automatic validation of data when it is persisted. I&rsquo;ve jotted down some notes here on how to configure validators in the latest version of Mongoose (3.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Using Mongoose</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">21 04 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        One of the things I really like about MongoDB is its flexibility. Data is schemaless, and so you can insert pretty much any JSON object you like into a MongoDB collection. Having not spent too much time with so-called NoSQL databases, this takes a little bit of getting used to.
One area which can cause problems, however, is if your application relies on data being structured in a certain way. For many apps, this is the case - for example, you may wish to loop through an array of items, displaying them in a list, expecting each item to have certain fields to be rendered in the same layout.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Using Mongoose</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">21 04 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        One of the things I really like about MongoDB is its flexibility. Data is schemaless, and so you can insert pretty much any JSON object you like into a MongoDB collection. Having not spent too much time with so-called NoSQL databases, this takes a little bit of getting used to.
One area which can cause problems, however, is if your application relies on data being structured in a certain way. For many apps, this is the case - for example, you may wish to loop through an array of items, displaying them in a list, expecting each item to have certain fields to be rendered in the same layout.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Learning Angular</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">07 04 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The last week has been an intense period of training. I&rsquo;ve taken up the offer of a project to be built using AngularJS, and so my head has been down in tutorials, books and online docs.
JavaScript Before you start learning Angular, you need to know JavaScript, and know it well. Get started with JavaScript with Eloquent JavaScript and buy The Good Parts.
Thinkster Entitled A Better Way to Learn AngularJS, the Thinkster course is excellent.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Learning Angular</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">07 04 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        The last week has been an intense period of training. I&rsquo;ve taken up the offer of a project to be built using AngularJS, and so my head has been down in tutorials, books and online docs.
JavaScript Before you start learning Angular, you need to know JavaScript, and know it well. Get started with JavaScript with Eloquent JavaScript and buy The Good Parts.
Thinkster Entitled A Better Way to Learn AngularJS, the Thinkster course is excellent.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Becoming Angular</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">31 03 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        During my time at Mubaloo I was a vocal supporter of Backbone.js. I liked the promise that it would &lsquo;give structure to web applications&rsquo;. It also seemed very lightweight, and as we were building mobile web applications, this seemed like an important consideration, especially given the processing power of mobile devices at the time.
Building apps with Backbone was certainly much better than the alternative, but after using it for a while, it became very apparent that you need to write a lot of boilerplate code in a Backbone-based app.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Becoming Angular</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">31 03 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        During my time at Mubaloo I was a vocal supporter of Backbone.js. I liked the promise that it would &lsquo;give structure to web applications&rsquo;. It also seemed very lightweight, and as we were building mobile web applications, this seemed like an important consideration, especially given the processing power of mobile devices at the time.
Building apps with Backbone was certainly much better than the alternative, but after using it for a while, it became very apparent that you need to write a lot of boilerplate code in a Backbone-based app.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Self Employment</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">25 03 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        While I was away, I had a lot of time to think about the future. The past 8 years building web apps have been a lot of fun - challenging, sure, but fun too. Rather quickly, I came to the conclusion that I wanted to return to doing the job I love.
Prior to going away, to add a bit of money to our travelling fund, I took on some contract work in addition to my full-time job at Mubaloo.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Self Employment</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">25 03 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        While I was away, I had a lot of time to think about the future. The past 8 years building web apps have been a lot of fun - challenging, sure, but fun too. Rather quickly, I came to the conclusion that I wanted to return to doing the job I love.
Prior to going away, to add a bit of money to our travelling fund, I took on some contract work in addition to my full-time job at Mubaloo.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A New Beginning</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">18 03 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Well, I&rsquo;ve been away for a little while. 200 days&rsquo; worh of travelling has changed many aspects of me and my life, but I&rsquo;m actually happy to be back and looking forward to getting back into the world of web development.
I&rsquo;m sure things have progressed at a fast rate over the past 7 months, and so I&rsquo;m expecting a bit of research and training to hone my skills once again.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A New Beginning</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Blogs on Tom Spencer</a> <span class="article__date">18 03 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Well, I&rsquo;ve been away for a little while. 200 days&rsquo; worh of travelling has changed many aspects of me and my life, but I&rsquo;m actually happy to be back and looking forward to getting back into the world of web development.
I&rsquo;m sure things have progressed at a fast rate over the past 7 months, and so I&rsquo;m expecting a bit of research and training to hone my skills once again.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">No Free Lunch</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">26 01 2014</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>On paper static typing sounds strictly superior to dynamic typing. The compiler can track the data flow throughout our code and tell us when we're using the data incorrectly. This clearly eliminates a whole class of errors that are otherwise possible. What's more, types allow us to encode the business logic of our application allowing us to write code that's provably correct.</p><p>All this is unarguably correct, however these benefits do not come for free. One major problem is that static typing requires us to declare all the relationships globally. When you have global relationships a change at any level requires global refactoring at every level.</p><p>In my opinion, this makes static typing poorly suited for situations where your requirements are incomplete or subject to change, and in reality there are very few scenarios where your requirements are set in stone.</p><p>In most cases, we only care about a local contract between any two functions. What we want to know is that the function being called produces the type expected by the caller. A modification of a local contract should not cause global change in our code base.</p><p>Another cost of static typing is that it forces us to handle cases that are not part of the application workflow. For example, our code might have an undefined behavior, but the interface does not allow the user to access this state. This is a case of a tree falling in the woods when no one's around.</p><p>Regardless of the type system that you use, you will need to do functional testing in order to ensure that the business logic does what's intended. At the end of the day, the goal of the application is to handle the intended use cases as opposed to providing a proof of correctness.</p><p>When I look at the GitHub issues for my own projects such as <a href='https://github.com/yogthos/Selmer'>Selemer</a> or <a href='https://github.com/yogthos/markdown-clj/issues?page=1&state=closed'>markdown-clj</a>, vast majority of them stem from lack of specification. Practically none of these issues would have been caught by the type system. Had I used a statically typed language to write these projects, I would've simply had to jump through more hoops to end up with the same result.</p><p>In my opinion the value added by a static type system has to be weighed against the complexity of the problem and the cost of errors. Since it's obviously useful in some cases and provides dubious value in others, an optional type system might provide the right balance. Static typing is a tool and it should be up to the developer to decide how and when to apply it.</p><p>With an optional static checker we can add types where it makes sense and leave the rest of the code dynamic. This is precisely the situation <a href='http://blog.circleci.com/supporting-typed-clojure/'>CircleCI found themselves in</a>.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure High Performance Programming Review</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">09 12 2013</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>First thing I'd like to say is that I'm very excited by the shift in nature of Clojure books that are coming out. There are already many excellent books about the language itself. Some of these include <a href='http://www.amazon.com/The-Joy-Clojure-Michael-Fogus/dp/1617291412/'>The Joy of Clojure</a>, <a href='http://www.amazon.com/Programming-Clojure-Stuart-Halloway/dp/1934356867'>Programming Clojure</a>, and <a href='http://www.amazon.com/Clojure-Action-Amit-Rathore/dp/1935182595'>Clojure in Action</a>.</p><p>This year we can add <a href='http://www.amazon.com/Clojure-Data-Analysis-Cookbook-Rochester-ebook/dp/B00BECVV9C'>Clojure Data Analysis Cookbook</a>, <a href='http://clojure-cookbook.com/'>Clojure Cookbook</a>, my own <a href='http://pragprog.com/book/dswdcloj/web-development-with-clojure'>Web Development With Clojure</a>, and <a href='http://www.amazon.com/Clojure-Performance-Programming-Shantanu-Kumar-ebook/dp/B00GTE1RVW'>Clojure High Performance Programming</a> to the roster. All these books focus on applying the language in the real world.</p><p>To me this indicates that developers are moving from simply experimenting with the language to actually using it professionally. The results from the <a href='http://cemerick.com/2013/11/18/results-of-the-2013-state-of-clojure-clojurescript-survey/'>2013 State of Clojure & ClojureScript</a>, where more than half the respondents reported using Clojure at work, appear to corroborate this idea.</p><p>One of the things that makes Clojure attractive is the fact that it's one of the more performant dynamic languages. As can be seen in the recent round of <a href='http://www.techempower.com/benchmarks/'>TechEmpower Benchmarks</a>, Clojure web frameworks fare quite well compared to the popular offerings in Ruby and Python. Since performance is a major factor in using Clojure, a book discussing high performance programming is a welcome addition.</p><p>The book starts off by introducing the reader to performance use case classification. It does a decent job of explaining the background concepts and the vocabulary that will be used throughout.</p><p>Different types of scenarios are discussed and their related performance concerns. For example, when we deal with user interfaces, responsiveness is our main concern. On the other hand if we're doing data-processing then we want to optimize CPU and memory usage.</p><p>The author then moves on to discuss how common Clojure idioms impact the performance of the application. Understanding what goes on behind the scenes helps reason about potential pitfalls down the road.</p><p>There's a good discussion about the explicit use of <code>loop/recur</code> over higher order functions that illustrates a way to squeeze out additional performance. In another section the author goes on to explain the impact of laziness on performance in functional languages. </p><p>There are also tips regarding the use of different data formats. One example compares the benefits of EDN over JSON. EDN can save memory by using interned symbols and keywords, while JSON uses string keys which will not be interned. The author explains that in addition to saving memory, interning also avoids heap usage and this helps minimize garbage collection. This is something you would definitely want to consider if you were working with a high performance application.</p><p>The techniques used by some of the popular libraries, such as <a href='https://github.com/ptaoussanis/nippy'>Nippy</a>, are examined to see how they achieve high performance. These kinds of real world examples are very helpful. Not only do we learn about the theory, but we also get to see how it's applied in practice.</p><p>In general, the book covers a wide range of topics, but only offers a superficial overview for many. The reader will most certainly need to do further research in order to apply many of the concepts discussed.</p><p>If you're looking for a refresher or a primer on the topics discussed, then it's not a bad place to start. However, if you're looking for a comprehensive discussion on doing high performance programming with Clojure, you'll likely be left wanting.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://yogthos.net/files/selmererror.png" alt="Making Selmer User Friendly">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Making Selmer User Friendly</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">21 11 2013</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>It's been nearly 5 month since Selmer was released. In that time many bugs have been squashed and lots of new features added. However, there is one aspect that remained shameful and that was error reporting.</p><p>When Selmer failed to parse a template it would often produce error messages that were less than useful. For example, given the following template:</p><pre><code class="xml">&lt;html&gt;
  &lt;body&gt;
    {% blok %}
    {% endblock %}
    &lt;h2&gt;Hello {{name}}&lt;/h2&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre><p>we'd end up with the following error after trying to render it:</p><pre><code>Exception in thread &quot;main&quot; java.lang.Exception: unrecognized tag: :blok - did you forget to close a tag?
</code></pre><p>While the error indicated the name of the problem tag, it didn't say what template this tag originated from or on what line it appeared.</p><p>These types of errors can result in a lot of wasted time and frustration. It would be much better to provide a clear error that contains the actual offending tag along with the name of the template and the line number.</p><p>As of version <code>0.4.8</code>, Selmer has a validator that checks the following cases:</p><ul><li>can the tag be parsed successfully</li><li>is the filter found in the map of filters</li><li>does the tag contain a name</li><li>is the tag name found in the map of tags</li><li>if a tag is a block tag, is the corresponding closing tag found</li><li>is the tag a closing tag for an opening tag that's not present</li></ul><p>Here's the error returned by the validator when rendering the above template:</p><pre><code>Exception in thread &quot;main&quot; java.lang.Exception: Unrecognized tag: {% blok %} on line 3 for template file:/Users/Yogthos/selmer-test/resources/index.html
</code></pre><p>This gives us a lot more information as to what went wrong and where. This is a big improvement on the original error, however we still have an ugly stacktrace to look at to figure out what happened.</p><p>It would be even better to return a distinct validation error that could be intercepted by some middleware to produce a friendly error page.</p><p>This is precisely what Selmer does as of version <code>0.5.3</code>. The validator will now return <code>ex-info</code> with a key <code>:type</code> that's set to <code>:selmer-validation-error</code>.</p><p>It will also contain an error page template that can be rendered using the <code>ex-data</code> attached to the exception. We can now write a simple middleware function to catch these errors and render the error page:</p><pre><code class="clojure">&#40;defn template-error-page &#91;handler&#93;
  &#40;fn &#91;request&#93;
    &#40;try
      &#40;handler request&#41;
      &#40;catch clojure.lang.ExceptionInfo ex
        &#40;let &#91;{:keys &#91;type error-template&#93; :as data} &#40;ex-data ex&#41;&#93;
          &#40;if &#40;= :selmer-validation-error type&#41;
            {:status 500
             :body   &#40;selmer.parser/render error-template data&#41;}
            &#40;throw ex&#41;&#41;&#41;&#41;&#41;&#41;&#41;
</code></pre><p>Using the above middleware, we'll see the following page whenever the parser fails to compile a template:</p><p><center> <img src="http://yogthos.net/files/selmererror.png" alt="Selmer error" /> </center></p><p>We can now immediately tell that an error occurred during the template compilation and see only the information pertaining to the nature of the error.</p><p>Of course, we wouldn't want to display this information when running in production. A simple solution would be to set a <code>dev</code> flag and check for it in our middleware.</p><p>This is precisely what the latest <a href='http://www.luminusweb.net/'>Luminus</a> template will do using the <a href='https://github.com/weavejester/environ'>environ</a> library. The <code>project.clj</code> now contains an <code>:env</code> key under the <code>:dev</code> profile with the <code>:selmer-dev</code> flag set to <code>true</code>:</p><pre><code class="clojure">:dev {:dependencies &#91;&#91;ring-mock &quot;0.1.5&quot;&#93;
                     &#91;ring/ring-devel &quot;1.2.1&quot;&#93;&#93;
      :env {:selmer-dev true}}}
</code></pre><p>The middleware will check that the key is present and only render the error page in development mode:</p><pre><code class="clojure">&#40;defn template-error-page &#91;handler&#93;
  &#40;if &#40;env :selmer-dev&#41;
    &#40;fn &#91;request&#93;
      &#40;try
        &#40;handler request&#41;
        &#40;catch clojure.lang.ExceptionInfo ex
          &#40;let &#91;{:keys &#91;type error-template&#93; :as data} &#40;ex-data ex&#41;&#93;
            &#40;if &#40;= :selmer-validation-error type&#41;
              {:status 500
               :body &#40;parser/render error-template data&#41;}
              &#40;throw ex&#41;&#41;&#41;&#41;&#41;&#41;
    handler&#41;&#41;
</code></pre><p>When it comes to writing libraries it's easy to forget about the little things like error reporting and documentation. However, these things are just as important as having good code and a clean API. </p><p>In the end, this is what makes the difference between a pleasant development experience and one that's fraught with frustration.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Public perceptions of Christianity—a call to art</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">29 09 2013</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>First of all, I write this to myself as much as anybody. Now, with that said…</p>

<p>I am concerned about how Christianity is perceived by those who don’t call themselves ‘Christian.’ It’s not that Christians are ridiculed in the media (we’ve always been ridiculed), but rather, what people assume I mean when I call myself a Christian is so very different from what I actually mean that I’m almost hesitant to use the word.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Simple Parallel Processing in PHP with pcntl_fork()</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">19 09 2013</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>For a recent project I needed to process some code in parallel. A colleague pointed me to the <code>pcntl_fork()</code> function, and it turns out it’s not quite as scary and complicated as I thought. So I turned the simple use case into a generic function.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Simple Parallel Processing in PHP with pcntl_fork()</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">19 09 2013</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>For a recent project I needed to process some code in parallel. A colleague pointed me to the <code>pcntl_fork()</code> function, and it turns out it’s not quite as scary and complicated as I thought. So I turned the simple use case into a generic function.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Web Development With Clojure Beta</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">28 08 2013</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I'm happy to announce that <a href='http://pragprog.com/book/dswdcloj/web-development-with-clojure'>Web Development With Clojure</a> has finally reached beta and it's now available for purchase.</p><p>The book covers working with the core Ring/Compojure stack, common libraries as well as techniques for accomplishing common tasks. My main goal is to make the reader comfortable with the Clojure ecosystem and demonstrate how to take an application from inception all the way to deployment.</p><p>It's been a long journey to get to this point and I learned much along the way. This book is my way to share that experience with you and hopefully save you time when working on your projects.</p><p>There's still some clean up left to do and you might see a few typos here and there. However, there won't be any changes to the core content at this point and I hope that you'll be curious enough to take a look. :)</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://yogthos.net/files/selmercommits.png" alt="Why I&#39;m Productive in Clojure">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Why I&#39;m Productive in Clojure</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">18 08 2013</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I find that I often get excited about learning a new language, but after I use it for a while it will inevitably lose its lustre. Eventually it becomes just another language in my tool box. </p><p>One exception to this rule is Clojure. I still enjoy using the language as much as I did when I first learned it. The reason for this is that it strikes the right balance between power and simplicity.</p><h3 id="the&#95;balance&#95;of&#95;power">The Balance of Power</h3><p>Some languages are simple but they're also verbose. You've probably heard people say that verbosity really doesn't matter. These people will go to great length to point out that all languages are Turing complete and that in certain languages you simply have to write a bit more code.</p><p>I think that's missing the point however. The question is not whether something can be expressed in principle. It's how well the language maps to the problem being solved. One language will let you think in terms of your problem domain, while another will force you to translate the problem to its constructs.</p><p>The latter is often tedious and rarely enjoyable. You end up writing a lot of boilerplate code and constantly repeating yourself. I hope you'll agree that there is a certain amount of irony involved in having to write repetitive code.</p><p>Other languages aren't verbose and they provide many different tools for solving problems. Unfortunately, working in such languages is often akin to trying to decide on a particular set of screwdrivers at a hardware megastore.</p><p>You end up comparing this brand against that, checking the number of bits that comes with each set, seeing which one's on sale today, and soon you forget why you wanted a screwdriver in the first place. </p><p>The more features there are the more things you have to keep in your head to work with the language effectively. With many languages I find myself constantly expending mental overhead thinking about all the different features and how they interact with one another.</p><p>What matters to me in a language is whether I can use it without thinking about it. When the language is lacking in expressiveness I'm acutely aware that I'm writing code that I shouldn't be. On the other hand when the language has too many features I often feel overwhelmed or I get distracted playing with them.</p><p>To make an analogy with math, it's nicer to have a general formula that you can derive others from than having to memorize a whole bunch of formulas for specific problems.</p><p>This is where Clojure comes in. With it I can always easily derive a solution to a particular problem from a small set of general patterns. The number of things I have to keep in my head is not overbearing.</p><p>All you need to become productive is to learn a few simple concepts and a bit of syntax. However, the number of ways that these concepts can be combined to solve all manner of problems appears to be inexhaustible. I've been writing Clojure for years and I discover new ways to combine the things I already know every single day.</p><p>Macros are a good example of this. The fact that you can transform the language using itself allows tackling a wide range of problems that would otherwise require a range of specific tools and language features.</p><h3 id="interactive&#95;development">Interactive Development</h3><p>When I'm solving a problem in Clojure I inevitably want to write an elegant solution that expresses the gist of it cleanly and clearly. This is largely due to the fact that the development process is interactive. </p><p>When I work with the REPL I can fumble around looking for a solution and make sense of it through experimentation. Once I've internalized the problem I can quickly write a clean solution using my newly gained understanding.</p><p>The REPL also helps keep me engaged in trying to find the solution. Being able to try things and get immediate feedback is enjoyable. Even when your code doesn't do what you want you can see the progression and that is often enough of a motivator to keep going.</p><p>Another important feature of the REPL is that it encourages refactoring. I'm much more likely to refactor code when I can easily test it without disrupting my workflow.</p><h3 id="finishing&#95;things">Finishing Things</h3><p>Interactivity alone isn't enough however. All the feedback in the world wouldn't make one bit of difference if you couldn't actually solve your problem in a reasonable amount of time.</p><p>I find that I have a sharp falloff curve when it comes to staying engaged in a project. You've probably noticed this phenomenon yourself. When you start a project you're excited and you enjoy seeing it take shape.</p><p>However, after working on a project for some amount of time the excitement wanes. Eventually, you might even dread having to touch the code again. I find that it's critical to get the core functionality working before I hit this stage.</p><p>Once the project solves a particular problem that I have I'll start using it. At this point I get to reap the benefits of having spent the effort on it. This also lets me identify the functionality that I'm missing through usage. There is a lot more incentive to add features to a project that you're actually using.</p><p>Most recently I found this to be the case working on <a href='https://github.com/yogthos/Selmer'>Selmer</a>. I was able to implement the base parser in just a couple of days, while <a href='https://github.com/cesarbp'>cesarbp</a> implemented the logic for the filters.</p><p>It took a couple of more days to get the template inheritance logic working. All of a sudden we had a usable library in under a week of effort. I'm already actively using it for actual work and new features are added piecemeal as the need comes up.</p><p>Here's the GitHub <a href='https://github.com/yogthos/Selmer/graphs/code-frequency'>activity</a> graph for Selmer:</p><p><a href='https://github.com/yogthos/Selmer/graphs/code-frequency'><img src="http://yogthos.net/files/selmercommits.png" alt="Selmer activity" /></a></p><p>As you can see there's a big initial spike with a very sharp falloff. A similar patten can be seen in my other projects such as <a href='https://github.com/yogthos/clj-pdf'>clj-pdf</a> and with <a href='https://github.com/yogthos/luminus'>Luminus</a>:</p><p><a href='https://github.com/yogthos/clj-pdf/graphs/code-frequency'><img src="http://yogthos.net/files/clj-pdfcommits.png" alt="clj-pdf activity" /></a></p><p><a href='https://github.com/yogthos/luminus/graphs/code-frequency'><img src="http://yogthos.net/files/luminuscommits.png" alt="Luminus activity" /></a></p><p>As the project matures bugs are inevitably found or new features are added, these correspond the occasional spikes in the activity. However, if the initial phase of the project can't be completed in a timely fashion then nothing else can happen.</p><p>In my experience, if you can't get something interesting working in a few days the likelihood of actually finishing the project starts rapidly approaching zero.</p><p>With Clojure you can get things done fast, fast enough that you get something working while the initial spark of excitement is still present. I would hazard to guess that this is the reason why Clojure has so many great libraries despite being a young language.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Introducing Selmer</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">30 07 2013</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <h2 id="rationale">Rationale</h2><p>There are a number of templating engines available in Clojure. Some of the popular ones include <a href='https://github.com/weavejester/hiccup'>Hiccup</a>, <a href='https://github.com/cgrand/enlive'>Enlive</a>, <a href='https://github.com/Raynes/laser'>Laser</a>, <a href='https://github.com/davidsantiago/stencil'>Stencil</a>, <a href='https://github.com/shenfeng/mustache.clj'>mustache.clj</a> and <a href='https://github.com/danlarkin/clabango'>Clabango</a>.</p><p>As <a href='http://yogthos.net/blog/41-New+Templating+Engine+in+Luminus'>I've mentioned previously</a>, my personal preference is for Clabango syntax. In my opinion it provides the right balance between simplicity and flexibility. Being modeled on Django template syntax it's also very accessible to those who are new to Clojure web development.</p><p>However, one major downside to Clabango is that it's slow. On TechEmpower <a href='http://www.techempower.com/benchmarks/#section=data-r6&hw=i7&test=fortune&f=4-0-1s'>fortunes benchmark</a> Luminus is crawling behind the Compojure results. Yes, you read that right, it's nearly 20 times slower for Clabango to render the results. The difference being that the Compojure benchmark is using Hiccup for rendering the results while Luminus is using Clabango.</p><p>The core problem is that Clabango always parses the source files when rendering a template. This is very expensive as it involves disk access and scanning each character in the source file each time a page is served. Dan states that <a href='https://github.com/danlarkin/clabango/issues/13'>performance has not been a priority</a>.</p><p>On top of that, some of the existing behaviours put limitations on how much the performance can ultimately be improved. For example, the child templates aren't required to put their content inside blocks. Clabango parses the templates and creates the AST that's then evaluated. This means that you can put blocks inside the <code>if</code> tags and decide at runtime whether they will be included. If inheritance resolution is pushed to compile time this becomes a problem.</p><p>After having some discussions with <a href='https://github.com/bitemyapp'>bitemyapp</a> and <a href='https://github.com/cesarbp'>ceaserbp</a> we decided that it would be worth writing a fresh impelementation with pefromance as its primary goal. Another reason is that I would like to be able to ensure that the templating engine in Luminus isn't a compromise between speed and convenience. Owning the implementation is the best way to achieve that.</p><h2 id="enter&#95;selmer">Enter Selmer</h2><p>All this resulted in <a href='https://github.com/yogthos/Selmer'>Selmer</a> named after <a href='http://en.wikipedia.org/wiki/Selmer_guitar'>the guitar favored by Django Reinhardt</a> whom in turn Django is named after. Selmer aims to be a near drop in replacement for Clabango. The current version is already quite fast keeping pace with Stencil which is one of the faster engines around.</p><p>In order to minimize the work that's done at runtime Selmer splits the process into three distinct steps. These steps include preprocessing, compilation and rendering. </p><p>First, Selmer will resolve the inheritance hierarchy and generate the definitive template source to be compiled. The <code>extends</code> and <code>include</code> tags will be handled at this time.</p><p>The compilation step then produces a vector of text nodes and runtime transformer functions.</p><p>The renderer uses these compiled templates to generate its output. The text gets rendered without further manipulation while the transformers use the context map to generate their output at runtime.</p><p>Using this approach we minimize the amount of logic that needs to be executed during each request as well as avoiding any disk access in the process.</p><p>In order not to have to restart the application when the source templates are changed the renderer checks the last updated timestamp of the template. When the timestamp is changed a recompile is triggered.</p><h2 id="performance&#95;tricks">Performance Tricks</h2><p>To our chagrin the first run of the parser ran no better than Clabango. This was rather disappointing considering we took pains to be mindful of the performance issues. However, this mystery was quickly solved by profiling the parser.</p><p>Sure enough majority of time was spent in reflection calls. One major problem was that the renderer had to check whether each node was text or a function:</p><pre><code class="clojure">&#40;defn render &#91;template params&#93;  
  &#40;let &#91;buf &#40;StringBuilder.&#41;&#93;
    &#40;doseq &#91;element template&#93; 
      &#40;.append buf &#40;if &#40;string? element&#41; element &#40;element params&#41;&#41;&#41;&#41;
    &#40;.toString buf&#41;&#41;&#41;
</code></pre><p>Protocols offer an elegant solution to this problem. With their help we can move this work to compile time as follows:</p><pre><code class="clojure">&#40;defprotocol INode
  &#40;render-node &#91;this context-map&#93; &quot;Renders the context&quot;&#41;&#41;

&#40;deftype FunctionNode &#91;handler&#93;
  INode
  &#40;render-node &#94;String &#91;this context-map&#93;
    &#40;handler context-map&#41;&#41;&#41;

&#40;deftype TextNode &#91;text&#93;
  INode
  &#40;render-node &#94;String &#91;this context-map&#93;
    text&#41;&#41;
</code></pre><p>Now our parser can happily run along and call <code>render-node</code> on each element:</p><pre><code class="clojure">&#40;defn render-template &#91;template context-map&#93;
  &quot;&quot;&quot; vector of &#94;selmer.node.INodes and a context map.&quot;&quot;&quot;
  &#40;let &#91;buf &#40;StringBuilder.&#41;&#93;
    &#40;doseq &#91;&#94;selmer.node.INode element template&#93;
        &#40;if-let &#91;value &#40;.render-node element context-map&#41;&#93;
          &#40;.append buf value&#41;&#41;&#41;
    &#40;.toString buf&#41;&#41;&#41;

</code></pre><p>With this change and a few type annotations the performance improved dramatically. Running <a href='https://github.com/bitemyapp/clojure-template-benchmarks'>clojure-template-benchmarks</a> the results are comparable to Stencil. Here are the results from benchmarking on my machine:</p><h3 id="clabango">Clabango</h3><ul><li>Simple Data Injection<ul><li>Execution time mean : 657.530826 µs</li><li>Execution time std-deviation : 2.118301 µs</li></ul></li><li>Small List (50 items)<ul><li>Execution time mean : 2.446739 ms</li><li>Execution time std-deviation : 17.448003 µs</li></ul></li><li>Big List (1000 items)<ul><li>Execution time mean : 28.230365 ms</li><li>Execution time std-deviation : 173.518425 µs</li></ul></li></ul><h3 id="selmer">Selmer</h3><ul><li>Simple Data Injection<ul><li>Execution time mean : 42.444958 µs</li><li>Execution time std-deviation : 235.652171 ns</li></ul></li><li>Small List (50 items)<ul><li>Execution time mean : 209.158509 µs</li><li>Execution time std-deviation : 4.045131 µs</li></ul></li><li>Big List (1000 items)<ul><li>Execution time mean : 3.223797 ms</li><li>Execution time std-deviation : 55.511322 µs    </li></ul></li></ul><h3 id="stencil">Stencil</h3><ul><li>Simple Data Injection<ul><li>Execution time mean : 92.317566 µs</li><li>Execution time std-deviation : 213.253353 ns</li></ul></li><li>Small List (50 items)<ul><li>Execution time mean : 290.403204 µs</li><li>Execution time std-deviation : 1.801479 µs</li></ul></li><li>Big List (1000 items)<ul><li>Execution time mean : 1.223634 ms</li><li>Execution time std-deviation : 4.264979 µs    </li></ul></li></ul><p>As you can see Selmer is showing a large improvement over Clabango and has no trouble keeping up with Stencil.</p><p>Obviously, this benchmark is fairly simplistic so you can take it with a grain of salt. If anybody would like to put together a more comprehensive suite that would be great. :)</p><h2 id="current&#95;status">Current status</h2><p>The library implements all the functionality offered by Clabango and passes the Clabango test sutie. There are a few minor deviations, but overall it should work as a drop in replacement without the need to change your existing HTML templates. </p><p>We also have a few new features such as the Django <code>{{block.super}}</code> tag support and ability to use filters in if statements. In Selmer you can write things like:</p><pre><code class="clojure">&#40;selmer.filters/add-filter! :empty? empty?&#41;

&#40;render 
  &quot;{% if files|empty? %}
   no files available 
   {% else %} 
       {% for file in files %}{{file}}{% endfor %} 
   {% endif %}&quot;
  {:files &#91;&#93;}&#41;
</code></pre><p>Switching to Selmer involves swapping the <code>&#91;clabango &quot;0.5&quot;&#93;</code> dependency for <code>&#91;selmer &quot;0.5.3&quot;&#93;</code> and referencing <code>selmer.parser</code> instead of <code>clabango.parser</code>. Selmer provides the same API for rendering templates using the <code>selmer.parser/render</code> and <code>selmer.parser/render-file</code> functions.</p><p>One major area of difference is in how custom tags and filters are defined. Defining a filter is done by calling <code>selmer.filters/add-filter!</code> with the id of the filter and the filter function:</p><pre><code class="clojure">&#40;use 'selmer.filters&#41;

&#40;add-filter! :embiginate #&#40;.toUpperCase %&#41;&#41;

&#40;render &quot;{{shout|embiginate}}&quot; {:shout &quot;hello&quot;}&#41;
=&gt;&quot;HELLO&quot;
</code></pre><p>Defining custom tags is equally simple using the <code>selmer.parser/add-tag!</code> macro:</p><pre><code class="clojure">&#40;use 'selmer.parser&#41;

&#40;add-tag! :foo
  &#40;fn &#91;args context-map&#93;
    &#40;str &quot;foo &quot; &#40;first args&#41;&#41;&#41;&#41;

&#40;render &quot;{% foo quux %} {% foo baz %}&quot; {}&#41;
=&gt;&quot;foo quux foo baz&quot;
</code></pre><p>tags can also contain content and intermediate tags:</p><pre><code class="clojure">&#40;add-tag! :foo
  &#40;fn &#91;args context-map content&#93;
    &#40;str content&#41;&#41;
  :bar :endfoo&#41;

&#40;render &quot;{% foo %} some text {% bar %} some more text {% endfoo %}&quot; {}&#41;
=&gt;&quot;{:foo {:args nil, :content \&quot; some text \&quot;}, :bar {:args nil, :content \&quot; some more text \&quot;}}&quot;
</code></pre><p>Selmer also supports overriding the default tag characters using <code>:tag-open</code>, <code>:tag-close</code>, <code>:filter-open</code>, <code>:filter-close</code> and <code>:tag-second</code> keys:</p><pre><code class="clojure">&#40;render &quot;&#91;% for ele in foo %&#93;&lt;&lt;&#91;{ele}&#93;&gt;&gt;&#91;%endfor%&#93;&quot;
                 {:foo &#91;1 2 3&#93;}
                 {:tag-open \&#91;
                  :tag-close \&#93;}&#41;
</code></pre><p>This makes it much easier to use it in conjunction with client-side frameworks such as AngularJs.</p><p>One limitation Selmer has is the way it handles inheritance. Since the inheritance block hierarchy is compiled before the parsing step, any content in child templates must be encapsulated in block tags. Free-floating tags and text will simply be ignored by the parser. This is in line with <a href='http://stackoverflow.com/questions/1408925/django-templates-include-and-extends'>Django behavior</a>.</p><p>So there you have it. If you like Django template syntax or just want a fast templating engine then give Selmer a try.</p><p>As it is a new project there may be bugs and oddities so don't hesitate to open an issue on the project page if you find any. So far I haven't found any problems in switching my application from Clabango to Selmer and the test coverage is fairly extensive at this point. </p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure core.async Channels</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">28 06 2013</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p><a href="https://github.com/clojure/core.async">core.async</a> is a new contrib library for Clojure that adds support for asynchronous programming using channels.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_rationale"><a class="anchor" href="#_rationale"></a>Rationale</h2>
<div class="sectionbody">
<div class="paragraph">
<p>There comes a time in all good programs when components or subsystems must stop communicating directly with one another. This is often achieved via the introduction of queues between the producers of data and the consumers/processors of that data. This architectural indirection ensures that important decisions can be made with some degree of independence, and leads to systems that are easier to understand, manage, monitor and change, and make better use of computational resources, etc.</p>
</div>
<div class="paragraph">
<p>On the JVM, the <a href="http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html">java.util.concurrent</a> package provides some good concurrent blocking queues, and they are a viable and popular choice for Clojure programs. However, in order to use the queues one must dedicate one or more actual threads to their consumption. Per-thread stack allocation and task-switching overheads limit the number of threads that can be used in practice. Another limitation of j.u.c. queues is there is no way to block waiting on a set of alternatives.</p>
</div>
<div class="paragraph">
<p>On JavaScript engines, there are no threads and no queues.</p>
</div>
<div class="paragraph">
<p>Thread overheads or lack of threads often cause people to move to systems based upon events/callbacks, in the pursuit of greater efficiency (often under the misnomer 'scalability', which doesn&#8217;t apply since you can&#8217;t scale a single machine). Events complect communication and flow of control. While there are various mechanisms to make events/callbacks cleaner (FRP, Rx/Observables) they don&#8217;t change their fundamental nature, which is that upon an event an arbitrary amount of other code is run, possibly on the same thread, leading to admonitions such as "don&#8217;t do too much work in your handler", and phrases like "callback hell".</p>
</div>
<div class="paragraph">
<p>The objectives of core.async are:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>To provide facilities for independent threads of activity, communicating via queue-like <em>channels</em></p>
</li>
<li>
<p>To support both real threads and shared use of thread pools (in any combination), as well as ClojureScript on JS engines</p>
</li>
<li>
<p>To build upon the work done on CSP and its derivatives</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>It is our hope that async channels will greatly simplify efficient server-side Clojure programs, and offer simpler and more robust techniques for front-end programming in ClojureScript.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_history"><a class="anchor" href="#_history"></a>History</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The roots of this style go back at least as far as <a href="http://en.wikipedia.org/wiki/Communicating_sequential_processes">Hoare&#8217;s Communicating Sequential Processes (CSP)</a>, followed by realizations and extensions in e.g. <a href="http://en.wikipedia.org/wiki/Occam_programming_language">occam</a>, <a href="http://www.cs.kent.ac.uk/projects/ofa/jcsp/">Java CSP</a> and the <a href="http://golang.org/">Go programming language</a>.</p>
</div>
<div class="paragraph">
<p>In modern incarnations, the notion of a channel becomes first class, and in doing so provides us the indirection and independence we seek.</p>
</div>
<div class="paragraph">
<p>A key characteristic of channels is that they are blocking. In the most primitive form, an unbuffered channel acts as a rendezvous, any reader will await a writer and vice-versa. Buffering can be introduced, but unbounded buffering is discouraged, as bounded buffering with blocking can be an important tool coordinating pacing and back pressure, ensuring a system doesn&#8217;t take on more work than it can achieve.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_details"><a class="anchor" href="#_details"></a>Details</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_just_a_library"><a class="anchor" href="#_just_a_library"></a>Just a library</h3>
<div class="paragraph">
<p><strong>core.async</strong> is a library. It doesn&#8217;t modify Clojure. It is designed to support Clojure 1.5+.</p>
</div>
</div>
<div class="sect2">
<h3 id="_creating_channels"><a class="anchor" href="#_creating_channels"></a>Creating channels</h3>
<div class="paragraph">
<p>You can create a channel with the <a href="http://clojure.github.io/core.async/#clojure.core.async/chan">chan</a> function. This will return a channel that supports multiple writers and readers. By default, the channel is unbuffered, but you can supply a number to indicate a buffer size, or supply a buffer object created via <a href="http://clojure.github.io/core.async/#clojure.core.async/buffer">buffer</a>, <a href="http://clojure.github.io/core.async/#clojure.core.async/dropping-buffer">dropping-buffer</a> or <a href="http://clojure.github.io/core.async/#clojure.core.async/sliding-buffer">sliding-buffer</a>.</p>
</div>
<div class="paragraph">
<p>The fundamental operations on channels are putting and taking values. Both of those operations potentially block, but the nature of the blocking depends on the nature of the thread of control in which the operation is performed. core.async supports two kinds of threads of control - ordinary threads and IOC (inversion of control) 'threads'. Ordinary threads can be created in any manner, but IOC threads are created via <a href="http://clojure.github.io/core.async/#clojure.core.async/go">go blocks</a>. Because JS does not have threads, only <code>go</code> blocks and IOC threads are supported in ClojureScript.</p>
</div>
</div>
<div class="sect2">
<h3 id="_go_blocks_and_ioc_threads"><a class="anchor" href="#_go_blocks_and_ioc_threads"></a>go blocks and IOC 'threads'</h3>
<div class="paragraph">
<p><code>go</code> is a macro that takes its body and examines it for any channel operations. It will turn the body into a state machine. Upon reaching any blocking operation, the state machine will be 'parked' and the actual thread of control will be released. This approach is similar to that used in <a href="http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx">C# async</a>. When the blocking operation completes, the code will be resumed (on a thread-pool thread, or the sole thread in a JS VM). In this way the inversion of control that normally leaks into the program itself with event/callback systems is encapsulated by the mechanism, and you are left with straightforward sequential code. It will also provide the illusion of threads, and more important, separable sequential subsystems, to ClojureScript.</p>
</div>
<div class="paragraph">
<p>The primary channel operations within go blocks are <a href="http://clojure.github.io/core.async/#clojure.core.async/%3E!">&gt;!</a> (<em>put</em>) and <a href="http://clojure.github.io/core.async/#clojure.core.async/&lt;!">&lt;!</a> (<em>take</em>). The go block itself immediately returns a channel, on which it will eventually put the value of the last expression of the body (if non-nil), and then close.</p>
</div>
</div>
<div class="sect2">
<h3 id="_channel_on_ordinary_threads"><a class="anchor" href="#_channel_on_ordinary_threads"></a>Channel on ordinary threads</h3>
<div class="paragraph">
<p>There are analogous operations for use on ordinary threads - <a href="http://clojure.github.io/core.async/#clojure.core.async/%3E!!">&gt;!!</a> (<em>put blocking</em>) and <a href="http://clojure.github.io/core.async/#clojure.core.async/&lt;!!">&lt;!!</a> (<em>take blocking</em>), which will block the thread on which they are called, until complete. While you can use these operations on threads created with e.g. future, there is also a macro, <a href="http://clojure.github.io/core.async/#clojure.core.async/thread">thread</a>, analogous to <code>go</code>, that will launch a first-class thread and similarly return a channel, and should be preferred over <code>future</code> for channel work.</p>
</div>
</div>
<div class="sect2">
<h3 id="_mixing_modes"><a class="anchor" href="#_mixing_modes"></a>Mixing modes</h3>
<div class="paragraph">
<p>You can put on a channel from either flavor of <code>&gt;!</code>/<code>&gt;!!</code> and similarly take with either of <code>&lt;!</code>/<code>&lt;&lt;!</code> in any combination, i.e. the channel is oblivious to the nature of the threads which use it.</p>
</div>
</div>
<div class="sect2">
<h3 id="_alt"><a class="anchor" href="#_alt"></a>alt</h3>
<div class="paragraph">
<p>It is often desirable to be able to wait for any one (and only one) of a set of channel operations to complete. This powerful facility is made available through the <a href="http://clojure.github.io/core.async/#clojure.core.async/alts!">alts!</a> function (for use in <code>go</code> blocks), and the analogous <a href="http://clojure.github.io/core.async/#clojure.core.async/alts!!">alts!!</a> (<em>alts blocking</em>). If more than one operation is available to complete, one can be chosen at random or by priority (i.e. in the order they are supplied). There are corresponding <a href="http://clojure.github.io/core.async/#clojure.core.async/alt!">alt!</a> and <a href="http://clojure.github.io/core.async/#clojure.core.async/alt!!">alt!!</a> macros that combine the choice with conditional evaluation of expressions.</p>
</div>
</div>
<div class="sect2">
<h3 id="_timeouts"><a class="anchor" href="#_timeouts"></a>Timeouts</h3>
<div class="paragraph">
<p>Timeouts are just channels that automatically close after a period of time. You can create one with the <a href="http://clojure.github.io/core.async/#clojure.core.async/timeout">timeout</a> function, then just include the timeout in an <code>alt</code> variant. A nice aspect of this is that timeouts can be shared between threads of control, e.g. in order to have a set of activities share a bound.</p>
</div>
</div>
<div class="sect2">
<h3 id="_the_value_of_values"><a class="anchor" href="#_the_value_of_values"></a>The value of values</h3>
<div class="paragraph">
<p>As with STM, the pervasive use of persistent data structures offers particular benefits for CSP-style channels. In particular, it is always safe and efficient to put a Clojure data structure on a channel, without fear of its subsequent use by either the producer or consumer.</p>
</div>
</div>
<div class="sect2">
<h3 id="_contrasting_go_language_channels"><a class="anchor" href="#_contrasting_go_language_channels"></a>Contrasting Go language channels</h3>
<div class="paragraph">
<p>core.async has obvious similarities to Go channels. Some differences with Go are:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>All of the operations are expressions (not statements)</p>
</li>
<li>
<p>This is a library, not syntax</p>
</li>
<li>
<p><code>alts!</code> is a function (and supports a runtime-variable number of operations)</p>
</li>
<li>
<p>Priority is supported in <code>alt</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Finally, Clojure is hosted, i.e. we are bringing these facilities to existing platforms, not needing a custom runtime. The flip-side is we don&#8217;t have the underpinnings we would with a custom runtime. Reaching existing platforms remains a core Clojure value proposition.</p>
</div>
</div>
<div class="sect2">
<h3 id="_whither_actors"><a class="anchor" href="#_whither_actors"></a>Whither actors?</h3>
<div class="paragraph">
<p>I remain unenthusiastic about actors. They still couple the producer with the consumer. Yes, one can emulate or implement certain kinds of queues with actors (and, notably, people often do), but since any actor mechanism already incorporates a queue, it seems evident that queues are more primitive. It should be noted that Clojure&#8217;s mechanisms for concurrent use of state remain viable, and channels are oriented towards the flow aspects of a system.</p>
</div>
</div>
<div class="sect2">
<h3 id="_deadlocks"><a class="anchor" href="#_deadlocks"></a>Deadlocks</h3>
<div class="paragraph">
<p>Note that, unlike other Clojure concurrency constructs, channels, like all communications, are subject to deadlocks, the simplest being waiting for a message that will never arrive, which must be dealt with manually via timeouts etc. CSP proper is amenable to certain kinds of automated correctness analysis. No work has been done on that front for core.async as yet.</p>
</div>
<div class="paragraph">
<p>Also note that async channels are not intended for fine-grained computational parallelism, though you might see examples in that vein.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_future_directions"><a class="anchor" href="#_future_directions"></a>Future directions</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Networks channels and distribution are interesting areas for attention. We will also being doing performance tuning and refining the APIs.</p>
</div>
<div class="sect2">
<h3 id="_team"><a class="anchor" href="#_team"></a>Team</h3>
<div class="paragraph">
<p>I&#8217;d like to thank the team that helped bring core.async to life:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Timothy Baldridge</p>
</li>
<li>
<p>Ghadi Shayban</p>
</li>
<li>
<p>Alex Miller</p>
</li>
<li>
<p>Alex Redington</p>
</li>
<li>
<p>Sam Umbach</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>And once again, Tom Faulhaber for his work on autodoc.</p>
</div>
</div>
<div class="sect2">
<h3 id="_status"><a class="anchor" href="#_status"></a>Status</h3>
<div class="paragraph">
<p>While the library is still in an early state , we are ready for people to start trying it out and giving us feedback. The CLJS port is still work in progress. Please have a look at the <a href="https://github.com/clojure/core.async/tree/master/examples">examples</a>, which we will expand over time.</p>
</div>
<div class="paragraph">
<p>It should be noted that the protocols behind the implementation should still be considered an implementation detail for the time being, until we finish our exploratory work around network channels, which might impact their design.</p>
</div>
<div class="paragraph">
<p>I hope that these async channels will help you build simpler and more robust programs.</p>
</div>
<div class="paragraph">
<p>Rich</p>
</div>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">lib-noir access rule madness</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">12 06 2013</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Access rule handling in <a href='https://github.com/noir-clojure/lib-noir'>lib-noir</a> has seen some major rework. James Reeves pointed out that the way the <code>restrict</code> macro worked was not ideal as it wasn't entirely idiomatic and wasn't very composable. For example it didn't take into account the use of the <code>context</code> macro in Compojure.</p><p>While there are some breaking changes, it's pretty easy to migrate the old rules and the new approach provides a lot more flexibility.</p><p>The first thing that's changed is how the restricted routes are defined. The macro now wraps the handler itself instead of the whole route. So instead of doing</p><pre><code class="clojure">&#40;restricted GET &quot;/private&quot; &#91;&#93; handler&#41;
</code></pre><p>you would now write:</p><pre><code class="clojure">&#40;GET &quot;/private&quot; &#91;&#93; &#40;restricted handler&#41;&#41;
</code></pre><p>Access rules definitions in the <code>noir.util.middleware/app-handler</code> have been revamped as well. The rules can now be specified by passing either a function representing a single rule or a map representing a group of rules.</p><p>When specified as a function, the rule must accept a single parameter that is the request map. Such rules will implicitly redirect to the "/" URI.</p><p>The rule group map contains the following keys:</p><ul><li><code>:redirect</code> - the URI string or a function to specify where requests will be redirected to if rejected (optional defaults to "/")</li><li><code>:uri</code> - the URI for which the rules in the map will be activated (optional if none specified applies to all URIs)</li><li><code>:uris</code> - a vector of URI patterns for which the rules in the map will be activated (optional)</li><li><code>:rule</code> - a single rule function for the group</li><li><code>:rules</code> - a vector containing the rule functions associated with the specified <code>:redirect</code> and the <code>:uri</code></li><li><code>:on-fail</code> - alternative to <code>:redirect</code> allows providing a function that accepts a request and handles the failure case</li></ul><p>The <code>:rules</code> key can point to either a vector or a map. If the rules are a vector the default behavior is that every rule in the group must succeed. If rules are specified as a map, you can provide the resolution strategy using the <code>:any</code> and <code>:every</code> keys.</p><p>Let's take a look at an example of how this all works below:</p><pre><code class="clojure">&#40;def-restricted-routes

&#40;defroutes app-routes
 ;;restricted routes
 &#40;GET &quot;/restricted&quot; &#91;&#93; &#40;restricted &quot;this page is restricted&quot;&#41;&#41;
 &#40;GET &quot;/restricted1&quot; &#91;&#93; &#40;restricted &quot;this is another restricted page&quot;&#41;&#41;
 &#40;GET &quot;/users/:id&quot; &#91;&#93; &#40;restricted &quot;howdy&quot;&#41;&#41;
 &#40;GET &quot;/admin&quot; &#91;&#93; &#40;restricted &quot;admin route&quot;&#41;&#41;
 &#40;GET &quot;/config&quot; &#91;&#93; &#40;restricted &quot;config route&quot;&#41;&#41;
 &#40;GET &quot;/super-secret&quot; &#91;&#93; &#40;restricted &quot;secret route&quot;&#41;&#41;
 ;;public routes
 &#40;GET &quot;/denied1&quot; &#91;&#93; &quot;denied&quot;&#41;
 &#40;GET &quot;/denied2&quot; &#91;&#93; &quot;denied differently&quot;&#41;&#41;

&#40;def app 
 &#40;middleware/app-handler 
   &#91;app-routes&#93;
   :access-rules 
   &#91;&#40;fn &#91;req&#93; &#40;session/get :user&#41;&#41;

    {:uri &quot;/restricted&quot;
     :redirect &quot;/denied1&quot;
     :rule &#40;fn &#91;req&#93; false&#41;}

    {:redirect &#40;fn &#91;req&#93; 
                 &#40;log/info &#40;str &quot;redirecting &quot; &#40;:uri req&#41;&#41;&#41;
                 &quot;/denied2&quot;&#41;
     :uri &quot;/users/&#42;&quot;
     :rule &#40;fn &#91;req&#93; false&#41;}

    {:uris &#91;&quot;/admin&#42;&quot; &quot;/config&#42;&quot;&#93;
     :rules {:any &#91;&#40;fn &#91;req&#93; &#40;session/get :admin&#41;&#41;
                   &#40;fn &#91;req&#93; &#40;session/get :root&#41;&#41;&#93;}}

    {:on-fail &#40;fn &#91;req&#93; &quot;you tried to access the super secret page!&quot;&#41;
     :uri &quot;/super-secret&#42;&quot;
     :rules &#91;&#40;fn &#91;req&#93; &#40;session/get :admin&#41;&#41;
             &#40;fn &#91;req&#93; &#40;session/get :root&#41;&#41;&#93;}

    {:uri &quot;/super-secret&#42;&quot;
     :rules {:every &#91;&#40;fn &#91;req&#93; &#40;session/get :admin&#41;&#41;
                     &#40;fn &#91;req&#93; &#40;session/get :root&#41;&#41;&#93;
             :any   &#91;&#40;fn &#91;req&#93; &#40;session/get :zeus&#41;&#41;
                     &#40;fn &#91;req&#93; &#40;session/get :athena&#41;&#41;&#93;}}
&#93;&#41;&#41;
</code></pre><p>The first rule will be activated for any handler that's marked as restricted. This means that all of the restricted pages will redirect to <code>&quot;/&quot;</code> if there is no user in the session.</p><p>The second rule will only activate if the request URI matches <code>&quot;/restricted&quot;</code> and will be ignored for other URIs. The <code>&quot;/restricted&quot;</code> route will redirect to the <code>&quot;/denied1&quot;</code> URI.</p><p>The third rule will match any requests matching the <code>&quot;/users/&quot;</code> URI pattern. These requests will be redirected to the <code>&quot;/denied2&quot;</code> URI and the URI of the request will be logged.</p><p>The next rule group matches both the <code>&quot;/admin&#42;&quot;</code> and the <code>&quot;/config&#42;&quot;</code> patterns and required that either the <code>:admin</code> or the <code>:root</code> keys are set in the session in addition to the <code>:user</code> key specified by the global rule.</p><p>Next, we have a rule group that uses <code>:on-fail</code> function that can provide its own handler instead of doing a redirect. It requires that both  the <code>:admin</code> or the <code>:root</code> keys are set in the session.</p><p>Finally, we have a group that uses a mix of <code>:every</code> and <code>:any</code> keys to specify its rules.</p><p>The <code>access-rule</code> macro has been removed in favor of specifying rule groups directly in the handler. This makes it easier to see how all the rules are defined and what routes each set of rules affects.</p><p>With this new approach we can create independent rule groups for specific URI patterns as well as easily specify generic rules that affect all restricted handlers.</p><p>I found the new rule managing scheme to work better for my projects. I'd be interested on getting feedback whether it works for others as well and I'm always open to suggestions for improvements. :)</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">what&#39;s new in lib-noir</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">25 05 2013</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>It's been nearly a year since <a href='https://github.com/noir-clojure/lib-noir'>lib-noir</a> was split out into a stand-alone library. During this time the work on it has continued at a steady pace. There have been numerous bug fixes and many new features have been added to the library.</p><p>Many of these come either from user suggestions or contributions. So, if there is something that you'd like to see improved don't hesitate to submit an issue or make a pull request.</p><p>In this post I'd like to highlight some of the major new features that have been recently added.</p><h3 id="middleware">Middleware</h3><p>The <code>app-handler</code> in <code>noir.util.middleware</code> now accepts optional<code>:middleware</code> and <code>:access-rules</code> parameters.</p><p>Since the outer middleware is evaluated first, if you wrap the <code>app-handler</code> in custom middleware it will execute before any of the standard middleware is executed. This is a problem if you wish to get access to things like the session, eg:</p><pre><code class="clojure">&#40;defn log-user-in-session &#91;handler&#93;
  &#40;fn &#91;req&#93;
    &#40;timbre/info &#40;session/get :user&#41;&#41;
    &#40;handler req&#41;&#41;&#41;

&#40;def app &#40;-&gt; &#40;middleware/app-handler all-routes&#41;
             log-user-in-session&#41;&#41;
</code></pre><p>If we try to run our app with the above handler we'll get the following exception:</p><pre><code class="clojure">java.lang.ClassCastException: clojure.lang.Var$Unbound cannot be cast to java.util.concurrent.Future
</code></pre><p>This happens due to the fact that <code>noir.session</code> uses the <code>&#42;noir-session&#42;</code> dynamic variable to keep track of the session. This variable is bound by the <code>wrap-noir-session</code> middleware. Since the <code>log-user-in-session</code> executes before it, the session is not yet bound.</p><p>The <code>:middleware</code> key allows specifying a vector containing custom middleware to wrap the handler before the standard middleware:</p><pre><code class="clojure">&#40;def app &#40;middleware/app-handler all-routes
          :middleware &#91;log-user-in-session&#93;&#41;&#41;
</code></pre><p>Now, the <code>log-user-in-session</code> will be called after the <code>wrap-noir-session</code> is called and work as expected.</p><p>The <code>:access-rules</code> key allows specifying the access rules for the <code>wrap-access-rules</code> middleware. Each set of rules should be specified as a vector with the contents matching the <code>wrap-access-rules</code> arguments:</p><pre><code class="clojure">&#40;defn private-pages &#91;method url params&#93;    
    &#40;session/get :user-id&#41;&#41;

&#40;def app &#40;middleware/app-handler all-routes 
          :access-rules
          &#91;&#91;{:redirect &quot;/unauthorized&quot;} private-pages&#93;&#93;&#41;&#41;
</code></pre><p>There's also a new middleware wrapper called <code>wrap-rewrites</code> that allows rewriting URIs based on regex. </p><p>The rewrite rules should be supplied as pairs of the regex and the string the matching URL should be rewritten with. The first regex that matches the request's URI will cause it to be replaced with its corresponding string before calling the wrapped handler:</p><pre><code class="clojure">&#40;wrap-rewrites handler #&quot;/foo&quot; &quot;/bar&quot;&#41;
</code></pre><p>Above, all occurances of  the<code>/foo</code> URI will be replaced with <code>/bar</code>.</p><h3 id="routes">Routes</h3><p>There's now a <code>noir.util.route/def-restricted-routes</code> macro for creating groups of restricted routes. Where before you had to do something like this:</p><pre><code class="clojure">&#40;defroutes private-routes
  &#40;restricted GET &quot;/route1&quot; &#91;&#93; handler1&#41;
  &#40;restricted GET &quot;/route2&quot; &#91;&#93; handler2&#41;
  &#40;restricted GET &quot;/route3&quot; &#91;&#93; handler3&#41;
  &#40;restricted GET &quot;/route4&quot; &#91;&#93; handler4&#41;&#41;
</code></pre><p>you can now simply do:</p><pre><code class="clojure">&#40;def-restricted-routes private-routes
  &#40;GET &quot;/route1&quot; &#91;&#93; handler1&#41;
  &#40;GET &quot;/route2&quot; &#91;&#93; handler2&#41;
  &#40;GET &quot;/route3&quot; &#91;&#93; handler3&#41;
  &#40;GET &quot;/route4&quot; &#91;&#93; handler4&#41;&#41;
</code></pre><p>The macro will automatically mark all the routes as restricted for you. </p><p>Finally, the access rules used to control the <code>restricted</code> routes are more flexible now as well. The redirect target can now point to a function as well as a string, eg:</p><pre><code class="clojure">&#40;def app &#40;middleware/app-handler all-routes 
          :access-rules
          &#91;&#91;{:redirect 
             &#40;fn &#91;&#93; 
              &#40;println &quot;redirecting&quot;&#41; &quot;/unauthorized&quot;&#41;} 
             private-pages&#93;&#93;&#41;&#41;
</code></pre><p>As always, <a href='http://www.luminusweb.net/'>Luminus</a> provides the latest <code>lib-noir</code>, so all the new features are available there as well.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Packaging a Clojure+ClojureScript jar</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">22 05 2013</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I maintain a Clojure Markdown parser library called <a href='https://github.com/yogthos/markdown-clj'>markdown-clj</a>. I originally wrote it because I was curious to see just how concise a Clojure Markdown parser would be. Turns out that it's pretty concise. :)</p><p>Then I saw <a href='http://briancarper.net/blog/415/clojure-and-markdown-and-javascript-and-java-and'>a post</a> from Brian Carper that highlighted a problem with having different Markdown parsers on the client and the server.</p><p>Since Markdown specification is somewhat loose, most implementations interpret it differently. This means that if you're rendering a preview on the client using a JavaScript library and using a different library, such as <a href='https://github.com/sirthias/pegdown'>pegdown</a>, to render it on the server you may get some surprises.</p><p>Since my library was already written in pure Clojure I figured it wouldn't be difficult to cross-compile it to ClojureScript as well.</p><p>That turned out to be very easy to do. I split out the element transformers into a separate namespace that's shared between Clojure and ClojureScript cores. However, for the longest time I only packaged it for distribution as a Clojure library.</p><p>I finally had a bit of free time to look at ClojureScript packaging over the weekend and I'm happy to report that the dependency now works for both Clojure and ClojureScript out of the box.</p><p>While pure ClojureScript libraries compile without any extra work, I found a few gotchas that are specific to cross-compiling. </p><p>If you have a project that contains both Clojure and ClojureScript code in it, then <strong>only</strong> the <code>clj</code> files will be packaged in the jar by default. After some reading of the <a href='https://github.com/emezeske/lein-cljsbuild'>lein-cljsbuild</a> docs I found the solution. </p><p>Here's what I ended up doing to get <code>cljs</code> namespaces to be packaged along with the <code>clj</code> namespaces:</p><pre><code class="clojure">:cljsbuild
{:crossovers &#91;markdown.transformers&#93;
  :crossover-path &quot;crossover&quot;
  :crossover-jar true        
  :builds {:main
           {:source-paths &#91;&quot;src-cljs&quot;&#93;
            :jar true
            :compiler {:output-to &quot;js/markdown.js&quot;
                       :optimizations :advanced
                       :pretty-print false}}
           :dev 
           {:compiler {:optimizations :whitespace
                       :pretty-print true}}}}
</code></pre><p>I specify the <code>:crossover-path</code>, note that this path has to be different from your <code>:source-paths</code> or the files there will be overwritten.</p><p>Next, I added the <code>:corssover-jar true</code> to indicate that I wish the crossover namespaces to appear in the resulting jar.</p><p>I also added <code>:jar true</code> to the <code>:main</code> section of the <code>:builds</code>. This is needed to include the namespaces in the <code>src-cljs</code> source directory.</p><p>Finally, you also need to include <code>:clojurescript? true</code> in <code>project.clj</code> to indicate that the project contains ClojureScript sources. Here's the complete project file that I'm using:</p><pre><code class="clojure">&#40;defproject markdown-clj &quot;0.9.25&quot;
  :clojurescript? true
  :description &quot;Markdown parser&quot;
   :url &quot;https://github.com/yogthos/markdown-clj&quot;
   :license {:name &quot;Eclipse Public License&quot;
             :url &quot;http://www.eclipse.org/legal/epl-v10.html&quot;}
   :dependencies &#91;&#91;org.clojure/clojure &quot;1.5.1&quot;&#93;
                  &#91;criterium &quot;0.3.1&quot; :scope &quot;test&quot;&#93;&#93;
   :plugins &#91;&#91;lein-cljsbuild &quot;0.3.2&quot;&#93;&#93;
   :hooks &#91;leiningen.cljsbuild&#93;
   :test-selectors {:default &#40;complement :benchmark&#41;
                    :benchmark :benchmark
                    :all &#40;constantly true&#41;}
   
   :cljsbuild
   {:crossovers &#91;markdown.transformers&#93;
    :crossover-path &quot;crossover&quot;
    :crossover-jar true        
    :builds {:main
             {:source-paths &#91;&quot;src-cljs&quot;&#93;
              :jar true
              :compiler {:output-to &quot;js/markdown.js&quot;
                         :optimizations :advanced
                         :pretty-print false}}
             :dev 
             {:compiler {:optimizations :whitespace
                         :pretty-print true}}}}&#41;
</code></pre><p>The resulting jar will contain all your <code>clj</code> and <code>cljs</code> files along with the crossover namespaces.</p><p>For me, being able to manage dependencies using Leiningen is a definite killer feature when it comes to ClojureScript.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure Data Analysis Cookbook Review</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">24 04 2013</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I was recently asked to review the <a href='http://www.packtpub.com/clojure-data-analysis-cookbook/book'>Clojure Data Analysis Cookbook</a>. Data analysis happens to one of the major niches where Clojure has been gaining popularity. However, the documentation on the subject is far from focused. </p><p>The book provides a collection of recipes for accomplishing common tasks associated with analyzing different types of data sets. It starts out by showing how to read data from a variety of sources such as JSON, CSV, and JDBC. The next chapter provides a number of examples of how to sanitize the collected data and sample large data sets. After covering loading and sanitizing the data, the book discusses a number of different strategies for processing it.</p><p>Some of the highlights include using the Clojure STM, parallel processing of the data, including useful tricks for partitioning, using <a href='http://clojure.com/blog/2012/05/08/reducers-a-library-and-model-for-collection-processing.html'>reducers</a>, and distributed processing with Hadoop and Casalog.</p><p>I found the sections on handling large amounts of data particularly interesting. Often times, it's easy to come up with a solution that works for a small data set, but doesn't scale to handle large amounts of data. One of the techniques the book discusses is the use of lazy sequences. Another example is using heuristics to decide how to partition large data sets data sets effectively.</p><p>The book closes with a chapter dealing with the presentation the processed data. First, it covers using Incanter charts and then shows how to display the results in the browser with ClojureScript and <a href='http://nvd3.org/'>NVD3</a>.</p><p>For the most part, the book is very much example oriented. The examples are accompanied by explantation of how they all fit together. If you're like me and like to get hands on experience then I think you'll like the style of the book.</p><p>The examples are short in size and easy to understand. I found that the best way to work through the book was by following along with a REPL.</p><p>The book also introduces the reader to a number of libraries. Some, such as <a href='http://incanter.org/'>Incanter</a> are well known, while others like <a href='https://github.com/protoflex/parse-ez'>parse-ez</a> less so. In my experience, the documentation for many Clojure libraries is often lacking. The recipes in the book serve as a good reference for how to make the most of the tools available.</p><p>I would say one missed opportunity in the book is that the examples don't seem to build on each other. You'll see many examples of doing specific tasks, but they will tend to be self contained and don't build up to anything more substantial. </p><p>I suspect this was done in order to keep content accessible so that the reader can look at any section without having to have read the others. Conversely, don't expect to see examples of how to structure your projects and build applications end to end.</p><p>Overall, I would say this book is aimed at somebody who is already comfortable using Clojure and would like to learn some of the more advanced techinques for working with data processing and analysis. If you're thinking of using Clojure for analyzing your data sets this book will likely save you a lot of time and serve as a handy reference down the road.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Introducing cljs-ajax</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">09 04 2013</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I recently started working on a project using ClojureScript and it's turning out to be a really good experience so far. I've been using <a href='https://github.com/levand/domina'>Domina</a> and <a href='https://github.com/Prismatic/dommy'>Dommy</a> for DOM manipulation and templating. Both libraries are very easy to use and provide all  the functionality needed for common operations.</p><p>Surprisingly, I didn't find any up to date libraries for handling Ajax. The only one I could find is <a href='https://github.com/ibdknox/fetch'>fetch</a>. Unfortunately, it depends on Noir which is no longer maintained.</p><p>I ended up writing a wrapper for <code>goog.net.XhrIo</code> called <a href='https://github.com/yogthos/cljs-ajax'>cljs-ajax</a>. It provides an API similar to <a href='https://github.com/dakrone/clj-http'>clj-http</a> and handles all the nitty gritty details for you.</p><p>Currently, the API provides <code>ajax-request</code>, <code>GET</code>, and <code>PUT</code> functions. The <code>ajax-request</code> function accepts the following parameters:</p><ul><li><code>uri</code> - the URI for the request</li><li><code>method</code> - a string representing the HTTP request type, eg: "PUT", "DELETE", etc.</li><li><code>format</code> - a keyword indicating the response format, can be either <code>:json</code> or <code>:edn</code>, defaults to <code>:edn</code></li><li><code>handler</code> - success handler, a function that accepts the response as a single argument</li><li><code>error-handler</code> - error handler, a function that accepts a map representing the error with keys <code>:status</code> and <code>:status-text</code></li><li><code>params</code> - a map of params to be sent to the server</li></ul><p>The <code>GET</code> and <code>POST</code> are helper functions that accept a URI followed by a map of options containing any of the following keys:</p><ul><li><code>:handler</code> - the handler function for successful operation should accept a single parameter which is the deserialized response</li><li><code>:error-handler</code> - the handler function for errors, should accept a map with keys <code>:status</code> and <code>:status-text</code></li><li><code>:format</code> - the format for the response <code>:edn</code> or <code>:json</code> defaults to <code>:edn</code></li><li><code>:params</code> - a map of parameters that will be sent with the request</li></ul><p>Here's some example usage:</p><pre><code class="clojure">&#40;ns foo
 &#40;:require &#91;ajax.core :refer &#91;GET POST&#93;&#93;&#41;&#41;

&#40;defn handler &#91;response&#93;
 &#40;.log js/console &#40;str response&#41;&#41;&#41;

&#40;defn error-handler &#91;{:keys &#91;status status-text&#93;}&#93;
 &#40;.log js/console 
  &#40;str &quot;something bad happened: &quot; status &quot; &quot; status-text&#41;&#41;&#41;

&#40;GET &quot;/hello&quot;&#41;

&#40;GET &quot;/hello&quot; {:handler handler
               :error-handler error-handler}&#41;

&#40;POST &quot;/hello&quot;&#41;

&#40;POST &quot;/send-message&quot; 
      {:params {:message &quot;Hello World&quot;
                :user    &quot;Bob&quot;}
      :handler handler
      :error-handler error-handler}&#41;

&#40;POST &quot;/send-message&quot; 
      {:params {:message &quot;Hello World&quot;
                :user    &quot;Bob&quot;}
      :handler handler
      :format :json
      :error-handler error-handler}&#41;
</code></pre><p>The latest version of Luminus comes packaged with a ClojureScript example when the <code>+cljs</code> option is selected. Let's create a new project called <code>ajax-example</code> and take a look at how it works:</p><pre><code>lein new luminus ajax-example +cljs
</code></pre><p>The <code>project.clj</code> will contain the dependencies for Domina, Dommy, and cljs-ajax as well as a <code>cljsbuild</code> configuration. The current version of cljsbuild references an old version of ClojureScript, so the latest version is also explicitly included as a dependency.</p><p>In order to use the ClojureScript from our page we'll first need to compile it. This is done by running <code>lein cljsbuild once</code>. The resulting artifact will be placed under <code>resources/public/js/site.js</code> as specified in the cljsbuild section of the project.</p><p>You'll notice that the build takes a while to run. Luckily, if we run it using <code>lein cljsbuild auto</code> it will run much faster and any time we make changes to any of the ClojureScript namespaces they will trigger an incremental build.</p><p>Working with the auto build running is nearly as seamless as working with plain old JavaScript. You make a change in the source, save, and reload the page. The compilation step tends to take under a second, so the intermediate delay is barely noticeable.</p><p>Our project has a source directory called <code>src-cljs</code> where ClojureScript namespaces live. It contains a file called <code>main.cljs</code>. This example illustrates using GET and POST calls to interact with the server as well as rendering DOM elements. Let's take a look inside it:</p><pre><code class="clojure">&#40;ns cljs-test.main
 &#40;:require &#91;ajax.core :refer &#91;GET POST&#93;&#93;
           &#91;domina :refer &#91;value by-id destroy-children! append!&#93;&#93;
           &#91;domina.events :refer &#91;listen!&#93;&#93;
           &#91;dommy.template :as template&#93;&#41;&#41;

&#40;defn render-message &#91;{:keys &#91;message user&#93;}&#93;
 &#91;:li &#91;:p {:id user} message &quot; - &quot; user&#93;&#93;&#41;

&#40;defn render-messages &#91;messages&#93;
 &#40;let &#91;messages-div &#40;by-id &quot;messages&quot;&#41;&#93;
   &#40;destroy-children! messages-div&#41;
   &#40;-&gt;&gt; messages
        &#40;map render-message&#41;
        &#40;into &#91;:ul&#93;&#41;
        template/node
        &#40;append! messages-div&#41;&#41;&#41;&#41;

&#40;defn add-message &#91;&#95;&#93;
 &#40;POST &quot;/add-message&quot;
       {:params {:message &#40;value &#40;by-id &quot;message&quot;&#41;&#41;
                 :user    &#40;value &#40;by-id &quot;user&quot;&#41;&#41;}
        :handler render-messages}&#41;&#41;

&#40;defn &#94;:export init &#91;&#93;
 &#40;GET &quot;/messages&quot; {:handler render-messages}&#41;
 &#40;listen! &#40;by-id &quot;send&quot;&#41;
          :click add-message&#41;&#41;
</code></pre><p>Here, we have a couple of functions to render the messages we receive from the server. The <code>render-message</code> function accepts a map with the keys message and user and creates a list item. The <code>render-messages</code> will create a list from the messages and render it using <code>template/node</code> function. The rendered messages will be appended to the div with the id <code>messages</code> using the <code>append!</code> function.</p><p>Next, we have a function to add a a new message. It grabs the values from elements selected by their ids and sends them as params named message and user. The server responds with a list of current messages. So we use <code>render-messages</code> as the response handler.</p><p>In our <code>init</code> function, we send a GET request to grab the current messages, then we bind the <code>add-message</code> function to the button with the id <code>send</code>.</p><p>On the server side we have a <code>ajax-example.routes.cljsexample</code> namespace. It provides the routes to render the page and handle the <code>/messages</code> and <code>/add-message</code> operations.</p><pre><code class="clojure">&#40;ns ajax-example.routes.cljsexample
 &#40;:require &#91;compojure.core :refer :all&#93;
           &#91;noir.response :as response&#93;
           &#91;ajax-example.views.layout :as layout&#93;&#41;&#41;

&#40;def messages
 &#40;atom
   &#91;{:message &quot;Hello world&quot;
     :user    &quot;Foo&quot;}
    {:message &quot;Ajax is fun&quot;
     :user    &quot;Bar&quot;}&#93;&#41;&#41;

&#40;defroutes cljs-routes
 &#40;GET &quot;/cljsexample&quot; &#91;&#93; &#40;layout/render &quot;cljsexample.html&quot;&#41;&#41;
 &#40;GET &quot;/messages&quot; &#91;&#93; &#40;response/edn @messages&#41;&#41;
 &#40;POST &quot;/add-message&quot; &#91;message user&#93;
       &#40;response/edn
         &#40;swap! messages conj {:message message :user user}&#41;&#41;&#41;&#41;
</code></pre><p>As you can see, the routes simply return EDN responses to the client. Finally, we have the template for the actual example page, that looks as follows:</p><pre><code class="xml">{% extends &quot;cljs&#95;test/views/templates/base.html&quot; %}


{% block content %}

&lt;br/&gt;
&lt;div id=&quot;messages&quot;&gt;&lt;/div&gt;
&lt;textarea id=&quot;message&quot;&gt;&lt;/textarea&gt;
&lt;br/&gt;
&lt;input type=&quot;text&quot; id=&quot;user&quot;&gt;&lt;/input&gt;
&lt;br/&gt;
&lt;button id=&quot;send&quot;&gt;add message&lt;/button&gt;

&lt;!--  scripts --&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;js/site.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
	cljs&#95;test.main.init&#40;&#41;;
&lt;/script&gt;

{% endblock %}
</code></pre><p>The page references the <code>site.js</code> script that will be output by the compiler and calls the <code>init</code> function that we saw above.</p><p>Overall, I feel that ClojureScript is rapidly becoming a viable alternative to using JavaScript on the client. There are still some rough edges, but most things work out of the box and you get many of the same benefits associated with using Clojure on the server.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">a book is coming</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">23 03 2013</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>First of all, I'd like to thank all those who've helped with Luminus. Since the original release on Clojars at the end of December there's been over <a href='https://clojars.org/luminus/lein-template'>700 downloads</a>, and the framework site has over 3,500 unique visits!</p><p>There's also been many contributions for improved documentation, template fixes, and lib-noir improvements. I'm really thankful for all the help improving the framework and moving it forward. I'd especially like to thank <a href='http://about.me/edtsech'>Ed Tsech</a>, who's been toiling on it with me for the last few months. :)</p><p>I'm really glad to be able to contribute to popularizing the language and making it more accessible. On that note I have some exciting news. I've recently got signed by the <a href='http://pragprog.com/'>The Pragmatic Programmers</a> to write a book on web development using Clojure.</p><p>There is a number of books discussing the fundamentals of Clojure as a language. However, none of the books focus on applying these fundamentals to building real-world solutions. Respondents of the <a href='http://cemerick.com/2012/07/19/2012-state-of-clojure-survey/'>2012 State of Clojure survey</a> indicated that there still exists a gap in traditional documentation. Specifically, an interest in current tools, libraries, and best practices is not being met. It is my goal to help fill this gap.</p><p>I will provide an overview of Clojure as a web development platform, highlighting exactly what makes it so effective. The book will take a tutorial-focused approach to building a production-ready web application from conception to deployment.</p><p>The target audience is anyone interested in using Clojure as a web development platform. This includes: those who are currently using the JVM for development; Ruby and Python users who would like to take advantage of the breadth of features and libraries offered by the JVM; and readers simply interested in learning how to develop web applications using Clojure.</p><p>I'm quite thrilled about this project and I hope to write the book I wish I had when I spent countless hours googling for tutorials and examples. :)</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">New Templating Engine in Luminus</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">10 03 2013</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I'm happy to announce that <a href='http://www.luminusweb.net/'>Luminus</a> now defaults to using <a href='https://github.com/danlarkin/clabango'>Clabango</a> for HTML templating instead of <a href='https://github.com/weavejester/hiccup'>Hiccup</a>.</p><p>I'd like to explain some of the reasoning behind this decision. The primary drive behind Luminus is to make Clojure web development more accessible. This means that the barrier to entry for those who are new to the language should be as low as possible.</p><p>Since Clabango is based on the <a href='https://docs.djangoproject.com/en/1.10/intro/overview/#design-your-templates'>Django templates</a>, it's immediately familiar to anybody who's done templating with other frameworks such as Django, Rails, or JSP. This also makes it easier to migrate exiting sites to use Luminus.</p><p>Because the templates are written in plain HTML it's easy to work with designers and other people who aren't versed in Clojure.</p><p>Finally, Clabango enforces the separation between the application logic and the presentation. When using Hiccup it's for one to start bleeding into the other if you're not careful.</p><p>However, if you are a fan of Hiccup there's nothing to worry about.  Everything will work as it did before if you use the <code>+hiccup</code> flag when creating the application.</p><p>As always feedback and suggestions are most welcome. :)</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">New kid on the templating block</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">02 03 2013</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <h2 id="update:&#95;<a href='https://github.com/yogthos/Selmer'>Selmer</a>&#95;is&#95;currently&#95;the&#95;recommended&#95;django&#95;style&#95;templating&#95;engine">Update: <a href='https://github.com/yogthos/Selmer'>Selmer</a> is currently the recommended Django style templating engine</h2><p>As you may know, there are a few Clojure templating engines floating around. The two most popular ones are probably <a href='https://github.com/weavejester/hiccup'>Hiccup</a> and <a href='https://github.com/cgrand/enlive'>Enlive</a>.</p><p>Hiccup is a nice and simple templating engine. Unfortunately, its biggest advantage is also it's greatest weakness. Since Hiccup templates are written using Clojure data structures, they're simply part of your regular code.</p><p>This makes the templates inaccessible to people not versed in Clojure. For example, if you're working with a designer, you can't just give them your template to work with.</p><p>Another issue is that it makes it easy for your frontend and backend logic to bleed into each other if you're not careful. Finally, you have to redeploy your site any time you wish to make a change to the layout.</p><p>Enlive avoids these problems by using a more traditional approach and using plain HTML markup for its templates. The problem with Enlive lies in its complexity. This spawned <a href='https://github.com/Raynes/laser'>Laser</a>, which also allows using pure HTML without any additional markup for its templates. In the words of the author:</p><blockquote><p>Enlive does its job and is the precursor to the way laser does things. However, it is very large and (arguably?) complex compared to laser. laser strives to be as simple as possible. </p></blockquote><p>If you haven't already checked out Laser I certainly urge you to do so!</p><p>However, the engine I'd like to focus on in this post is <a href='https://github.com/danlarkin/clabango'>Clabango</a>. It's modeled after Django's templating library and I found that it clicked with me immediately. </p><p>Let's take a look at how to convert the example <a href='http://www.luminusweb.net/docs/guestbook.md'>guestbook application</a> from Luminus to use Clabango instead of Hiccup.</p><p>We'll first create the project with support for H2 embedded DB by running:</p><pre><code>lein new luminus guestbook +h2
</code></pre><p>We'll then open up our <code>project.clj</code> and add the Clabango <code>&#91;clabango &quot;0.5&quot;&#93;</code> dependency it.</p><p>Next, we'll create a <code>templates</code> folder under resources/public. This is where all the Clabango templates will live.</p><p>Clabango provides two way to load templates using the <code>clabango.parser</code> namespace. We can either use <code>render-file</code> function to load a template from a file or <code>render</code> to load it from a string.</p><p>These functions take two parameters, the template source and a map containing the items that will be populated in the template when it's compiled.</p><p>For example, if we had a template such as:</p><pre><code class="xml">&lt;h2&gt;Hello {{user}}&lt;/h2&gt;
</code></pre><p>We could then render it by calling <code>render</code> as follows:</p><pre><code class="clojure">&#40;render &quot;&lt;h2&gt;Hello {{user}}&lt;/h2&gt;&quot; {:user &quot;John&quot;}&#41;
</code></pre><p>Clabango will then replace every occurance of <code>{{user}}</code> with <code>John</code> instead. In case <code>user</code> happens to be a map, we can access its keys using the dot notation:</p><pre><code class="xml">&lt;h2&gt;Hello {{user.last}}&quot;, &quot; {{user.first}}&lt;/h2&gt;
</code></pre><p>The  templates provide support for some other useful things like filters, tag definitions, and template inheritance. However, we won't worry about any of that right now.</p><p>Let's take a look how to load up the templates using the <code>render</code> function. We won't use <code>render-file</code> since it looks for resources relative to the <code>src</code> folder. We'll use <code>lib-noir.io/slurp-resource</code> to load our templates from the <code>public</code> folder instead. We'll create a helper in our <code>guestbook.util</code> namespace to do that:</p><pre><code class="clojure">&#40;ns guestbook.util  
  &#40;:require ...
            &#91;clabango.parser :as parser&#93;&#41;&#41;


&#40;defn render &#91;template params&#93;
  &#40;parser/render &#40;io/slurp-resource template&#41; params&#41;&#41;
</code></pre><p>With that out of the way, let's create the model for our application. We'll open up the <code>guestboook.models.schema</code> namespace and replace <code>create-users-table</code> with  <code>create-guestbook</code> table:</p><pre><code class="clojure">&#40;defn create-guestbook-table &#91;&#93;
  &#40;sql/with-connection
    db-spec
    &#40;sql/create-table
      :guestbook
      &#91;:id &quot;INTEGER PRIMARY KEY AUTO&#95;INCREMENT&quot;&#93;
      &#91;:timestamp :timestamp&#93;
      &#91;:name &quot;varchar&#40;30&#41;&quot;&#93;
      &#91;:message &quot;varchar&#40;200&#41;&quot;&#93;&#41;
    &#40;sql/do-commands
      &quot;CREATE INDEX timestamp&#95;index ON guestbook &#40;timestamp&#41;&quot;&#41;&#41;&#41;
</code></pre><p>then update <code>create-tables</code> to call it instead:</p><pre><code class="clojure">&#40;defn create-tables
  &quot;creates the database tables used by the application&quot;
  &#91;&#93;
  &#40;create-guestbook-table&#41;&#41;
</code></pre><p>We'll also update the <code>init</code> function in the <code>guestbook.handler</code> to call <code>create-tables</code> if the database isn't already initialized:</p><pre><code class="clojure">&#40;defn init &#91;&#93;
  &#40;if-not &#40;schema/initialized?&#41; &#40;schema/create-tables&#41;&#41;
  &#40;println &quot;guestbook started successfully...&quot;&#41;&#41;
</code></pre><p>Next, let's open up the <code>guestbook.models.db</code> namespace and replace the code to create and retrieve users with the code to save and load messages:</p><pre><code class="clojure">&#40;ns guestbook.models.db
  &#40;:use korma.core
        &#91;korma.db :only &#40;defdb&#41;&#93;&#41;
  &#40;:require &#91;guestbook.models.schema :as schema&#93;&#41;&#41;

&#40;defdb db schema/db-spec&#41;

&#40;defentity guestbook&#41;

&#40;defn save-message
  &#91;name message&#93;
  &#40;insert guestbook 
          &#40;values {:name name
                   :message message
                   :timestamp &#40;new java.util.Date&#41;}&#41;&#41;&#41;

&#40;defn get-messages &#91;&#93;
  &#40;select guestbook&#41;&#41;
</code></pre><p>We can test that everything works by calling <code>save-message</code> from the REPL to create some messages and then calling <code>get-messages</code> to see that they're retrieved correctly. If everything works as expected then we're ready to take a look at making our pages. </p><p>First, let's create a template for the home page. We'll do this by making a <code>welcome.html</code> file under the <code>resources/public/templates</code> folder.</p><p>Here is where we finally get to see Clabango in action. We'll first use it to iterate the messages and create a list from them:</p><pre><code class="xml">&lt;ul&gt;
{% for item in messages %}
  &lt;li&gt; 
      &lt;blockquote&gt;{{item.message}}&lt;/blockquote&gt;
      &lt;p&gt; - {{item.name}}&lt;/p&gt;
      &lt;time&gt;{{item.timestamp}}&lt;/time&gt;
  &lt;/li&gt;
{% endfor %}
&lt;/ul&gt;
</code></pre><p>As you can see above, we use a <code>for</code> iterator to walk the messages. Since each message is a map with the <code>message</code>, <code>name,</code> and <code>timestamp</code> keys, we can access them by name.</p><p>Next, we'll add an error block for displaying errors that might be populated by the controller:</p><pre><code class="xml">{% if error %}
&lt;p&gt;{{error}}&lt;/p&gt;
{% endif %}
</code></pre><p>Here we simply check if the error field was populated and display it. Finally, we'll create a form to allow users to submit their messages:</p><pre><code class="xml">&lt;form action=&quot;/&quot; method=&quot;POST&quot;&gt;
	&lt;p&gt;Name: &lt;input type=&quot;text&quot; name=&quot;name&quot; value={{name}}&gt;&lt;/p&gt;
	&lt;p&gt;Message: &lt;input type=&quot;text&quot; name=&quot;message&quot; value={{message}}&gt;&lt;/p&gt;
	&lt;input type=&quot;submit&quot; value=&quot;comment&quot;&gt;
&lt;/form&gt;
</code></pre><p>This takes care of creating the template, now let's take a look at how we populate the templated fields in our controller.</p><p>We'll navigate to the <code>guestbook.routes.home</code> namespace and update our home function to render the template when called:</p><pre><code class="clojure">&#40;defn home-page &#91;&amp; &#91;name message error&#93;&#93;
  &#40;layout/common   
    &#40;util/render &quot;/templates/welcome.html&quot; 
                 {:error    error
                  :name     name
                  :message  message
                  :messages &#40;db/get-messages&#41;}&#41;&#41;&#41;
</code></pre><p>Above, we simply create a map with all the fields we wish to populate. Then we pass it along with the name of the template file to the <code>render</code> function we defined earlier. Note that we can keep using the Hiccup layout to create the skeleton for the pages.  The rest of the code in the <code>home</code> namespace stays the same as it was:</p><pre><code class="clojure">&#40;defn save-message &#91;name message&#93;
  &#40;cond
 
    &#40;empty? name&#41;
    &#40;home-page name message &quot;Some dummy who forgot to leave a name&quot;&#41;
 
    &#40;empty? message&#41;
    &#40;home-page name message &quot;Don't you have something to say?&quot;&#41;
 
    :else
    &#40;do
      &#40;db/save-message name message&#41;
      &#40;home-page&#41;&#41;&#41;&#41;

&#40;defroutes home-routes
  &#40;GET &quot;/&quot; &#91;&#93; &#40;home-page&#41;&#41;
  &#40;POST &quot;/&quot; &#91;name message&#93; &#40;save-message name message&#41;&#41;
  &#40;GET &quot;/about&quot; &#91;&#93; &#40;about-page&#41;&#41;&#41;
</code></pre><p>As you can see, Clabango is very simple to use and allows cleanly separating your markup from your controllers. I think it's an excellent addition to the ever growing Clojure toolbox.</p><p>Complete sources for this post are available <a href='https://github.com/yogthos/clabango-guestbook'>here</a>.</p><p><strong>update</strong><hr/></p><p>The approach I took with putting templates under the <code>resources</code> folder will not work with template inheritance. So, you're best off simply using <code>render-file</code> from Clabango and keeping your templates under the <code>src</code> folder.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">lib-noir updates</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">24 02 2013</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I've had a bit of time to hack on lib-noir recently. Specifically, I decided to update the handling of access rules.</p><p>Previously, you could use <code>wrap-access-rules</code> by passing one or more rule functions. Each function would accept a <code>method</code>, <code>url</code>, and <code>params</code> and return a boolean indicating whether the rule is satisfied. Using these functions the wrapper would then decide wether the page should be displayed or if the client will be redirected to "/".</p><p>This was serviceable for doing some basic restrictions, like making pages private where a rule would check if a user was in the session:</p><pre><code class="clojure">&#40;defn private-page &#91;method url params&#93;
  &#40;session/get :user&#41;&#41;
</code></pre><p>However, it provided no way to redirect to a different URIs based on what rules failed. The update allows using multiple <code>wrap-access-rules</code> wrappers each redirecting to its own redirect URI, as follows:</p><pre><code class="clojure">&#40;-&gt; handler
  &#40;wrap-access-rules rule1&#41;
  &#40;wrap-access-rules {:redirect &quot;/unauthorized&quot;} rule2 rule3&#41;&#41;
</code></pre><p>The first set of rules that fails will redirect to its redirect target, defaulting to "/" if none is provided. This way we can create rule groups each having different behaviours.</p><p>Another addition is the <code>noir.util.route/access-rule</code> macro. The macro accepts a URI pattern and a condition. The condition is only checked if the URI of the page being checked matches the pattern.</p><p>The macro implicitly defines the <code>method</code>, <code>url</code>, and <code>params</code> variables, so they can be used by the logic in the condition:</p><pre><code class="clojure">&#40;def private-pages
  &#40;access-rule &quot;/private/:id&quot; &#40;= &#40;session/get :user&#41; &#40;first params&#41;&#41;&#41;&#41;
</code></pre><p>The above rule will only be triggered for pages matching the "/private/:id" pattern. Hopefully, the new additions will make it easier to work with access rules in lib-noir. Complete documentation for the feature is available at <a href='http://www.luminusweb.net/docs/routes.md'>Luminus</a>.</p><p>I'm also interested in hearing any feedback and suggestions regarding the current implementation. :)</p><p> <strong>update</strong><hr/></p><p>After a bit of discussion with <a href='https://github.com/edtsech'>Ed Tsech</a>, we decided that it would be better to make the parameters to the <code>access-rule</code> explicit.</p><p>So, now instead of defining access-rule by simply providing the URL pattern and a condition, you would also pass the arguments vector with the method, url, and params:</p><pre><code class="clojure">&#40;def private-pages 
  &#40;access-rule &quot;/private/:id&quot;  &#91;&#95; &#95; params&#93; 
    &#40;= &#40;session/get :user&#41; &#40;first params&#41;&#41;&#41;&#41;
</code></pre><p>While it's slightly more verbose, it's a lot less magical and there's no risk of the macro masking any variables in scope.</p> 
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Notes to self on working as a Christian web developer</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">20 02 2013</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>These are some notes to myself on how I would like to approach my work, at least, an <em>ideal</em> for who I would like to be as a Christian web developer. I write this mostly to organise my own thoughts, but I am publishing it just in case there are others who might find it helpful.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">One Ring to rule them all</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">11 01 2013</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The latest release of <a href='http://www.luminusweb.net/'>Luminus</a> is no longer using a custom <code>server.clj</code> which starts up Jetty using <code>run-jetty</code>. Instead, it now relies on <a href='https://github.com/weavejester/lein-ring'>lein-ring</a>, which in turns uses <a href='https://github.com/weavejester/ring-server'>ring-server</a> to create the server.</p><p>Snice you no longer have a <code>-main</code> in the project, you can't use <code>lein run</code> to start it up for development. Instead, use <code>lein ring server</code>, which will run Jetty for you.</p><p>If you need to start the server from within a REPL, then you can use the new <code>repl</code> namespace, which provides <code>start-server</code> and <code>stop-server</code> functions.</p><p>When you're packaging the application as a standalone, you run would now run <code>lein ring uberjar</code> instead of <code>lein uberjar</code>. The <code>-main</code> will be created by <code>lein-ring</code> for you based on the handler specified in your <code>project.clj</code>.</p><p>This means that all the configuration now lives under <code>project.clj</code> and gets picked up consistently both in development and production modes.</p><p>The new changes also simplify Heroku deployment. You no longer need to specify <code>+heroku</code>, the application will have all the necessary settings to run on Heroku out of the box.</p><p>Finally, I dropped support for Leiningen 1.x as it doesn't have support for profiles. There's no good reason to continue using it instead of upgrading to 2.x.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Luminus progress report</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">08 01 2013</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The work on the framework continues steadily, and I've been integrating some of the feedback I got on the initial release.</p><p>I quickly discovered that simply using different files for template modules is insufficient. Many features need to update the <code>project.clj</code> with dependencies or other options.</p><p>To deal with this I made a <a href='https://github.com/yogthos/luminus-template/blob/master/src/leiningen/new/dependency_injector.clj'>util</a> which reads in the project file and injects dependencies, plugins and other options. Now each plugin can add its own project elements independently of others.</p><p>I'm considering taking the same approach to managing the layout as well. For example, if bootstrap support was selected, then its js/css would be included in <code>layout/common</code>. Another use case would be to update the application routes if a module provided some new routes of its own.</p><p>I'd also like to highlight some of the additions to lib-noir. There are several new namespaces, such as <code>noir.util.cache</code>, <code>noir.io</code>, and <code>noir.util.route</code>. Let's take a look at each of these in turn.</p><h4 id="caching">Caching</h4><p>Basic caching is provided via <code>noir.util.cache</code>. Cache allows wrapping any expr using <code>&#40;cache id expr&#41;</code>, and the expr will only be evaluated if it's not found in the cache or if the cache has been invalidated. In case expr throws an exception the current cached value will be kept.</p><p>There are a couple of helpers for invalidating the cache. First, there's <code>invalidate-cache!</code>, which takes a key and removes it from the cache. Then, there's <code>clear-cache!</code> which removes all currently cached items.</p><p>It's also possible to set the timeout for cached items using <code>set-cache-timeout!</code> and passing it a value in seconds. If an item remains in the cache longer than the timeout, the cache will attempt to refresh the value by running the expr associated with the item.</p><p>Finally, you can set the maximum size of the cache by calling <code>set-cache-size!</code>, when the cache grows past the specified size, oldest items will be removed to make room for new ones.</p><p>I'm currently using the cache in <a href='http://http://www.luminusweb.net/'>Luminus</a> for the documentation pages. Luminus fetches the documentation from github as markdown and then translates it to HTML. This is slow enough to be noticeable to the user. On top of that, github is known to have an occasional outage or two. :) </p><p>With this scheme, I can keep the docs up to date without having to redeploy the site, and I don't have to worry about the latency or github uptime. </p><h4 id="io">IO</h4><p>The <code>noir.io</code> namespace provides some helper functions to make it easier to handle static resources.</p><p>You can get the absolute path to the public directory of your application by calling <code>resource-path</code>.</p><p>If you need to read a file located in the public folder you can get a URL for the resource by calling <code>get-resource</code> and provided the path relative to the public directory.</p><p>If the resource is a text file, such as a markdown document, you can use <code>slurp-resource</code> to read it into a string.</p><p>Another addition is the <code>upload-file</code> function which saves the file generated by a <code>multipart/form-data</code> form POST to a path relative to the public folder. An example can be seen here:</p><pre><code class="clojure">&#40;ns myapp.upload
  ...
  &#40;:require &#91;noir.io :as io&#93;&#41;&#41;
 
&#40;defn upload-page &#91;&#93;
  &#40;common/layout
    &#91;:h2 &quot;Upload a file&quot;&#93;
    &#40;form-to {:enctype &quot;multipart/form-data&quot;}
             &#91;:post &quot;/upload&quot;&#93;            
             &#40;file-upload :file&#41;            
             &#40;submit-button &quot;upload&quot;&#41;&#41;&#41;&#41;
              
&#40;defn handle-upload &#91;file&#93;
  &#40;upload-file &quot;/uploads&quot; file&#41;
  &#40;redirect
    &#40;str &quot;/&quot; &#40;session/get :user&#41; &quot;/&quot; &#40;:filename file&#41;&#41;&#41;&#41;
   
&#40;defroutes upload-routes
  &#40;GET &quot;/upload&quot; &#91;&#93; &#40;upload-page&#41;&#41;
  &#40;POST &quot;/upload&quot; &#91;file&#93; &#40;handle-upload file&#41;&#41;&#41;
</code></pre><h4 id="access&#95;rules">Access rules</h4><p>Noir used to have a <code>pre-route</code> macro, which allowed for filtering and redirecting based on some rules.</p><p>Now, <code>lib-noir</code> provides a <code>restricted</code> macro which provides similar functionality.</p><p>You can define access rules as functions which accept the method, url, and params. The function then returns a boolean to indicate if the rule succeeded or not.</p><p>For example, if we wanted to restrict access to a page so that it's only accessible if the id in session matches the id in the page, we could write a rule like this:</p><pre><code class="clojure">&#40;defn user-page &#91;method url params&#93; 
  &#40;and &#40;= url &quot;/private/:id&quot;&#41;
       &#40;= &#40;first params&#41; &#40;session/get :user&#41;&#41;&#41;&#41;
</code></pre><p>Then we wrap our handler in <code>wrap-access-rules</code> middleware. The middleware accepts one or more access rule functions, and checks if restricted pages match any of the rules provided.</p><pre><code class="clojure">&#40;def app &#40;-&gt; all-routes
             &#40;middleware/app-handler&#41;
             &#40;middleware/wrap-access-rules user-page&#41;&#41;&#41;  
</code></pre><p>With that in place, we can restrict access to our page as follows.</p><pre><code class="clojure">&#40;restricted GET &quot;/private/:id&quot; &#91;id&#93; &quot;private!&quot;&#41;
</code></pre><p>Note that, you have to use <code>noir.util.middleware/app-handler</code> for <code>wrap-access-rules</code> to work correctly. Or manually bind the <code>noir.request/&#42;request&#42;</code>, eg:</p><pre><code class="clojure">&#40;defn wrap-request-map &#91;handler&#93;
  &#40;fn &#91;req&#93;
    &#40;binding &#91;noir.request/&#42;request&#42; req&#93;
      &#40;handler req&#41;&#41;&#41;&#41;
</code></pre><p><strong>update</strong> I've since made <code>wrap-request-map</code> public in <code>lib-noir</code>, so if you need to wrap the request for any reason, you don't need to roll your own.</p><p>I hope you find the new features useful, and as always I'm open to feedback and suggestions for improvements as well as new features.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Luminus progress updates</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">28 12 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>In this post I'd like to give some updates on the progress of Luminus and the direction it's moving in. </p><p>I've had some great chats over at #clojure on IRC, and there's been lots of ideas and brainstorming. It's a very friendly and informative place if you haven't yet visited. :)</p><p>After talking it over with Raynes we decided that it would be much better to simply add things to <a href='https://github.com/noir-clojure/lib-noir'>lib-noir</a> than to roll a new library. So, lib-luminus is no more, and instead all the updates will be happening in <code>lib-noir</code> now.</p><p>All the current helper functions have already been rolled into version 0.3.0 of <code>lib-noir</code>, so definitely switch to it if you're using <code>lib-luminus</code> currently. The good news is that all you need to do is replace <code>&#91;lib-luminus &quot;0.1.5&quot;&#93;</code> with <code>&#91;lib-noir &quot;0.3.0&quot;&#93; in your </code>project.clj`, and update your namespaces to reference it instead. The function names and behaviour haven't changed.<br /></p><p>This segues into the next topic of how the line is drawn between what goes into the library and what belongs in the template. </p><p>The strategy here is to add functionality to `lib-noir, while putting configuration in the template. This facilitates an easy path for upgrades as the library continues to improve and evolve, while keeping all the customization in the hands of the user. It also means that the template will act as documentation for how to configure your application.</p><p>As the template continues to grow, it will be increasingly difficult to please everybody with a single template. For example, somebody might want to use  PostreSQL for their db, while another person might like MySQL, and yet another uses CouchDB and doesn't want to see any of the SQL business at all. </p><p>As these things tend to be rather polarizing, the approach will be to let people choose the items they want. Luminus aims to be more of a buffet, where you pick what's on your plate, as opposed omakase with the chef telling you what to eat. :)</p><p>To this end, the latest release of Luminus provides a base template which can be extended using <code>+feature</code> notation. Currently, there's two features supported, the first is the addition of bootstrap into the project and the second is support for SQLite.</p><p>The way this works is if you want to make a basic application, you'd do the same thing you did before.</p><pre><code class="bash">lein new luminus myapp
</code></pre><p>But if you wanted to have bootstrap in your app, then you'd simply do this:</p><pre><code class="bash">lein new luminus myapp +bootstrap
</code></pre><p>The best part is that you can mix different extensions together, eg:<pre><code class="bash">lein new luminus myapp +bootstrap +sqlite
</code></pre></p><p>When you do that, both features will be added to the resulting project. However, if they have any common files between the two features, then the latest one overwrites the former.</p><p>Hopefully, this approach will provide an easy way to add extended configuration while keeping things compartmentalized and easy to maintain. The latest documentation and examples are available at the official <a href='http://www.luminusweb.net'>Luminus</a> site.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Luminus: a web framework for Clojure</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">24 12 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Since the retirement of Noir, there aren't any batteries included web frameworks for Clojure. As I mentioned in an <a href='https://yogthos.net/blog/33-Moving+to+Compojure'>earlier post</a>, moving to Compojure is fairly painless. However, you still have to put a lot of things together by hand.</p><p>I suspect this isn't a problem for most people who've already been doing Clojure development. However, it can be daunting for beginners and it also means having to write a lot of boiler plate when making a new site.</p><p>I decided to see if I could tie some common libraries together to provide a more comprehensive solution for creating web applications in Clojure. This led to the creation of the <a href='http://www.luminusweb.net'>Luminus</a> framework, which follows in footsteps of Noir in attempting to make web development in Clojure an easy and accessible experience.</p><p>The framework consists of two parts, first is the <a href='https://github.com/yogthos/lib-luminus'>lib-luminus</a>, which provides some useful utility functions, which I found to be helpful when writing applications. The second is the <a href='https://github.com/yogthos/luminus-template'>luminus-template</a>, which is used to generate the base application.</p><p>The resulting app is ready to be run standalone or deployed as a war. It can also be run on <a href='http://www.heroku.com/'>Heroku</a> by following the steps in the <a href='https://devcenter.heroku.com/articles/clojure'>official documentation</a>.</p><p>The application generated by the template can be easily modified to fit your needs and shouldn't be any more restrictive than a standard Compojure app. This avoids some of the issues with Noir, where things like using custom middleware were problematic.</p><p>The documentation site for Luminus is built using the framework in the spirit of eating my own dog food, and its source is available on <a href='https://github.com/yogthos/luminus'>github</a> as well.</p><p>Hopefully this will be useful in helping people get started. I intend to continue working on it and I'm always open to suggestions, patches, and collaboration. :)</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Creating Leiningen Templates</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">16 12 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>If you've used Leiningen before, you've already seen templates in action. When you create a project using <code>lein new myproject</code>, you end up with a project folder with a namespace called myproject and a core.clj inside it. </p><p>The templates are really useful if you need to setup some common boilerplate for your project. In the last post I referenced a template for Compojure, which creates a new batteries included project.</p><p>Leiningen uses the <a href='https://github.com/Raynes/lein-newnew'>lein-newnew</a> plugin for this task. All you have to do to create a new template is to run <code>lein new template &lt;template name&gt;</code>. In my case I created a template called <code>compojure-app</code>:</p><pre><code class="bash">lein new template compojure-app
</code></pre><p>As all Leiningen projects, it will contain the <code>project.clj</code>, which will contain the description for our project:</p><pre><code class="clojure">&#40;defproject compojure-app/lein-template &quot;0.2.7&quot;
  :description &quot;Compojure project template for Leiningen&quot;
  :url &quot;https://github.com/yogthos/compojure-template&quot;
  :eval-in-leiningen true
  :license {:name &quot;Eclipse Public License&quot;
            :url &quot;http://www.eclipse.org/legal/epl-v10.html&quot;}
  :dependencies &#91;&#91;leinjacker &quot;0.2.0&quot;&#93;&#93;&#41;
</code></pre><p>It looks like a regular project file, except for the <code>eval-in-leiningen</code> key which <del>causes Leiningen to launch a subprocess</del> prevents Leiningen from launching a separate process for the given project during the build time.</p><p>The actual template resides under</p><pre><code>src/compojure-template/leiningen/new/compojure&#95;app.clj
</code></pre><p>It looks as follows:</p><pre><code class="clojure">&#40;ns leiningen.new.compojure-app
  &#40;:use &#91;leiningen.new.templates :only &#91;renderer sanitize year -&gt;files&#93;&#93;
        &#91;leinjacker.utils :only &#91;lein-generation&#93;&#93;&#41;&#41;

&#40;def project-file
  &#40;if &#40;= &#40;lein-generation&#41; 2&#41;
    &quot;project&#95;lein2.clj&quot;
    &quot;project&#95;lein1.clj&quot;&#41;&#41;

&#40;defn compojure-app
  &quot;Create a new Compojure project&quot;
  &#91;name&#93;
  &#40;let &#91;data {:name name
              :sanitized &#40;sanitize name&#41;
              :year &#40;year&#41;}
        render #&#40;&#40;renderer &quot;compojure&#95;app&quot;&#41; % data&#41;&#93;
    &#40;println &quot;Generating a lovely new Compojure project named&quot; &#40;str name &quot;...&quot;&#41;&#41;
    &#40;-&gt;files data
             &#91;&quot;.gitignore&quot;  &#40;render &quot;gitignore&quot;&#41;&#93;
             &#91;&quot;project.clj&quot; &#40;render project-file&#41;&#93;
             &#91;&quot;README.md&quot;   &#40;render &quot;README.md&quot;&#41;&#93;
             &#91;&quot;src/{{sanitized}}/handler.clj&quot;      &#40;render &quot;handler.clj&quot;&#41;&#93;
             &#91;&quot;src/{{sanitized}}/server.clj&quot;       &#40;render &quot;server.clj&quot;&#41;&#93;
             &#91;&quot;src/{{sanitized}}/common.clj&quot; &#40;render &quot;common.clj&quot;&#41;&#93;
             &#91;&quot;resources/public/css/screen.css&quot; &#40;render &quot;screen.css&quot;&#41;&#93;
             &quot;resources/public/js&quot;
             &quot;resources/public/img&quot;
             &quot;src/{{sanitized}}/models&quot;
             &#91;&quot;test/{{sanitized}}/test/handler.clj&quot; &#40;render &quot;handler&#95;test.clj&quot;&#41;&#93;&#41;&#41;&#41;
</code></pre><p>The <code>compojure-app</code> function is where all the fun happens, and it's what gets called when we run <code>lein new compojure-app myapp</code> to create an application using this template.</p><p>The function is mostly self explanatory. It uses the <code>render</code> function from <code>leiningen.new.templates</code> to take the template files and put them at the specified path. The <code>{{sanitized}}</code> tag ensures that the generated names for the package folders are valid.</p><p>Our template files live under </p><pre><code>src/compojure-template/leiningen/new/compojure&#95;app
</code></pre><p>and they don't need to have the same folder structure as the resulting project. As you can see above, we specify the resulting path explicitly in our template.</p><p>The template files look exactly like any regular Clojure source file, except for the <code>{{name}}</code> anchor. This will be replaced with the name of the application we specified when creating the project. Here's the <code>common.clj</code> template as an example:</p><pre><code class="clojure">&#40;ns {{name}}.common
  &#40;:use &#91;hiccup.page :only &#91;html5 include-css&#93;&#93;&#41;&#41;
       
&#40;defn layout &#91;&amp; body&#93;
  &#40;html5 
    &#91;:head
     &#91;:title &quot;Welcome to {{name}}&quot;&#93;
     &#40;include-css &quot;/css/screen.css&quot;&#41;&#93;
    &#40;into &#91;:body&#93; body&#41;&#41;&#41;
</code></pre><p>Every occurrence of <code>{{name}}</code> will be replaced with myapp instead and we'll have our namespace and greeting customized.</p><p>Once you've created your template, you'll need to install it using <code>lein install</code> and then add it as a plugin to your profile under <code>&#126;/.lein/profiles.clj</code> using the following format:</p><pre><code class="clojure">{:user
  {:plugins &#91;&#91;compojure-app/lein-template &quot;0.2.7&quot;&#93;&#93;}}
</code></pre><p>That's it, you can now use your new template and never have to write boilerplate for this kind of project again.</p><p>If you wish to make your template available to others you can publish it to <a href='https://clojars.org/'>Clojars</a> by running <code>lein deploy clojars</code> from the console.</p><p>Any template published on Clojars can be used directly without needing to add it to your plugins in the <code>profiles.clj</code> as shown above.</p><p>The complete source for the template discussed in this post is available <a href='https://github.com/yogthos/compojure-template'>here</a>.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Moving to Compojure</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">15 12 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>It was <a href='http://blog.raynes.me/blog/2012/12/13/moving-away-from-noir/'>recently announced</a> that <a href='https://github.com/noir-clojure/noir'>Noir</a> is being deprecated. The primary reason cited is that it simply doesn't add a lot of useful functionality over what's already available in Compojure and makes it difficult to integrate other middleware, such as <a href='https://github.com/cemerick/friend'>friend</a>. </p><p>The useful parts of Noir have been moved to <a href='https://github.com/noir-clojure/lib-noir'>lib-noir</a>. Together, Compojure and lib-noir provide a very similar experience to what you're already used to if you've been using Noir up to now.</p><p>There are some differences of course. The main one is that instead of using the <code>defpage</code> macro, you would now declare your routes using <code>defroutes</code>.</p><p>So, if you previously had something like the following:</p><pre><code class="clojure">&#40;defpage &quot;/&quot; &#91;&#93;
  &#40;common/layout 
    &#40;form-to &#91;:post &quot;/&quot;&#93;                           
              &#40;text-area {:placeholder &quot;say something...&quot;} &quot;message&quot;&#41; 
              &#91;:br&#93;
              &#40;text-field {:placeholder &quot;name&quot;} &quot;id&quot;&#41;
              &#40;submit-button &quot;post message&quot;&#41;&#41;&#41;&#41;

&#40;defpage &#91;:post &quot;/&quot;&#93; params
  &#40;common/layout 
    &#91;:p &#40;:id params&#41; &quot; says &quot; &#40;:message params&#41;&#93;&#41;&#41;
</code></pre><p>Noir would then create the GET and POST routes for "/" behind the scenes. With Compojure we'll have to define the routes explicitly using <code>defroutes</code>.</p><pre><code class="clojure">&#40;defroutes app-routes  
  &#40;GET &quot;/&quot; &#91;&#93; &#40;message&#41;&#41;
  &#40;POST &quot;/&quot; params &#40;display-message params&#41;&#41;
  &#40;route/resources &quot;/&quot;&#41;
  &#40;route/not-found &quot;Not Found&quot;&#41;&#41;
</code></pre><p>Then, we'll write the <code>message</code> and <code>display-message</code> functions and put the logic for the pages in them.</p><pre><code class="clojure">&#40;defn message &#91;&#93;
  &#40;html5 
    &#91;:body 
     &#40;form-to &#91;:post &quot;/&quot;&#93;                           
              &#40;text-area {:placeholder &quot;say something...&quot;} &quot;message&quot;&#41; 
              &#91;:br&#93;
              &#40;text-field {:placeholder &quot;name&quot;} &quot;id&quot;&#41;
              &#40;submit-button &quot;post message&quot;&#41;&#41;&#93;&#41;&#41;

&#40;defn display-message &#91;params&#93;
  &#40;let &#91;form-params &#40;:form-params params&#41;&#93; 
    &#40;html5 
      &#91;:body 
       &#91;:p &#40;get form-params &quot;id&quot;&#41; &quot; says &quot; &#40;get form-params &quot;message&quot;&#41;&#93;&#93;&#41;&#41;&#41;
</code></pre><p>The Noir template comes with a <code>common</code> namespace which defines a layout macro, which we use to wrap our pages so that we don't have to keep typing in the boilerplate. We can easily write a helper function to do the same thing.</p><pre><code class="clojure">&#40;ns myapp.common
  &#40;:use &#91;hiccup.def :only &#91;defhtml&#93;&#93; 
        &#91;hiccup.page :only &#91;include-css&#93;&#93;&#41;&#41;
       
&#40;defhtml layout &#91;&amp; body&#93;  
  &#91;:head
   &#91;:title &quot;Welcome to myapp&quot;&#93;
   &#40;include-css &quot;/css/screen.css&quot;&#41;&#93;
  &#40;into &#91;:body&#93; body&#41;&#41;
</code></pre><p>The next difference is that our request map contains the complete request as opposed to just the form params as is the case with the one in <code>defpage</code>.</p><p>This means that we have to grab the <code>:form-params</code> key from it to access the form parameters. Another thing to note is that the parameter keys are strings, meaning that we can't destructure them using <code>:keys</code>.</p><p>This problem is also easily addressed  by a macro which will grab the form-params and keywordize them for us. Note that the original request map will still be available as <code>request</code> in the resulting function.</p><pre><code class="clojure">&#40;defmacro page &#91;f form-params &amp; body&#93;
  `&#40;defn &#126;f &#91;&#126;'request&#93;
     &#40;let &#91;&#126;form-params 
           &#40;into {} &#40;for &#91;&#91;k# v#&#93; &#40;:form-params &#126;'request&#41;&#93; 
                      &#91;&#40;keyword k#&#41; v#&#93;&#41;&#41;&#93;
       &#126;@body&#41;&#41;&#41;
</code></pre><p>Now, we can rewrite our app as follows:</p><pre><code class="clojure">&#40;page message &#91;&#93;
  &#40;layout
    &#40;form-to &#91;:post &quot;/&quot;&#93;                           
             &#40;text-area {:placeholder &quot;say something...&quot;} &quot;message&quot;&#41; 
             &#91;:br&#93;
             &#40;text-field {:placeholder &quot;name&quot;} &quot;id&quot;&#41;
             &#40;submit-button &quot;post message&quot;&#41;&#41;&#41;&#41;

&#40;page display-message {:keys &#91;id message&#93;}
  &#40;layout
      &#91;:p id &quot; says &quot; message&#93;&#41;&#41;

&#40;defroutes app-routes  
  &#40;GET &quot;/&quot; &#91;&#93; &#40;message &#91;&#93;&#41;&#41;
  &#40;POST &quot;/&quot; params &#40;display-message params&#41;&#41;
  &#40;route/resources &quot;/&quot;&#41;
  &#40;route/not-found &quot;Not Found&quot;&#41;&#41;
</code></pre><p><strong>update</strong></p><p>Turns out Compojure already provides the functionality provided by the page macro, and to get the form params, we can destructure them as follows:</p><pre><code class="clojure">&#40;defn display-message &#91;id message&#93;
  &#40;layout &#91;:p id &quot; says &quot; message&#93;&#41;&#41;

&#40;defroutes app-routes  
  &#40;POST &quot;/&quot; &#91;id message&#93; &#40;display-message id message&#41;&#41;
  &#40;route/not-found &quot;Not Found&quot;&#41;&#41;
</code></pre><p>Big thanks to James Reeves  aka <a href='https://github.com/weavejester'>weavejester</a> on <a href='http://www.reddit.com/r/Clojure/comments/14wlew/migrating_from_noir_to_compojure/c7h50m1'>setting me straight</a> there. :)</p><p>This is starting to look very similar to the Noir style apps we're used to. Turns out that migrating from Noir to Compojure is fairly painless. </p><p>If you use lib-noir when converting your existing Noir application, then the changes end up being minimal. You can continue using noir.crypt, noir.validation, and etc. as you did before. The only caveat is that you now have to remember to add the appropriate wrappers to your handler, eg:</p><pre><code class="clojure">&#40;-&gt; handler
  &#40;wrap-noir-cookies&#41;
  &#40;session/wrap-noir-session 
    {:store &#40;memory-store session/mem&#41;}&#41;
  &#40;wrap-noir-validation&#41;&#41;
</code></pre><p>One thing which Noir provided was a nice batteries included template. I created a similar one called <a href='https://github.com/yogthos/compojure-template'>compojure-app</a>.</p><p>To use the template you can simply run:</p><pre><code class="bash">lein new compojure-app myapp
</code></pre><p>The template sets up a project with a <code>main</code>, which can be compiled into a standalone using <code>lein uberjar</code> or into a deployable WAR using <code>leing ring uberwar</code>. The project is setup to correctly handle loading static resources located in <code>resources/public</code> and correctly handle the servlet context. </p><p>When run with <code>lein run</code> the project will pickup the dev dependencies and use the <code>wrap-reload</code>, so that changes to source are picked up automatically in the running app.</p><p>This should get all the boiler plate out of the way and let you focus on making your app just as you did with Noir. :)</p><br />
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Simple Parallel Processing with PHP and proc_open()</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">05 12 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        You can find a reasonably sensible example of how to perform parallel processing with PHP using the `popen()` function at wellho.net. Sometimes though, the requirement to pass all the parameters to your function via command line arguments can be limiting.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Simple Parallel Processing with PHP and proc_open()</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">05 12 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        You can find a reasonably sensible example of how to perform parallel processing with PHP using the `popen()` function at wellho.net. Sometimes though, the requirement to pass all the parameters to your function via command line arguments can be limiting.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">ClojureScript Adventures</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">26 10 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I finally got a chance to play around a bit more with ClojureScript. When I was updating <a href='https://github.com/yogthos/markdown-clj'>markdown-clj</a> to compile to it, the extent of interaction was to accept a markdown string and return the corresponding HTML.</p><p>This time around I decided to dive into doing interop with JavaScript and actual interaction with the page. I wrote a silly <a href='https://github.com/yogthos/Clojure-Tetris'>Tetris game</a> a while back, and it seemed like a perfect fit for the task.</p><p>So, let's see what's involved in porting Clojure to ClojureScript and Canvas. First, I had to separate the pure Clojure code from any code which relies on Java interop. The original code can be seen <a href='https://github.com/yogthos/Clojure-Tetris/blob/f614a66524647870bc387ca9615a119bc7d76a36/src/tetris.clj'>here</a>.</p><p>After, splitting it up, I ended up with a <a href='https://github.com/yogthos/Clojure-Tetris/blob/master/src/tetris/game.clj'>game namespace</a> which contains the bulk of the game logic, and a <a href='https://github.com/yogthos/Clojure-Tetris/blob/master/src/tetris/core.clj'>core namespace</a> containing all the logic pertaining to the UI and input. The split turned out to be fairly painless since I already had the game logic separated from UI in the original design.</p><p>Now it's time to add some ClojureScript to the project. First, we need to create a new source folder for the ClojureScript namespaces. In my project I called this folder <code>src-cljs</code>. Then we need some way to compile our script.</p><p>The easiest way to do that is to use the <a href='https://github.com/emezeske/lein-cljsbuild'>lein-cljsbuild plugin</a>. With it you can specify the ClojureScript sources, Clojure namespaces you'd like to reference, and the output Js files to produce.</p><p>In my case the project file looks as follows:</p><pre><code class="clojure">&#40;defproject tetris &quot;0.1.0-SNAPSHOT&quot;
  :description &quot;a simple Tetris game&quot;
  :url &quot;https://github.com/yogthos/Clojure-Tetris&quot;
  :license {:name &quot;Eclipse Public License&quot;
            :url &quot;http://www.eclipse.org/legal/epl-v10.html&quot;}
  
  :dependencies &#91;&#91;org.clojure/clojure &quot;1.4.0&quot;&#93;&#93;
  :plugins &#91;&#91;lein-cljsbuild &quot;0.2.9&quot;&#93;&#93;
  
  :source-paths &#91;&quot;src&quot;&#93;
  :main tetris.core

  :cljsbuild {:crossovers &#91;tetris.game&#93;
              :builds
              &#91;{:source-path &quot;src-cljs&quot;
                :compiler
                {:output-to &quot;js/tetris.js&quot;
                 :optimizations :advanced
                 :pretty-print false}}&#93;}&#41;
</code></pre><p>All that's needed to include ClojureScript compilation is to add the <code>lein-cljsbuild</code> in the plugins and specify the options for the <code>cljsbuild</code>. The <code>crossovers</code> section specifies a vector of Clojure namespaces which will be included during compilation.</p><p>Once the project file is setup, we have two options for invoking ClojureScript compilation. We can either run <code>lein cljsbuild once</code> or <code>lein cljsbuild auto</code>. When using the auto option, the build will watch for changes in the source and automatically recompile the Js files as needed. This takes much less time than when compiling using the once option, and turns out to be quite handy for development.</p><p>The ClojureScript version of the UI, which uses the canvas, can be seen <a href='https://github.com/yogthos/Clojure-Tetris/blob/master/src-cljs/tetris/core.cljs'>here</a> . </p><p>Interacting with JavaScript turns out to be pretty simple and the syntax is similar to Java interop in Clojure. However, there are some differences  which are worth mentioning.</p><p>Any standard Js functions can be accessed using the <code>js</code> namespace, for example if we want to make a logger which logs to the console we can write something like the following:</p><pre><code class="clojure">&#40;defn log &#91;&amp; items&#93;
  &#40;.log js/console &#40;apply str items&#41;&#41;&#41;
</code></pre><p>This works exactly like the Java interop, where we denote methods by using the <code>.</code> notation and pass in the object as the first argument.</p><p>Exporting functions so that they're visible from JavaScript is also quite simple. Instead of denoting them with <code>-</code> as we do when we interop with Java, we use <code>&#94;:export</code> annotation:</p><pre><code class="clojure">&#40;defn &#94;:export init &#91;&#93;
  &#40;log &quot;Hello ClojureScript!&quot;&#41;&#41;
</code></pre><p>One thing that's not obvious is the interaction with JavaScript object properties. To access these we use <code>&#40;.-property obj&#41;</code> notation. Where <code>-</code> indicates that we're referencing a property and not a function. Writing properties is accomplished by calling the <code>set!</code> function. Here's an example:</p><pre><code class="clojure">&#40;defn &#94;:export init &#91;&#93;
  &#40;let &#91;canvas &#40;.getElementById js/document &quot;canvas&quot;&#41;
        ctx    &#40;.getContext canvas &quot;2d&quot;&#41;
        width  &#40;.-width canvas&#41; 
        height &#40;.-height canvas&#41;&#93;
 
    &#40;log &quot;width: &quot; width &quot;, height: &quot; height&#41;

    ;;set a property
    &#40;set! &#40;.-fillStyle ctx&#41; &quot;black&quot;&#41;

    &#40;.fillRect ctx 0 0 width height&#41;&#41;&#41;
</code></pre><p>Another quirk I ran into is that <code>:use</code> doesn't seem to work in the namespace declaration as it expects a collection.</p><p>For example, if you have the following setup:<pre><code class="clojure">&#40;ns foo&#41;

&#40;defn bar &#91;&#93;&#41;

&#40;ns hello
 &#40;:use foo&#41;&#41;

&#40;defn &#94;:export init &#91;&#93;
	&#40;js/alert &quot;Hello from ClojureScript!&quot;&#41;&#41;
</code></pre></p><p>the compiler throws the following error:<pre><code class="clojure">java.lang.UnsupportedOperationException: nth not supported on this type: Symbol
</code></pre></p><p>Fortunately, both <code>&#40;:use &#91;foo :only &#91;bar&#93;&#93;&#41;</code> and <code>&#40;:require foo&#41;</code> work as expected. </p><p>Finally, to make a timer, it's possible to use <code>js/setTimeout</code> and simply pass it the function to call after the timeout:</p><pre><code class="clojure">&#40;declare game-loop&#41;
&#40;defn game-loop &#91;state&#93;
  &#40;if &#40;not &#40;:game-over state&#41;&#41;
    &#40;js/setTimeout
      &#40;fn &#91;&#93; &#40;game-loop &#40;update-state state&#41;&#41;&#41;
      10&#41;&#41;&#41;     
</code></pre><p>Everything else appeared to work exactly as it does in Clojure itself. The only caveat when porting code is that it cannot contain any Java interop or use libraries which do so. In case of the game, I simply put the game logic into a shared namespace and wrote separate UI logic for both Java and JavaScript versions.</p><p>To try out the ClojureScript version simply grab <a href='https://raw.github.com/yogthos/Clojure-Tetris/master/js/tetris.js'>tetris.js</a> and <a href='https://raw.github.com/yogthos/Clojure-Tetris/master/tetris.html'>tetris.html</a> which expects the tetris.js file to be in the <code>js</code> folder relative to it. </p><p>One thing to note is that ClojureScript is definitely chunky compared to writing JavaScript by hand. The game weighs in at a hefty 100k. That said, it should be noted that jQuery weighs in about that as well, and nobody would claim that it's outrageous for a site to include it. </p><p>I feel that the benefits of ClojureScript offers far outweigh the downsides of its size. You get a much nicer language without all the quirks of working in JavaScript, immutability, persistent data structures, and the ability to easily share code between the server and the browser.</p><p>The good news is that ClojureScript is under active development, and performance and size are both targets for future improvement. As it stands I find it very usable for many situations.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/files/report1.png" alt="making reporting easy">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">making reporting easy</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">17 10 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>There are a bunch of reporting options out there, <a href='http://community.jaspersoft.com/project/jasperreports-library'>JasperReports</a> is one popular example. While it's got a ton of features, it often involves a disproportionate amount of effort to create even the simplest of reports. <a href='http://java-bytes.blogspot.ca/2009/06/jasper-reports-example.html'>Here's</a> what's involved in simply printing out some fields from the database to a PDF.</p><p>Let's see if we can make things easier with Clojure. We'll produce the same report as the one in the linked example.</p><p>First, we'll create our database connection using <a href='https://github.com/clojure/java.jdbc'>java.jdbc</a>.</p><pre><code class="clojure">&#40;def db {:classname &quot;org.postgresql.Driver&quot;
           :subprotocol &quot;postgresql&quot;
           :subname &quot;//localhost:5432/testdb&quot;
           :user &quot;user&quot;
           :password &quot;secret&quot;}&#41;
</code></pre><p>then we'll make an employee table and populate it with the sample data</p><pre><code class="clojure">&#40;defn create-employee-table &#91;&#93;
  &#40;sql/create-table
    :employee
    &#91;:name &quot;varchar&#40;50&#41;&quot;&#93;
    &#91;:occupation &quot;varchar&#40;50&#41;&quot;&#93;
    &#91;:place &quot;varchar&#40;50&#41;&quot;&#93;
    &#91;:country &quot;varchar&#40;50&#41;&quot;&#93;&#41;&#41;

&#40;sql/with-connection 
  db
  &#40;create-employee-table&#41;
  &#40;sql/insert-rows 
    :employee
    &#91;&quot;Babji, Chetty&quot;, &quot;Engineer&quot;, &quot;Nuremberg&quot;, &quot;Germany&quot;&#93;
    &#91;&quot;Albert Einstein&quot;, &quot;Engineer&quot;, &quot;Ulm&quot;, &quot;Germany&quot;&#93;
    &#91;&quot;Alfred Hitchcock&quot;, &quot;Movie Director&quot;, &quot;London&quot;, &quot;UK&quot;&#93;
    &#91;&quot;Wernher Von Braun&quot;, &quot;Rocket Scientist&quot;, &quot;Wyrzysk&quot;, &quot;Poland &#40;Previously Germany&#41;&quot;&#93;
    &#91;&quot;Sigmund Freud&quot;, &quot;Neurologist&quot;, &quot;Pribor&quot;, &quot;Czech Republic &#40;Previously Austria&#41;&quot;&#93;
    &#91;&quot;Mahatma Gandhi&quot;, &quot;Lawyer&quot;, &quot;Gujarat&quot;, &quot;India&quot;&#93;
    &#91;&quot;Sachin Tendulkar&quot;, &quot;Cricket Player&quot;, &quot;Mumbai&quot;, &quot;India&quot;&#93;
    &#91;&quot;Michael Schumacher&quot;, &quot;F1 Racer&quot;, &quot;Cologne&quot;, &quot;Germany&quot;&#93;&#41;&#41;
</code></pre><p>finally we'll write a function to read the records from the table.</p><pre><code class="clojure">&#40;defn read-employees &#91;&#93;
  &#40;sql/with-connection db 
    &#40;sql/with-query-results rs &#91;&quot;select &#42; from employee&quot;&#93; &#40;doall rs&#41;&#41;&#41;&#41;
</code></pre><p>Let's run <code>read-employees</code> to make sure everything is working as expected, we should see something like the following:</p><pre><code class="clojure">&#40;clojure.pprint/pprint &#40;read-employees&#41;&#41;

&#40;{:country &quot;Germany&quot;,
  :place &quot;Nuremberg&quot;,
  :occupation &quot;Engineer&quot;,
  :name &quot;Babji, Chetty&quot;}
 {:country &quot;Germany&quot;,
  :place &quot;Ulm&quot;,
  :occupation &quot;Engineer&quot;,
  :name &quot;Albert Einstein&quot;}
  ...&#41;
</code></pre><p>You'll notice that the result is simply a list of maps where the keys are the names of the columns in the table.</p><p>We're now ready to generate our report, <a href='https://github.com/yogthos/clj-pdf'>clj-pdf</a> provides a <code>template</code> macro, which uses <code>$</code> to create anchors which are populated from the data using the keys of the same name. </p><p>The template returns a function which accepts a sequence of maps and applies the supplied template to each element in the sequence. In our case, since we're building a table, the template is simply a vector with the names of the keys for each cell in the row.</p><pre><code class="clojure">&#40;def employee-template 
  &#40;template &#91;$name $occupation $place $country&#93;&#41;&#41;
</code></pre><p>if we pass our data to the template we'll end up with the following:</p><pre><code class="clojure">&#40;employee-template &#40;take 2 &#40;read-employees&#41;&#41;&#41;

&#40;&#91;&quot;Babji, Chetty&quot; &quot;Engineer&quot; &quot;Nuremberg&quot; &quot;Germany&quot;&#93; 
 &#91;&quot;Albert Einstein&quot; &quot;Engineer&quot; &quot;Ulm&quot; &quot;Germany&quot;&#93;&#41;
</code></pre><p>All that's left is to stick this data into our report:</p><pre><code class="clojure">&#40;pdf
 &#91;{}
  &#40;into &#91;:table 
         {:border false
          :cell-border false
          :header &#91;{:color &#91;0 150 150&#93;} &quot;Name&quot; &quot;Occupation&quot; &quot;Place&quot; &quot;Country&quot;&#93;}&#93;
        &#40;employee-template &#40;read-employees&#41;&#41;&#41;&#93;
 &quot;report.pdf&quot;&#41;
</code></pre><p>here's the result of running the above code, which looks just as we'd expect:</p><p><img src="/files/report1.png" alt="table report" /></p><p>It only took a few lines to create the report and we can see and manipulate the layout of the report in one place. Of course, the template we used for this report was completely boring, so let's look at another example. Here we'll output the data in a list, and style each element:</p><pre><code class="clojure">&#40;def employee-template-paragraph 
  &#40;template 
    &#91;:paragraph 
     &#91;:heading $name&#93;
     &#91;:chunk {:style :bold} &quot;occupation: &quot;&#93; $occupation &quot;\n&quot;
     &#91;:chunk {:style :bold} &quot;place: &quot;&#93; $place &quot;\n&quot;
     &#91;:chunk {:style :bold} &quot;country: &quot;&#93; $country
     &#91;:spacer&#93;&#93;&#41;&#41;
</code></pre><p>when writing the report, we can mix the templated elements with regular ones:</p><pre><code class="clojure">&#40;pdf 
  &#91;{:font {:size 11}}      
   &#91;:heading {:size 14} &quot;Employees Test&quot;&#93;
   &#91;:line&#93;
   &#91;:spacer&#93;
   &#40;employee-template-paragraph &#40;read-employees&#41;&#41;&#93;
  &quot;report.pdf&quot;&#41;
</code></pre><p>here's the new report with the fancy formatting applied to it:</p><p><img src="/files/report2.png" alt="list report" /></p><p>I think that this approach provides a lot of flexibility while keeping things concise and clear. In my experience there are many situations where all you need is a simple well formatted report, and the effort to create that report should be minimal.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Why Christians should watch movies</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">10 10 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Why would Christians watch movies at all? They are full of violence and bad language and plenty of other things we try to avoid. They are made by people who have completely different world views than our own, and disagree with most of the beliefs we hold most dear. Why would we fill our heads with all this simply for the sake of <em>entertainment</em>?</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Making services with Liberator</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">09 09 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><a href='http://clojure-liberator.github.com/'>Liberator</a> is a recent Clojure library for writing RESTful services. Its primary feature is that it puts strong emphasis on decoupling the front end and the back end of the application.</p><p>Conceptually, Liberator provides a very clean way to reason about your service operations. Each request passes through a series of conditions and handlers defined in the resource. These map to the codes specified by the <a href='http://www.ietf.org/rfc/rfc2616.txt'>HTTP rfc</a>, such as 200 - OK, 201 - created, 404 - not found, etc. This makes it very easy to write standards compliant services and to group the operations logically.</p><p>While the official site has some fairly decent documentation, I found there were a few areas where I had to dig around and look through the source to figure out what to do.</p><p>In this post I'll walk you through the steps to create a simple application which serves static resources, provides basic session management, and JSON operations.</p><p>Our application will be structures as follows:</p><pre><code>src/liberator&#95;service
         server.clj
         resources.clj
         static&#95;resources.clj
         ui.clj
resources/public
         site.js
project.clj
</code></pre><p>Our <code>project.clj</code> will look as follows:<pre><code class="clojure">&#40;defproject liberator-example &quot;0.1.0-SNAPSHOT&quot;
  :description &quot;Example for the Liberator library&quot;
  :url &quot;https://github.com/yogthos/liberator-example&quot;
  :license {:name &quot;Eclipse Public License&quot;
            :url &quot;http://www.eclipse.org/legal/epl-v10.html&quot;}
  :dependencies &#91;&#91;org.clojure/clojure &quot;1.4.0&quot;&#93;
                 &#91;compojure &quot;1.0.2&quot;&#93;
                 &#91;liberator &quot;0.5.0&quot;&#93;
                 &#91;sandbar &quot;0.4.0-SNAPSHOT&quot;&#93;
                 &#91;org.clojure/data.json &quot;0.1.2&quot;&#93;
                 &#91;ring/ring-jetty-adapter &quot;1.1.0&quot;&#93;&#93;
  :dev-dependencies &#91;&#91;lein-ring &quot;0.7.3&quot;&#93;&#93;
  :ring {:handler liberator-service.server/handler}
  :main liberator-service.server&#41;
</code></pre></p><p>Now we'll take a look at the service namespace, in it we'll add the required libraries and create an atom to hold the session information.<pre><code class="clojure">&#40;ns liberator-service.server
  &#40;:use &#91;liberator.representation :only &#91;wrap-convert-suffix-to-accept-header&#93;&#93;
        &#91;ring.middleware.multipart-params :only &#91;wrap-multipart-params&#93;&#93;
        ring.middleware.session.memory
        sandbar.stateful-session
        compojure.core 
        &#91;compojure.handler :only &#91;api&#93;&#93;
        liberator-service.ui
        liberator-service.resources
        liberator-service.static-resources&#41;
  &#40;:require
   &#91;ring.adapter.jetty :as jetty&#93;&#41;&#41;

&#40;defonce my-session &#40;atom {}&#41;&#41;
</code></pre></p><p> Next we will define the routes which our application responds to. In our case we've defined routes for serving the home page, our services, and static content:<pre><code class="clojure">&#40;defn assemble-routes &#91;&#93;
  &#40;routes
    &#40;GET   &quot;/&quot; &#91;&#93; home&#41;
    &#40;POST &quot;/login&quot; &#91;&#93; login&#41;
    &#40;POST &quot;/logout&quot; &#91;&#93; logout&#41;
    &#40;GET   &quot;/resources/:resource&quot; &#91;resource&#93; static&#41;&#41;&#41;
</code></pre></p><p>we'll also need to create a handler for the application:<pre><code class="clojure">&#40;defn create-handler &#91;&#93;
  &#40;fn &#91;request&#93;
    &#40;&#40;-&gt;
       &#40;assemble-routes&#41;
       api
       wrap-multipart-params
       &#40;wrap-stateful-session {:store &#40;memory-store my-session&#41;}&#41;
       &#40;wrap-convert-suffix-to-accept-header
         {&quot;.html&quot; &quot;text/html&quot;
          &quot;.txt&quot; &quot;text/plain&quot;
          &quot;.xhtml&quot; &quot;application/xhtml+xml&quot;
          &quot;.xml&quot; &quot;application/xml&quot;
          &quot;.json&quot; &quot;application/json&quot;}&#41;&#41;
      request&#41;&#41;&#41;
</code></pre></p><p>The session handling in our handler is provided by the <code>wrap-stateful-session</code> from the <a href='https://github.com/brentonashworth/sandbar'>sandbar</a> library. The <code>wrap-convert-suffix-to-accept-header</code> is used by the Liberator to decide what types of requests it will accept. Finally, we'll create a main to run our service:<pre><code class="clojure">&#40;defn start &#91;options&#93;
  &#40;jetty/run-jetty
   &#40;fn &#91;request&#93;
     &#40;&#40;create-handler&#41; request&#41;&#41;
   &#40;assoc options :join? false&#41;&#41;&#41;

&#40;defn -main
  &#40;&#91;port&#93;
     &#40;start {:port &#40;Integer/parseInt port&#41;}&#41;&#41;
  &#40;&#91;&#93;
     &#40;-main &quot;8000&quot;&#41;&#41;&#41;
</code></pre></p><p>Next let's write a resource which will display a login page:<pre><code class="clojure">&#40;ns liberator-service.ui
  &#40;:use hiccup.page
        hiccup.element
        hiccup.form
        sandbar.stateful-session
        &#91;liberator.core :only &#91;defresource&#93;&#93;&#41;&#41;

&#40;defresource home
  :available-media-types &#91;&quot;text/html&quot;&#93;
  :available-charsets &#91;&quot;utf-8&quot;&#93;
  :handle-ok &#40;html5 &#91;:head &#40;include-js
                             &quot;http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js&quot;
                             &quot;/resources/site.js&quot;&#41;&#93;
                    &#91;:body
                       &#91;:div#message&#93;
                       &#91;:div#login
                        &#40;text-field &quot;user&quot;&#41;
                        &#40;password-field &quot;pass&quot;&#41;
                        &#91;:button {:type &quot;button&quot; :onclick &quot;login&#40;&#41;&quot;} &quot;login&quot;&#93;&#93;&#93;&#41;&#41;
</code></pre></p><p>Here we get a glimpse at how Liberator works. We use <code>defresource</code> to define the handler for the <code>home</code> route we specified earlier in our service. The resource specifies what media types it provides as well as the encoding for the content. If the handler is invoked successfully then the <code>:handle-ok</code> handler is called and its output is set as the body of the <code>response</code>.  In our <code>site.js</code> we'll define <code>login</code> and <code>logout</code> functions which will use POST to call login and logout operations on the server:<pre><code class="javascript">function login&#40;&#41; {
	$&#40;&quot;#message&quot;&#41;.text&#40;&quot;sending login request&quot;&#41;;
	$.post&#40;&quot;/login&quot;, 
	       {user: $&#40;&quot;#user&quot;&#41;.val&#40;&#41;, pass: $&#40;&quot;#pass&quot;&#41;.val&#40;&#41;}, 
    	       function&#40;{window.location.reload&#40;true&#41;;},
    	       &quot;json&quot;&#41;
         .error&#40; function&#40;xhr, textStatus, errorThrown&#41; {       			 
      			 $&#40;&quot;#message&quot;&#41;.text&#40;textStatus + &quot;: &quot; + xhr.responseText&#41;;
   	 }&#41;;
}

function logout&#40;&#41; {
    $.post&#40;&quot;/logout&quot;, 
           function&#40;&#41; {window.location.reload&#40;true&#41;;}&#41;;					  	
}
</code></pre></p><p>Since we reference a local JavaScript file, we'll need to create a handler to serve it. We'll create a <code>static-resources</code> namespace for this purpose:<pre><code class="clojure">&#40;ns liberator-service.static-resources  
  &#40;:use &#91;liberator.core :only &#91;defresource&#93;&#93;
        &#91;ring.util.mime-type :only &#91;ext-mime-type&#93;&#93;&#41;
  &#40;:require &#91;clojure.java.io :as io&#93;&#41;&#41;

&#40;let &#91;static-dir  &#40;io/file &quot;resources/public/&quot;&#41;&#93;
  &#40;defresource static
    :available-media-types
    #&#40;let &#91;file &#40;get-in % &#91;:request :route-params :resource&#93;&#41;&#93;       
       &#40;if-let &#91;mime-type &#40;ext-mime-type file&#41;&#93;
         &#91;mime-type&#93;
         &#91;&#93;&#41;&#41;

    :exists?
    #&#40;let &#91;file &#40;get-in % &#91;:request :route-params :resource&#93;&#41;&#93;       
       &#40;let &#91;f &#40;io/file static-dir file&#41;&#93;
         &#91;&#40;.exists f&#41; {::file f}&#93;&#41;&#41;
    
    :handle-ok &#40;fn &#91;{{{file :resource} :route-params} :request}&#93;                 
                 &#40;io/file static-dir file&#41;&#41;&#41;

    :last-modified &#40;fn &#91;{{{file :resource} :route-params} :request}&#93;                                                               
                     &#40;.lastModified &#40;io/file static-dir file&#41;&#41;&#41;&#41;
</code></pre></p><p>When our home page requests <code>/resources/site.js</code>, this resource will set the mime type to "text/javascript" based on the extension of the file. It will check if the resource exists and the last modified time, and finally serve the resource in <code>:handle-ok</code> as needed.</p><p>Now let's create a resource which the client can call to login and create a session on the server. We'll put it in the <code>resources</code> namespace:<pre><code class="clojure">&#40;ns liberator-service.resources
  &#40;:use clojure.data.json                        
        sandbar.stateful-session
        &#91;liberator.core :only &#91;defresource request-method-in&#93;&#93;&#41;&#41;
</code></pre></p><p>For our testing, we'll simply create a dummy list of users and a helper to check if one matches our login params:<pre><code class="clojure">&#40;def users &#91;{:user &quot;foo&quot; 
             :pass &quot;bar&quot;
             :firstname &quot;John&quot;
             :lastname &quot;Doe&quot;}&#93;&#41;

&#40;defn valid-user &#91;user&#93;
  &#40;some #&#40;= user &#40;select-keys % &#91;:user :pass&#93;&#41;&#41; users&#41;&#41;
</code></pre></p><p>and now we'll create the login resource itself:<pre><code class="clojure">&#40;defresource login
  :available-media-types &#91;&quot;application/json&quot; &quot;text/javascript&quot;&#93;
  :method-allowed? &#40;request-method-in :post&#41;  
  :authorized?     &#40;fn &#91;{{user :params} :request}&#93;                 
                     &#40;or &#40;session-get :user&#41; &#40;valid-user user&#41;&#41;&#41;
  
  :post! &#40;fn &#91;{{{:keys &#91;user&#93;} :params} :request :as ctx}&#93;
           &#40;session-put! :user user&#41;&#41;
  
  :handle-unauthorized &#40;fn &#91;ctx&#93; &#40;:message ctx&#41;&#41;  
  :handle-created      &#40;json-str {:message &quot;login successful&quot;}&#41;&#41;
</code></pre></p><p>Again, the above is fairly straight forward. We specify the media types the handler responds to,  set it to allow the POST request type , check if the supplied user params are valid, and either create the user or return an error based on whether the <code>:authorized?</code> handler succeeds.</p><p>As I mentioned above, each handler responds to a specific HTTP code. For example, if <code>:authorized?</code> returns false then the code will be set to 401, which will cause <code>:handle-unauthorized</code> handler to be invoked. If <code>:authorized?</code> it true then the <code>:post!</code> handler gets called, and if it succeeds then subsequently<code>:handle-created</code>. Next we need a logout resource, and it looks as follows:<pre><code class="clojure">&#40;defresource logout
  :available-media-types &#91;&quot;application/json&quot; &quot;text/javascript&quot;&#93;
  :method-allowed? &#40;request-method-in :post&#41;  
  :post!           &#40;session-delete-key! :user&#41;
  :handle-created  &#40;json-str {:message &quot;logout successful&quot;}&#41;&#41;
</code></pre></p><p>You might have noticed that Liberator is pretty flexible regarding what you can supply as the handler. It can either be a callable function, an evaluated expression, or a value.</p><p>Now that we have a way for the user to login and logout, let's revisit our UI handler and update it to render different content based on whether there is a user in the session:<pre><code class="clojure">&#40;ns liberator-service.ui
  &#40;:use hiccup.page
        hiccup.element
        hiccup.form
        sandbar.stateful-session
        liberator-service.resources
        &#91;liberator.core :only &#91;defresource&#93;&#93;&#41;&#41;

&#40;defn get-user &#91;&#93;
  &#40;first &#40;filter #&#40;= &#40;session-get :user&#41; &#40;get-in % &#91;:user&#93;&#41;&#41; users&#41;&#41;&#41;

&#40;def login-page 
  &#91;:body
   &#91;:div#message&#93;
   &#91;:div#login
    &#40;text-field &quot;user&quot;&#41;
    &#40;password-field &quot;pass&quot;&#41;
    &#91;:button {:type &quot;button&quot; :onclick &quot;login&#40;&#41;&quot;} &quot;login&quot;&#93;&#93;&#93;&#41;

&#40;defn home-page &#91;&#93; 
  &#91;:body
   &#40;let &#91;{firstname :firstname lastname :lastname} &#40;get-user&#41;&#93; 
     &#91;:div#message &#40;str &quot;Welcome &quot; firstname &quot; &quot; lastname&#41;&#93;&#41;
   &#91;:div#logout 
    &#91;:button {:type &quot;button&quot; :onclick &quot;logout&#40;&#41;&quot;} &quot;logout&quot;&#93;&#93;&#93;&#41;

&#40;defresource home
  :available-media-types &#91;&quot;text/html&quot;&#93;
  :available-charsets &#91;&quot;utf-8&quot;&#93;
  :handle-ok &#40;html5 &#91;:head &#40;include-js
                             &quot;http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js&quot;
                             &quot;/resources/site.js&quot;&#41;&#93;
                    &#40;if &#40;session-get :user&#41; &#40;home-page&#41; login-page&#41;&#41;&#41;
</code></pre></p><p>That's all there is to it. We have a page which checks if there is a user in the session, if there is then it dsiplays the content of the <code>home-page</code> and if not then the <code>login-page</code> content is displayed. The page interacts with the service by calling <code>login</code> and <code>logout</code> resources via Ajax.</p><p>Complete source for the example is available <a href='https://github.com/yogthos/liberator-example'>here</a>. </p><p>Overall, I definitely think that Liberator makes writing RESTful applications easy and natural. This is a fairly different approach from <a href='http://www.webnoir.org/'>Noir</a>, where you think in terms of pages and simply implement the UI and the backend portion for each one. </p><p>While the Noir approach can easily result in tight coupling between the UI and the backend, the Liberator ensures that we're always thinking in terms of service operations whenever any interaction between the service and the client is happening.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Noir tutorial - part 7</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">03 09 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>In the <a href='http://yogthos.net/blog/28-Noir+tutorial+-+part+6'>last part</a> of the tutorial we saw how we can use a request handler wrapper to fix the redirect URLs. There is another option for doing this that I'd like to mention.</p><p>As we've seen, the <code>defpage</code> params only contain form parameters, but there is a way to access the complete parameter map provided by <code>ring</code> using the <code>noir.request/ring-request</code> helper. </p><p>If the application is running on a servlet its context will show up in this map and we can use it in our redirects. We can write a simple macro called <code>local-redirect</code> which will do this for us:<pre><code class="clojure">&#40;defmacro local-redirect &#91;url&#93;
  `&#40;noir.response/redirect 
     &#40;if-let &#91;context# &#40;:context &#40;noir.request/ring-request&#41;&#41;&#93;
       &#40;str context# &#126;url&#41; &#126;url&#41;&#41;&#41;
</code></pre></p><p>The advantage to this approach is that we do not try to infer if the redirect is supposed to be local or not. If we want to redirect to the local servlet context we can do it explicitly, and if we wish to do an absolute redirect then we can use the <code>noir.response/redirect</code> directly.</p><p>With that out of the way, I'd like to cover using the servlet init function and accessing files located on the classpath of the servlet. This allows us to run a function once when our serlvet starts up. </p><p>For example, we might want to read in a configuration file and setup some environment parameters based on it. To do that we'll open up our <code>project.clj</code> and add an <code>:init</code> key to our map or ring parameters:<pre><code class="clojure">&#40;defproject my-website &quot;0.1.0-SNAPSHOT&quot;
            :description &quot;my Noir website&quot;
            :dependencies &#91;&#91;org.clojure/clojure &quot;1.4.0&quot;&#93;
                           &#91;noir &quot;1.3.0-beta3&quot;&#93;
                           &#91;org.clojure/java.jdbc &quot;0.2.3&quot;&#93;
                           &#91;postgresql/postgresql &quot;9.1-901.jdbc4&quot;&#93;
                           &#91;joda-time &quot;2.0&quot;&#93;&#93;
            :dev-dependencies &#91;&#91;lein-ring &quot;0.7.3&quot;&#93;&#93;
            :ring {:handler my-website.server/handler

                   ;;initialization function which will be run 
                   ;;once when the servlet is loaded
                   :init my-website.config/init-config}
            :main my-website.server&#41;
</code></pre></p><p><strong>update:</strong> with Leiningen 2.0 you will need to use <code>:plugins</code> instead of <code>:dev-dependencies</code> to get <code>lein-ring</code> to work correctly:</p><pre><code class="clojure">&#40;defproject my-website &quot;0.1.0-SNAPSHOT&quot;
            :description &quot;my Noir website&quot;
            :dependencies &#91;&#91;org.clojure/clojure &quot;1.4.0&quot;&#93;
                           &#91;noir &quot;1.3.0-beta3&quot;&#93;
                           &#91;org.clojure/java.jdbc &quot;0.2.3&quot;&#93;
                           &#91;postgresql/postgresql &quot;9.1-901.jdbc4&quot;&#93;
                           &#91;joda-time &quot;2.0&quot;&#93;&#93;

            ;;lein 2
            :plugins &#91;&#91;lein-ring &quot;0.7.5&quot;&#93;&#93;
            ;;lein 1
            :dev-dependencies &#91;&#91;lein-ring &quot;0.7.3&quot;&#93;&#93;

            :ring {:handler my-website.server/handler

                   ;;initialization function which will be run 
                   ;;once when the servlet is loaded
                   :init my-website.config/init-config}
            :main my-website.server&#41;
</code></pre><p>Now we'll create a new namespace which the <code>:init</code> key is pointing to, and create an <code>init-config</code> function in it:<pre><code class="clojure">&#40;ns my-website.config
  &#40;:use clojure.java.io&#41;&#41;

&#40;defn init-config &#91;&#93; 
  &#40;println &quot;servlet has been initialized&quot;&#41;&#41;
</code></pre></p><p>If you build and deploy the application, the "servlet has been initialized" message is printed in the server log once after deployment. Now, let's add a configuration file in our <code>resources</code> folder:<pre><code class="bash">touch my&#95;webapp/resources/site.config
</code></pre></p><p>When we run <code>lein ring uberwar</code> this file will be packaged under <code>/WEB-INF/classes/</code> path in the servlet. To access this file we'll need to add the following function to our config namespace:<pre><code class="clojure">&#40;def config-file &quot;site.config&quot;&#41;

&#40;defn load-config-file &#91;&#93;
  &#40;let &#91;url &#40;.. 
              &#40;Thread/currentThread&#41; 
              getContextClassLoader 
              &#40;findResource config-file&#41;&#41;&#93; 
    &#40;if &#40;or &#40;nil? url&#41; 
            &#40;.. url 
              getPath 
              &#40;endsWith &#40;str &quot;jar!/&quot; config-file&#41;&#41;&#41;&#41;
      &#40;doto &#40;new java.io.File config-file&#41; 
        &#40;.createNewFile&#41;&#41;
      url&#41;&#41;&#41;
</code></pre></p><p>The <code>load-config-file</code> function will get the context class loader and attempt to find the resource by name. If the resource is found we will get back a URL pointing to it. Unfortunately, if we're running as a standalone jar, we cannot modify the resource inside it. So, in case the URL is nil, meaning that the file was not found, or if it ends with "jar!/site.config" we will create a new file instead. When running standalone, the file will be created in the same folder as the jar.</p><p>Now that we have a function to read the configuration, let's load it so we can actually use it. To do that we will add an atom to hold the configuration, and update our init-config function as follows:<pre><code class="clojure">&#40;def app-config &#40;atom nil&#41;&#41;

&#40;defn init-config &#91;&#93;
  &#40;with-open
    &#91;r &#40;java.io.PushbackReader. &#40;reader &#40;load-config-file&#41;&#41;&#41;&#93;
    &#40;if-let &#91;config &#40;read r nil nil&#41;&#93;
      &#40;reset! app-config config&#41;&#41;&#41;
  &#40;println &quot;servlet has been initialized&quot;&#41;&#41;
</code></pre></p><p>In our <code>log-stats</code> namespace the path to the logs is currently hard coded. Let's change it to read the path from our config file. We'll open our <code>resources/config</code> and add the following to it:<pre><code class="clojure">{:log-path &quot;logs/&quot;}
</code></pre></p><p>Then in our <code>log-stats</code> namespace we'll change all references to "logs/" to (:log-path @app-config) instead:<pre><code class="clojure">&#40;ns my-website.views.log-stats
  ...
  &#40;:use ... my-website.config&#41;&#41;

&#40;defpage &#91;:post &quot;/get-logs&quot;&#93; params  
  &#40;response/json 
    &#40;hits-per-second 
      &#40;read-logs &#40;last-log &#40;:log-path @app-config&#41;&#41;&#41;&#41;&#41;&#41;
</code></pre></p><p>To ensure that the application still runs correctly standalone we will have to call <code>init-config</code> in our <code>-main</code> in the <code>server</code> namespace:<pre><code class="clojure">&#40;ns my-website.server
  &#40;:use my-website.config&#41;
  ...&#41;

&#40;defn -main &#91;&amp; m&#93;
  &#40;let &#91;mode &#40;keyword &#40;or &#40;first m&#41; :dev&#41;&#41;
        port &#40;Integer. &#40;get &#40;System/getenv&#41; &quot;PORT&quot; &quot;8080&quot;&#41;&#41;&#93;
    &#40;init-config&#41;
    &#40;server/start port {:mode mode
                        :ns 'my-website}&#41;&#41;&#41;
</code></pre></p><p>Now the log path can be specified in the <code>config</code> file without having to rebuild and redeploy the application each time. Complete source for this section is available <a href='https://github.com/yogthos/Noir-tutorial/commit/4b7d185b2aaa5e8af539344d9f1df677271ea44a'>here</a>.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/files/tomcat.png" alt="Noir tutorial - part 6">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Noir tutorial - part 6</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">02 09 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>In the <a href='https://www.yogthos.net/blog/22'>first part</a> of the tutorial we've already seen how to run our application in standalone mode.  Here we will look at what we need to do to deploy it on an application server such as <a href='http://glassfish.java.net/'>Glassfish</a>, <a href='http://tomcat.apache.org/'>Tomcat</a>, <a href='http://www.jboss.org/'>jBoss</a>, or <a href='http://immutant.org/'>Immutant</a> which is a modification of jBoss geared specifically towards Clojure.</p><p>There are numerous reasons as to why you might want to do this. For example, an application server lets you run multiple applications at the same time. Another advantage is that the application server can take care of the configuration details, such as handling database connections. </p><p>When building real world applications, you will likely have separate dev/staging/prod configurations. Instead of having different builds for our application, we can instead configure our application servers appropriately for each environment. Then we can have a single build process which is much less error prone in my opinion. We can also configure CI, such as <a href='http://jenkins-ci.org/'>Jenkins</a> to build our application and automatically deploy it to the server ensuring that we always have the latest code running.</p><p>Finally, if you plan on using a hosting provider, you may end up deploying on a shared application server as opposed to being able to run your application standalone. </p><p>Let's go over the prerequisites for building our application into a WAR and deploying it to a server. You will need to setup an application server of your choice for this section. I will be using Tomcat, but the steps will be similar for other servers as well. If you will be using Tomcat, then download the <a href='http://apache.mirror.nexicom.net/tomcat/tomcat-7/v7.0.29/bin/apache-tomcat-7.0.29.zip'>latest version</a>. To start up the server you simply unpack the archive, navigate to the resulting directory, and run:<pre><code class="bash">chmod +x bin/catalina.sh
bin/catalina.sh start
Using CATALINA&#95;BASE:   apache-tomcat-7.0.29
Using CATALINA&#95;HOME:   apache-tomcat-7.0.29
Using CATALINA&#95;TMPDIR: apache-tomcat-7.0.29/temp
Using JRE&#95;HOME:        /Library/Java/Home
Using CLASSPATH:       apache-tomcat-7.0.29/bin/bootstrap.jar:apache-tomcat-7.0.29/bin/tomcat-juli.jar
</code></pre></p><p>Your Tomcat should now be up and running and you can test it by navigating to <a href='http://localhost:8080'>localhost:8080</a>: <center><img src="/files/tomcat.png" alt="tomcat" /></center> With the application server running, let's prepare our application for deployment. First, we must ensure that the <code>server</code> namespace requires all the namespaces in our views package, and has the <code>gen-class</code> directive specified:<pre><code class="clojure">&#40;ns my-website.server
  &#40;:require &#91;noir.server :as server&#93;
            &#91;my-website.views 
             common
             files
             log-stats
             users
             welcome&#93;&#41;     
  &#40;:gen-class&#41;&#41;
</code></pre></p><p>This will ensure that the server and the views are compiled during the build step, which is needed for them to be picked up by the application server when the application is deployed. Next, we will change <code>server/load-views</code> call to <code>server/load-vews-ns</code>:<pre><code class="clojure">&#40;server/load-views-ns 'my-website.views&#41;
</code></pre></p><p>If you used Leiningen 2 to create the project template, then <code>load-views-ns</code> should already be set correctly.</p><p>Finally, we have to add a handler which will be used instead of the <code>-main</code> when running on the application server:<pre><code class="clojure">&#40;def base-handler 
  &#40;server/gen-handler 
    {:mode :prod, 
     :ns 'my-website 
     :session-cookie-attrs {:max-age 1800000}}&#41;&#41;
</code></pre></p><p>It is possible to chain different handlers together. In our case, we will need a wrapper for our handler to prepend the servlet context to all the requests coming to our servlet. This is a workaround for a <a href='https://github.com/noir-clojure/noir/issues/120'>bug</a> in the current version of Noir, which ignores it. Without this fix none of the redirects will work correctly as they will be routed to the base application server URL instead.</p><p>Each wrapper is a function which accepts the current handler, and returns a function which accepts a request, does something to it, and then return the result of calling  the handler on it. The result is in turn a handler itself, so we can chain as many wrappers together as we like. In our case we will override the <code>resolve-url</code> function in <code>noir.options</code> with one of our own making:<pre><code class="clojure">&#40;defn fix-base-url &#91;handler&#93;
  &#40;fn &#91;request&#93;    
    &#40;with-redefs &#91;noir.options/resolve-url 
                  &#40;fn &#91;url&#93;                    
                    ;prepend context to the relative URLs
                    &#40;if &#40;.contains url &quot;://&quot;&#41; 
                      url &#40;str &#40;:context request&#41; url&#41;&#41;&#41;&#93;
      &#40;handler request&#41;&#41;&#41;&#41;
</code></pre></p><p>Above, we will check that the URL contains "://", if not then we treat it as a local URL and prepend the servlet context to it. Now we have to hook it up with our initial handler to produce the final request handler for our servlet:<pre><code class="clojure">&#40;def handler &#40;-&gt; base-handler fix-base-url&#41;&#41;
</code></pre></p><p>Now that we've created our handler, we need to point our <code>project.clj</code> to it:<pre><code class="clojure">&#40;defproject my-website &quot;0.1.0-SNAPSHOT&quot;
            :description &quot;my Noir website&quot;
            :dependencies &#91;&#91;org.clojure/clojure &quot;1.4.0&quot;&#93;
                           &#91;noir &quot;1.3.0-beta3&quot;&#93;
                           &#91;org.clojure/java.jdbc &quot;0.2.3&quot;&#93;
                           &#91;postgresql/postgresql &quot;9.1-901.jdbc4&quot;&#93;&#93;
            :dev-dependencies &#91;&#91;lein-ring &quot;0.7.3&quot;&#93;&#93;
            :ring {:handler my-website.server/handler}
            :main my-website.server&#41;
</code></pre></p><p>We've also added <code>lein-ring</code> plugin to our <code>dev-dependencies</code>, this is required for generating the WAR artifact from our build. Under the <code>:ring</code> key we set the <code>:handler</code> to the one we defined above.</p><p>Let's test that our project builds correctly and produces a working WAR by running the following commands from the temrinal:<pre><code class="bash">lein deps
Copying 29 files to Noir-tutorial/lib
&#91;INFO&#93; snapshot thneed:thneed:1.0.0-SNAPSHOT: checking for updates from clojars
&#91;INFO&#93; snapshot thneed:thneed:1.0.0-SNAPSHOT: checking for updates from central
Copying 5 files to Noir-tutorial/lib/dev

lein ring uberwar
Compiling my-website.server
Compilation succeeded.
Created Noir-tutorial/my-website-0.1.0-SNAPSHOT-standalone.war
</code></pre></p><p>If we have our application server running, then we should be able to simply drop this WAR in its deployment folder and the server will take care of the rest. If we're using Tomcat, then we have to copy it to the <code>webapps</code> folder:<pre><code class="bash">cp my-website-0.1.0-SNAPSHOT-standalone.war ../apache-tomcat-7/webapps/my-website.war
</code></pre></p><p>Make sure to replace the <code>../apache-tomcat-7</code> above with the location of your Tomcat server. We can now take a look at our server log and see that the application was deployed successfully:<pre><code class="bash">tail -f logs/catalina.out
...
INFO: Deploying web application archive apache-tomcat-7.0.29/webapps/my-website.war
</code></pre></p><p>Now let's navigate to <a href='http://localhost:8080/my-website'>localhost:8080/my-website</a> and we should see our application running: <center><img src="/files/website-on-tomcat.png" alt="website" /></center></p><p>One last thing to note is that any Ajax calls in our pages will have to use the servlet context to be resolved correctly. A workaround for this issue is to use <code>noir.request/ring-request</code> to check if a context is present and set it as a hidden field on the page:<pre><code class="clojure">&#40;ns my-website.views.log-stats
  &#40;:require &#91;my-website.views.common :as common&#93;
            &#91;noir.request :as request&#93;
            &#91;noir.response :as response&#93;&#41;
  &#40;:use clojure.java.io hiccup.page hiccup.form noir.core&#41;
  &#40;:import java.text.SimpleDateFormat&#41;&#41;

&#40;defpage &quot;/access-chart&quot; &#91;&#93;
  &#40;common/basic-layout
    &#40;include-js &quot;/js/site.js&quot;&#41;
    &#40;hidden-field &quot;context&quot; &#40;:context &#40;request/ring-request&#41;&#41;&#41;
    &#91;:div#hits-by-time &quot;loading...&quot;&#93;&#41;&#41;
</code></pre></p><p>Then we can check this value and prepend it to the URL when making our Ajax query:<pre><code class="javascript">$&#40;document&#41;.ready&#40;function&#40;&#41;{	
    var context = $&#40;'#context'&#41;.val&#40;&#41;;
    var url = '/get-logs';
    if &#40;context&#41; url = context + url;
    var options = {xaxis: { mode: &quot;time&quot;, 
                            minTickSize: &#91;1, &quot;minute&quot;&#93;}};
	$.post&#40;url, function&#40;data&#41;{
	    $.plot&#40;$&#40;&quot;#hits-by-time&quot;&#41;, &#91;data&#93;, options&#41;;
	    }&#41;;		
}&#41;;
</code></pre></p><p>As usual, the complete code for this section is available <a href='https://github.com/yogthos/Noir-tutorial/tree/e5964216fd009239d1494c7cfcb7888f4f6b374d'>here</a>.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/files/access-chart.png" alt="Noir tutorial - part 5">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Noir tutorial - part 5</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">01 09 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>In this section we will learn how to add some JavaScript to the application and how to use Ajax to query the service. We'll use  the <a href='http://code.google.com/p/flot/'>flot</a> <a href='http://jquery.com/'>jQuery</a> library to display the usage statistics for our site. When the page loads it will call the service which will parse today's access log and return a JSON response which will be used to generate the chart.</p><p>First, let's generate some sample usage data in the apache <a href='http://httpd.apache.org/docs/1.3/logs.html#combined'>combined log format</a>:<pre><code class="clojure">&#40;defn gen-log-line &#91;&#91;cur-time&#93;&#93; 
  &#40;let &#91;new-time &#40;doto &#40;new java.util.Date&#41; &#40;.setTime &#40;+ &#40;.getTime cur-time&#41; &#40;rand-int 5000&#41;&#41;&#41;&#41;
        browsers &#91;&quot;\&quot;Mozilla/5.0 &#40;Macintosh; Intel Mac OS X 10.7; rv:15.0&#41; Gecko/20100101 Firefox/15.0\&quot;&quot;
                  &quot;\&quot;Mozilla/5.0 &#40;Linux; U; Android 2.2; en-gb; LG-P500 Build/FRF91&#41; AppleWebKit/533.1 &#40;KHTML, like Gecko&#41;\&quot;&quot;
                  &quot;\&quot;Mozilla/5.0 &#40;X11; Linux i686&#41; AppleWebKit/536.11 &#40;KHTML, like Gecko&#41; Chrome/20.0.1132.57 Safari/536.11\&quot;&quot;&#93;&#93;
    &#91;new-time
     &#40;-&gt;&gt;
       &#40;concat
         &#40;interpose &quot;.&quot; &#40;take 4 &#40;repeatedly #&#40;rand-int 255&#41;&#41;&#41;&#41;
         &#91;&quot; - - &#91;&quot; &#40;.format &#40;new java.text.SimpleDateFormat 
                                  &quot;dd/MMM/YYYY:HH:mm:ss ZZZZ&quot;&#41; new-time&#41; &quot;&#93;&quot;&#93;
         &#91;&quot; \&quot;GET /files/test.jpg\&quot; &quot; 200 &quot; &quot; &#40;rand-int 4000&#41; &quot; \&quot;http://my-website/files/test.jpg\&quot; &quot; &#40;first &#40;shuffle browsers&#41;&#41;&#93;&#41;
       &#40;apply str&#41;&#41;&#93;&#41;&#41;
 
&#40;defn gen-test-logs &#91;size&#93;
  &#40;-&gt;&gt; &#40;gen-log-line &#91;&#40;new java.util.Date&#41;&#93;&#41;
    &#40;iterate gen-log-line&#41;
    &#40;take size&#41;
    &#40;map second&#41;
    &#40;interpose &quot;\n&quot;&#41;
    &#40;apply str&#41;&#41;&#41;

&#40;spit &quot;test-log.txt&quot; &#40;gen-test-logs 500&#41;&#41;
</code></pre></p><p>If you run the above in the REPL, you will end up with <code>test-log.txt</code> file which should have the contents that look roughly like the following:</p><pre><code>120.138.220.117 - - &#91;31/Aug/2012:21:06:47 -0400&#93; &quot;GET /files/test.jpg&quot; 200 3989 &quot;http://my-website/files/test.jpg&quot; &quot;Mozilla/5.0 &#40;Linux; U; Android 2.2; en-gb; LG-P500 Build/FRF91&#41; AppleWebKit/533.1 &#40;KHTML, like Gecko&#41;&quot;
201.59.151.159 - - &#91;31/Aug/2012:21:06:49 -0400&#93; &quot;GET /files/test.jpg&quot; 200 1729 &quot;http://my-website/files/test.jpg&quot; &quot;Mozilla/5.0 &#40;Linux; U; Android 2.2; en-gb; LG-P500 Build/FRF91&#41; AppleWebKit/533.1 &#40;KHTML, like Gecko&#41;&quot;
122.39.249.88 - - &#91;31/Aug/2012:21:06:51 -0400&#93; &quot;GET /files/test.jpg&quot; 200 1650 &quot;http://my-website/files/test.jpg&quot; &quot;Mozilla/5.0 &#40;Linux; U; Android 2.2; en-gb; LG-P500 Build/FRF91&#41; AppleWebKit/533.1 &#40;KHTML, like Gecko&#41;&quot;
...
</code></pre><p>Now that we have a log file with some access logs in it, we'll parse those logs into structured data to make them easier to analyze:</p><pre><code class="clojure">&#40;defn round-ms-down-to-nearest-sec &#91;date&#93;
  &#40;let &#91;date &#40;.parse 
               &#40;new SimpleDateFormat 
                    &quot;dd/MMM/yyyy:HH:mm:ss zzzzz&quot;&#41; 
               date&#41;&#93; 
    &#40; &#42; 1000 &#40;quot &#40;.getTime date&#41; 1000&#41;&#41;&#41;&#41;

&#40;defn parse-line &#91;line&#93;
  {:ip &#40;re-find #&quot;\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b&quot; line&#41; 
   :access-time &#40;round-ms-down-to-nearest-sec 
                  &#40;second &#40;re-find #&quot;\&#91;&#40;.&#42;?&#41;\&#93;&quot; line&#41;&#41;&#41; }&#41;

&#40;defn read-logs &#91;file&#93; 
  &#40;with-open &#91;rdr &#40;reader file&#41;&#93; 
    &#40;doall &#40;map parse-line &#40;line-seq rdr&#41;&#41;&#41;&#41;&#41;
</code></pre><p>Above, we simply return a map containing the ip and the access-time for each line in the logs. Using this map we can aggregate the logs by IP to get unique hits, and then group them by time to see hits per second:<pre><code class="clojure">&#40;defn hits-per-second &#91;logs&#93;
  &#40;-&gt;&gt; logs 
    &#40;group-by :ip&#41;
    &#40;map #&#40;first &#40;second %&#41;&#41;&#41;
    &#40;group-by :access-time&#41;    
    &#40;map &#40;fn &#91;&#91;t hits&#93;&#93; &#91;t &#40;count hits&#41;&#93;&#41;&#41;
    &#40;sort-by first&#41;&#41;&#41;

&#40;hits-per-second &#40;read-logs &quot;test-log.txt&quot;&#41;&#41;
=&gt;&#40;&#91;1346460948000 2&#93; &#91;1346460949000 1&#93; &#91;1346460954000 1&#93; ...&#41;
</code></pre></p><p>We now have a list where each element has a time rounded down to the nearest second with a number of unique hits associated with it. This happens to be the exact format that <a href='http://people.iola.dk/olau/flot/examples/time.html'>flot time series is expecting</a>. We can serve the this data as JSON by using <code>noir.response/json</code>:<pre><code class="clojure">&#40;defpage &#91;:post &quot;/get-logs&quot;&#93; params
  &#40;response/json &#40;hits-per-second &#40;read-logs &quot;test-log.txt&quot;&#41;&#41;&#41;&#41;
</code></pre></p><p>Finally, we will have to create the page with a placeholder where our chart will be displayed and reference a Js file which will create shortly:<pre><code class="clojure">&#40;defpage &quot;/access-chart&quot; &#91;&#93;
  &#40;common/basic-layout
    &#40;include-js &quot;/js/site.js&quot;&#41;
    &#91;:div#hits-by-time &quot;loading...&quot;&#93;&#41;&#41;
</code></pre></p><p>We will also have to add the CSS to set the height and width of the chart as well as the margin:</p><pre><code>#hits-by-time {
        margin: 25px;
	width: 400px;
	height: 400px;
}
</code></pre><p>All that's left to do is to add the JavaScript which will get the stats and display them. To do that we'll have to <a href='http://code.google.com/p/flot/downloads/list'>download flot</a>, and put <code>jquery.flot.min.js</code> in the <code>resources/public/js</code> folder.</p><p>Then we will include it and jQuery in the header of our page. This can be done using <code>include-js</code> from Hiccup. We'll open up our <code>common</code> namespace and modify the <code>basic-layout</code> as follows:<pre><code class="clojure">&#40;defpartial basic-layout &#91;&amp; content&#93;
  &#40;html5
    &#91;:head
     &#91;:title &quot;my-website&quot;&#93;
     &#40;include-css &quot;/css/reset.css&quot;&#41;
     &#40;include-js &quot;http://code.jquery.com/jquery-1.7.2.min.js&quot;
                 &quot;/js/jquery.flot.min.js&quot;
                 &quot;/js/site.js&quot;&#41;&#93;
    &#91;:body content&#93;&#41;&#41;
</code></pre></p><p>Now let's create a <code>site.js</code> file in <code>resources/public/js</code> and add the following to it:<pre><code class="javascript">$&#40;document&#41;.ready&#40;function&#40;&#41;{	
    var options = {xaxis: {mode: &quot;time&quot;, 
                           minTickSize: &#91;1, &quot;minute&quot;&#93;}};
	$.post&#40;'/get-logs', function&#40;data&#41;{
	    $.plot&#40;$&#40;&quot;#hits-by-time&quot;&#41;, &#91;data&#93;, options&#41;;
	    }&#41;;		
}&#41;;
</code></pre></p><p>If all went well, then when we start up our site and browse to <a href='http://localhost:8080/access-chart'>localhost:8080/access-chart</a>. we should see something like this: <center><img src="/files/access-chart.png" alt="access chart" /></center></p><p>Finally, <a href='http://yogthos.net/stats-viewer/'>here's</a> some fun daily stats for the blog generated using the above approach. The sources for this part of the tutorial can be found <a href='https://github.com/yogthos/Noir-tutorial/tree/6bd33d6121edccc1406b5e854e5c980a9f5d30dc'>here</a>.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/files/menu.png" alt="Noir tutorial - part 4">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Noir tutorial - part 4</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">25 08 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <h3 id="securing&#95;pages">Securing Pages</h3><p>This part of the tutorial will focus on controlling page visibility, form validation, and handling complex form parameters. In the <a href='http://yogthos.net/blog/25-Noir+tutorial+-+part+3'>last section</a> we added support for uploading files, it would make sense to make the <code>upload</code> page private. This way only registered users can access it.</p><p>Noir provides a <a href='http://webnoir.org/autodoc/1.2.1/noir.core-api.html#noir.core/pre-route'><code>pre-route</code></a> macro for handling this. However, we will not be using it for a couple of reasons. </p><p>First, there is currently a bug in Noir, where <code>pre-route</code> ignores the servlet context, meaning that unless our application is deployed to "/" the routing will not work as expected. The second reason is that you have to remember to add a <code>pre-route</code> entry for each page that you want to make private. </p><p>A better solution, in my opinion, is to simply write a macro which will behave the same way as defpage, but will check if there is a user in session and redirect to "/" otherwise. With this approach we make pages private right in their definition. Let's open up our <code>common</code> namespace and add the macro:<pre><code class="clojure">&#40;defmacro private-page &#91;path params &amp; content&#93;
  `&#40;noir.core/defpage 
     &#126;path 
     &#126;params 
     &#40;if &#40;session/get :user&#41; 
      &#40;do &#126;@content&#41; 
      &#40;resp/redirect &quot;/&quot;&#41;&#41;&#41;&#41;
</code></pre></p><p>As you can see it has exactly same signature as <code>defpage</code> and calls it  internally as you normally would, but only adds the content if the session contains a user, otherwise the page will redirect to "/".</p><p>Now, we'll go to our <code>files</code> namespace and mark all the pages as private:<pre><code class="clojure">&#40;common/private-page &quot;/upload&quot; {:keys &#91;info&#93;}
  ...&#41;

&#40;common/private-page &#91;:post &quot;/upload&quot;&#93; {:keys &#91;file&#93;}
  ...&#41;

&#40;common/private-page &quot;/files/:name&quot; {:keys &#91;name&#93;} 
  ...&#41;
</code></pre></p><p>Let's test that it works by navigating to <a href='http://localhost:8080/upload'>localhost:8080/upload</a> without logging in. We should be redirected right back to "/".</p><h3 id="site&#95;navigation">Site navigation</h3><p>Since we now have a couple of pages that we will be navigating we can add a navigation menu in our <code>common</code> namespace:<pre><code class="clojure">&#40;defn menu &#91;&#93;
  &#91;:div.menu
   &#91;:ul
    &#91;:li &#40;form-to &#91;:post &quot;/logout&quot;&#93; &#40;submit-button &quot;logout&quot;&#41;&#41;&#93;    
    &#91;:li &#40;link-to &quot;/upload&quot; &quot;my files&quot;&#41;&#93;
    &#91;:li &#40;link-to &quot;/&quot; &quot;home&quot;&#41;&#93;&#93;&#93;&#41;

&#40;defpartial layout &#91;&amp; content&#93;
  &#40;html5
    &#91;:head
     &#91;:title &quot;my-website&quot;&#93;
     &#40;include-css &quot;/css/reset.css&quot;&#41;&#93;
    &#91;:body               
     &#40;if-let &#91;user &#40;session/get :user&#41;&#93;
       &#91;:div
        &#40;menu&#41;
        &#91;:h2 &quot;welcome &quot; user&#93;&#93;
       &#91;:div.login
        &#40;login-form&#41; &#91;:p &quot;or&quot;&#93; &#40;link-to &quot;/signup&quot; &quot;sign up&quot;&#41;&#93;&#41;     
     content&#93;&#41;&#41;
</code></pre></p><p>Now, if a user logs in, they will see the navigation menu and can either select home or their files page. To keep things clean we'll also move the <code>logout</code> link into our menu. This is functional, but it's rather ugly, so let's add some CSS to make it a bit nicer. We'll open up our stock <code>resources/public/css/reset.css</code> which was generated for our site and add the following to it:</p><pre><code>.menu ul {
    list-style: none;
    margin: 0;
    padding-left: 0;
}
.menu li {
    float: right;
    position: relative;
    margin-right: 20px;
}
</code></pre><p>Things should look much better now: <center> <img src="/files/menu.png" alt="menu" /> </center></p><h3 id="input&#95;validation">Input Validation</h3><p>Next, let's reexamine our sign up page, previously we didn't bother doing any validation when creating a new user, so let's add some now. Noir provides a simple way to validate input fields via the <a href='http://www.webnoir.org/autodoc/1.2.1/noir.validation-api.html'><code>noir.validation</code></a> namespace. Let's open the <code>users</code> namespace and add it in:<pre><code class="clojure">&#40;ns my-website.views.users
  &#40;:use &#91;noir.core&#93;
        hiccup.core hiccup.form&#41;
  &#40;:require &#91;my-website.views.common :as common&#93;
            &#91;my-website.models.db :as db&#93;
            &#91;noir.util.crypt :as crypt&#93;
            &#91;noir.session :as session&#93;
            &#91;noir.response :as resp&#93;
            &#91;noir.validation :as vali&#93;&#41;&#41;
</code></pre></p><p>Next we will create our validation function:<pre><code class="clojure">&#40;defn valid? &#91;{:keys &#91;handle pass pass1&#93;}&#93;
  &#40;vali/rule &#40;vali/has-value? handle&#41;
             &#91;:handle &quot;user ID is required&quot;&#93;&#41;
  &#40;vali/rule &#40;vali/min-length? pass 5&#41;
             &#91;:pass &quot;password must be at least 5 characters&quot;&#93;&#41;  
  &#40;vali/rule &#40;= pass pass1&#41;
             &#91;:pass &quot;entered passwords do not match&quot;&#93;&#41;
  &#40;not &#40;vali/errors? :handle :pass :pass1&#41;&#41;&#41;
</code></pre></p><p>The function will check that all the fields conform to the rules, such as user id being provided, minimum password length, and that retyped password matches the original. The rules have the following form:<pre><code class="clojure">&#40;rule validator &#91;:filed-name &quot;error message&quot;&#93;&#41;
</code></pre></p><p>where the validator must return a boolean. We'll also need a helper for displaying the error on the page:<pre><code class="clojure">&#40;defpartial error-item &#91;&#91;first-error&#93;&#93;
  &#91;:p.error first-error&#93;&#41;
</code></pre></p><p>Next we will update our <code>signup</code> page to show the errors generated by the validator:<pre><code class="clojure">&#40;defpage &quot;/signup&quot; {:keys &#91;handle error&#93;}
  &#40;common/layout
    &#91;:div.error error&#93;
    &#40;form-to &#91;:post &quot;/signup&quot;&#93;
             &#40;vali/on-error :handle error-item&#41;
             &#40;label &quot;user-id&quot; &quot;user id&quot;&#41;
             &#40;text-field &quot;handle&quot; handle&#41;
             &#91;:br&#93;
             &#40;vali/on-error :pass error-item&#41;
             &#40;label &quot;pass&quot; &quot;password&quot;&#41;
             &#40;password-field &quot;pass&quot;&#41;             
             &#91;:br&#93;
             &#40;vali/on-error :pass1 error-item&#41;
             &#40;label &quot;pass1&quot; &quot;retype password&quot;&#41;
             &#40;password-field &quot;pass1&quot;&#41;             
             &#91;:br&#93;
             &#40;submit-button &quot;create account&quot;&#41;&#41;&#41;&#41;
</code></pre></p><p>All we have to do here is add <code>on-error</code> statements for each field we're validating. Finally, we'll have to update the <code>POST</code> part of the page, to call the validator and return the errors:<pre><code class="clojure">&#40;defpage &#91;:post &quot;/signup&quot;&#93; user
  &#40;if &#40;valid? user&#41;
    &#40;try 
      &#40;db/add-user &#40;update-in &#40;dissoc user :pass1&#41; &#91;:pass&#93; crypt/encrypt&#41;&#41;
      &#40;resp/redirect &quot;/&quot;&#41;
      &#40;catch Exception ex
        &#40;render &quot;/signup&quot; &#40;assoc user :error &#40;.getMessage ex&#41;&#41;&#41;&#41;&#41;
    &#40;render &quot;/signup&quot; user&#41;&#41;&#41;
</code></pre></p><p>This should give you a basic idea of how to validate input using Noir, and more details about validation can be found on the <a href='http://www.webnoir.org/tutorials/forms'>official site</a>.</p><p>One thing you'll notice that when we navigate to the <code>signup</code> page, we still see the login option as well as the link to sign up: <center> <img src="/files/signup1.png" alt="sign up" /> </center> This is because our layout adds these to every page. We can fix this by splitting <code>layout</code> in the <code>common</code> namespace as follows:<pre><code class="clojure">&#40;defpartial basic-layout &#91;&amp; content&#93;
  &#40;html5
    &#91;:head
     &#91;:title &quot;my-website&quot;&#93;
     &#40;include-css &quot;/css/reset.css&quot;&#41;&#93;
    &#91;:body content&#93;&#41;&#41;

&#40;defpartial layout &#91;&amp; content&#93;  
  &#40;basic-layout 
    &#91;:div
     &#40;if-let &#91;user &#40;session/get :user&#41;&#93;      
       &#91;:div
        &#40;menu&#41;
        &#91;:h2 &quot;welcome &quot; user&#93;&#93;
       &#91;:div
        &#91;:div.login
         &#40;login-form&#41; 
         &#91;:p &quot;or&quot;&#93; 
         &#40;link-to &quot;/signup&quot; &quot;sign up&quot;&#41;&#93;&#93;&#41;
     content&#93;&#41;&#41;
</code></pre></p><p>Then we simply change:<pre><code class="clojure">&#40;defpage &quot;/signup&quot; {:keys &#91;handle error&#93;}
  &#40;common/layout
  ...&#41;

&#40;defpage &quot;/signup&quot; {:keys &#91;handle error&#93;}
  &#40;common/basic-layout
  ...&#41;
</code></pre></p><p>Another clean up item is to make our form items aligned, to do that we can use the following bit of CSS:</p><pre><code>label {
    margin-left: 10px;
    width:120px; 
    float:left;
}
</code></pre><p>The sign up page should now look as follows: <center> <img src="/files/signup2.png" alt="sign up" /> </center></p><h3 id="complex&#95;form&#95;items">Complex Form Items</h3><p>Now that we've cleaned up our <code>singup</code> page, we'll turn our attention back to file management. We'll add the ability for the user to filter files by their type. To do that we will first create a function in our <code>db</code> namespace to get all the file types from our database:<pre><code class="clojure">&#40;defn file-types &#91;&#93;
  &#40;map :type &#40;db-read &quot;select distinct type from file&quot;&#41;&#41;&#41;
</code></pre></p><p>Then in our <code>files</code> namespace we will create a new helper called <code>select-files-by-type</code>:<pre><code class="clojure">&#40;defn select-files-by-type &#91;&#93;  
  &#40;let &#91;file-types &#40;db/file-types&#41;&#93; 
    &#40;form-to &#91;:post &quot;/show-files&quot;&#93;
             &quot;select file types to show&quot;
             &#40;into 
               &#40;with-group &quot;file-types&quot;&#41;
               &#40;for &#91;type file-types&#93;
                 &#91;:div 
                  type
                 &#40;check-box type&#41;&#93;&#41;&#41;
             &#40;submit-button &quot;show files&quot;&#41;&#41;&#41;&#41;
</code></pre></p><p>which we will add to our "/upload" page:<pre><code class="clojure">&#40;common/private-page &quot;/upload&quot; {:keys &#91;info&#93;}
  &#40;common/layout       
    &#91;:h2.info info&#93;
    &#40;select-files-by-type&#41;
    &#40;list-files&#41;
    &#40;form-to {:enctype &quot;multipart/form-data&quot;}
             &#91;:post &quot;/upload&quot;&#93;
             &#40;label :file &quot;File to upload&quot;&#41;
             &#40;file-upload :file&#41;
             &#91;:br&#93;
             &#40;submit-button &quot;upload&quot;&#41;&#41;&#41;&#41;
</code></pre></p><p>This function will read the file types from the database and create a checkbox group from them. When we hit submit we'll see something like the following in our params:<pre><code class="clojure">{&quot;image/png&quot; &quot;true&quot;, &quot;image/jpeg&quot; &quot;true&quot;}
</code></pre></p><p>Where the value of each selected checkbox will appear as a key in the params map with the value of "true". We will now have to update our <code>list-files</code> function to accept optional file type restriction and in turn pass it to <code>list-files</code> in <code>db</code> namespace:<pre><code class="clojure">&#40;defn list-files &#91;&amp; &#91;types&#93;&#93;  
  &#40;into &#91;:ul&#93;
        &#40;for &#91;name &#40;db/list-files types&#41;&#93;             
          &#91;:li.file-link &#40;link-to &#40;str &quot;/files/&quot; name&#41; name&#41; 
           &#91;:span &quot;  &quot;&#93; 
           &#91;:div.file&#93;&#93;&#41;&#41;&#41;
</code></pre></p><p>The following changes will have to be made to retrieve files based on type:<pre><code class="clojure">&#40;defn params-query &#91;params&#93;
  &#40;apply str &#40;interpose &quot;, &quot; &#40;repeat &#40;count params&#41; &quot;?&quot;&#41;&#41;&#41;&#41;

&#40;defn list-files &#91;&amp; &#91;types&#93;&#93;
  &#40;map :name 
       &#40;if types
         &#40;apply &#40;partial db-read &#40;str &quot;select name from file where type in &#40;&quot; &#40;params-query types&#41; &quot;&#41;&quot;&#41;&#41; types&#41;
         &#40;db-read &quot;select name from file&quot;&#41;&#41;&#41;&#41;
</code></pre></p><p>The <code>params-query</code> helper will create an appropriate WHERE clause based on the number of types we pass in, and <code>list-files</code> will now check if types have been passed in and create the appropriate query.  Finally, we'll add a new page which will display the selected files:<pre><code class="clojure">&#40;common/private-page &#91;:post &quot;/show-files&quot;&#93; params
  &#40;let &#91;file-types &#40;keys params&#41;&#93; 
    &#40;common/layout 
      &#91;:h2 &quot;showing files types &quot; 
       &#40;apply str &#40;interpose &quot;, &quot; file-types&#41;&#41;&#93;
      &#40;list-files file-types&#41;
      &#40;link-to &quot;/upload&quot; &quot;back&quot;&#41;&#41;&#41;&#41;
</code></pre></p><p>The "/upload" page should now look as follows: <center> <img src="/files/file-upload1.png" alt="file upload" /> </center> When we select some files and hit "show files" button we should see our new "show-files" page: <center> <img src="/files/show-files.png" alt="file upload" /> </center></p><h3 id="summary">Summary</h3><p>In this section we covered the following topics:</p><ul><li>restricting access to pages</li><li>creating a navigation menu</li><li>input validation</li><li>handling inputs from multi part items such as check boxes</li></ul><p>The complete code for this section is available <a href='https://github.com/yogthos/Noir-tutorial/tree/ee1bd8aaa90b8144015201bf8fc5a99f7d007e57'>here</a>.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/files/file-upload.png" alt="Noir tutorial - part 3">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Noir tutorial - part 3</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">22 08 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><a href='http://yogthos.net/blog/23-Noir+tutorial+-+part+2'>Last time</a> we created a database to store users, and created pages allowing users to create new accounts and login. This time we'll look at how we can allow users to upload files to the server and how to serve them back using the proper content type. To make things easy, we'll stick our files in the database, so let's design a table to hold them:<pre><code class="clojure">&#40;defn create-file-table &#91;&#93;
  &#40;sql/with-connection 
    db
    &#40;sql/create-table
      :file
      &#91;:type &quot;varchar&#40;50&#41;&quot;&#93;
      &#91;:name &quot;varchar&#40;50&#41;&quot;&#93;
      &#91;:data &quot;bytea&quot;&#93;&#41;&#41;&#41;
</code></pre></p><p>if we run the above in the REPL a file table should be created. We'll now need a few helper functions to read the list of files and add new files to the table:<pre><code class="clojure">&#40;defn to-byte-array &#91;f&#93;  
  &#40;with-open &#91;input &#40;new java.io.FileInputStream f&#41;
              buffer &#40;new java.io.ByteArrayOutputStream&#41;&#93;
    &#40;clojure.java.io/copy input buffer&#41;
    &#40;.toByteArray buffer&#41;&#41;&#41;

&#40;defn store-file &#91;{:keys &#91;tempfile filename content-type&#93;}&#93;
  &#40;sql/with-connection 
    db
    &#40;sql/update-or-insert-values
      :file
      &#91;&quot;name=?&quot; filename&#93;
      {:type content-type 
       :name filename
       :data &#40;to-byte-array tempfile&#41;}&#41;&#41;&#41;

&#40;defn list-files &#91;&#93;
  &#40;map :name &#40;db-read &quot;select name from file&quot;&#41;&#41;&#41;

&#40;defn get-file &#91;name&#93;
  &#40;first &#40;db-read &quot;select &#42; from file where name=?&quot; name&#41;&#41;&#41;
</code></pre></p><p>The first helper is used by <code>store-file</code> to copy the file out of the input stream into a byte array and then store it in the table. The other two functions simply read the file columns from our database.</p><h3 id="uploading&#95;files">Uploading Files</h3><p>We'll create a new namespace called <code>files</code> under views, and make a page facilitating the uploads:<pre><code class="clojure">&#40;ns my-website.views.files
  &#40;:use hiccup.util
        noir.core
        hiccup.core
        hiccup.page
        hiccup.form
        hiccup.element&#41;
  &#40;:require &#91;my-website.views.common :as common&#93;
            &#91;my-website.models.db :as db&#93;
            &#91;noir.response :as resp&#93;&#41;&#41;

&#40;defpage &quot;/upload&quot; {:keys &#91;info&#93;}
  &#40;common/layout    
    &#91;:h2.info info&#93;
    &#40;form-to {:enctype &quot;multipart/form-data&quot;}
             &#91;:post &quot;/upload&quot;&#93;
             &#40;label :file &quot;File to upload&quot;&#41;
             &#40;file-upload :file&#41;
             &#91;:br&#93;
             &#40;submit-button &quot;upload&quot;&#41;&#41;&#41;&#41;

</code></pre></p><p>There shouldn't be anything too surprising here, we create an "/upload" page with a an info header and a form. On the form we set <code>enctype</code> to <code>multipart/form-data</code>, then we use <code>file-upload</code> function from <code>hiccup.form</code> to create the file upload dialog and add a submit button. As a note, all Hiccup helper functions also accept a map of attributes as an optional first parameter, these attributes will be merged with the ones already provided by the helper.</p><p>Now we'll have to make its POST counterpart to handle the upload request on the server:<pre><code class="clojure">&#40;defpage &#91;:post &quot;/upload&quot;&#93; {:keys &#91;file&#93;}
  &#40;render &quot;/upload&quot;
    {:info 
      &#40;try
        &#40;db/store-file file&#41; 
        &quot;file uploaded successfully&quot;
        &#40;catch Exception ex
          &#40;do
            &#40;.printStackTrace ex&#41;
            &#40;str &quot;An error has occured while uploading the file: &quot;
              &#40;.getMessage ex&#41;&#41;&#41;&#41;&#41;}&#41;&#41;
</code></pre></p><p>Here we accept the params, grab the file and pass it to <code>store-file</code> function we created earlier in the <code>db</code> namespace. The file is a map containing the following keys:</p><ul><li>:tempfile - the file itself</li><li>:filename - the name of the file being uploaded</li><li>:content-type - the content type of the file being uploaded</li><li>:size - size of the file in bytes</li></ul><p>eg:<pre><code class="clojure">{:size 422668, 
 :tempfile #&lt;File /var/folders/0s/1vrmt9wx6lqdjlg1qtgc34600000gn/T/ring-multipart-3157719234459115704.tmp&gt;, 
 :content-type &quot;image/jpeg&quot;, 
 :filename &quot;logo.jpg&quot;}
</code></pre></p><p>We can now test that file uploading works correctly by navigating to <a href='localhost:8080/upload'>localhost:8080/upload</a> and uploading a file.</p><p><center> <img src="/files/file-upload.png" alt="file upload" /> </center> once we hit upload we should see the following:</p><p><center> <img src="/files/file-uploaded.png" alt="file uploaded" /> </center></p><h3 id="serving&#95;files">Serving Files</h3><p>At this point it might be nice to be able to see what files we have on the server, so let's update our "/upload" page to display a list of files and allow downloading them:<pre><code class="clojure">&#40;defn list-files &#91;&#93;
  &#40;into &#91;:ul&#93;
        &#40;for &#91;name &#40;db/list-files&#41;&#93;             
          &#91;:li.file-link &#40;link-to &#40;str &quot;/files/&quot; name&#41; name&#41; 
           &#91;:span &quot;  &quot;&#93; 
           &#91;:div.file&#93;&#93;&#41;&#41;&#41;

&#40;defpage &quot;/upload&quot; {:keys &#91;info&#93;}
  &#40;common/layout    
    &#91;:h2.info info&#93;
    &#40;list-files&#41;
    &#40;form-to {:enctype &quot;multipart/form-data&quot;}
             &#91;:post &quot;/upload&quot;&#93;
             &#40;label :file &quot;File to upload&quot;&#41;
             &#40;file-upload :file&#41;
             &#91;:br&#93;
             &#40;submit-button &quot;upload&quot;&#41;&#41;&#41;&#41;

&#40;defpage &quot;/files/:name&quot; {:keys &#91;name&#93;}
  &#40;let &#91;{:keys &#91;name type data&#93;} &#40;db/get-file name&#41;&#93;
    &#40;resp/content-type type &#40;new java.io.ByteArrayInputStream data&#41;&#41;&#41;&#41;
</code></pre></p><p>Above, <code>list-files</code> reads the file names from the database, using the helper function we defined earlier and then sticks them into an unordered list. Notice, that Hiccup allows literal notation for any HTML tags, the syntax is as follows:<pre><code class="clojure">&#91;:tag {:attr &quot;value&quot;} content&#93;
</code></pre></p><p>So, if we don't have a helper function for a particular tag, or we need to make a custom tag, we can always just make a vector and set the attributes we care about. </p><p>The new "/files/:name" page we defined uses <code>resp/content-type</code> function to set the appropriate content type when returning the file. It accepts the content type string and an input stream as parameters. </p><p>If we reload the page after making the above changes we should see the following: <center> <img src="/files/files-list.png" alt="files list" /> </center></p><p>and when we click on the file link it should display the image in the browser: <center> <img src="/files/file.png" alt="files list" /> </center></p><h3 id="summary">Summary</h3><p>In this section we learned the following:</p><ul><li>storing files in the database</li><li>setting custom attributes on Hiccup elements</li><li>using <code>multipart/form-data</code> form to upload a binary file</li><li>serving a file with a custom content type</li></ul><p>The complete code for this section is available <a href='https://github.com/yogthos/Noir-tutorial/tree/8686d50e2ed6863a63e48428209de6fe7ad58af8'>here</a>.</p><p>In the <a href='http://yogthos.net/blog/26-Noir+tutorial+-+part+4'>next section</a> we'll talk about creating private pages, form input validation, and handling multi-select form parameters, such as multi checkbox set.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/files/metaballs.png" alt="Reflecting on performance">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Reflecting on performance</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">21 08 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I'm going to take a short break from Noir tutorials and  do a post on optimization and profiling instead. I was playing around with rendering <a href='http://en.wikipedia.org/wiki/Metaballs'>Metaballs</a> and I stumbled on a neat visualization.</p><p><center> <img src="/files/metaballs.png" alt="metaballs" /> </center></p><p>To get the above effect we simply calculate the influence of each metaball on each point on the screen based on the distances to each ball's center and radius:</p><p>i<sub>mp</sub> = r<sub>mp</sub> / &#8730; (&#948;x<sub>mp</sub><sup>2</sup> + &#948;y<sub>mp</sub><sup>2</sup>)</p><p>where r is the radius of the metabll and <em>&#948;x<sub>mp</sub></em> and <em>&#948;y<sub>mp</sub></em> are the <em>x</em> and <em>y</em> distances from the center of the metaball <emph>m</emph> to the point <emph>p</emph>. The resulting color <emph>c<sub>p</sub></emph> of the point is the sum of all the influences:</p><p>c<sub>p</sub> = &#931; i<sub>mp</sub></p><p>The algorithm is on the order of <emph>n<sup>2</sup></emph>, given a small number of metaballs relative to the number of pixels and a square viewport. Unsurprisingly, this runs quite slowly without optimizations, so let's see if we can do anything about that.</p><p>The code to accomplish this is as follows:<pre><code class="clojure">;;compute influence of each metaball
&#40;defn influence &#91;{:keys &#91;x y radius&#93;} px py&#93;
  &#40;let &#91;dx &#40;- x px&#41;
        dy &#40;- y py&#41;&#93;
    &#40;/ radius &#40;Math/sqrt &#40;+ &#40;&#42; dx dx&#41; &#40;&#42; dy dy&#41;&#41;&#41;&#41;&#41;&#41;

;;compute the resulting r g b values based on influence
&#40;defn compute-color &#91;x y &#91;red-cur green-cur blue-cur&#93; ball&#93;   
  &#40;let &#91;influence &#40;influence ball x y&#41;
        &#91;r g b&#93; &#40;:color ball&#41;&#93; 
    &#91;&#40;+ red-cur &#40;&#42; influence r&#41;&#41;
     &#40;+ green-cur &#40;&#42; influence g&#41;&#41;
     &#40;+ blue-cur &#40;&#42; influence b&#41;&#41;&#93;&#41;&#41;

...
;;reverse direction if we hit the edge of the screen
&#40;defn direction &#91;p v&#93;
  &#40;if &#40;or &#40;&gt; p SIZE&#41; &#40;neg? p&#41;&#41; &#40;- v&#41; v&#41;&#41;

;;compute the position and velocity of the ball
&#40;defn move &#91;{:keys &#91;x y vx vy radius color&#93;}&#93;
  &#40;let &#91;vx &#40;direction x vx&#41;
        vy &#40;direction y vy&#41;&#93;
    {:x &#40;+ x vx&#41;
     :y &#40;+ y vy&#41;
     :vx vx
     :vy vy
     :radius radius
     :color color}&#41;&#41;

;;for each x,y coordinate compute the color
&#40;reduce &#40;partial compute-color x y&#41; &#91;0 0 0&#93; balls&#41;

;;run this in a loop where we move the 
;;balls around and render them
&#40;loop &#91;balls &#40;take 2 &#40;repeatedly metaball&#41;&#41;&#93;      
      &#40;draw canvas balls&#41;
      &#40;recur &#40;map move balls&#41;&#41;&#41;
</code></pre></p><p><a href='https://gist.github.com/3411102'>complete code can be seen here</a></p><p>First thing to do is to time our our loop:<pre><code class="clojure">&#40;loop &#91;balls &#40;take 2 &#40;repeatedly metaball&#41;&#41;&#93;      
      &#40;time &#40;draw canvas balls&#41;&#41;
      &#40;recur &#40;time &#40;map move balls&#41;&#41;&#41;&#41;

&quot;Elapsed time: 250.345 msecs&quot;
&quot;Elapsed time: 0.004 msecs&quot;
&quot;Elapsed time: 171.136 msecs&quot;
&quot;Elapsed time: 0.005 msecs&quot;
&quot;Elapsed time: 212.646 msecs&quot;
&quot;Elapsed time: 0.004 msecs&quot;
</code></pre></p><p>As can be expected the draw function eclipses the move function. So we'll focus on what's happening in our rendering code and see where the CPU time is being spent. Instead of guessing, let's profile the application using <a href='https://visualvm.github.io/'>VisualVM</a>, which should already be bundled with your JVM, and see what's happening.</p><p><center> <img src="/files/profile1.png" alt="initial profiling" /> </center></p><p>We can see that the vast majority of the CPU time is being spent in the <code>color</code> function, and that reflection is the culprit. So, let's see why reflection is happening by setting the <code>&#42;warn-on-reflection&#42;</code> flag to true:<pre><code class="clojure">&#40;set! &#42;warn-on-reflection&#42; true&#41;
</code></pre></p><pre><code class="bash">Reflection warning, metaballs.clj:32 - call to java.awt.Color ctor can't be resolved.
Reflection warning, metaballs.clj:40 - call to setColor can't be resolved.
Reflection warning, metaballs.clj:40 - call to fillRect can't be resolved.
Reflection warning, metaballs.clj:52 - reference to field getBufferStrategy can't be resolved.
Reflection warning, metaballs.clj:53 - reference to field getDrawGraphics can't be resolved.
Reflection warning, metaballs.clj:64 - reference to field dispose can't be resolved.
Reflection warning, metaballs.clj:65 - reference to field contentsLost can't be resolved.
Reflection warning, metaballs.clj:66 - reference to field show can't be resolved.
</code></pre><p>Now we know precisely which spots are causing us trouble. Let's see if adding some annotations will improve things. First warning we hit happens when we  create a new instance of <code>Color</code>:<pre><code class="clojure">&#40;defn color-in-range &#91;c&#93;
  &#40;int
    &#40;cond 
      &#40;&lt; c 0&#41; 0
      &#40;&gt; c 255&#41; 255
      :default c&#41;&#41;&#41;

&#40;defn color &#91;r g b&#93;
  &#40;new Color &#40;color-in-range r&#41; &#40;color-in-range g&#41; &#40;color-in-range b&#41;&#41;&#41;
</code></pre></p><p>what's happening here is that even though we cast the result into <code>int</code> inside <code>color-in-range</code>, <code>color</code> is not aware of it and uses reflection to resolve the constructor for <code>Color</code>. So we should be doing the cast inside <code>color</code> instead:<pre><code class="clojure">&#40;defn color &#91;r g b&#93;
  &#40;new Color &#40;int &#40;color-in-range r&#41;&#41; 
             &#40;int &#40;color-in-range g&#41;&#41; 
             &#40;int &#40;color-in-range b&#41;&#41;&#41;&#41;
</code></pre></p><p>The rest of the warnings simply require annotations for the classes in the function arguments:<pre><code class="clojure">&#40;defn paint-square &#91;g color x y size&#93;
  &#40;doto g
    &#40;.setColor color&#41;
    &#40;.fillRect x y size size&#41;&#41;&#41;
</code></pre></p><p>becomes<pre><code class="clojure">&#40;defn paint-square &#91;&#94;Graphics g &#94;Color color x y size&#93;
  &#40;doto g
    &#40;.setColor color&#41;
    &#40;.fillRect x y size size&#41;&#41;&#41;
</code></pre></p><p>and so on. Finally, we'll cast our distances to doubles when we compute the influence:<pre><code class="clojure">&#40;defn influence &#91;{:keys &#91;x y radius&#93;} px py&#93;
  &#40;let &#91;dx &#40;double &#40;- x px&#41;&#41;
        dy &#40;double &#40;- y py&#41;&#41;&#93;
    &#40;double &#40;/ radius &#40;Math/sqrt &#40;+ &#40;&#42; dx dx&#41; &#40;&#42; dy dy&#41;&#41;&#41;&#41;&#41;&#41;&#41;
</code></pre></p><p><a href='https://gist.github.com/3411106'>optimized version can be seen here</a></p><p>Now that we've annotated our code let's see if performance is any better:<pre><code class="clojure">&quot;Elapsed time: 55.424 msecs&quot;
&quot;Elapsed time: 55.399 msecs&quot;
&quot;Elapsed time: 55.373 msecs&quot;
&quot;Elapsed time: 55.482 msecs&quot;
</code></pre></p><p>Indeed it is, we went from ~200ms to ~55ms a 4X improvement in speed! Let's see what the profiler has to say now:</p><p><center> <img src="/files/profile2.png" alt="profile" /> </center></p><p>From here we can clearly see that majority of the time is spent in the paint-square function, meaning that our code performs as it should. Turns out the the only real factor on performance is reflection. </p><p>We could've spent time doing random optimizations here and there, but it's clear from profiling which functions are actually eating up the resources and need optimizing. While this is a toy project, the technique is equally effective for large projects where it might be much more difficult to guess which functions need tuning.</p><p>P.S. try setting a negative radius for some of the metaballs in the scene :P</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/files/noirtutorial1.3.png" alt="Noir tutorial - part 2">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Noir tutorial - part 2</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">18 08 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>This is the second part of the Noir tutorial, where we'll continue to cover the basics of building a website. In the comments for part 1, somebody suggested  that Noir might be abandoned. This is absolutely not the case, I've contacted Chris Granger and this is what he has to say:</p><blockquote><p>Hey Dmitri,<br /></p></blockquote><blockquote><p>Light Table actually uses Noir, so it's certainly still alive. I'm not the primary one driving things day to day right now, Raynes has been helping out with that. </p></blockquote><blockquote><p>Cheers,<br /></p></blockquote><blockquote><p>Chris. </p></blockquote><p>Hopefully, this should put any fears regarding the health of the project to rest. And with that out of the way, lets continue building our site. In the <a href='http://yogthos.net/blog/22-Noir+tutorial+-+part+1'>previous section of the tutorial</a> we setup a basic project and learned how to add pages to it. This time let's look at how to persist data to a database, create sessions, and do some basic user management.</p><h3 id="database&#95;access">Database Access</h3><p>There are several Clojure libraries for dealing with relational databases, such as <a href='http://sqlkorma.com/'>SQLKorma</a>, <a href='http://clojureql.org/'>ClojureQL</a>, <a href='http://budu.github.com/lobos/index.html'>Lobos</a>, and [clojure.data.jdbc])(http://clojure.github.com/java.jdbc/doc/clojure/java/jdbc/UsingSQL.html). In this tutorial we'll be using clojure.data.jdbc to keep things simple, but I do encourage you to take a look at the others.</p><h4 id="setting&#95;up&#95;the&#95;db&#95;connection">Setting up the DB connection</h4><p>First, we'll need to define our database connection, this can be done by either providing a map of connection parameters:<pre><code class="clojure">&#40;def db {:subprotocol &quot;postgresql&quot;
         :subname &quot;//localhost/my&#95;website&quot;
         :user &quot;admin&quot;
         :password &quot;admin&quot;}&#41;
</code></pre></p><p>by specifying the JNDI name for a connection managed by the application server:<pre><code class="clojure">&#40;def db {:name &quot;jdbc/myDatasource&quot;}&#41;
</code></pre></p><p>I personally like this option, because it completely separates the code in the application from the environment. For example, if you have dev/staging/production servers, you can point the JNDI connection to their respective databases, and when you deploy your application it will pick it up from the environment.</p><p>Finally, you can provide a JDBC data source, which you configure manually:<pre><code class="clojure">&#40;def db
  {:datasource
    &#40;doto &#40;new PGPoolingDataSource&#41;
     &#40;.setServerName   &quot;localhost&quot;&#41;
     &#40;.setDatabaseName &quot;my&#95;website&quot;&#41;
     &#40;.setUser         &quot;admin&quot;&#41;
     &#40;.setPassword     &quot;admin&quot;&#41;
     &#40;.setMaxConnections 10&#41;&#41;}&#41;
</code></pre></p><p>At this point you should setup a database and create a schema for this tutorial called <code>my&#95;website</code>. I will be using PostgreSQL so if you use a different DB there might be slight syntactic differences in your SQL. Once you have the DB up and running, we'll need to add the clojure.data.jdbc and JDBC driver dependencies to <code>project.clj</code>:<pre><code class="clojure">&#40;defproject my-website &quot;0.1.0-SNAPSHOT&quot;
  :description &quot;&quot;my Noir website&quot;&quot;
  :dependencies &#91;&#91;org.clojure/clojure &quot;1.4.0&quot;&#93;
                 &#91;noir &quot;1.3.0-beta3&quot;&#93;
                 &#91;org.clojure/java.jdbc &quot;0.2.3&quot;&#93;
                 &#91;postgresql/postgresql &quot;9.1-901.jdbc4&quot;&#93;&#93;
  :main my-website.server&#41;
</code></pre></p><h4 id="using&#95;to&#95;the&#95;database">Using to the Database</h4><p>Next, let's create a new namespace called <code>my-website.models.db</code> in the models directory of our project, and open it up. Here we'll first need to add a require statement for clojure.data.jdbc:<pre><code class="clojure">&#40;ns my-website.models.db
  &#40;:require &#91;clojure.java.jdbc :as sql&#93;&#41;&#41;
</code></pre></p><p>now let's create a connection:<pre><code class="clojure">&#40;def db 
  {:subprotocol &quot;postgresql&quot;
   :subname &quot;//localhost/my&#95;website&quot;
   :user &quot;admin&quot;
   :password &quot;admin&quot;}&#41;
</code></pre></p><p>we'll add the following function which will allow us to create the <code>users</code> table:<pre><code class="clojure">&#40;defn init-db &#91;&#93;
  &#40;try
  &#40;sql/with-connection
    db
    &#40;sql/create-table
      :users
      &#91;:id &quot;SERIAL&quot;&#93;
      &#91;:handle &quot;varchar&#40;100&#41;&quot;&#93;
      &#91;:pass   &quot;varchar&#40;100&#41;&quot;&#93;&#41;&#41;
  &#40;catch Exception ex
    &#40;.getMessage &#40;.getNextException ex&#41;&#41;&#41;&#41;&#41;
</code></pre></p><p>Here's you'll notice that the <code>create-table</code> needs to be wrapped in a <code>with-connection</code> statement which ensures that the connection is cleaned up correctly after we're done with it. The only other thing to note is the use of "SERIAL" for the id field in the table, which is PostgreSQL specific way to create auto incrementing fields. It's also possible to use keywords such as <code>:int</code>, <code>:boolean</code>, and <code>:timestamp</code> for field types as well as the corresponding SQL string as is done in the above example. The whole statement is wrapped in a try block, so if we get any errors when it runs we'll print the error message.</p><p>In the REPL we'll run:</p><pre><code>&#40;init-db&#41;
</code></pre><p>If your DB is configured correctly, then you should now have a <code>users</code> table. We'll now write a function to add a user to it:<pre><code class="clojure">&#40;defn add-user &#91;user&#93;
  &#40;sql/with-connection 
    db
    &#40;sql/insert-record :users user&#41;&#41;&#41;
</code></pre></p><p>now test that the function works correctly:<pre><code class="clojure">&#40;add-user {:handle &quot;foo&quot; :pass &quot;bar&quot;}&#41;
=&gt;{:pass &quot;bar&quot;, :handle &quot;foo&quot;, :id 1}
</code></pre></p><p>finally we'll need a way to read the records from the database, I wrote the following helper function to do that:<pre><code class="clojure">&#40;defn db-read &#91;query &amp; args&#93;
  &#40;sql/with-connection 
    db
    &#40;sql/with-query-results 
      res 
      &#40;vec &#40;cons query args&#41;&#41; &#40;doall res&#41;&#41;&#41;&#41;
</code></pre></p><p>the function accepts an SQL string and optional parameters:<pre><code class="clojure">&#40;db-read &quot;select &#42; from users&quot;&#41;
&#40;{:pass &quot;bar&quot;, :handle &quot;foo&quot;, :id 1}&#41;

&#40;db-read &quot;select &#42; from users where id=?&quot; 1&#41;
&#40;{:pass &quot;bar&quot;, :handle &quot;foo&quot;, :id 1}&#41;

</code></pre></p><p>we'll write another helper function to fetch the user by handle<pre><code class="clojure">&#40;defn get-user &#91;handle&#93;
  &#40;first 
    &#40;db-read &quot;select &#42; from users where handle=?&quot; handle&#41;&#41;&#41;
</code></pre></p><p>at this point we've got a user table and helper functions to create and query users. Let's hook that up to our pages and provide the functionality to create user accounts and allow users to login.</p><h3 id="creating&#95;a&#95;registration&#95;page">Creating a Registration Page</h3><p>Noir provides a very simple way to manage sessions using <a href='http://www.webnoir.org/autodoc/1.2.0/noir.session-api.html'>noir.ession</a> namespace. Let's update our site to allow a user to create an account. First we'll create a new namespace called <code>my-website.views.users</code> and add the following code to it:<pre><code class="clojure">&#40;ns my-website.views.users
  &#40;:use &#91;noir.core&#93;
        hiccup.core hiccup.form&#41;
  &#40;:require &#91;my-website.views.common :as common&#93;
            &#91;my-website.models.db :as db&#93;
            &#91;noir.util.crypt :as crypt&#93;
            &#91;noir.session :as session&#93;
            &#91;noir.response :as resp&#93;&#41;&#41;

&#40;defpage &quot;/signup&quot; {:keys &#91;handle error&#93;}
  &#40;common/layout
    &#91;:div.error error&#93;
    &#40;form-to &#91;:post &quot;/signup&quot;&#93;
             &#40;label &quot;user-id&quot; &quot;user id&quot;&#41;
             &#40;text-field &quot;handle&quot; handle&#41;
             &#91;:br&#93;
             &#40;label &quot;pass&quot; &quot;password&quot;&#41;
             &#40;password-field &quot;pass&quot;&#41;             
             &#91;:br&#93;
             &#40;submit-button &quot;create account&quot;&#41;&#41;&#41;&#41;

&#40;defpage &#91;:post &quot;/signup&quot;&#93; user
  &#40;try 
    &#40;db/add-user &#40;update-in user &#91;:pass&#93; crypt/encrypt&#41;&#41;
    &#40;resp/redirect &quot;/&quot;&#41;
    &#40;catch Exception ex
      &#40;render &quot;/signup&quot; &#40;assoc user :error &#40;.getMessage ex&#41;&#41;&#41;&#41;&#41;&#41;
</code></pre></p><p>You'll notice that we've required a few new namespaces which we'll be using shortly. Otherwise, we see a similar setup to what we did in the first part of the tutorial, except when we accept the post from the form, we actually add the user to the database.</p><p>We will encrypt the user password using <code>noir.util.crypt</code> and then attempt to store the user in the database. If we fail to add the user we'll render our signup page again, but this time with an error message.</p><p><center> <img src="/files/noirtutorial1.3.png" alt="create user" /> <br/> create user page</p><p><img src="/files/noirtutorial1.4.png" alt="create user error" /> <br/> error displayed when user creation fails</p><p></center> Notice that we pass the user fields back to the defpage displaying the form, so if we get an error we don't have to make the user retype all their information.</p><h3 id="session&#95;management">Session Management</h3><p>At this point we need to provide the users with the ability to login with their accounts. Let's go to the <code>common</code> namespace and add a way for users to login. We'll need to add <a href='http://www.webnoir.org/autodoc/1.2.0/noir.session-api.html'><code>noir.session</code></a> to our <code>:require</code> statement:<pre><code class="clojure">&#40;ns my-website.views.common
  ...
  &#40;:require &#91;noir.session :as session&#93;&#41;
</code></pre></p><p>then we'll go back to <code>users</code> namespace and create a page to handle logins:<pre><code class="clojure">&#40;defpage &#91;:post &quot;/login&quot;&#93; {:keys &#91;handle pass&#93;}
  &#40;render &quot;/&quot; 
          &#40;let &#91;user &#40;db/get-user handle&#41;&#93; 
            &#40;if &#40;and user &#40;crypt/compare pass &#40;:pass user&#41;&#41;&#41;
              &#40;session/put! :user handle&#41;
              {:handle handle :error &quot;login failed&quot;}&#41;&#41;&#41;&#41;
</code></pre></p><p>We'll use <code>noir.crypt</code> to validate the password against the one we have in the database, and if the password matches we'll stick the user handle into the session. The syntax for updating the session is fairly straightforward, and the <a href='http://www.webnoir.org/autodoc/1.2.0/noir.session-api.html'>documentation page</a> explains it well. We'll be using <code>get</code>, <code>put!</code>, and <code>clear!</code> functions, notice that <code>put!</code> and <code>clear!</code> have an exclamation mark at the end indicating that they mutate the data in place.</p><p>The users will also need a way to logout, so let's add a page to handle that as well:<pre><code class="clojure">&#40;defpage &#91;:post &quot;/logout&quot;&#93; &#91;&#93;
  &#40;session/clear!&#41;
  &#40;resp/redirect &quot;/&quot;&#41;&#41;
</code></pre></p><p>When the user logs out, we'll simply clear the session and send them back to the homepage. We will now go to our <code>common</code> namespace and add the <code>noir.session</code> and <code>hiccup.form</code> in our namespace:<pre><code class="clojure">&#40;ns my-website.views.common
  &#40;:use &#91;noir.core :only &#91;defpartial&#93;&#93;
        hiccup.element 
        hiccup.form
        &#91;hiccup.page :only &#91;include-css html5&#93;&#93;&#41;
  &#40;:require &#91;noir.session :as session&#93;&#41;&#41;
</code></pre></p><p>then add a helper function to create the login form:<pre><code class="clojure">&#40;defn login-form &#91;&#93;
  &#40;form-to &#91;:post &quot;/login&quot;&#93;           
           &#40;text-field {:placeholder &quot;user id&quot;} &quot;handle&quot;&#41;                        
           &#40;password-field {:placeholder &quot;password&quot;} &quot;pass&quot;&#41;                        
           &#40;submit-button &quot;login&quot;&#41;&#41;&#41;
</code></pre></p><p>and finally add it to our layout:<pre><code class="clojure">&#40;defpartial layout &#91;&amp; content&#93;
            &#40;html5
              &#91;:head
               &#91;:title &quot;my-website&quot;&#93;
               &#40;include-css &quot;/css/reset.css&quot;&#41;&#93;
              &#91;:body               
               &#40;if-let &#91;user &#40;session/get :user&#41;&#93;
                  &#91;:h2 &quot;welcome &quot; user 
                    &#40;form-to &#91;:post &quot;/logout&quot;&#93; &#40;submit-button &quot;logout&quot;&#41;&#41;&#93;
                  &#91;:div.login
                   &#40;login-form&#41; &#91;:p &quot;or&quot;&#93; &#40;link-to &quot;/signup&quot; &quot;sign up&quot;&#41;&#93;&#41;
               
               content&#93;&#41;&#41;
</code></pre></p><p>At this point our main page should look like the following: <center> <img src="/files/noirtutorial1.5.png" alt="login" /> </center></p><p>and after we sign up and login, we should see:</p><p><center> <img src="/files/noirtutorial1.6.png" alt="logged in" /> </center></p><p>The logout button should take us back to the login page by clearing the user session. We now have a complete website with some basic user management, the only thing left to add is actual content. :)</p><h3 id="summary">Summary</h3><p>In this section we learned the following:</p><ul><li>how to setup the database and do basic queries</li><li>do basic authentication using <code>noir.crypt</code></li><li>use sessions to store user information</li></ul><p>Hopefully this is enough to get you started using Noir and making your sites with it. If I omitted anything important let me know in comments and I'll be glad to go over it.</p><p>The complete source for this part of the tutorial is available <a href='https://github.com/yogthos/Noir-tutorial/tree/f83a894933922eda2b78c84de2e8eb28891eeda5'>here</a>. Also, for an example of a complete real world site you can see the source for this blog <a href='https://github.com/yogthos/yuggoth'>here</a>.</p><p>In the <a href='http://yogthos.net/blog/25-Noir+tutorial+-+part+3'>next section</a> we'll talk about setting content types and doing file uploads and downloads.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/files/noir.png" alt="Noir tutorial - part 1">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Noir tutorial - part 1</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">17 08 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <h3 id="background">Background</h3><p>Clojure web stack consists of <a href='https://github.com/ring-clojure/ring'>Ring</a>, which is the base HTTP library akin to Python's WSGI and Ruby's Rack. On top of Ring lives <a href='https://github.com/weavejester/compojure'>Compojure</a>, which provides some basic routing, and that in turn is leveraged by <a href='http://www.webnoir.org/'>Noir</a> to provide a simple framework for developing websites. Here's we'll see how to use Noir to build a basic website. </p><h3 id="setting&#95;up&#95;a&#95;noir&#95;project&#95;with&#95;leiningen">Setting Up a Noir Project With Leiningen</h3><p>The easiest way to get Noir setup is to use <a href='https://github.com/technomancy/leiningen/'>Leiningen 2</a>, which has become the de facto build tool for Clojure. Once you have Leiningen installed, you can simply do the following to get a template site created:<pre><code class="bash">lein new noir my-website
cd my-website
</code></pre></p><p>Alternatively, if you're using <a href='http://code.google.com/p/counterclockwise/'>Counterclockwise</a> with Eclipse, then all you need to do is make a new Leiningen project and put <code>noir</code> in the <code>&quot;Leiningen Template to use:&quot;</code> field.</p><h4 id="project&#95;structure">Project Structure</h4><p>The template site will have the following structure:<pre><code class="bash">/my-website
  project.clj
  --src/
     --my&#95;website/
       server.clj
       --models/
       --views/common.clj
               welcome.clj
  --test/my&#95;website
  --resources/public/
                  --css/reset.css
                  --img/
                  --js/
</code></pre></p><p>The skeleton application contains a few files in it. The <code>project.clj</code> file is used for building the application and managing dependencies by Leiningen. Under the <code>src</code> folder, we  have the folder called <code>my&#95;website</code> which contains <code>server.clj</code>. This file contains the entry point to our application. It loads up all the views and provides a main function which can be used to start the application.</p><p>The <code>models</code> folder is used to keep the data layer of the application, such as code for the database access and table management. The <code>views</code> folder contains the namespaces describing the pages of our application and their supporting code. The template contains <code>common.clj</code> which provides a basic layout and any code shared between the pages. The <code>welcome.clj</code> is the namespace where an example page is defined.</p><h3 id="dependency&#95;management">Dependency Management</h3><p>Let's first look at the <code>project.clj</code> file:<pre><code class="clojure">&#40;defproject my-site &quot;0.1.0-SNAPSHOT&quot;
            :description &quot;FIXME: write this!&quot;
            :dependencies &#91;&#91;org.clojure/clojure &quot;1.4.0&quot;&#93;
                           &#91;noir &quot;1.3.0-beta3&quot;&#93;&#93;
            :main my-site.server&#41;
</code></pre></p><p>The file is fairly self explanatory, and currently only contains dependencies for Clojure and Noir.</p><h4 id="running&#95;the&#95;project&#95;in&#95;development&#95;mode">Running the Project in Development Mode</h4><p>At this point we should be able to start up our website:<pre><code class="bash">lein run

Starting server...
2012-08-16 09:39:22.479:INFO::Logging to STDERR via org.mortbay.log.StdErrLog
Server started on port &#91;8080&#93;.
You can view the site at http://localhost:8080
#&lt;Server Server@2206270b&gt;
2012-08-16 09:39:22.480:INFO::jetty-6.1.25
2012-08-16 09:39:22.521:INFO::Started SocketConnector@0.0.0.0:8080
</code></pre></p><p>Let's point the browser to <a href='http://localhost:8080'><code>localhost:8080</code></a> and  make sure everything is working as expected. We should be greeted with a Noir help page since we haven't defined one for "/" route yet. At this point we can start editing our pages and any changes we make should be reflected immediately.</p><p><center> <img src="/files/noir.png" alt="noir" /> </center></p><h3 id="creating&#95;pages">Creating Pages</h3><p>Noir provides two primary way to manipulate pages. One useful macro is <code>defpartial</code> which simply wraps the body in <code>html</code> function from Hiccup, which will generate the resulting HTML string from our content:<pre><code class="clojure">&#40;defpartial foo &#91;content&#93;
  &#91;:p content&#93;&#41;

&#40;foo &quot;some stuff&quot;&#41;
&quot;&lt;p&gt;some stuff&lt;/p&gt;&quot;
</code></pre></p><p>The other is <code>defpage</code>, this macro will create a Compojure route for the specified URL. It has the following syntax:<pre><code class="clojure">&#40;defpage url params content&#41;
</code></pre></p><p>By default <code>defpage</code> is expected to return an HTML string. How that string is generated is up to you. In this tutorial we'll be using Hiccup, but you could just as easily use something like <a href='http://paulosuzart.github.com/blog/2012/03/25/web-noir-plus-enlive-template/'>Enlive</a> to create your templates using actual HTML. Noir itself is completely agnostic in this regard. </p><p>Now, let's look at the parameters that <code>defpage</code> accepts. First we have a URL which supports the following formats:</p><ul><li>a simple string such as <code>&quot;/welcome&quot;</code></li><li>a RESTful path such as <code>&quot;/welcome/:user&quot;</code> where the key <code>:user</code> will be appended to the params map with the value provided when the URL is accessed</li><li>a vector specifying the request type which the page responds too : <code>&#91;:post &quot;/welcome&quot;&#93;</code></li></ul><p>Next, we have params, which is simply a map of keywords and their associated values generated from the request parameters. Any keys from the URL will also appear in this map:<pre><code class="clojure">&#40;defpage &quot;/welcome/:user&quot; {:keys &#91;user&#93;}
  &#40;html &#91;:html &#91;:body &quot;hello &quot; user&#93;&#93;&#41;&#41;
</code></pre></p><p>Finally, we add the actual page content to be rendered. As I mentioned above the result <strong>must</strong> be a string, so generally we'll wrap the contents of each page in <code>&#40;common/layout ...&#41;</code> which was provided by the template. The official documentation for <code>defpage</code> with lots of other examples and details is available <a href='http://www.webnoir.org/tutorials/routes'>here</a>.</p><h4 id="handling&#95;form&#95;input">Handling Form Input</h4><p>When making pages with forms the general pattern is to create a <code>defpage</code> for the GET request which will contain the UI, and another for POST which contains the server component. To test that out, let's change <code>welcome.clj</code> to look like the following:<pre><code class="clojure">&#40;ns my-website.views.welcome
  &#40;:require &#91;my-website.views.common :as common&#93;
            &#91;noir.content.getting-started&#93;&#41;
  &#40;:use &#91;noir.core :only &#91;defpage&#93;&#93;
        hiccup.core hiccup.form&#41;&#41;

&#40;defpage &quot;/welcome&quot; {:keys &#91;greeting&#93;}
  &#40;common/layout
    &#40;if greeting &#91;:h2 greeting&#93;&#41;
    &#40;form-to &#91;:post &quot;/welcome&quot;&#93;
      &#40;label &quot;name&quot; &quot;name&quot;&#41;
      &#40;text-field &quot;name&quot;&#41;
      &#40;submit-button &quot;submit&quot;&#41;&#41;&#41;&#41;

&#40;defpage &#91;:post &quot;/welcome&quot;&#93; {:keys &#91;name&#93;}
  &#40;noir.core/render &quot;/welcome&quot; 
    {:greeting &#40;str &quot;Welcome &quot; name&#41;}&#41;&#41;
</code></pre></p><p>As can be seen above, the page which responds to GET creates a form and submits it to its POST counterpart. It in turn generates a greeting and renders the page with it. Note that the names for fields used in the form get translated into keys in the params map when we submit it. </p><p><center> <img src="/files/noirtutorial1.1.png" alt="initial page" /></p><p>before submit</p><p><img src="/files/noirtutorial1.2.png" alt="initial page" /></p><p>and after submit </center></p><p>This covers the basic model for creating pages and interacting with them. Now, let's look at how we can package our website into a standalone application. </p><h3 id="packaging&#95;and&#95;running&#95;standalone">Packaging and Running Standalone</h3><p>To package our project we need to change our server to compile into a class, we can do this by simply adding <code>gen-class</code> to its namespace like so:<pre><code class="clojure">&#40;ns my-website.server
  &#40;:require &#91;noir.server :as server&#93;&#41; 
  &#40;:gen-class&#41;&#41;
</code></pre></p><p>Now we can build and run our project:<pre><code class="bash">lein uberjar
java -jar my-website-0.1.0-SNAPSHOT-standalone.jar

Starting server...
2012-08-16 20:12:47.846:INFO::Logging to STDERR via org.mortbay.log.StdErrLog
2012-08-16 20:12:47.846:INFO::jetty-6.1.x
2012-08-16 20:12:47.882:INFO::Started SocketConnector@0.0.0.0:8080
Server started on port &#91;8080&#93;.
You can view the site at http://localhost:8080
</code></pre></p><h3 id="summary">Summary</h3><p>To recap, in this section of the tutorial we learned the following:</p><ul><li>how to create a new Noir project</li><li>manage dependencies</li><li>create pages</li><li>handle submits from forms</li><li>create a standalone instance of our application</li></ul><p>Next time we'll look at how to do session management and database access. </p><p><a href='http://yogthos.net/blog/23-Noir+tutorial+-+part+2'>continue to part 2</a></p><p>The source for the tutorial is available <a href='https://github.com/yogthos/Noir-tutorial/tree/c70514189612f369efb75e1a601a1d10a5b15492'>here</a>.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Easy PDF reports with clj-pdf</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">16 08 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>A few months ago I was tasked with generating reports for one of the applications I was working on. I looked around for some off the shelf libraries for doing this sort of thing. The most popular library in the Java world appears to be iText. It's a mature library with lots of features, but it takes entirely too much code to produce anything useful with it. On top of that, the latest version licensed under LGPL2 is 2.1.7 which, while serviceable, is full of quirks and odd behaviors.</p><p>After spending a bit of time playing with it I decided that it would make more sense to have a declarative API for describing the PDF document. I really like the way <a href='http://weavejester.github.com/hiccup/'>Hiccup</a> allows generating HTML using nested vectors, and decided that something similar could be done for generating PDF documents.</p><p>This lead to the creating of <a href='https://github.com/yogthos/clj-pdf'>clj-pdf</a>, which allows describing the document using this approach. Each vector represents a different element, such as a paragraph, a list, or a table. Internally, I leverage iText to produce the actual PDF document, but the API is completely declarative. The library attempts to abstract away any of the quirks as well as provide useful elements such as headings, spacers, page breaks, etc.</p><p>Let's look at how this all works in practice. A document is simply a vector which contains metadata describing it followed by one or more inner elements:<pre><code class="clojure">&#91;{:title &quot;My document&quot;} &quot;some content here...&quot;&#93;
</code></pre></p><p>In the spirit of Hiccup, each element is represented by a vector, where the first item must be a tag describing the type of the element, followed by optional metadata, and finally the content of the element. For example if we wanted to create a paragraph we'd do the following:<pre><code class="clojure">&#91;:paragraph &quot;a fine paragraph&quot;&#93;
</code></pre></p><p>to set the font style we could add the following metadata:<pre><code class="clojure">&#91;:paragraph
  {:style :bold :size 10 :family :halvetica :color &#91;0 255 221&#93;}
  &quot;Lorem ipsum dolor sit amet, consectetur adipiscing elit.&quot;&#93;
</code></pre></p><p>any metadata in an element will propagate to its children:<pre><code class="clojure">&#91;:paragraph
  {:style :bold :size 12 :family :halvetica :color &#91;0 255 221&#93;}
  &quot;Lorem ipsum dolor sit amet, consectetur adipiscing elit.&quot;
  &#91;:phrase &quot;some text here&quot;&#93;&#93;
</code></pre></p><p>here the phrase will inherit the font style of its parent paragraph. However, the child element is always free to overwrite the parent metadata:<pre><code class="clojure">&#91;:paragraph
  {:style :bold :size 12}
  &quot;Lorem ipsum dolor sit amet, consectetur adipiscing elit.&quot;
  &#91;:phrase {:style :normal :size 10} &quot;some text here&quot;&#93;&#93;
</code></pre></p><p>This provides us with a lot of flexibility, while allowing to specify defaults for the entire document. The library attempts to provide reasonable behavior out of the box, so that adding metadata should not be necessary in most cases. </p><p>Some reports might include things like usage statistics. And to that end I leveraged the excellent <a href='http://www.jfree.org/jfreechart/'>JFreeChart</a> library to provide a simple charting API:<pre><code class="clojure">&#91;:chart {:type :line-chart 
         :title &quot;Line Chart&quot; 
         :x-label &quot;checkpoints&quot; 
         :y-label &quot;units&quot;} 
  &#91;&quot;Foo&quot; &#91;1 10&#93; &#91;2 13&#93; &#91;3 120&#93; &#91;4 455&#93; &#91;5 300&#93; &#91;6 600&#93;&#93;
  &#91;&quot;Bar&quot; &#91;1 13&#93; &#91;2 33&#93; &#91;3 320&#93; &#91;4 155&#93; &#91;5 200&#93; &#91;6 300&#93;&#93;&#93;
</code></pre></p><p>At this time bar charts, line charts, time series, and pie charts are supported. And because a chart is just an image, all the image styling, such as scaling and alignment, can be applied to it as well.</p><p>Since the API is completely declarative, it doesn't actually have to be encoded in Clojure structures. We could instead encode it in something like JSON, which is exactly what I ended up doing next. I created a service which would accept POST requests containing JSON encoded documents and return PDF documents. The service can be accessed by any application regardless of what language its written in, and can even be called by JavaScript from a browser as can be seen <a href='http://yogthos.net/instant-pdf/'>here</a>.</p><p>Documentation and examples are available on the <a href='https://github.com/yogthos/clj-pdf'>github project page</a>.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Blogging with Noir</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">14 08 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Writing a blog engine in Noir turned out to be a very pleasant experience. The <a href='https://github.com/yogthos/yuggoth'>engine</a> which is currently powering this blog  supports all the features one would expect from a blogging engine, some of which include:</p><ul><li>content caching</li><li>RSS feed</li><li>tags</li><li>markdown in posts and comments with live preview</li><li>syntax highlighting</li><li>file uploads and management through web UI</li><li>captchas for comments</li><li>latest comments view</li><li>controlling post visibility</li></ul><p>All that weighs in at under 1K lines of Clojure, and some 50 lines of Js. I've outlined some of the quirks I ran into <a href='http://yogthos.net/blog/16-Noir+tricks'>previously</a>. Now, I'd like to talk about what went right and what facilitated writing a complete functional website in only a few hundred lines of code.</p><p>I used <a href='https://github.com/clojure/java.jdbc/'>clojure.java.jdbc</a> for database access. The library is very easy to use and provides all the basic functionality you'd expect with minimal fuss. You can define a database either using a map:<pre><code class="clojure">&#40;def mysql-db {:subprotocol &quot;postgresql&quot;
               :subname &quot;//127.0.0.1:3306/clojure&#95;test&quot;
               :user &quot;clojure&#95;test&quot;
               :password &quot;clojure&#95;test&quot;}&#41;
</code></pre></p><p>by providing a JNDI name and configuring a JNDI data source on the app server:<pre><code class="clojure">&#40;def my-db {:name &quot;jdbc/myDatasource&quot;}&#41;
</code></pre></p><p>or by simply instantiating a data source as I do in the blog:<pre><code class="clojure">&#40;def db 
  {:datasource 
    &#40;doto &#40;new PGPoolingDataSource&#41;
       &#40;.setServerName   &#40;:host blog-config&#41;&#41;
       &#40;.setDatabaseName &#40;:schema blog-config&#41;&#41;
       &#40;.setUser         &#40;:user blog-config&#41;&#41;
       &#40;.setPassword     &#40;:pass blog-config&#41;&#41;
       &#40;.setMaxConnections 10&#41;&#41;}&#41;
</code></pre></p><p>Calling SQL commands is straightforward as well, all statements must be wrapped with a <code>with-connection</code> statement. This ensures that any result sets are cleaned up and the connection is closed once you're done with it. I found the library to be very intuitive and easy to work with. The documentation <a href='https://github.com/clojure/java.jdbc/tree/master/doc/clojure/java/jdbc'>is available on github</a> and covers most use cases. All of my db interaction ended up fitting in just under 250 lines, which makes it easy to keep on top of.</p><p><a href='http://www.webnoir.org/'>Noir</a> has been indispensable in making things concise and easy to manage. Noir and <a href='http://weavejester.github.com/hiccup/'>Hiccup</a> make it trivial to organize the pages and their controllers into self contained chunks.</p><p>Because it encourages making things stateless, it's easy to add functionality in isolated chunks. This means that you can add a particular feature, such as RSS support, without having to worry how it might interact with existing code. I find this especially important when writing side projects as it means that you have a very short ramp up time when you come back to a project after not having touched it for a while.</p><p>I'm personally a fan of using Hiccup for generating HTML, as it allows using the full power of Clojure for templating. However, some people have concerns about not having the actual HTML that designers can then style. Fortunately, there's nothing inherent to Noir that ties it to Hiccup. A <code>defpage</code> simply has to return an HTML string, how that string gets generated is entirely up to you. And there's a <a href='http://paulosuzart.github.com/blog/2012/03/25/web-noir-plus-enlive-template/'>great guide</a> for using Noir with <a href='https://github.com/cgrand/enlive/'>Enlive</a>, which is designed for HTML based templating. Again, I have to point out the thoughtfulness of design which separates creating routes and serving pages from the libraries which deal with actually generating them.</p><p>For Markdown parsing I dredged up <a href='https://github.com/yogthos/markdown-clj'>an old library of mine</a>, and with a few tweaks it's been doing its job as far as far as this blog is concerned. One advantage of this particular library is that it compiles to both Clojure and ClojureScript, so I can do previews in the browser and guarantee that they will be rendered the same by the server.</p><p>I added the ability to add language hinting using github style markdown, eg: &#96;&#96;&#96;clojure, to output tags compatible with the <a href='http://alexgorbatchev.com/SyntaxHighlighter/'>syntax highlighter</a>, which I then use to do code highlighting in the browser.</p><p>I also didn't find any readily available libraries for generating RSS from Clojure, so I proceeded to make <a href='https://github.com/yogthos/clj-rss'>clj-rss</a>, which turned out to be very easy thanks to the excellent XML support in the standard library and a few macros.</p><p>For my captcha needs I turned to a Java library called <a href='http://mvnrepository.com/artifact/net.sf.jlue/jlue-core'>jlue</a>. Thanks to the excellent Java interop, using it is quite seamless:<pre><code class="clojure">&#40;defn gen-captcha &#91;&#93;
  &#40;let &#91;text &#40;gen-captcha-text&#41;
        captcha &#40;doto &#40;new Captcha&#41;&#41;&#93;
    &#40;session/put! :captcha 
                  {:text text 
                   :image &#40;.gen captcha text 250 40&#41;}&#41;&#41;&#41;

&#40;defpage &quot;/captcha&quot; &#91;&#93;
  &#40;gen-captcha&#41;
  &#40;resp/content-type 
    &quot;image/jpeg&quot; 
    &#40;let &#91;out &#40;new ByteArrayOutputStream&#41;&#93;
      &#40;ImageIO/write &#40;:image &#40;session/get :captcha&#41;&#41; &quot;jpeg&quot; out&#41;
      &#40;new ByteArrayInputStream &#40;.toByteArray out&#41;&#41;&#41;&#41;&#41;
</code></pre></p><p>Finally, all of the building and packaging is handled by <a href='http://github.com/technomancy/leiningen/'>Leiningen</a>, which makes it trivial to track dependencies and package up the resulting application. In my case I'm deploying the blog to Tomcat, and so I simply build a WAR using:<pre><code class="bash">lein ring uberwar
</code></pre></p><p>The resulting WAR can be dropped on any Java application server. If you wanted to deploy to Heroku, you simply have to add a <code>Procfile</code> to the root directory of the project with the following contents:<pre><code class="bash">web: lein trampoline run -m yuggoth.server
</code></pre></p><p>Overall, I experienced very few issues and found the experience to be overwhelmingly positive. In my opinion the current tools and libraries available in Clojure allow writing web sites just as easily, if not more so, as most of the established languages out there.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Why be conservative</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">11 08 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p><a href='https://plus.google.com/110981030061712822816/posts'>Steve Yegge</a> has made a post introducing the idea of liberalism and conservatism in programming languages. While it is an entertaining read I have to question the usefulness of the proposed metric.</p><p>In my opinion the language either gets out of your way and makes it easy to do what you need to do or it doesn't. I don't really care how it does it as long as at the end of the day I enjoy using it and I'm productive in it.</p><p>It can certainly be argued that Clojure is conservative in some ways. As has been pointed out in the results of the <a href='http://java.dzone.com/articles/results-2012-state-clojure'>2012 State of Clojure</a> survey, some people find the process for contributing to the language too restrictive. Rich Hickey is very cautious about adding new features and about the way they're added to the language.</p><p>But I would argue that this is in fact a good thing and the end result is a cleaner and more consistent language. Destructuring is a concrete example of this. At one point people were asking for named arguments for functions and Rich resisted the idea of adding them. Instead, we got destructuring which is a more powerful and general purpose tool. It can be used for naming arguments in functions, but it can also be used for many other things as well.</p><p>Let's consider what the result would have been if Clojure was more liberal about adding features, and named arguments were in fact added. There would now be two separate ways to do the same thing, each with its own quirks. Different code bases would use different rules for naming function parameters and you would have to make adapters to make them work together.</p><p>The more eagerly features get accepted into a language, the more likely they it is that the solution won't be elegant or general purpose. Which means that inevitably a new feature needs to be added to cover the case which isn't adequately addressed by the original attempt. </p><p>In my opinion this quickly leads to having a crufty syntax, and requires a lot of mental overhead to work with code written by others. Since, some people will prefer this or that particular style of doing things you have to be aware of every quirk and their interactions.</p><p>Fact of the matter is that Lisp is already phenomenally powerful, more so than most languages out there. It would seem prudent not to be rash about trying to improve it. </p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Setting up Eclipse for Clojure</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">07 08 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The <a href='http://cemerick.com/2012/08/06/results-of-the-2012-state-of-clojure-survey/'>Results of the 2012 State of Clojure survey</a> are out, and they look very exciting indeed. More people are using Clojure, the community is growing, and for the most part things appear to be progressing well. However, one notable problem that people are reporting is actually getting started with Clojure.</p><p>I'd like to spend some time here to help people actually get up and running with the language. First, I'll cover setting up the development environment. Many Clojure users gravitate towards Emacs, which is a natural choice for Lisp development. But if you're new to Clojure and you haven't used Emacs before, I would strongly suggest against learning both Emacs and Clojure at the same time. </p><p>The reason being is that Emacs is fairly arcane in many ways, and it behaves very differently from traditional IDEs, such as NetBeans or Eclipse. Learning a new language, which has very different syntax from languages you might be used to, and requires learning a new programming paradigm is enough to keep one busy without having to learn a quirky IDE on the side.</p><p>My recommendation would be to grab a copy of <a href='http://www.eclipse.org/downloads/packages/eclipse-ide-java-developers/junor'>Eclipse</a> and install the <a href='http://code.google.com/p/counterclockwise/'>Counterclockwise plugin</a>. Installing the plugin is incredibly simple, once you have Eclipse running follow the following steps:</p><ul><li>navigate to the "Install new Software" tab under the help menu</li><li>paste in the CCW update URL: http://ccw.cgrand.net/updatesite in the "Work with:" text field</li><li>check the "Clojure Programming" checkbox and hit the "Next" button</li></ul><p>Counterclockwise takes care of setting up Clojure and Leiningen for you. And once the plugin is installed, you will be able to create a new Clojure project or a new Leiningen project. I would recommend making Leiningen projects, since they allow easily managing dependencies by updating the <code>project.clj</code> file in the project directory. I'll touch more on this later.</p><p>At this point, I'll assume that you have Eclipse with CCW up and running. So, navigate to File->new->project in Eclipse menu. Then select Leiningen->Leiningen project. Here you'll see the <code>default</code> Leiningen Template filled in. And only thing you have to do is provide a project name. Let's call our project "clojure-test" and hit the finish button.</p><p>You should now see a new project in your Package Explorer view on the left. The project template will have a <code>src</code> folder which will contain the package folder named <code>clojure&#95;test</code>. Since Java cannot use dashes in names, all the dashes in package folders for namespaces get converted to underscores. The pckage will contain a <code>core.clj</code> file, and its contents should look like the following:<pre><code class="clojure">&#40;ns clojure-test.core&#41;

&#40;defn -main
  &quot;I don't do a whole lot.&quot;
  &#91;&amp; args&#93;
  &#40;println &quot;Hello, World!&quot;&#41;&#41;
</code></pre></p><p>Let's open it and then hit the run button. You should see a REPL pop up momentarily on the bottom of the IDE. If all went well, your project should be ready to work on. The code that's in the file will have already been loaded up in the REPL when we hit run, and we should now be able to call our <code>-main</code> function.</p><p>To do that, let's write the code which calls main below it:<pre><code class="clojure">&#40;-main&#41;
</code></pre></p><p>Then navigate the cursor inside the call body and hit CTRL+ENTER on Linux/Windows or CMD+ENTER on OS X. You should see "Hello, World!" printed in the REPL view on the bottom. We can now change the behavior of the <code>-main</code> function and after it is reloaded the new behavior will be available next time it's called.</p><p>I would also recommend enabling the "strict/paredit" mode under Preferences->Clojure->Editor section. This will allow the editor to keep track of balancing the parens for you. It might seem odd at first, but I highly encourage you to stick with it. </p><p>Another useful feature of the editor is the ability to select code by expression. If you navigate inside a function and press ALT+SHIFT+UP (use CMD instead of ALT in OS X), then inner body of the expression will be selected, pressing it again, will select the expression, and then the outer body, and so on. Conversely pressing ALT+SHIFT+DOWN will narrow the selection. This allows you to quickly navigate nested structures, and select code by chunks of logic as opposed to simply selecting individual lines.</p><p>I've also mentioned the <code>project.clj</code> file in your project folder earlier. This file should look like the following:<pre><code class="clojure">&#40;defproject clojure-test &quot;0.1.0-SNAPSHOT&quot;
  :description &quot;FIXME: write description&quot;
  :url &quot;http://example.com/FIXME&quot;
  :license {:name &quot;Eclipse Public License&quot;
            :url &quot;http://www.eclipse.org/legal/epl-v10.html&quot;}
  :dependencies &#91;&#91;org.clojure/clojure &quot;1.3.0&quot;&#93;&#93;&#41;
</code></pre></p><p>You can add new dependencies to your project by simply sticking them in the dependencies vector. For example, if we wanted to add an HTTP client, we'd go to http://clojuresphere.herokuapp.com/ click on clj-http link. From there select the <a href='http://clojars.org/clj-http/clj-http'>Clojars link</a> and copy the following:<pre><code class="clojure">&#91;clj-http &quot;0.5.2&quot;&#93;
</code></pre></p><p>now we'll simply paste it under dependencies in our <code>project.clj</code>:<pre><code class="clojure">:dependencies &#91;&#91;org.clojure/clojure &quot;1.3.0&quot;&#93;
               &#91;clj-http &quot;0.5.2&quot;&#93;&#93;
</code></pre></p><p>In our package explorer view on the left we should be able to expand "Leiningen dependencies" and see the <code>clj-http</code> jar included there. We will now have to kill our current REPL, to do that navigate to the terminal view next to it and press the stop button. When we start a new instance of the REPL, the library will be available for use. In the core file we can now add it to the namespace:<pre><code class="clojure">&#40;ns clojure-test.core
 &#40;:require &#91;clj-http.client :as client&#93;&#41;&#41;
</code></pre></p><p>and test using the client by typing<pre><code class="clojure">&#40;client/get &quot;http://google.com&quot;&#41;
</code></pre></p><p>and running it as we did earlier. This should cover all the basics of using Clojure with Counterclockwise, and allow you to get hacking on your project.</p><p>I'd also recommend visiting the following sites:</p><ul><li><a href='http://www.4clojure.com/'>4Clojure</a> is an excellent site for practicing small exercises in Clojure. Be sure to make an account and follow some of the top users. When you solve a problem, you'll be able to see how others solve it and get a taste for idiomatic Clojure code.</li><li><a href='http://java.ociweb.com/mark/clojure/article.html'>Clojure - Functional Programming for the JVM</a> is a very comprehensive introduction to Clojure aimed at Java programmers.</li><li><a href='http://clojuredocs.org/'>ClojureDocs</a> is an excellent documentation site for Clojure which contains many examples on using the functions in the standard library.</li><li><a href='http://www.webnoir.org/'>Noir</a> is an great Clojure framework for making web apps, in fact this blog is built on top of it with source available <a href='http://github.com/yogthos/yuggoth'>here</a>.</li></ul><p>There are many other great Clojure sites that I failed to mention here, but the above should provide a good starting point.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Serving RSS with Clojure</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">04 08 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>I recently got invited to join <a href='http://planet.clojure.in/'>Planet Clojure</a>, which is an excellent place for keeping up with what people are up to in Clojure world. As part of being syndicated I had to add an <a href='http://en.wikipedia.org/wiki/RSS'>RSS</a> feed to my blog. A cursory Google search came up with lots of tutorials for parsing RSS, but nothing regarding generating it. Turns out that it's very straight forward and it takes less than a 50 lines of code to create a proper RSS feed for your site.</p><p>First, a bit of background about RSS. Essentially, it's a very simple syndication format designed to allow pushing out notifications about frequently updated content such as blog posts. RSS is served as XML and each feed has to consist of a channel tag with some metadata and item tags, each one describing a specific update such as a new blog post.</p><p>All we have to do to create our RSS feed is to structure the data accordingly and serialize it to XML. Clojure standard library provides a simple way to output XML using the <code>emit</code> function in the <code>clojure.xml</code> namespace. It accepts data in the following format:<pre><code class="clojure">{:tag :tag-name :attrs attrs-map :content &#91;content&#93;}
</code></pre></p><p>The content in the above can contain a mix of strings and tags. One thing to be aware of is that any other content will result in a null pointer exception, so it's one of rare cases where that doesn't get handled gracefully by default. Once we've constructed a proper tag we can serialize it to XML as follows:<pre><code class="clojure">&#40;with-out-str 
  &#40;clojure.xml/emit 
    {:tag :channel :attrs nil :content &#91;&#93;}&#41;&#41;
</code></pre></p><p>which results in<pre><code class="xml">&lt;?xml version='1.0' encoding='UTF-8'?&gt;
&lt;channel&gt;
&lt;/channel&gt;
</code></pre></p><p>Note that <code>emit</code> needs to be wrapped in <code>with-out-str</code> to capture its output into a string. RSS also specifies the format in which time should be output, so we'll make a helper function to handle that:<pre><code class="clojure">&#40;defn format-time &#91;time&#93; 
  &#40;.format &#40;new java.text.SimpleDateFormat 
                &quot;EEE, dd MMM yyyy HH:mm:ss ZZZZ&quot;&#41; time&#41;&#41;
</code></pre></p><p>Writing out the tags by hand gets tedious, so I wrote a macro to output the tags for us: <pre><code class="clojure">&#40;defmacro tag &#91;id attrs &amp; content&#93;
  `{:tag &#126;id :attrs &#126;attrs :content &#91;&#126;@content&#93;}&#41;
</code></pre></p><p>I covered macros briefly in an <a href='http://yogthos.net/blog/14'>earlier post</a>. The only new syntax used here is the <code>&#126;@</code> notation, which simply says that the items in content should be inserted into the enclosing structure, eg:<pre><code class="clojure">&#40;tag :foo nil &quot;foo&quot; &quot;bar&quot; &quot;baz&quot;&#41;
{:tag :foo, :attrs nil, :content &#91;&quot;foo&quot; &quot;bar&quot; &quot;baz&quot;&#93;}
</code></pre></p><p>Armed with this macro let's write the function to describe an individual post. The function accepts the site, the author and a map describing the post as parameters, then generates the appropriate tags as per RSS specification.<pre><code class="clojure">&#40;defn item &#91;site author {:keys &#91;id title content time&#93;}&#93;
  &#40;let &#91;link &#40;str site &quot;/&quot; id &#41;&#93; 
    &#40;tag :item nil
         &#40;tag :guid nil link&#41;
         &#40;tag :title nil title&#41;
         &#40;tag :dc:creator nil author&#41;
         &#40;tag :description nil content&#41;
         &#40;tag :link nil link&#41;
         &#40;tag :pubDate nil &#40;format-time time&#41;&#41;
         &#40;tag :category nil &quot;clojure&quot;&#41;&#41;&#41;&#41;
</code></pre></p><p>Let's test that it does what we expect:<pre><code class="clojure">&#40;item &quot;http://yogthos.net&quot;
      &quot;Yogthos&quot; 
      {:id 1 
       :title &quot;Test post&quot; 
       :content &quot;Some content&quot; 
       :time &#40;new Date&#41;}&#41;

{:content
 &#91;{:content &#91;&quot;http://yogthos.net/1&quot;&#93;, :attrs nil, :tag :guid}
  {:content &#91;&quot;Test post&quot;&#93;, :attrs nil, :tag :title}
  {:content &#91;&quot;Yogthos&quot;&#93;, :attrs nil, :tag :dc:creator}
  {:content &#91;&quot;Some content&quot;&#93;, :attrs nil, :tag :description}
  {:content &#91;&quot;http://yogthos.net/1&quot;&#93;, :attrs nil, :tag :link}
  {:content &#91;&quot;Sat, 04 Aug 2012 18:16:03 -0400&quot;&#93;,
   :attrs nil,
   :tag :pubDate}
  {:content &#91;&quot;clojure&quot;&#93;, :attrs nil, :tag :category}&#93;,
 :attrs nil,
 :tag :item}
</code></pre></p><p>If we pass the above to <code>xml/emit</code> we'll get the corresponding XML. Next we'll need a function which will will create the representation of the channel:<pre><code class="clojure">&#40;defn message &#91;site title author posts&#93;
  &#40;let &#91;date &#40;format-time &#40;new Date&#41;&#41;&#93; 
    &#40;tag :rss {:version &quot;2.0&quot;
               :xmlns:dc &quot;http://purl.org/dc/elements/1.1/&quot;
               :xmlns:sy &quot;http://purl.org/rss/1.0/modules/syndication/&quot;}
         &#40;update-in 
           &#40;tag :channel nil
                &#40;tag :title nil &#40;:title &#40;first posts&#41;&#41;&#41;
                &#40;tag :description nil title&#41;
                &#40;tag :link nil site&#41;
                &#40;tag :lastBuildDate nil date&#41;
                &#40;tag :dc:creator nil author&#41;
                &#40;tag :language nil &quot;en-US&quot;&#41;
                &#40;tag :sy:updatePeriod nil &quot;hourly&quot;&#41;
                &#40;tag :sy:updateFrequency nil &quot;1&quot;&#41;&#41;
           &#91;:content&#93;
           into &#40;map &#40;partial item site author&#41; posts&#41;&#41;&#41;&#41;&#41;
</code></pre></p><p>Again, this is fairly straight forward, the function takes the site url, blog title, the author and the posts. Then it creates the necessary tags to describe the channel and inserts the formatted posts into it. We should now be able to generate valid RSS content by calling it with some data:<pre><code class="clojure">&#40;message &quot;http://yogthos.net&quot; &quot;My blog&quot; &quot;Yogthos&quot; 
         &#91;{:id 1 
           :title &quot;Test post&quot; 
           :content &quot;Some content&quot; 
           :time &#40;new Date&#41;}&#93;&#41;

{:content
 &#91;{:content
   &#91;{:content &#91;&quot;Test post&quot;&#93;, :attrs nil, :tag :title}
    {:content &#91;&quot;My blog&quot;&#93;, :attrs nil, :tag :description}
    {:content &#91;&quot;http://yogthos.net&quot;&#93;, :attrs nil, :tag :link}
    {:content &#91;&quot;Sat, 04 Aug 2012 18:23:06 -0400&quot;&#93;,
     :attrs nil,
     :tag :lastBuildDate}
    {:content &#91;&quot;Yogthos&quot;&#93;, :attrs nil, :tag :dc:creator}
    {:content &#91;&quot;en-US&quot;&#93;, :attrs nil, :tag :language}
    {:content &#91;&quot;hourly&quot;&#93;, :attrs nil, :tag :sy:updatePeriod}
    {:content &#91;&quot;1&quot;&#93;, :attrs nil, :tag :sy:updateFrequency}
    {:content
     &#91;{:content &#91;&quot;http://yogthos.net/blog/1&quot;&#93;, :attrs nil, :tag :guid}
      {:content &#91;&quot;Test post&quot;&#93;, :attrs nil, :tag :title}
      {:content &#91;&quot;Yogthos&quot;&#93;, :attrs nil, :tag :dc:creator}
      {:content &#91;&quot;Some content&quot;&#93;, :attrs nil, :tag :description}
      {:content &#91;&quot;http://yogthos.net/blog/1&quot;&#93;, :attrs nil, :tag :link}
      {:content &#91;&quot;Sat, 04 Aug 2012 18:23:06 -0400&quot;&#93;,
       :attrs nil,
       :tag :pubDate}
      {:content &#91;&quot;clojure&quot;&#93;, :attrs nil, :tag :category}&#93;,
     :attrs nil,
     :tag :item}&#93;,
   :attrs nil,
   :tag :channel}&#93;,
 :attrs
 {:version &quot;2.0&quot;,
  :xmlns:dc &quot;http://purl.org/dc/elements/1.1/&quot;,
  :xmlns:sy &quot;http://purl.org/rss/1.0/modules/syndication/&quot;},
 :tag :rss}
</code></pre></p><p>Finally, we'll write a function which converts the message to XML:<pre><code class="clojure">&#40;defn rss-feed &#91;site title author posts&#93;
  &#40;with-out-str &#40;emit &#40;message site title author posts&#41;&#41;&#41;&#41;
</code></pre></p><p>We can confirm that we're generating valid content by pasting it to <a href='http://validator.w3.org/feed/#validate_by_input'>W3C Feed Validation Service</a>. This is all that's needed to create a valid RSS message. It can now be served over HTTP using your favorite library or framework. </p><p>Complete code for the example can be found <a href='https://gist.github.com/3260456'>here</a>.</p><h2 id="updates">Updates</h2><p>I've since rolled all of the above into a (hopefully :) friendly <a href='https://github.com/yogthos/clj-rss'>clj-rss</a> library.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Noir tricks</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">02 08 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>This blog is built on top of <a href='http://www.webnoir.org/'>Noir</a>, which is quite excellent for the most part. However, I did run into one problem which I spent a bit of time on. I'd like to share my workarounds to save others time.</p><p>First issue I noticed is that <code>response/redirect</code> doesn't respect the servlet context. This means that if you're not deploying your app to the root context, your redirects will not work properly. </p><p>After some digging and questions on the Google groups I found out that the offending function is <code>resolve-url</code> in <code>noir.options</code> namespace. When it builds the URL string it doesn't check for the context and as such the resulting URL ends up redirecting to the root of the app server regardless of what context the servlet was deployed at.</p><p>My workaround for this is a bit of a hack, and if anybody has a better solution I'd love to know, but it works well for most purposes. In my <code>server.clj</code> I added a new handler wrapper, which redefines the offending function with one that checks if the URL is relative and prepends the context to it as needed.<pre><code class="clojure">&#40;defn fix-base-url &#91;handler&#93;
  &#40;fn &#91;request&#93;
    &#40;with-redefs &#91;noir.options/resolve-url 
                  &#40;fn &#91;url&#93; 
                    ;prepend context to the relative URLs
                    &#40;if &#40;.contains url &quot;://&quot;&#41;
                      url &#40;str &#40;:context request&#41; url&#41;&#41;&#41;&#93;
      &#40;handler request&#41;&#41;&#41;&#41;
</code></pre></p><p>A related issue is that <code>pre-route</code> doesn't respect the context either. I decided to simply write a macro for defining private pages:<pre><code class="clojure">&#40;defmacro private-page &#91;path params &amp; content&#93;
  `&#40;noir.core/defpage 
     &#126;path 
     &#126;params 
     &#40;if &#40;session/get :admin&#41; 
       &#40;do &#126;@content&#41; &#40;resp/redirect &quot;/&quot;&#41;&#41;&#41;&#41;
</code></pre></p><p>An added advantage of the macro is that I don't have to remember to update <code>pre-routes</code> when I want to make a page private. </p><p>Also, there are a couple of things to be aware of if you wish to make a WAR. Make sure that all your views are required in your server namespace, <code>:gen-class</code> is set and that <code>server/load-views-ns</code> is used instead of <code>server/load-views</code>:<pre><code class="clojure">&#40;ns yuggoth.server
  &#40;:require 
   ...
   &#91;yuggoth.views archives auth blog comments common profile rss upload&#93;&#41;
   &#40;:gen-class&#41;&#41;

&#40;server/load-views-ns 'yuggoth.views&#41;
</code></pre></p><p>In your project.clj add the following:<pre><code class="clojure">:ring {:handler yuggoth.server/handler}
</code></pre></p><p>With the above in place you can build an uberwar with<pre><code class="bash">lein ring uberwar
</code></pre></p><p>The resulting WAR should deploy on any app server such as Tomcat or Glassfish without problems. Aside from the above quirks, I haven't run into any other issues with Noir, and I'm absolutely in love with it. </p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">open access</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">31 07 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Sometimes you might run into a situation where you're using a library which defines a certain function in a way that might not work the way you need it to in a particular context. To make things worse, this function might be used by the library internally, so you can't simply write your own version and use it. </p><p>In some languages it's possible to use <a href='http://en.wikipedia.org/wiki/Monkey_patch'>monkey patching</a> to get around this problem. This approach allows you to simply redefine the offending function at runtime with your own version. The downside of this approach is that the change is global and as such might interact poorly with other code which expects the original version.</p><p> In Clojure it's possible redefine an existing function in a particular context using <code>with-redefs</code>. This approach gives us the ability to make runtime modifications in a safer fashion where we know exactly what code is affected. </p><p>Let's look at an example where we have a <code>get-data</code> function defined in namespace <code>foo</code> which is used by <code>display-results</code> in namespace <code>bar</code>. When we write tests for <code>bar</code> we would like to use preset test data instead of calling out to the database:<pre><code class="clojure">&#40;ns foo&#41;

&#40;defn get-data &#91;&#93;
  ;gets some data from a db
  &#41;

&#40;ns bar
 &#40;:require foo&#41;&#41;

&#40;defn display-results &#91;&#93;
  &#40;apply str &#40;interpose &quot;, &quot; &#40;foo/get-data&#41;&#41;&#41;&#41;

&#40;ns tests
  &#40;:use clojure.test&#41;
  &#40;:require foo bar&#41;&#41;

&#40;deftest display-results-test
  &#40;with-redefs &#91;foo/get-data &#40;fn&#91;&#93; &#91;&quot;Doe&quot;, &quot;John&quot;&#93;&#41;&#93;
    &#40;is &#40;= &quot;Doe, John&quot; &#40;bar/display-results&#41;&#41;&#41;&#41;&#41;
</code></pre></p><p>Now any code that references <code>foo/get-data</code> inside the <code>with-redefs</code> scope will get <code>&#91;&quot;Doe&quot;, &quot;John&quot;&#93;</code> as a result. </p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">a look at macros</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">27 07 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Lisp macros can be rather confusing and especially so for newcomers. In fact, the rule of thumb is not to use macros if you can avoid them. That said, macros can be an incredibly powerful tool and have innumerable uses. I'd like to give a concrete example of a macro that I'm using in this blog engine.</p><p>I wanted to be able to cache page content in memory, so that the page doesn't need to be generated for every single request. This means that before rendering a page I want to check if the page is in my cache, and if the cache hasn't expired then serve the cached page, otherwise render a new version and cache it.</p><p>First I created an atom which would store the cached content:<pre><code class="clojure">&#40;def cache &#40;atom {}&#41;&#41;
</code></pre></p><p>Next I wrote the cache logic for the <code>/blog</code> page:<pre><code class="clojure">&#40;defpage &quot;/blog/:postid&quot; {:keys &#91;id&#93;}
  &#40;let &#91;last-updated &#40;:time &#40;get @cache id&#41;&#41;
        cur-time     &#40;.getTime &#40;new java.util.Date&#41;&#41;&#93;

    &#40;if &#40;or &#40;nil? last-updated&#41;
            &#40;&gt; &#40;- cur-time last-updated&#41; 10000&#41;&#41;
      &#40;swap! cache assoc id {:time cur-time 
                             :content &#40;entry &#40;db/get-post id&#41;&#41;}&#41;&#41;
    &#40;:content &#40;get @cache id&#41;&#41;&#41;
</code></pre></p><p>Obviously, we don't want to repeat this logic each time we wish to cache something, and we'd like an easy way to modify existing functions to allow caching. Here's where macros come in. One property of macros is that, unlike functions, they do not execute the s-expressions which are passed in. Let's look at how this works in practice:<pre><code class="clojure">&#40;defn foo &#91;&#93; &#40;println &quot;foo was called&quot;&#41;&#41;

&#40;defn bar &#91;f&#93;&#41;

&#40;bar &#40;foo&#41;&#41;

=&gt;foo was called
</code></pre></p><p>Here <code>foo</code> is executed as we would expect and "foo was called" is printed, but what happens if we make bar a macro instead?<pre><code class="clojure">&#40;defmacro bar &#91;f&#93;&#41;
&#40;bar &#40;foo&#41;&#41;
=&gt;
</code></pre></p><p>This time nothing is printed! In a macro the parameters are treated as data and are not evaluated unless we explicitly choose to do so:<pre><code class="clojure">&#40;defmacro bar &#91;f&#93; f&#41;
&#40;bar &#40;foo&#41;&#41;
=&gt;foo was called
</code></pre></p><p>A macro allows us to change code before it is compiled, and at compile time it is replaced with its output. We can check this by running <code>macroexpand</code>:<pre><code class="clojure">&#40;macroexpand '&#40;bar &#40;foo&#41;&#41;&#41;
=&gt;&#40;foo&#41;
</code></pre></p><p>We can see that <code>&#40;bar &#40;foo&#41;&#41;</code> simply gets replaced with <code>&#40;foo&#41;</code> which is what our macro is returning. While the previous version would evaluate to nil, and <code>foo</code> would never be executed.</p><p>As you might have guessed by now, we can pass any s-expression to a macro and then decide inside the macro whether we'd like to evaluate it. So, let's see how we can use this to make our caching macro:<pre><code class="clojure">&#40;defmacro cache &#91;id content&#93;
  `&#40;let &#91;last-updated# &#40;:time &#40;get @cached &#126;id&#41;&#41;
         cur-time#     &#40;.getTime &#40;new java.util.Date&#41;&#41;&#93;

      &#40;if &#40;or &#40;nil? last-updated#&#41;
              &#40;&gt; &#40;- cur-time# last-updated#&#41; 10000&#41;&#41;
        &#40;swap! cached assoc &#126;id {:time cur-time#
                                 :content &#126;content}&#41;&#41;
      &#40;:content &#40;get @cached &#126;id&#41;&#41;&#41;&#41;
</code></pre></p><p>We can move the logic which checks if we should use a cached value into our macro and pass in the id and the s-expression to run if cache needs to be updated. The code looks very similar to our original version, except for a few new symbols. First thing you'll notice is that we used ` in front of our <i>let</i> expression, this quotes the body of the expression. The # at the end of the binding names ensures that the names are unique and won't collide with other symbols at compile time. Finally ~ says that the next expression should be unquoted.</p><p>Let's run <i>macroexpand</i> again to make sure our macro is outputting something reasonable:<pre><code class="clojure">&#40;pprint &#40;macroexpand '&#40;cache postid &#40;entry &#40;get-post postid&#41;&#41;&#41;&#41;&#41;

&#40;let&#42;
 &#91;last-updated&#95;&#95;1294&#95;&#95;auto&#95;&#95;
  &#40;:time &#40;clojure.core/get @agents/cached postid&#41;&#41;
  cur-time&#95;&#95;1295&#95;&#95;auto&#95;&#95;
  &#40;.getTime &#40;new java.util.Date&#41;&#41;&#93;
 &#40;if
  &#40;clojure.core/or
   &#40;clojure.core/nil? last-updated&#95;&#95;1294&#95;&#95;auto&#95;&#95;&#41;
   &#40;clojure.core/&gt;
    &#40;clojure.core/- cur-time&#95;&#95;1295&#95;&#95;auto&#95;&#95; last-updated&#95;&#95;1294&#95;&#95;auto&#95;&#95;&#41;
    10000&#41;&#41;
  &#40;clojure.core/swap!
   agents/cached
   clojure.core/assoc
   postid
   {:content &#40;entry &#40;get-post postid&#41;&#41;, :time cur-time&#95;&#95;1295&#95;&#95;auto&#95;&#95;}&#41;&#41;
 &#40;:content &#40;clojure.core/get @agents/cached postid&#41;&#41;&#41;
</code></pre></p><p>This definitely looks like the logic we're expecting. Any time we use this macro, it will be replaced with the code similar to the above, where the s-expression is inside the <i>if</i> block, and only gets called if cache needs to be updated. Now we can easily cache any s-expressions with minimal change to the original code and all the caching logic sits in one convenient place:<pre><code class="clojure">&#40;defpage &quot;/blog/:postid&quot; {:keys &#91;postid&#93;}
  &#40;cache postid &#40;entry &#40;db/get-post postid&#41;&#41;&#41;&#41;
</code></pre></p><p>As I've mentioned before, there are many other uses for macros, but I hope this gives a clear example of a concrete situation where a macro facilitates cleaner code and provides an easy way to avoid repetition.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">less is more</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">20 07 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>An expressive language has many benefits. The most obvious one is that you have to write less code to solve your problem. The reason you write less code is often not because the syntax is more terse, but because you're using better abstractions. For example, instead of writing a loop, you can use an iterator function to do the work:</p><pre><code class="clojure">&#40;loop &#91;count 0
         &#91;head &amp; tail&#93; items&#93;
    &#40;if tail
      &#40;recur &#40;+ count head&#41; tail&#41;
      &#40;+ count head&#41;&#41;&#41;

&#40;reduce + items&#41;
</code></pre><p>One non-obvious benefit of having less code is that it makes it much easier to throw code away. In a verbose language where you have to write a lot of code to solve simple problems, you tend to become attached to that code. In a language where you can express complex things in a relatively few lines, it's not a big issue to replace those with a few different lines. This encourages refactoring as you go, instead of waiting until you have a mountain of code accumulated and you really need to do something about it.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">perfection</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">20 07 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>There's a quote by Antoine de Saint-Exupery that says: "Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away". I think any experienced programmer can relate to that. You always strive to find the most elegant solution which describes the problem simply and clearly. </p><p>A lot of novice programmers have a habit of writing clever code which uses some esoteric properties of the language, or other tricks to get the job done. An experienced programmer knows that the real cleverness lies in being able to solve a problem with very simple code, that might even seem obvious in retrospect. </p><p>Eventually one develops an intuition for coming up with solutions which do not involve kludges, avoid edge cases, and forgo cleverness in favor of simplicity. Sometimes, however, this can lead to paralysis, where you don't yet know the elegant solution and you are unwilling to write down the one you know to be imperfect.</p><p>I find that REPL development is a great tool for overcoming this dilemma. You can quickly start experimenting with your problem, and through the experimentation gain the understanding necessary to implement it properly. At this point you can  easily refactor your existing ugly solution into something beautiful. </p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">all things being equal</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">13 07 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>You might have heard terms such as <a href='http://en.wikipedia.org/wiki/Anonymous_function'>anonymous functions</a>, <a href='http://en.wikipedia.org/wiki/First-class_function'>first class functions</a>,  <a href='http://en.wikipedia.org/wiki/Higher-order_function'>higher order functions</a>, and <a href='http://en.wikipedia.org/wiki/Closure_%28computer_science%29'>closures</a>. These might sounds mathy and imposing, but they're very simple ideas. In fact, I'll argue that they make the language simpler and more consistent.</p><p>In some languages there's a distinction between a function and a variable. You can assign variables, pass them in as parameters, and return them. Yet when it comes to functions, all you can do is define them and call them. </p><p>If you take a moment to think about it, I think you'll agree that this distinction is fairly arbitrary. There's no practical reason why we shouldn't be able to do all the things we do with variables with functions. </p><p>Let's look at some things that become possible once this distinction is erased. Sometimes we like to use values inline and not assign them to a variable, we usually do this because the value is only going to appear once, and we don't want to go through the ceremony of naming it.</p><p>If our language supports anonymous functions, we can do the same thing with a small piece of logic. If it's only needed in a single situation then we can make an anonymous function and call it directly:<pre><code class="clojure">    &#40;&#40;fn &#91;x&#93; &#40;&#42; 2 x&#41;&#41; 5&#41;
    10
</code></pre></p><p>Here we created an anonymous function which takes a value and multiplies it by 2, and we passed 5 to it as a parameter. Just as we name values which we reuse in multiple places, so can we name functions:<pre><code class="clojure">    &#40;def times-2 &#40;fn &#91;x&#93; &#40;&#42; 2 x&#41;&#41;&#41;
</code></pre></p><p>and then call them by their name instead<pre><code class="clojure">    &#40;times-2 5&#41;
    10
</code></pre></p><p>The other thing we said that we can do with variables is pass them as parameters to functions. By being able to pass functions to other functions, we're able to decompose our logic into smaller chunks. </p><p>If we takes our <code>times-2</code> function and pass it in as a parameter to an iterator function such as map, it in turn can apply it to each element in a collection:<pre><code class="clojure">    &#40;map times-2 '&#40;1 2 3 4&#41;&#41;
    &#40;2 4 6 8&#41;
</code></pre></p><p>You might recognize this as the <a href='http://en.wikipedia.org/wiki/Strategy_pattern'>strategy pattern</a> from OO. Turns out that all the complexity in the pattern comes from the idea of treating functions as second class citizens. Which brings us to the idea of a first class function. All that means is that a function is treated no differently than a variable. The only other thing we haven't defined is the higher order function, <code>map</code> in the above example is such a function. Once again, there's nothing complicated about the concept. Any function which can accept another function as a parameter is a higher order function.</p><p>Finally, what happens if functions can return functions as output. There are many uses for this, but I'd like to focus on one that will be familiar from OO. When we create a class we often use a constructor to initialize some data that will be available to the methods of the instantiated object. </p><p>In a functional language we can achieve this by having a function which takes some parameters and returns another function. Because the inner function was defined in scope where the parameters are declared it too can access them. Here's an example:<pre><code class="clojure">    &#40;defn foo &#91;x&#93;
      &#40;fn &#91;y&#93; &#40;&#42; x y&#41;&#41;&#41;

    &#40;&#40;foo 2&#41; 5&#41;
    10
</code></pre></p><p>Function <code>foo</code> accepts parameter <code>x</code> and returns an anonymous function which in turn accepts a parameter <code>y</code> and multiplies them together. Function <code>foo</code> is said to <i>close over</i> its parameters, and hence it's called a closure. Unlike a constructor a closure does not introduce any special cases. It's just a function that returns a result which itself happens to be a function.</p><p>Treating functions as first class citizens makes the language more uniform. Instead of having special constructs for specific cases, we have a general purpose tool that we can apply in many situations. </p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">limits of mutation</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">12 07 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>When you start learning functional programming you will quickly notice that you can't simply mutate data in place as you might be used to. Initially you might find this odd and restrictive, but it turns out there are also some tangible benefits to this approach.</p><p>Mutable data structures are very simple in nature. They reference a location in memory where some value can be stored, when that value changes the old one is simply replaced with the new.</p><p><a href='http://en.wikipedia.org/wiki/Persistent_data_structure'>Persistent data structures</a> create revisions of the data when changes are made. We pay a small penalty in performance compared to in place mutation, but we gain a history of changes that exists as long as its referenced somewhere. </p><p>This means that if a function accepts some data as a parameter, you don't have to worry if anybody else is referencing that data when you work with it. Any time you change the data you get a new version without paying the penalty of copying it. By contrast, we always have to be aware if a reference may be used else where when working with mutable data. By removing this worry, we can reduce the scope of things that we need to keep in our heads when trying to understand what a particular piece of code does. </p><p>The benefits stack up as your project grows, as it becomes infeasible to keep the totality of the code in ones head. And it's a huge benefit when working in a threaded environment and shared data can easily be corrupted.</p><p>What might seem like an inconvenience at first turns out to be a net benefit. Ensuring that the data is not modified outside the intended context has been offloaded to the language instead of being done by you manually. I would liken this to use of garbage collection, where the language is responsible for most memory reclamation. In both cases it's better to let the machine do tasks that can be automated leaving you to solve the real problems.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">we&#39;ll do it live!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">10 07 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>One thing I love about working in Clojure is how interactive the development environment is. Clojure being a Lisp provides a REPL (read, evaluate, print, loop), which works exactly like it sounds. You send an expression to the reader, which will then evaluate it, print the result, and wait for another expression to read.</p><p>Clojure IDEs provide tight integration with the REPL. It is possible to connect your application to it and have it load all the libraries and dependencies. At this point you can write your new code in the IDE and have the REPL evaluate it in the context of your running application.</p><p>In non-trivial applications it's often necessary to build up a particular state before you can add more functionality. For example a user has to login then view some data from a backend, then you need to write functions to format and display this data. With a REPL you can get the application to the state where the data is loaded and then write the display logic interactively without having to reload the application every time you make a change.</p><p>I find this method of development a lot more satisfying, as you get immediate feedback from your application when you add or modify code, and you can easily try things and see how they work. It encourages extermination and refactoring code as you go, which I think helps write better and cleaner code. </p><p>This technique is common in Lisp and Smalltalk development, but for reasons unknown has not penetrated into mainstream languages.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">lost in patterns</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">09 07 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Design patterns are heavily used in the OO world, and there are many lengthy books written about them. I'd like to examine why this is and what these patterns stem from exactly. </p><p>As the name implies, design patterns are templates for structuring code to solve common problems. This is a fine idea in and of itself, but the following question needs to be asked. If programming is ultimately about automation, and patterns are repetitive tasks by their very nature, then why are we forced to write them out by hand each time?</p><p>The reason for this appears to be due to lack of abstraction in the language. Many design patterns are simply specific cases of an underlying abstraction which unifies them. Having a language which can express such abstractions means that you don't have to learn many different patterns for specific situations. </p><p>Bruce Lee once said "I fear not the man who has practiced ten thousand kicks once. But I fear the man who has practiced one kick ten thousand times". I think this applies here as well: it's better to learn a general solution for many problems, than to have a specific solution for each small problem you run into.</p><p>So, next time you're looking at a language, don't simply look at the one that has the bigger list of features, instead look for one with a few features that work well together.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">living in a structured world</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">08 07 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>If you've seen any Lisp code before, you've probably noticed that it looks different from other languages in that the parens come before the function name, prefix notation is prevalent, and that functions are often nested inside one another. The technical term for this is that Lisp uses <a href='http://en.wikipedia.org/wiki/S-expression'>s-expressions</a>. </p><p>These might look awkward at first, and many newcomers immediately think that they can and should be improved upon. Surely it would be easy to write a preprocessor that would let you write code as you write it in other languages and then convert it to s-expressions. This is absolutely true and in fact there is one prominent attempt called <a href='http://www.dwheeler.com/readable/sweet-expressions.html'>sweet-expressions</a>. Despite all that, the idea just doesn't catch on and I'd like to explore what the advantages of working with raw s-expressions are.</p><p>One immediate benefit is that Lisp syntax follows the <a href='http://en.wikipedia.org/wiki/Principle_of_least_astonishment'>principle of least astnoishment</a> very well. Any time you read code, it always follows the pattern of <code>&#40;function-name arguments&#41;</code>,  which makes for very consistent looking code. This helps reduce the mental overhead when reading and writing code, instead of worrying about language quirks you can focus on the actual problem you're solving.</p><p>Another benefit is that the code provides extra information about itself, which is not available in other languages. With s-expressions you can visually see how functions relate to one another. In essence the code is rendered as a tree representing the execution logic.</p><p>Finally, the s-expressions make editing code a completely different experience from other languages. Instead of working in terms of lines, you work in terms of functions. With a <a href='http://emacswiki.org/emacs/ParEdit'>ParEdit</a> style editor you can select code not by line but by function! Now you can easily select, move, and reparent pieces of logic. Editing code becomes like playing with Lego pieces and arranging them in different ways.</p><p>In my experience these things make the language more enjoyable to work with and the benefits far outweigh any perceived ugliness. After a while you don't even see the parens.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Temporally oblivious</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">04 07 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Objects are state machines, yet no mainstream OO language ensures the consistency of the internal state of the object over time. This means that in a multi-threaded environment it's possible to see the internal state of the object while it's being updated. What's even worse is that even if you don't see a partial state, you might be seeing an unexpected state, since someone else with a reference to the object might have updated it for their use, which conflicts with the way you're using it.</p><p>The whole situation is fairly messy, but what is the alternative you might ask. My answer would be not to use in place mutation unless absolutely necessary. Instead it's much better to use <a href='http://en.wikipedia.org/wiki/Persistent_data_structure'>persistent data structures</a>, which <em>are</em> temporally aware. A persistent data structure works in a fashion akin to version control. Any time a change to the data is made, a delta is created between the existing data and the new data. From user perspective you're simply copying the data, but you're only paying the price of the change.</p><p>This concept turns out to be very powerful as it inherently contextualizes any changes. It also allows doing things like rollbacks trivially as you just have to unwind your operations to see a previous state.<br /></p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">why all the parens</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">28 06 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>A common complaint you hear from people about Lisp is that there are too many parens. Let's compare what's involved in writing a Java method to writing a Clojure function:<pre><code class="java">    public static void foo&#40;String bar, Integer baz&#41; {
        System.out.println&#40;bar + &quot;, &quot; + baz&#41;;
    }
</code></pre></p><pre><code class="clojure">    &#40;defn foo &#91;bar baz&#93; 
      &#40;println bar &quot;, &quot; baz&#41;&#41;
</code></pre><p>The number of parens is exactly the same, but there's clearly more noise in the Java version. In my opinion the noise adds up and it distracts from the intent of the code. The more code you have the harder it is to tell what it's doing and conversely the harder it is to spot bugs in it. I'll illustrate this with a concrete example. </p><p>The problem is to display a formatted address given the fields representing it. Commonly an address has a street, a city, a postal code, and a country. We'll have to examine each of these pieces, remove the null and empty ones and insert some separator between them.</p><p>So given something like</p><pre><code>street: 1 Main street
city: Toronto
posal: A1B 2C3
country: Canada</code></pre><p>we'd like to output</p><pre><code>1 Main street, Toronto, A1B 2C3, Canada</code></pre><p>we should obviously handle empty fields and not have <em>,,</em> if the field isn't there, and we should make sure we handle nulls in case the whole address is null or some fields in the address are null.</p><p>Let's first examine how we would write this in Java:<pre><code class="java">    public static String concat&#40;String... strings&#41; {
        if &#40;null == strings&#41; return null;
        StringBuffer sb = new StringBuffer&#40;&#41;;
        for &#40;String s : strings&#41; {
            if &#40;null == s || s.equals&#40;&quot;&quot;&#41;&#41; continue;
            sb.append&#40;s&#41;;
            sb.append&#40;','&#41;;
        }
        String s =  sb.toString&#40;&#41;;
        return s.substring&#40;0, s.lastIndexOf&#40;','&#41;&#41;;
    }
</code></pre></p><ul><li>lines of code : 11</li><li>parens: 26</li><li>curly braces: 4</li><li>semicolons: 7</li><li>colons: 1</li><li>dots: 6</li></ul><p>Now let's compare this to Clojure:<pre><code class="clojure">    &#40;defn concat-fields &#91;&amp; fields&#93;
      &#40;apply str &#40;interpose &quot;,&quot; &#40;remove empty? fields&#41;&#41;&#41;&#41;
</code></pre></p><ul><li>lines of code : 2</li><li>parens: 8</li><li>brackets: 2</li></ul><p>The Clojure version has significantly less code, and a lot less noise. In addition, we didn't have to do any explicit null checks in our code, and we were able to write the complete solution simply by composing together functions from the standard library!</p><p>One very important difference between the Java version and the Clojure version is that the Java version talks about <strong>how</strong> something is being done, while the Clojure version talks about <strong>what</strong> is being done. In other words, we have to step through the Java version in our heads to understand what the code is doing. </p><p>In the Clojure version this step is not present because the code says what it's doing, and all the implementation details have been abstracted from us. This is code reuse at work, where we can write simple functions that do one thing well and chain them together to achieve complex functionality. </p><p>This bears a lot of resemblance with the Unix philosophy: "<a href='http://en.wikipedia.org/wiki/Unix_philosophy'>Write programs that do one thing and do it well. Write programs to work together. Write programs to handle text streams, because that is a universal interface.</a>" Except in our case we're dealing with functions instead of programs and common data structures as a universal interface in the language.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">popularity contests</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">23 06 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The argument that Lisp is not popular because it's somehow a bad language is not really sound. A lot of great technologies have lost out to inferior ones because of poor marketing. The Lisp community has not in general been great at marketing the language, and it is viewed as downright scary by majority of people. </p><p>It also doesn't help that there is no definitive standard distribution of Lisp, or a comprehensive standard library. Most people aren't going to jump through hoops to learn an esoteric language. So, it is no surprise that there aren't a lot of big commercial Lisp projects. It becomes a catch 22, where due to lack of Lisp developers companies develop apps in more popular languages, and people don't bother learning Lisp because there are no jobs for it.</p><p>Clojure avoids a lot of the pitfalls by running on the JVM and interfacing with Java. Java is rather dominant in the industry, a lot of companies already use it, and using alternative languages on the JVM is also becoming a fairly common practice. Strong Java integration also means that you have access to a great wealth of existing libraries. </p><p>Having the ability to introduce Clojure in an existing project without having to change your environment is a huge plus. You can continue to use the same build tools, the same IDE, and same application servers for deployment. The only thing that changes is the actual language.</p><p>From the language design perspective I think it is also an improvement over the traditional Lisp syntax. For example let's compare <code>let</code> in CL to <code>let</code> in Clojure:<pre><code class="clojure">    &#40;let 
      &#40;&#40;a1 b1&#41; 
       &#40;a2 b2&#41; 
       &#40;an bn&#41;&#41;
      &#40;some-code a1 a2 an&#41;&#41;

    &#40;let &#91;a1 b1
          a2 b2
          an bn&#93;
      &#40;some-code a1 a2 an&#41;&#41;
</code></pre></p><p>To me Clojure version is easier to read because there's less noise, and I find the literal vector notation helps break up the code visually. Which brings me to the second thing I like, having literal vector, set, and map notation. I find it makes code more legible and helps see what's going on in a function.</p><p>The next thing I really like, that Clojure introduces, is destructuring. You can take any arbitrary data structure and read it backwards. Here are a few examples of what I'm talking about:<pre><code class="clojure">    &#40;def {:a &#91;1 2 3&#93; :b {:c 4} :d 5}&#41;

    &#40;defn foo &#91;{a :a b :b}&#93;
      &#40;println a b&#41;&#41;

    &#40;defn bar &#91;{:keys &#91;a b d&#93;&#93;
      &#40;println a b d&#41;&#41;

    &#40;defn baz &#91;{&#91;a b c&#93; :a {d :c} :b e :d}&#93;
      &#40;println a b c&#41;&#41;
</code></pre></p><p>this also works in <code>let</code> statements, and again I find that it improves readability, especially in larger programs. While a minor nitpick I also like the naming conventions in Clojure standard library better. Names such as <code>car</code> and <code>cdr</code> are archaic in my opinion.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">why you shouldn&#39;t jump through loops</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">17 06 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>In Java passing logic as a parameter requires an inordinate amount of work and it's never the first choice to do so. So in most cases you're better off just writing a loop and doing the null check in it. Let's look at a concrete example of what I'm talking about here. Let's say we want to filter collections based on a predicate. The standard way you would do that in Java is to write a loop:<pre><code class="java">public static List&lt;Integer&gt; filterEven&#40;Collection&lt;Integer&gt; col&#41; {
    if &#40;null == col&#41; return null;
    List&lt;Integer&gt; result = new LinkedList&lt;Integer&gt;&#40;&#41;;
    for &#40;Integer i  : col&#41; {			
        if &#40;i % 2 == 0&#41; result.add&#40;i&#41;;			
     }		
     return result;
}
</code></pre></p><p>then if later I need to filter odd numbers I'll probably write another loop that looks almost identical except for the actual test. Obviously, the looping logic should be abstracted here, but let's look at what's involved in doing that in Java:<pre><code class="java">public interface Predicate&lt;T&gt; {
    public boolean matches&#40;T t&#41;;
}

public class EvenPredicate implements Predicate&lt;Integer&gt; {
	
    public boolean matches&#40;Integer i&#41; {
 	return i % 2 == 0; 
    }			
}

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

public class Filter {

    public static &lt;T&gt; List&lt;T&gt; filterCollection&#40;Collection&lt;T&gt; col, 
                                          Predicate&lt;T&gt; predicate&#41; {
        List&lt;T&gt; result = new LinkedList&lt;T&gt;&#40;&#41;;
	    for &#40;T t : col&#41; {			
                    if &#40;predicate.matches&#40;t&#41;&#41; {
                        result.add&#40;t&#41;;
                    }
            }		
            return result;
    }
}
</code></pre></p><p>That's a lot more work than just writing a loop, and unless you saw this pattern many times you probably wouldn't consider doing it. Now let's compare this to a language like Clojure, where I would use a higher order function and pass in the matcher without having to do any preliminary setup:<pre><code class="clojure">&#40;filter even? &#40;range 10&#41;&#41;
</code></pre></p><p>what if I wanted to write a loop to do that<pre><code class="clojure">&#40;loop &#91;nums &#40;range 10&#41;
       even-nums &#91;&#93;&#93;
    &#40;if &#40;empty? nums&#41;
        even-nums
        &#40;recur &#40;rest nums&#41; 
                  &#40;if &#40;even? &#40;first nums&#41;&#41; 
                     &#40;conj even-nums &#40;first nums&#41;&#41; even-nums&#41;&#41;&#41;&#41;
</code></pre></p><p>all of a sudden the situation is reversed, it's <i>a lot</i> more code to do explicit looping, and it's trivial to use a higher order function to do this task. So the language encourages you to write code through function composition by design. Being able to easily separate iteration from the logic applied inside it means that we can write code that's shorter, cleaner, and less error prone.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">I don&#39;t need a method to function</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">05 06 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Instance methods are always associated with a particular object that may or may not exist. This means that before we can call a method we must first check if an object is null. This becomes especially tedious if you have nested objects. For example if we have a following situation:<pre><code class="java">    users.getUser&#40;&quot;foo&quot;&#41;.getAddress&#40;&#41;.getStreet&#40;&#41;;
</code></pre></p><p>the above code would be unsafe, since every single method call could potentially lead to a null pointer. This means that we have to instantiate and check each object individually:<pre><code class="java">    String street = null;
    User user = users.getUser&#40;&quot;foo&quot;&#41;;
    if &#40;null != user&#41;
       Address address = user.getAddress&#40;&#41;;
       if &#40;null != address&#41;
           street = address.getStreet&#40;&#41;;
</code></pre></p><p>Not only is this tedious and error prone, but it's also one more thing that you actively have to think about.</p><p>Let's compare this situation to the functional approach. In a functional language functions exist independent of data, much like static methods in OO. This means that we can't get a null pointer while calling a function. The author of the function can do all the error checking in the function <strong>once</strong>, and the user does not need to worry about it. When you chain such functions together, the null values can bubble up as the result:<pre><code class="clojure">    &#40;:street &#40;:address &#40;:foo users&#41;&#41;&#41;
</code></pre></p><p>This code will not throw any null pointer exceptions, and instead a null value will be returned. It has less noise, it's less error prone, and it's easier to read.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Anatomy of a Reducer</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">15 05 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Last time, <a href="xref/../../08/reducers">I blogged</a> about Clojure&#8217;s new <a href="https://github.com/clojure/clojure/blob/master/src/clj/clojure/core/reducers.clj">reducers library</a>. This time I&#8217;d like to look at the details of what constitutes a reducer, as well as some background about the library.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_whats_a_reducing_function"><a class="anchor" href="#_whats_a_reducing_function"></a>What&#8217;s a Reducing Function?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The reducers library is built around transforming reducing functions. A reducing function is simply a binary function, akin to the one you might pass to <em>reduce</em>. While the two arguments might be treated symmetrically by the function, there is an implied semantic that distinguishes the arguments: the first argument is a result or accumulator that is being built up by the reduction, while the second is some new input value from the source being reduced. While <em>reduce</em> works from the 'left', that is neither a property nor promise of the reducing function, but one of <em>reduce</em> itself. So we&#8217;ll say simply that a reducing fn has the shape:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">(f result input) -&gt; new-result</code></pre>
</div>
</div>
<div class="paragraph">
<p>In addition, a reducing fn may be called with no args, and should then return an identity value for its operation.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_transforming_reducing_functions"><a class="anchor" href="#_transforming_reducing_functions"></a>Transforming Reducing Functions</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A function that transforms a reducing fn simply takes one, and returns another one:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">(xf reducing-fn) -&gt; reducing-fn</code></pre>
</div>
</div>
<div class="paragraph">
<p>Many of the core collection operations can be expressed in terms of such a transformation. Imagine if we were to define the cores of <em>map</em>, <em>filter</em> and <em>mapcat</em> in this way:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">(defn mapping [f]
  (fn [f1]
    (fn [result input]
      (f1 result (f input)))))

(defn filtering [pred]
  (fn [f1]
    (fn [result input]
      (if (pred input)
        (f1 result input)
        result))))

(defn mapcatting [f]
  (fn [f1]
    (fn [result input]
      (reduce f1 result (f input)))))</code></pre>
</div>
</div>
<div class="paragraph">
<p>There are a few things to note:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>The functions consist only of the core logic of their operations</p>
</li>
<li>
<p>That logic does not include any notion of collection, nor order</p>
</li>
<li>
<p>filtering and kin can 'skip' inputs by simply returning the incoming result</p>
</li>
<li>
<p>mapcatting and kin can produce more than one result per input by simply operating on result more than once</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Using these directly is somewhat odd, because we are operating on the reducing operation rather than the collection:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">(reduce + 0 (map inc [1 2 3 4]))
;;becomes
(reduce ((mapping inc) +) 0 [1 2 3 4])</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_reducers"><a class="anchor" href="#_reducers"></a>Reducers</h2>
<div class="sectionbody">
<div class="paragraph">
<p>We expect map/filter etc to take and return logical collections. The premise of the reducers library is that the minimum definition of collection is something that is reducible. reduce ends up using a protocol (CollReduce) to ask the collection to <em>reduce</em> itself, so we can make reducible things by extending that protocol. Thus, given a collection and a reducing function transformer like those above, we can make a reducible with a function like this:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">(defn reducer
  ([coll xf]
   (reify
    clojure.core.protocols/CollReduce
    (coll-reduce [_ f1 init]
      (clojure.core.protocols/coll-reduce coll (xf f1) init)))))</code></pre>
</div>
</div>
<div class="paragraph">
<p>Now:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">(reduce + 0 (map inc [1 2 3 4]))
;;becomes
(reduce + 0 (reducer [1 2 3 4] (mapping inc)))</code></pre>
</div>
</div>
<div class="paragraph">
<p>That&#8217;s better. It feels as if we have transformed the collection itself. Note:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>reducer ultimately asks the source collection to reduce <em>itself</em></p>
</li>
<li>
<p>reducer will work with any reducing function transformer</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Another objective of the library is to support reducer-based code with the same shape as our current seq-based code. Getting there is easy:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">(defn rmap [f coll]
  (reducer coll (mapping f)))

(defn rfilter [pred coll]
  (reducer coll (filtering pred)))

(defn rmapcat [f coll]
  (reducer coll (mapcatting f)))

(reduce + 0 (rmap inc [1 2 3 4]))
;=&gt; 14

(reduce + 0 (rfilter even? [1 2 3 4]))
;=&gt; 6

(reduce + 0 (rmapcat range [1 2 3 4 5]))
;=&gt; 20</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_from_reducible_to_parallel_foldable"><a class="anchor" href="#_from_reducible_to_parallel_foldable"></a>From Reducible to (Parallel) Foldable</h2>
<div class="sectionbody">
<div class="paragraph">
<p>While it is an interesting exercise to find another fundamental way to define the core collection operations, the end result is not much different, just faster, certainly something <a href="http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.104.7401">a state-of-the-art compilation and type system</a> (had we one) might do for us given sequence code. To stop here would be to completely miss the point of the library. These operations have different, fundamentally simpler semantics than their sequence-based counterparts.</p>
</div>
<div class="paragraph">
<p>How does one define parallel mapping/filtering/mapcatting etc? <em>We already did!</em> As long as the transformation itself doesn&#8217;t care about order (e.g. as <em>take</em> does), then a reducer is as foldable as its source. As with <em>reduce</em>, <em>fold</em> bottoms out on a protocol (CollFold), and our reducer can extend that:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">(defn folder
  ([coll xf]
     (reify
      ;;extend CollReduce as before

      CollFold
      (coll-fold [_ n combinef reducef]
        (coll-fold coll n combinef (xf reducef))))))</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note that:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><em>folder</em> has the same requirements as <em>reducer</em> - collection + reducing function transformer</p>
</li>
<li>
<p>when <em>fold</em> is applied to something that can&#8217;t fold, it devolves to <em>reduce</em></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Thus the real definitions of reducers/map et al use <em>folder</em> (while take uses <em>reducer</em>):</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">(defn rmap [f coll]
  (folder coll (mapping f)))

(defn rfilter [pred coll]
  (folder coll (filtering pred)))

(defn rmapcat [f coll]
  (folder coll (mapcatting f)))</code></pre>
</div>
</div>
<div class="paragraph">
<p>Thus a wide variety of collection transformations can instead be expressed as reducing function transformations, and applied in both sequential and parallel contexts, across a wide variety of data structures.</p>
</div>
<div class="paragraph">
<p>The library deals with several other details, such as:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>the transformers all need a nullary arity that just delegates to the transformed reducing function</p>
</li>
<li>
<p>the transformers support a ternary arity where 2 inputs are supplied per step, as occurs with reduce-kv and map sources</p>
</li>
<li>
<p>all of the reducers are curried</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>These additions are all mechanical, and are handled by macros. It is my hope that the above will help illuminate the core logic underlying the library.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_background"><a class="anchor" href="#_background"></a>Background</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Much prior work highlights the value of fold as a primary mechanism for collection manipulation, superior to iteration, although most of that work was done in the context of recursively defined functions on lists or sequences - i.e. fold implies foldl/foldr, and the results remain inherently sequential.</p>
</div>
<div class="paragraph">
<p>The two primary motivators for this library were the Haskell Iteratee library and Guy Steele&#8217;s ICFP '09 talk.</p>
</div>
<div class="sect2">
<h3 id="_haskell_iteratees"><a class="anchor" href="#_haskell_iteratees"></a>Haskell Iteratees</h3>
<div class="paragraph">
<p>The <a href="http://www.haskell.org/haskellwiki/Enumerator_and_iteratee">Haskell Enumerator/Iteratee library</a> and its antecedents are an inspiring effort to disentangle the source of data and the operations that might apply to it, and one of the first I think to reify the role of the 'iteratee'. An enumerator makes successive calls to the iteratee to supply it items, decoupling the iteratee from the data source. But the iteratee is still driving in some sense, as it is in charge of signaling Done, and, it returns on each step the next iteratee to use, effectively dictating a single thread of control. One benefit is that even operations like <em>take</em> can be defined functionally, as they can encode their internal state in the 'next' iteratee returned. OTOH, and unlike reducers, the design wraps the result being built up in a new iteratee each step, with potential allocation overhead.</p>
</div>
<div class="paragraph">
<p>Being an automaton in a state, an iteratee is like a reified left fold, and thus inherently serial. So, while they form quite a nice substrate for the design of, e.g. parsers, iteratees are unsuitable for defining things like map/filter etc if one intends to be able to parallelize them.</p>
</div>
</div>
<div class="sect2">
<h3 id="_guy_steeles_icfp_09_talk"><a class="anchor" href="#_guy_steeles_icfp_09_talk"></a>Guy Steele&#8217;s ICFP '09 talk</h3>
<div class="paragraph">
<p><a href="http://vimeo.com/6624203">Organizing Functional Code for Parallel Execution or, foldl and foldr Considered Slightly Harmful</a></p>
</div>
<div class="paragraph">
<p>This talk boils down to - stop programming with streams, lists, generators etc if you intend to exploit parallelism, as does the reducers library.</p>
</div>
<div class="paragraph">
<p>Where reducers diverges from that talk is in the structure of the fork/join parallel computation. Rather than map+reduce, reducers uses reduce+combine. This reflects 2 considerations:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>It is accepted fork/join practice that at some point you stop splitting in half and handle the leaves 'sequentially'</p>
<div class="ulist">
<ul>
<li>
<p>if the best way to do that at the top is <em>reduce</em>, why not at the bottom as well?</p>
</li>
</ul>
</div>
</li>
<li>
<p><em>map</em> forces a result per input</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>You can see the awkwardness of the latter in the map/reduce-oriented definition of parallel <em>filter</em> in the talk, which must 'listify' items or return empty lists, creating a bunch of concatenation busy-work for the reducing step. Many other collection algorithms suffer similarly in their map/reduce-oriented implementations, having greater internal complexity and wrapping the results in collection representations, with corresponding creation of more garbage and reduction busy-work etc vs the reducing function transformer versions of same.</p>
</div>
<div class="paragraph">
<p>It is interesting that the accumulator style is not completely absent from the reducers design, in fact it is important to the characteristics just described. What has been abandoned are the <em>single initial value</em> and <em>serial execution</em> promises of foldl/r.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_summary"><a class="anchor" href="#_summary"></a>Summary</h2>
<div class="sectionbody">
<div class="paragraph">
<p>I hope this makes reducers easier to understand, use and define.</p>
</div>
<div class="paragraph">
<p>Rich</p>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Reducers - A Library and Model for Collection Processing</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">08 05 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>I&#8217;m happy to have <a href="https://github.com/clojure/clojure/commit/89e5dce0fdfec4bc09fa956512af08d8b14004f6">pushed</a> today the beginnings of a new Clojure library for higher-order manipulation of collections, based upon <em>reduce</em> and <em>fold</em>. Of course, Clojure already has Lisp&#8217;s <em>reduce</em>, which corresponds to the traditional <em>foldl</em> of functional programming. <em>reduce</em> is based upon sequences, as are many of the core functions of Clojure, like <em>map</em>, <em>filter</em> etc. So, what could be better? It&#8217;s a long story, so I&#8217;ll give you the ending first:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>There is a new namespace: clojure.core.reducers</p>
</li>
<li>
<p>It contains new versions of <code>map</code>, <code>filter</code> etc based upon transforming reducing functions - reducers</p>
</li>
<li>
<p>It contains a new function, <code>fold</code>, which is a parallel reduce+combine</p>
</li>
<li>
<p><code>fold</code> uses fork/join when working with (the existing!) Clojure vectors and maps</p>
</li>
<li>
<p>Your new parallel code has exactly the same shape as your existing seq-based code</p>
</li>
<li>
<p>The reducers are composable</p>
</li>
<li>
<p>Reducer implementations are primarily functional - no iterators</p>
</li>
<li>
<p>The model uses regular data structures, not 'parallel collections' or other OO malarkey</p>
</li>
<li>
<p>It&#8217;s fast, and can become faster still</p>
</li>
<li>
<p>This is work-in-progress</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_basics"><a class="anchor" href="#_basics"></a>Basics</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The story starts best at the bottom.</p>
</div>
<div class="paragraph">
<p>Clojure and other functional languages have a function called <em>map</em> that takes a function and a collection/list.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>What does it mean to map a function on a collection?</p>
</li>
<li>
<p>What are the common signatures?</p>
</li>
<li>
<p>Do they <a href="http://www.infoq.com/presentations/Simple-Made-Easy">complect</a> what to do with how to do it?</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The classic recursive functional definition of <em>map</em> is to apply <em>f</em> to the first thing in the collection, then <em>cons</em> the result onto the result of mapping <em>f</em> on the <em>rest</em> of the collection. This definition includes plenty of 'how':</p>
</div>
<div class="ulist">
<ul>
<li>
<p>How: mechanism - recursion</p>
</li>
<li>
<p>How: order - sequentially</p>
</li>
<li>
<p>How: laziness - (often) lazily</p>
</li>
<li>
<p>How: representation - making a list/seq, or other concrete collection</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Newer OO frameworks will often remove some of these problems by having map be a function of <code>fn * Coll &#8594; Coll</code> for any type of Coll, removing the sequentiality but also losing the laziness, and they still specify a concrete collection result.</p>
</div>
<div class="paragraph">
<p>Semantically, and minimally, <em>map</em> means "apply-to-all" e.g. <code>(map inc coll)</code> means give me a (logical) collection where every item is one greater than it was in <em>coll</em>. But, <em>map</em> doesn&#8217;t know how to navigate around every collection - the use of seqs/lists/iterators/streams etc forces a shared known representation. Nor does <code>inc</code> (or any function) know how to apply itself to every collection representation, else we could just say <code>(inc coll)</code>.</p>
</div>
<div class="paragraph">
<p>The only thing that knows how to apply a function to a collection is the collection itself.</p>
</div>
<div class="paragraph">
<p>What is the generic gateway to a collection applying things to itself? In Clojure, it is (internal) <em>reduce</em>.</p>
</div>
<div class="paragraph">
<p>We now have a new super-generalized and minimal abstraction for collections - a collection is some set of things that, when given a function to apply to its contents, can do so and give you the result, i.e. <em>a collection is (at minimum) <strong>reducible</strong></em>. In other words, you can call <em>reduce</em> on it.</p>
</div>
<div class="paragraph">
<p>Thus, <code>core.reducers/map</code> is a function of <code>fn * reducible &#8594; reducible</code>. (Whereas <code>core/map</code> is a function of <code>fn * seqable &#8594; seqable</code>.)</p>
</div>
<div class="paragraph">
<p>Now, how? If someone is going to ask the result of <code>(map inc coll)</code> to reduce itself with some function <em>f</em>, <em>map</em> must ultimately ask <em>coll</em> to do the job. Rather than pass <em>coll f</em>, <em>map</em> passes <em>coll</em> a new, transformed, reducing function that takes what <em>coll</em> supplies, calls <code>inc</code> on it, and then calls <em>f</em> on that.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">(reduce + (r/map inc [1 2 3])) === (reduce (fn [ret x] (+ ret (inc x))) (+) [1 2 3])</code></pre>
</div>
</div>
<div class="paragraph">
<p>i.e. the core work of <em>map f</em> looks like this:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">(fn [f1]
  (fn [ret v]
    (f1 ret (f v))))</code></pre>
</div>
</div>
<div class="paragraph">
<p>It takes a reducing function f1, and returns a new reducing function that calls f1 after applying f to its input.</p>
</div>
<div class="paragraph">
<p>Thus you can define <em>map</em> as a function of <code>fn * reducible &#8594; reducible</code> by merely transforming the reducing function. Mapping is semantically a function of the function of <em><strong>one step</strong></em> of a reduction. This transformation is decomplected from both representation and order. We call functions such as this <em>map</em>, that take a reducible, and in turn return something reducible via transformation of the reducing function, reducers.</p>
</div>
<div class="paragraph">
<p>Now let&#8217;s revisit the hows above&#8230;&#8203;</p>
</div>
<div class="ulist">
<ul>
<li>
<p>How: mechanism - functional transformation of reducing function</p>
</li>
<li>
<p>How: order - doesn&#8217;t know</p>
</li>
<li>
<p>How: laziness - doesn&#8217;t know</p>
</li>
<li>
<p>How: representation - doesn&#8217;t build anything</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>It is important to note that now, when <code>(map f coll)</code> is called nothing happens except the creation of a recipe for a new collection, a recipe that is itself reducible. No work is done yet to the contained elements and no concrete collection is produced.</p>
</div>
<div class="paragraph">
<p>The beautiful thing is that this 'transformation of reducing function' mechanism also works for many of the traditional seq functions, like <em>filter</em>, <em>take</em>, <em>flatten</em> etc. Note the fact that <em>filter</em> is (potentially) contractive, and <em>flatten</em> is (potentially) expansive per step - the mechanism is general and not limited to 1:1 transformations. And other reducer definitions are as pretty as map&#8217;s - none of the imperativeness of iterators, or generators with yield.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_ok_so_wheres_my_cake"><a class="anchor" href="#_ok_so_wheres_my_cake"></a>Ok, So Where&#8217;s My Cake?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>If map doesn&#8217;t do the work of mapping, but merely creates a recipe, when does the work get done? When you reduce its result:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">(require '[clojure.core.reducers :as r])
(reduce + (r/filter even? (r/map inc [1 1 1 2])))
;=&gt; 6</code></pre>
</div>
</div>
<div class="paragraph">
<p>That should look familiar - it&#8217;s the same named functions, applied in the same order, with the same arguments, producing the same result as the Clojure&#8217;s seq-based fns. The difference is that, reduce being eager, and these reducers fns being out of the seq game, there&#8217;s no per-step allocation overhead, so it&#8217;s faster. Laziness is great when you need it, but when you don&#8217;t you shouldn&#8217;t have to pay for it.</p>
</div>
<div class="paragraph">
<p>The reducer fns are curried, and they can be easily composed:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">;;red is a reducer awaiting a collection
(def red (comp (r/filter even?) (r/map inc)))
(reduce + (red [1 1 1 2]))
;=&gt; 6</code></pre>
</div>
</div>
<div class="paragraph">
<p>Thus reduction 'recipes' (reducers) are first class.</p>
</div>
<div class="paragraph">
<p>What if we <em>want</em> a collection result? It&#8217;s good to know that into uses reduce:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">(into [] (r/filter even? (r/map inc [1 1 1 2])))
;=&gt; [2 2 2]</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note there are no intermediate collections produced.</p>
</div>
<div class="paragraph">
<p>And, of course, you don&#8217;t always want a result of the same collection type:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">(into #{} (r/filter even? (r/map inc [1 1 1 2])))
;=&gt; #{2}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_simplicity_is_opportunity"><a class="anchor" href="#_simplicity_is_opportunity"></a>Simplicity is Opportunity</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Decomplecting the core operations from representation and laziness has given us some speed, but what about the elimination of order? It should open the door to parallelism, but we are stuck with the semantics of <em>reduce</em> being <em>foldl</em>, i.e. it uses an accumulator and is <a href="http://vimeo.com/6624203">fundamentally serial</a>. We can parallelize reduction by using independent sub-reductions and combining their results, and the library defines a function that does just that: <em><strong>fold</strong></em>.</p>
</div>
<div class="paragraph">
<p>The primary signature of fold takes a combining function, a reducing function, and a collection and returns the result of combining the results of reducing subsegments of the collection, potentially in parallel. Obviously if the work is to occur in parallel, the functions must be associative, but they need not be commutative - <em>fold</em> preserves order. Note that there is no initial 'seed' or 'accumulator' value, as there may be with reduce and foldl. But, since the subsegments are themselves reduced (with <em>reduce</em>), it raises the question as to what supplies the seed values for those reductions?</p>
</div>
<div class="paragraph">
<p>The combining function (an associative binary fn) must have some 'identity' value, a value that, when combined with some X, yields X. 0 is an identity value for +, as is 1 for *. The combining fn must supply an identity value when called with no arguments (as do + and *). It will be called with no arguments to supply a seed for each leaf reduction. There is a fn (called <em>monoid</em>, shh!) to help you build such combining functions.</p>
</div>
<div class="paragraph">
<p>If no combining fn is supplied, the reducing fn is used. Simple folds look like reduces:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="clojure">(r/fold + [1 2 3 4])
;=&gt; 10</code></pre>
</div>
</div>
<div class="paragraph">
<p>But by promising less (i.e. not promising stepwise reduction from left or right) <em>fold</em> can do more - run in parallel. It does this when the collection is amenable to parallel subdivision. Ideal candidates are data structures built from trees. Clojure vectors and maps are trees, and have parallel implementations of <em>fold</em> based upon the <a href="https://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html">ForkJoin framework</a>.</p>
</div>
<div class="paragraph">
<p>What if the underlying collection is not amenable (e.g. is a sequence)? <em>fold</em> just devolves into <em>reduce</em>, producing the same semantic, if not physical, result.</p>
</div>
<div class="paragraph">
<p>There&#8217;s a tremendous amount you can accomplish with this reduce+combine strategy, especially when you consider that the map, filter etc reducers will not constitute independent layers of parallel jobs - they just transform the reducing fn working on the leaves.</p>
</div>
<div class="paragraph">
<p>You can have a look at the <code>cat</code> function included in the library for an interesting example of a combining fn. cat quickly gathers up the fold results, forming a binary tree with the reductions as leaves. It returns a highly abstract, yet now quite useful 'collection' that is just counted, reducible, foldable and seqable.</p>
</div>
<div class="paragraph">
<p>Oh yeah, perf. Don&#8217;t be surprised to see things become 2-3X faster, or more with more cores.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_more_opportunity_i_e_work"><a class="anchor" href="#_more_opportunity_i_e_work"></a>More Opportunity (i.e. Work)</h2>
<div class="sectionbody">
<div class="paragraph">
<p>As much fun as this is, there&#8217;s still more fun to be had by those so inclined:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>There are more seq fns that could become reducer fns</p>
</li>
<li>
<p>Given multiple iterable sources, we should be able to build a multi-reducible, recovering the multi-input capabilities of map.</p>
</li>
<li>
<p>Arrays, arraylists, strings etc are all amenable to parallel fold.</p>
<div class="ulist">
<ul>
<li>
<p>fork/join-based vector fold is 14 lines, so these are not difficult.</p>
</li>
</ul>
</div>
</li>
<li>
<p>Those IFn.LLL, DDD etc primitive-taking function interfaces can now spring to life.</p>
<div class="ulist">
<ul>
<li>
<p>We should be able to build primitive-transmitting reducer function pipelines.</p>
</li>
<li>
<p>We&#8217;d then need to look for and use them in the reductions of arrays and vectors of primitives</p>
</li>
</ul>
</div>
</li>
<li>
<p>Internal reduce solves the lazily dangling open resource problem, a problem solved similarly by <a href="http://www.haskell.org/haskellwiki/Enumerator_and_iteratee">Haskell&#8217;s enumerators and iteratees</a>. (Note that unlike iteratees, reducers do not allocate wrappers per step)</p>
<div class="ulist">
<ul>
<li>
<p>We need reducible I/O sources.</p>
</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_summary"><a class="anchor" href="#_summary"></a>Summary</h2>
<div class="sectionbody">
<div class="paragraph">
<p>By adopting an alternative view of collections as reducible, rather than seqable things, we can get a complementary set of fundamental operations that tradeoff laziness for parallelism, while retaining the same high-level, functional programming model. Because the two models retain the same shape, we can easily choose whichever is appropriate for the task at hand.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_follow_up"><a class="anchor" href="#_follow_up"></a>Follow Up</h2>
<div class="sectionbody">
<div class="paragraph">
<p>See the follow up <a href="xref/../../../05/15/anatomy-of-reducer">blog post</a> for more details about what constitutes a reducer, as well as some background about the library.</p>
</div>
<div class="paragraph">
<p>Rich</p>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">subject to change</h1>
                            <h2 class="article__feed"><a target="_blank" href="">(iterate think thoughts)</a> <span class="article__date">03 05 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>The OO world view requires us to classify data in order to work with it. For example if we're talking about a person, we might create a <code>Person</code> class and add some fields to it, such as <code>age</code>, <code>name</code>, and etc. Then we'll create instances of this class and use them in our program.</p><p>The problem with this approach is that the classification is only meaningful within a particular context. The classification is not inherent to the data itself, but rather it's a transient view of the data at a specific time in a particular domain.</p><p>When we create a class we make assumptions about the context in which the data will be used. These assumptions are often incomplete, and even when they are, the nature of the problem can change over time. The requirements may change, new requirements might come up, or we might have simply misunderstood the problem when we designed our classes.</p><p>The way OO deals with this is by remapping the classes to a new domain. We might extend the class, write a wrapper, or use an adapter pattern to bridge the contexts. But this is solving a problem we ourselves have introduced by assigning a permanent  classification to our data.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="/images/content/news/2012-02-17/clojure-community-layers.png" alt="Clojure Governance and How It Got That Way">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure Governance and How It Got That Way</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">17 02 2012</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div class="sect1">
<h2 id="_enter_rich_with_parentheses"><a class="anchor" href="#_enter_rich_with_parentheses"></a>Enter Rich, with Parentheses</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In the beginning, there was a guy with an idea. That guy was Rich Hickey, and his idea was to combine the power of Lisp with the reach of a modern managed runtime. He started with <a href="http://jfli.sourceforge.net/">Jfli</a>, embedding a JVM in Lispworks' Common Lisp implementation. When that proved inadequate, he took a two-year sabbatical to write the compiler that would eventually become <a href="https://clojure.org/">Clojure</a>: a completely new Lisp for the JVM with language-level concurrency support.</p>
</div>
<div class="paragraph">
<p>In late 2007, Rich Hickey presented Clojure at a meeting of the New York Lisp users' group, <a href="http://lispnyc.org/">LispNYC</a>. I was there, and I was so excited by what I saw that I wrote one of the <a href="http://stuartsierra.com/2007/11/15/clojure-a-lisp-worth-talking-about">first blog articles about Clojure</a>. Three days later, I was asking questions about Java interop on the <a href="http://groups.google.com/group/clojure">Clojure mailing list</a>.</p>
</div>
<div class="paragraph">
<p>Those early days were fun, participating in heady discussions about fundamental language features like <a href="http://groups.google.com/group/clojure/browse_thread/thread/3a76a052b419d4d1/d57ae6ad6efb0d4e?#d57ae6ad6efb0d4e">nil vs. false</a> and <a href="http://groups.google.com/group/clojure/browse_thread/thread/8b2c8dc96b39ddd7/5237b9d3ab300df8">argument order</a>. It felt like the beginning of something genuinely new. The community was tiny, and Rich participated in almost every discussion on the mailing list or IRC.</p>
</div>
<div class="paragraph">
<p>How times have changed. The Clojure mailing list has over five thousand members, and we just wrapped up the <a href="http://clojure-conj.org/">second international Clojure conference</a> with nearly four hundred attendees. Google Groups tells me I&#8217;ve racked up over a thousand posts on the mailing list, which is shocking to me. There are five books and counting about Clojure. People are building businesses and careers on it. Who would have guessed, in 2007, that we would be here in just four years?</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_enter_second_stuart"><a class="anchor" href="#_enter_second_stuart"></a>Enter Second Stuart</h2>
<div class="sectionbody">
<div class="paragraph">
<p>(That was a cheap shot. Hi, Stu! :)</p>
</div>
<div class="paragraph">
<p>In the Summer of 2008, Stuart Halloway started <a href="http://thinkrelevance.com/blog/2008/07/30/clojure.html">blogging about Clojure</a>. With his co-founder Justin Gehtland, Stuart H. had already <a href="http://thinkrelevance.com/">built a business</a> helping big companies navigate from ponderous Java development to more agile practices and more expressive languages like Ruby. Stuart H. decided that Clojure was the <a href="http://thinkrelevance.com/blog/2009/10/19/the-case-for-clojure.html">next big thing</a>. He wrote the <a href="http://pragprog.com/book/shcloj/programming-clojure">first book about Clojure</a> (soon to get a <a href="http://pragprog.com/book/shcloj2/programming-clojure">2nd edition</a>). When he and Rich met at the 2008 JVM Language Summit, they started a long conversation that would eventually become a partnership.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_clojure_contrib_the_beginning"><a class="anchor" href="#_clojure_contrib_the_beginning"></a>Clojure Contrib: The Beginning</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Around the same mid-2008 time frame, "clojure-contrib" began its life as a Subversion repository where community members could share code. There were twelve committers and no rules, just a bunch of Clojure source files containing code that we found useful. I contributed str-utils, seq-utils, duck-streams, and later test-is.</p>
</div>
<div class="paragraph">
<p>The growth of contrib eventually led to the need for some kind of library loading scheme more expressive than <code>load-file</code>. I wrote a primitive <code>require</code> function that took a file name argument and loaded it from the classpath. Steve Gilardi modified <code>require</code> to take a namespace symbol instead of a file. I suggested <code>use</code> as the shortcut for the common case of <code>require</code> followed by <code>refer</code>. This all happened fairly quickly, without a lot of consideration or planning, culminating in the <code>ns</code> macro. The peculiarities of the <code>ns</code> macro grew directly out of this work, so you can blame us for that.</p>
</div>
<div class="paragraph">
<p>Clojure-contrib also prompted a question that every open-source software project must grapple with: how to handle ownership. We&#8217;d already <a href="http://groups.google.com/group/clojure/browse_thread/thread/4eea23108b2ed46e/e69c92cd7be8826a">gone through two licenses</a>: the Common Public License and its successor, the Eclipse Public License.</p>
</div>
<div class="paragraph">
<p>Rich <a href="http://groups.google.com/group/clojure/browse_thread/thread/6de5840e5ab9abdf/306f63a87d34e5f1">proposed a Clojure Contributor Agreement</a> as a means to protect Clojure&#8217;s future. The motivation for the CA was to make sure Clojure would always be open-source but never trapped by a particular license. The Clojure CA is a covenant between the contributor and Rich Hickey: the contributor assigns joint ownership of his contributions to Rich. In return, Rich promises that Clojure will always be available under an open-source license approved by the <a href="http://www.fsf.org/">FSF</a> or the <a href="http://www.opensource.org/">OSI</a>.</p>
</div>
<div class="paragraph">
<p>Some open-source projects got stuck with the first license under which contributions were made. Under the CA, if the license ever needs to change again, there would be no obstacles and no need to get permission from every past contributor. Agreements like this have become standard practice for owners of large open-source projects like <a href="http://www.eclipse.org/legal/committer_process/EclipseIndividualCommitterAgreementFinal.pdf">Eclipse</a>, <a href="http://www.apache.org/licenses/icla.txt">Apache</a>, and <a href="http://www.oracle.com/technetwork/community/oca-486395.html">Oracle</a>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_clojurecore_and_new_contrib"><a class="anchor" href="#_clojurecore_and_new_contrib"></a>Clojure/core and "New Contrib"</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In 2010 I left my cozy academic job and went to work for Relevance, where Stuart Halloway and Rich were discussing a strategic partnership that would eventually become <a href="http://clojure.com/">Clojure/core</a>. So what is Clojure/core? It&#8217;s a business initiative of Relevance (though not an independent business entity) to provide consulting, training, and development-for-hire services around Clojure. Rich Hickey is an advisor to Clojure/core, but not a Relevance employee.</p>
</div>
<div class="paragraph">
<p>Members of Clojure/core, of which I am one, have made a commitment to spend their <a href="http://thinkrelevance.com/blog/2011/08/01/Friday-Update.html">20% time</a> supporting the Clojure ecosystem. Although Rich still personally reviews every patch for the language itself, the job of answering questions and organizing contributions from a 5000-member community is too big for one person, so Rich delegated that responsibility to Clojure/core.</p>
</div>
<div class="paragraph">
<p>The first big issue Clojure/core had to confront was the distribution of clojure-contrib. With sixty-plus libraries in one binary release, it was already unwieldy. Since clojure-contrib releases were tied to Clojure language releases, which happened infrequently, development had stalled. There was also vast confusion about what, exactly, clojure-contrib was meant to be. Was it an essential component of the language, a nascent standard library, or a load of crap? (I was inclined to the latter view, especially with regard to my own contributions.)</p>
</div>
<div class="paragraph">
<p>My attempts at <a href="https://github.com/clojure/clojure-contrib/commit/a6a92b9b3d2bfd9a56e1e5e9cfba706d1aeeaae5">modularizing clojure-contrib within a single Git repository</a> failed to improve the situation. Eventually, we settled on the solution of separate Git repositories for each library. This was a huge amount of work: dozens of repositories to create and hundreds of files to move. Many of the contrib libraries were stagnant, their original authors lacking time to continue working on them.</p>
</div>
<div class="paragraph">
<p>Finally, almost a year later, the situation has stabilized: <a href="xref/../../../../../dev/contrib_libs">contrib libraries</a>, each with its own Git repository, test suite, <a href="https://build.clojure.org/">continuous integration</a>, and independent release cycle. The overall code quality is higher and development is moving forward again.</p>
</div>
<div class="paragraph">
<p>It was a painful transition for everyone, not least for those of us trying to manage it all and bear the brunt of the inevitable carping. On top of everything else, the whole process overlapped with the release of Clojure 1.3, the first release to break backwards-compatibility in noticeable ways (non-dynamic Vars as a default, long/double as default numeric types).</p>
</div>
<div class="paragraph">
<p>Our technology choices for Clojure and "new contrib" — GitHub, JIRA, Hudson, and Maven — were driven by several concerns:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>to be first-class participants in the Java ecosystem</p>
</li>
<li>
<p>to preserve the future-proof licensing structure of the CA</p>
</li>
<li>
<p>to give library developers freedom to develop/release on their own schedule</p>
</li>
<li>
<p>to ensure changes are made only after a thorough review process</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The last point was particularly important for patches to the Clojure language. Clojure is <strong>very</strong> stable: since its first public release, implementation bugs have been rare and regressions almost nonexistent. Most reported bugs are edge cases in Java interop. But stability has a price: new features come more slowly. The majority of JIRA tickets on Clojure are really feature requests. Rich is extremely conservative about adding features to the language, and he has impressed this view on Clojure/core for the purpose of screening tickets.</p>
</div>
<div class="paragraph">
<p>To take one prominent example, <a href="http://groups.google.com/group/clojure/browse_thread/thread/aa57ab265f7474a/51bb53ca077154f8">named arguments were discussed</a> as far back as January 2008. Community members developed the <a href="http://groups.google.com/group/clojure/browse_thread/thread/d4f5f04f6894c741/4d3051dc6604df5d">defnk macro</a> to facilitate writing functions with named arguments, and <a href="http://groups.google.com/group/clojure/browse_thread/thread/de791a1a28659ea/6020c7db6bb74844">lobbied to add it</a> to Clojure. Finally, in March 2010, Rich made a <a href="https://github.com/clojure/clojure/commit/29389970bcd41998359681d9a4a20ee391a1e07c">one-line commit</a> adding support for map destructuring from sequential collections. This gave the benefit of keyword-style parameters everywhere destructuring is supported, including function arguments. By waiting, and thinking, we got something better than defnk. If defnk had been accepted earlier, we might have been stuck with an inferior implementation.</p>
</div>
<div class="paragraph">
<p>Conversely, the decision to move some libraries into the language, notably my testing library, was probably premature. (Stuart Halloway accepts blame for that one. :) Some of the decisions I made in that library could use revisiting, but now clojure.test is what we&#8217;re stuck with.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_clojuredev_and_the_future"><a class="anchor" href="#_clojuredev_and_the_future"></a>Clojure/dev and the Future</h2>
<div class="sectionbody">
<div class="paragraph">
<p>If there was one mistake that I personally made during the 1.3 migration, it was speaking as if Clojure/core <strong>owned</strong> Clojure and clojure-contrib. We don&#8217;t: Clojure is owned by Rich Hickey, and clojure-contrib is owned jointly by Rich Hickey and contributors. But we <strong>are</strong> the appointed stewards (and Stuarts!) of the open-source Clojure ecosystem. In that role, we have to make decisions about what we choose to invest time in supporting. Given limited time, and following Rich&#8217;s conservative position on new features, that decision is usually "no."</p>
</div>
<div class="paragraph">
<p>It&#8217;s a difficult position to be in. Most of Clojure/core&#8217;s members come from the free-wheeling, fast-paced open-source world of Ruby on Rails. We really don&#8217;t enjoy saying "no" all the time. But a conservative attitude toward new features is exactly the reason Clojure is so stable. Patches don&#8217;t get into the language until they have been <a href="xref/../../../../../dev/workflow">reviewed by at least three people</a>, one of them Rich Hickey. New libraries don&#8217;t get added to contrib without mailing-list discussions. None of the new contrib libraries has reached the 1.0.0 milestone, and probably won&#8217;t for some time. These hurdles are not arbitrary; they are an attempt to guarantee that new additions to Clojure reflect the same consideration and careful design that Rich invested in the original implementation.</p>
</div>
<div class="paragraph">
<p>So what is clojure-contrib today? It&#8217;s a curated set of libraries whose ownership and licensing is governed by the Clojure Contributor Agreement. It could also serve as a proving ground for new features in the language, but this does not imply that every contrib library will eventually make it into the language.</p>
</div>
<div class="paragraph">
<p>With the expansion of contrib, we&#8217;ve given name to another layer of organization: <strong>Clojure/dev</strong>. Clojure/dev is the set of all people who have signed the Clojure Contributor Agreement. This entitles them to participate in discussions on the <a href="http://groups.google.com/group/clojure-dev">clojure-dev mailing list</a>, submit patches on <a href="https://clojure.atlassian.net/projects/CLJ">JIRA</a>, and become committers on contrib libraries. Within Clojure/dev is the smaller set of people who have been tasked with screening Clojure language tickets. Clojure/core overlaps with both groups.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="/images/content/news/2012-02-17/clojure-community-layers.png" alt="Diagram showing layers of the Clojure community">
</div>
</div>
<div class="paragraph">
<p>At the tail end of this year&#8217;s <a href="http://clojure-conj.org/">Clojure/conj</a>, Stuart Halloway opened the first face-to-face meeting of Clojure/dev with these words: "This is the Clojure/dev meeting. It&#8217;s a meeting of volunteers talking about how they&#8217;re going to spend their free time. The only thing we owe each other is honest communication about when we&#8217;re planning to do something and when we&#8217;re not. There is no obligation for anybody in this room to build anything for anybody else."</p>
</div>
<div class="paragraph">
<p>One consensus that came out of the Clojure/dev meeting was that we need to get better at using our tools, particularly JIRA. We would like to streamline the processes of joining Clojure/dev, screening patches, and creating new contrib libraries. We also need better integration testing between Clojure and applications that use it. Application and library developers can help by running their test suites against pre-release versions of Clojure (alphas, betas, even SNAPSHOTs) and reporting problems early.</p>
</div>
<div class="paragraph">
<p>But Stu&#8217;s last point is an important one: no one in the Clojure community owes anybody anything. If you want something, it&#8217;s not enough to ask for it, you need to be willing to do the work to make it happen. At the same time, don&#8217;t let a lukewarm response to ideas on the mailing list dissuade you from implementing something you think is valuable. It might just be that no one has time to think about it. Recall keyword arguments: more than two years from inception to completion. We&#8217;re in this for the long haul. Join us, be patient, and let&#8217;s see where we can go.</p>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Introducing ClojureScript</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Clojure News</a> <span class="article__date">22 07 2011</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
	<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>The Clojure team is proud to introduce an important addition to the Clojure language ecosystem. <a href="https://github.com/clojure/clojurescript">ClojureScript</a> is a new compiler for Clojure that targets JavaScript.</p>
</div>
<div class="paragraph">
<p>A <a href="https://www.youtube.com/watch?v=tVooR-dF_Ag">video recording of the ClojureScript announcement</a> is available, along with <a href="http://cloud.github.com/downloads/clojure/clojurescript/clojurescript%20slides.pdf">slides (PDF) from the presentation</a>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_why_javascript"><a class="anchor" href="#_why_javascript"></a>Why JavaScript</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The Clojure language was first <a href="xref/../../../../../about/rationale#Rationale-Languages%20and%20Platforms">built on the Java Virtual Machine</a> because of its reach and power on server platforms. For non-server platforms, nothing has greater reach than JavaScript. It&#8217;s been called the <a href="http://www.hanselman.com/blog/JavaScriptisAssemblyLanguagefortheWebPart2MadnessorjustInsanity.aspx">assembly language of the Web</a>. But beyond Web browsers, JavaScript can be found in <a href="http://arstechnica.com/apple/news/2011/06/ios-5-brings-nitro-speed-to-home-screen-web-apps.ars">mobile devices</a>, <a href="http://developer.boxee.tv/JavaScript_API#Preface">set-top boxes</a>, and <a href="http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/Scripting/Scripting_Framework">desktop applications</a>. JavaScript has even made inroads on the server in <a href="http://couchdb.apache.org/">databases</a> and <a href="http://nodejs.org/">Web servers</a>. As a result of this reach, a lot of work has gone into making JavaScript engines performant, including JIT-compilation into native code.</p>
</div>
<div class="paragraph">
<p>But JavaScript&#8217;s weakness remains the language itself. Although it has some powerful features such as first-class functions, JavaScript is noted more for its flaws than for its strengths. It was never designed to be a language for large applications.</p>
</div>
<div class="paragraph">
<p>What if we had a modern, robust, powerful language that could reach to all the places that JavaScript does? This is the goal of ClojureScript.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_where_we_are"><a class="anchor" href="#_where_we_are"></a>Where We Are</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Try it out!  Follow the Quick Start instructions on the <a href="https://github.com/clojure/clojurescript/wiki">ClojureScript wiki</a>.</p>
</div>
<div class="paragraph">
<p>Here&#8217;s a partial list of what has been implemented so far:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Protocols and <code>deftype</code></p>
</li>
<li>
<p>Namespaces</p>
</li>
<li>
<p>Functions: <code>fn</code>, <code>defn</code>, multiple-arities, variadics</p>
</li>
<li>
<p>Destructuring</p>
</li>
<li>
<p>Higher-order functions: <code>map</code>, <code>reduce</code>, <code>filter</code>, &#8230;&#8203;</p>
</li>
<li>
<p>Data structures: lists, maps, vectors, sets</p>
</li>
<li>
<p>Data manipulation functions: <code>conj</code>, <code>assoc</code>, <code>update-in</code>,&#8230;&#8203;</p>
</li>
<li>
<p>Sequences and sequence functions: <code>first</code>, <code>rest</code>, &#8230;&#8203;</p>
</li>
<li>
<p>Macros: <code>assert</code>, <code>cond</code>, <code>doto</code>, <code>loop</code>, <code>-&gt;</code> and <code>-&gt;&gt;</code>, &#8230;&#8203;</p>
</li>
<li>
<p>Metadata</p>
</li>
<li>
<p>Reader in ClojureScript (think JSON but better)</p>
</li>
<li>
<p>Regular expressions</p>
</li>
<li>
<p>Atoms</p>
</li>
<li>
<p>Core libraries: <code>clojure.string</code>, <code>clojure.set</code>, <code>clojure.zip</code>, &#8230;&#8203;</p>
</li>
<li>
<p>REPL using JDK-embedded JavaScript (Rhino)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>ClojureScript is currently in Alpha status. The compiler and core libraries are usable for developing applications, but expect to find bugs and missing pieces of functionality. ClojureScript aims to be a complete implementation of the Clojure language, but some parts aren&#8217;t finished yet.</p>
</div>
<div class="paragraph">
<p>Some parts of the Clojure language have no direct analog in ClojureScript, in particular the concurrency primitives, since JavaScript is single-threaded. There may also be edge cases where the requirements of the JavaScript environment force ClojureScript to have slightly different semantics from Clojure. We will document these differences as we find them.</p>
</div>
<div class="paragraph">
<p>Obviously, any code making interop calls to Java, as most existing Clojure libraries do, will not work in ClojureScript. Code written in pure Clojure will <strong>probably</strong> work in ClojureScript with minor adjustments. For example, <a href="https://github.com/clojure/clojure/blob/master/src/clj/clojure/zip.clj">clojure.zip in Clojure</a> and <a href="https://github.com/clojure/clojurescript/blob/master/src/cljs/clojure/zip.cljs">clojure.zip in ClojureScript</a> are nearly identical. With a little effort, purely algorithmic code can be made portable between implementations. However, trying to abstract over all the differences among host platforms has never been a goal of Clojure, nor will it be a goal of ClojureScript.</p>
</div>
<div class="paragraph">
<p>We have a <a href="https://clojure.atlassian.net/projects/CLJS">ClojureScript JIRA instance</a> set up to track bugs. As with Clojure itself, submitting patches requires signing the <a href="xref/../../../../../dev/contributor_agreement">Clojure Contributor Agreement</a>. We can only accept patches through JIRA, not GitHub pull requests.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_relationship_to_google_closure"><a class="anchor" href="#_the_relationship_to_google_closure"></a>The Relationship to Google Closure</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Google has led the way in developing rich client-side applications in JavaScript. Because Google needs the Web to succeed as an application-delivery platform, they have released some of their JavaScript tools as open source under the name <strong>Closure</strong>. The homophonic name clash is unfortunate, but not something we can do anything about.</p>
</div>
<div class="paragraph">
<p><a href="http://code.google.com/closure/">Google Closure</a> is a suite of tools for delivering complex JavaScript applications to memory-constrained devices over slow connections. It consists of three parts: a large library of JavaScript classes and functions, a client-side templating system, and an optimizing JavaScript compiler. These parts are designed to work in symbiosis.</p>
</div>
<div class="paragraph">
<p>The Google Closure compiler is a sophisticated JavaScript-to-JavaScript compiler that performs whole-program analysis to inline and rearrange code for optimal performance on modern JavaScript runtimes. Most importantly, it eliminates unused or unreachable code. The Google Closure compiler makes it possible to have a large library of JavaScript functions written in a straightforward manner without concern for code size, and to deliver minified versions of only the code your application needs. However, taking full advantage of the Google Closure compiler requires adherence to strict conventions for JavaScript source code.</p>
</div>
<div class="paragraph">
<p>The ClojureScript compiler emits JavaScript which follows Google Closure&#8217;s code conventions, and then invokes the Google Closure compiler to generate compact, optimized JavaScript for delivery to clients. ClojureScript also makes use of the Google Closure library for capabilities such as event handling, DOM manipulation, and user interface widgets.</p>
</div>
<div class="paragraph">
<p>It is possible to use ClojureScript with JavaScript libraries other than Google Closure, but those libraries typically do not follow the conventions of the Google Closure compiler and therefore will not be able to take full advantage of its optimizations.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_what_clojurescript_is_not"><a class="anchor" href="#_what_clojurescript_is_not"></a>What ClojureScript is Not</h2>
<div class="sectionbody">
<div class="paragraph">
<p><strong>ClojureScript is not Clojure implemented in JavaScript.</strong></p>
</div>
<div class="paragraph">
<p>The Clojure community has tried various ways of generating JavaScript from Clojure in the past. One <a href="https://github.com/clojure/clojure-contrib/tree/master/clojurescript">early attempt by Chris Houser</a>, also called ClojureScript, used JavaScript as a implementation language for the core data structures and compiler, the way the current version of Clojure uses Java.</p>
</div>
<div class="paragraph">
<p>The new ClojureScript does not take this approach. Instead, ClojureScript is written entirely in <strong>Clojure</strong>, as a compiler which emits JavaScript and a large library of functions. Therefore, ClojureScript does not aim to provide a complete development environment in JavaScript. There is no <code>eval</code> and no runtime access to the ClojureScript compiler from within ClojureScript.</p>
</div>
<div class="paragraph">
<p><strong>ClojureScript is not JavaScript with Clojure syntax.</strong></p>
</div>
<div class="paragraph">
<p>Another approach sometimes used to overcome JavaScript&#8217;s syntactic shortcomings is to layer another syntax on top of it while keeping all of the JavaScript language semantics. <a href="http://common-lisp.net/project/parenscript/">Parenscript</a> and <a href="http://jashkenas.github.io/coffee-script/">CoffeeScript</a> are examples of this approach.</p>
</div>
<div class="paragraph">
<p>ClojureScript has the same language semantics as Clojure, not JavaScript. The ClojureScript compiler emits JavaScript, similar to the way the Clojure compiler emits Java bytecode.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_how_we_got_here"><a class="anchor" href="#_how_we_got_here"></a>How We Got Here</h2>
<div class="sectionbody">
<div class="paragraph">
<p>ClojureScript was initially developed by Rich Hickey, creator of Clojure. Members of the Clojure/core team, along with others invited from the Clojure community, have participated in the development of the compiler.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_where_to_learn_more"><a class="anchor" href="#_where_to_learn_more"></a>Where to Learn More</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/clojure/clojurescript/wiki">ClojureScript Wiki</a></p>
</li>
<li>
<p><a href="http://groups.google.com/group/clojure">Clojure Mailing List</a></p>
</li>
<li>
<p>\#clojure IRC on <a href="http://freenode.net/">Freenode</a></p>
</li>
</ul>
</div>
</div>
</div>
	
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">An introduction to Drush: The Drupal power tool</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">14 03 2011</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Drush is a tool that allows you to perform common Drupal tasks from the command line.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">An introduction to Drush: The Drupal power tool</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Web Development - James Sinclair</a> <span class="article__date">14 03 2011</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        Drush is a tool that allows you to perform common Drupal tasks from the command line.
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Communication, Knowledge, Bodies and God</h1>
                            <h2 class="article__feed"><a target="_blank" href="">James Sinclair</a> <span class="article__date">02 04 2007</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        <p>Why is communication so difficult?</p>

<p>Sometimes I will talk to somebody, and think that I’m expressing
myself really clearly when I’m not. I seem to make perfect sense. Yet
when I hear what the other person says in response, it is obvious that
they heard something quite different from what I thought I said.</p>
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.freecodecamp.org/espanol/news/favicon.png" alt="
                 Como remover duplicados en Excel: Eliminar filas duplicadas con algunos clics 
            ">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">
                 Como remover duplicados en Excel: Eliminar filas duplicadas con algunos clics 
            </h1>
                            <h2 class="article__feed"><a target="_blank" href="">
             freeCodeCamp.org 
        </a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                 Excel tiene muchas aplicaciones, como llevar un control del inventario, mantener una lista de correo, hacer informes de ventas y muchas otras. A medida que la base de datos crece, uno de los principales problemas que encuentran muchos usuarios es la obtención de valores y filas duplicadas. Esto puede hacer 
            
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.freecodecamp.org/espanol/news/favicon.png" alt="
                 Cómo solucionar problemas de Leetcode con Python en una sola línea 
            ">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">
                 Cómo solucionar problemas de Leetcode con Python en una sola línea 
            </h1>
                            <h2 class="article__feed"><a target="_blank" href="">
             freeCodeCamp.org 
        </a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                 Python es uno de los lenguajes de programación más potentes. Nos ofrece una serie de características y funcionalidades únicas que hace que sea sencillo escribir código con él. En este artículo, vamos a solucionar problemas de arreglos de Leetcode en una sola línea, usando una de las características más interesantes 
            
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.freecodecamp.org/espanol/news/favicon.png" alt="
                 Cómo codificar un scraping Bot con Selenium y Python. 
            ">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">
                 Cómo codificar un scraping Bot con Selenium y Python. 
            </h1>
                            <h2 class="article__feed"><a target="_blank" href="">
             freeCodeCamp.org 
        </a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                 Selenium es una herramienta diseñada para ayudarle a ejecutar pruebas automatizadas en aplicaciones web. Está disponible en varios lenguajes de programación. Aunque no es su propósito principal, Selenium también se usa en Python para web scraping, porque puede acceder a contenido renderizado en JavaScript (lo que las herramientas de scraping 
            
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.freecodecamp.org/espanol/news/favicon.png" alt="
                 Cada propiedad de fondo CSS ilustrada y explicadas con ejemplos de código🏅 
            ">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">
                 Cada propiedad de fondo CSS ilustrada y explicadas con ejemplos de código🏅 
            </h1>
                            <h2 class="article__feed"><a target="_blank" href="">
             freeCodeCamp.org 
        </a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                 Hoy vamos a aprender sobre cada una de las propiedades de fondo CSS con cada uno de sus posibles valores. Aprenderemos haciendo. ¡Vamos!🏅  Tabla de contenidos Todas las propiedades background-image background-size background-repeat background-position background-origin background-clip background-attachment background-color Atajos y combinaciones Conclusión También puedes ver este tutorial en YouTube:  Todas las 
            
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.freecodecamp.org/espanol/news/favicon.png" alt="
                 Explicación de la memoización, recursión y los bucles for en Python 
            ">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">
                 Explicación de la memoización, recursión y los bucles for en Python 
            </h1>
                            <h2 class="article__feed"><a target="_blank" href="">
             freeCodeCamp.org 
        </a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                 Hay más de una manera de hacer las cosas. Siempre hay diferentes puntos de vista y estilos de lanzamiento.~Tim HudsonEn este artículo, utilizaremos tres técnicas diferentes en Python para codificar un programa básico de Fibonacci que dará como resultado la suma de la secuencia. En este caso la secuencia 
            
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.freecodecamp.org/espanol/news/favicon.png" alt="
                 Guía de Git para contribuir en un proyecto de código abierto 
            ">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">
                 Guía de Git para contribuir en un proyecto de código abierto 
            </h1>
                            <h2 class="article__feed"><a target="_blank" href="">
             freeCodeCamp.org 
        </a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                 Una hoja de tips para tus contribuciones a un proyecto de códgio abierto.  Si estás leyendo este artículo, ya debes conocer que abundan los beneficios de ser un contribuidor de proyectos de código abierto (Puedes saltarte este artículo y navegar hasta el final si estás aquí por la hoja de 
            
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.freecodecamp.org/espanol/news/favicon.png" alt="
                 Practica Python Creando 6 Proyectos - Curso Gratis Paso a Paso de 2.5 Horas 
            ">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">
                 Practica Python Creando 6 Proyectos - Curso Gratis Paso a Paso de 2.5 Horas 
            </h1>
                            <h2 class="article__feed"><a target="_blank" href="">
             freeCodeCamp.org 
        </a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                 ¡Bienvenido(a)! Practica tus habilidades de Python creando 6 proyectos básicos paso a paso.  Practicar es clave para aprender a programar, así que veamos en más detalle los proyectos que crearás durante el curso. Estefania Cassingena Navone te guiará paso a paso para crear los siguientes proyectos: 🔹 Proyecto 1: Mad 
            
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.freecodecamp.org/espanol/news/favicon.png" alt="
                 Módulo datetime de Python: Cómo manejar fechas en Python 
            ">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">
                 Módulo datetime de Python: Cómo manejar fechas en Python 
            </h1>
                            <h2 class="article__feed"><a target="_blank" href="">
             freeCodeCamp.org 
        </a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                 En esta guía rápida del módulo datetime de Python, aprenderás a analizar fechas, extraer información significativa de las mismas, manejar objetos timedelta y mucho más. Así que, sin más preámbulos, ¡comencemos a contar el tiempo con Python! La mayoría de los lenguajes de programación proporcionan bibliotecas para el manejo fácil 
            
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.freecodecamp.org/espanol/news/favicon.png" alt="
                 Como Construir Un Sitio Web WordPress De Forma Local - Que Necesitas Saber 
            ">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">
                 Como Construir Un Sitio Web WordPress De Forma Local - Que Necesitas Saber 
            </h1>
                            <h2 class="article__feed"><a target="_blank" href="">
             freeCodeCamp.org 
        </a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                 WordPress es el sistema de gestión de contenido más popular del mundo. No importa si eres un experimentado desarrollador usando la tecnología que impulsa al 38% de los sitios web o si simplemente estás empezando con WordPress, construir de forma local en tu computadora es  a bajo costo, testing amigables, 
            
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="https://www.freecodecamp.org/espanol/news/favicon.png" alt="
                 Explicación de la declaración de importación de Python 
            ">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">
                 Explicación de la declaración de importación de Python 
            </h1>
                            <h2 class="article__feed"><a target="_blank" href="">
             freeCodeCamp.org 
        </a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                 Mientras aprendes a programar y lees algunos recursos te habrás encontrado con esta palabra 'abstracción' que simplemente significa reducir y reutilizar el código tanto como sea posible. Las funciones y los módulos facilitan la abstracción. Las funciones se crean cuando se quiere hacer algo repetidamente dentro de un archivo. Los 
            
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">State machines are wonderful tools</h1>
                            <h2 class="article__feed"><a target="_blank" href="">null program</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Single-primitive authenticated encryption for fun</h1>
                            <h2 class="article__feed"><a target="_blank" href="">null program</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Well-behaved alias commands on Windows</h1>
                            <h2 class="article__feed"><a target="_blank" href="">null program</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A guide to Windows application development using w64devkit</h1>
                            <h2 class="article__feed"><a target="_blank" href="">null program</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Effects of Fortuna</h1>
                            <h2 class="article__feed"><a target="_blank" href="">null program</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The cost of Java&#39;s EnumSet</h1>
                            <h2 class="article__feed"><a target="_blank" href="">null program</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to build and use DLLs on Windows</h1>
                            <h2 class="article__feed"><a target="_blank" href="">null program</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">More DLL fun with w64devkit: Go, assembly, and Python</h1>
                            <h2 class="article__feed"><a target="_blank" href="">null program</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">August 2019 Alpha</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Release notes from darling</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">December 2019 Alpha</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Release notes from darling</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Alpha: January 3, 2020</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Release notes from darling</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Alpha: January 20, 2020</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Release notes from darling</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Alpha: March 16, 2020</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Release notes from darling</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Alpha: March 31, 2020</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Release notes from darling</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Alpha: February 25, 2021</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Release notes from darling</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Introduction</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The TeX Hackery</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Ubuntu post-installation tricks</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">YAVP</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Recipe for a successful presentation</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">I’m not playing this stupid game anymore</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Poliqarp’s new protocol</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">ECLM 2008</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hacking away with JSON-RPC</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Forgetting</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Best OS ever</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">cl-netstrings</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Inward ripeness</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Recently read #1: Akhmatova meets Bashō (Vasil Bykaŭ, “The Wall”)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Today’s lesson: Mind the symlinks</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Another metapost</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">cl-morfeusz: A ninety minutes’ hack</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">You win some, you lose some, you talk some</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Who said Common Lisp programs cannot be small?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The immensely powerful tool</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">anti-procrastination.el</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Google Books</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Reactivation (and some ramblings on my blogging infrastructure)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure SET</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Downcasing strings</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The pitfalls of &lt;code&gt;lein swank&lt;/code&gt;</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hiking in the Apennines</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A case for symbol capture</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Sunflower</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Keyword arguments</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Last post here</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Hello world, again</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Dijkstran wheel of fortune: SPSS, Excel, VBA</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A quirk with JavaScript closures</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Meet my little friend createTree</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Color your own Europe with Clojure!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Combining virtual sequences&lt;br&gt;or, Sequential Fun with Macros&lt;br&gt;or, How to Implement Clojure-Like Pseudo-Sequences with Poor Man’s Laziness in a Predominantly Imperative Language</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Ever wanted to programmatically file a lawsuit? In Poland, you can.</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Lifehacking: How to get cheap home equipment using Clojure</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to call a private function in Clojure</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Lithium: an x86 assembler for Clojure</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">My top three iOS apps for mapping</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Lithium revisited: A 16-bit kernel (well, sort of) written in Clojure (well, sort of)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">2048: A close look at the source</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">DOS debugging quirk</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">You already use Lisp syntax</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Happy Programmers’ Day!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Re-framing text-mode apps</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Web of Documents</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Word Champions</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Careful with that middleware, Eugene</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Indenting cond forms</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure as a dependency</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Making of “Clojure as a dependency”</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">I made a website to guess tomorrow’s number of COVID-19 cases, and here’s what happened</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Things I wish Git had: Commit groups</h1>
                            <h2 class="article__feed"><a target="_blank" href="">code · words · emotions: Daniel Janus’s blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">News</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Planet Clojure</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">On the criteria to be used in decomposing systems into modules</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Planet Clojure</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">More On Types</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Planet Clojure</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Announcing Alda 2</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Planet Clojure</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">REPL vs CLI: IDE wars</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Planet Clojure</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Pre and post conditions in Clojure</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Planet Clojure</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Time traveling with Fluree</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Planet Clojure</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Announcing Clojure Morsels</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Planet Clojure</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Clojure Deref (July 2, 2021)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Planet Clojure</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A la carte specs for your re-frame subs and events</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Planet Clojure</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Debugging in Clojure</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Planet Clojure</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">What if data is a really bad idea?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Planet Clojure</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">What are the Clojure Tools?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Planet Clojure</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">What the Reagent Component?!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Planet Clojure</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Software Engineering Manager (Clojure Team)</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Planet Clojure</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">737 Max 8</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The Clean Code Blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Types and Tests</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The Clean Code Blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Classes vs. Data Structures</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The Clean Code Blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Why won&#39;t it...</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The Clean Code Blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Why Clojure?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The Clean Code Blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Circulatory</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The Clean Code Blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">What They Thought of Programmers.</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The Clean Code Blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Open Letter to the Linux Foundation</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The Clean Code Blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A New Hope</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The Clean Code Blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A Little Clojure</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The Clean Code Blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A Little More Clojure</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The Clean Code Blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">REPL Driven Design</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The Clean Code Blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The Disinvitation</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The Clean Code Blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Conference Conduct</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The Clean Code Blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Loopy</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The Clean Code Blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Solid Relevance</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The Clean Code Blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Pairing Guidelines</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The Clean Code Blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">if-else-switch</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The Clean Code Blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">On Types</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The Clean Code Blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">More On Types</h1>
                            <h2 class="article__feed"><a target="_blank" href="">The Clean Code Blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <p class="article__header-img">
                            <img loading="lazy" src="http://www.emezeta.com/img/logo.png" alt="Curiosidades y teorías de Undertale que quizás desconocías">
                        </p>
                        
                        <div class="article__titles">
                            <h1 class="article__title">Curiosidades y teorías de Undertale que quizás desconocías</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Emezeta blog</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        ¿Te gustó Undertale? ¡Pues prepárate para descubrir más de 30 curiosidades y teorías (en español) que quizás desconocías de este maravilloso juego!
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">GameShell Launcher 1.2 [2e041e6] update log</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Release notes from launcher</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">version 1.21 [4ad8806]</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Release notes from launcher</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">launcher 1.22 [37e4d65]</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Release notes from launcher</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">New zine: Hell Yes! CSS!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Julia Evans</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">An attempt at implementing char-rnn with PyTorch</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Julia Evans</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How I write useful programming comics</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Julia Evans</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">2020: Year in review</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Julia Evans</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Docker Compose: a nice way to set up a dev environment</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Julia Evans</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Daily blog posts about my time at RC</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Julia Evans</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Server-sent events: a simple way to stream events from a server</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Julia Evans</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Firecracker: start a VM in less than a second</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Julia Evans</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A little tool to make DNS queries</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Julia Evans</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Things your manager might not know</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Julia Evans</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Get better at programming by learning how things work</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Julia Evans</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">A tool to spy on your DNS queries: dnspeep</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Julia Evans</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">What problems do people solve with strace?</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Julia Evans</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Notes on building debugging puzzles</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Julia Evans</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">I put all of my comics online!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Julia Evans</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">The OSI model doesn&#39;t map well to TCP/IP</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Julia Evans</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">How to look at the stack with gdb</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Julia Evans</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Blog about what you&#39;ve struggled with</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Julia Evans</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">You can now buy print version of my zines!</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Julia Evans</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
            <a class="feed__article article" target="_blank" href="">
                <article>
                    <header class="article__header">
                        
                        <div class="article__titles">
                            <h1 class="article__title">Reasons why bugs might feel &quot;impossible&quot;</h1>
                            <h2 class="article__feed"><a target="_blank" href="">Julia Evans</a> <span class="article__date">06 07 2021</span></h2>
                        </div>
                    </header>
                    <main class="container article__main">
                        
                    </main>
                </article>
            </a>
            
        </main>
    </div>
    <footer class="footer">
        <hr class="separator">
        <p class="footer__text">
            Generated with <a class="footer__link" href="https://github.com/tanrax/RSSpaper">RSSpaper</a> and a lot of <span class="footer__heard">❤️</span>️
        </p>
    </footer>
</body>
</html>