How to Send Reminder Emails Based on Dates in Google Sheets

John Q Public runs a travel agency and they have thousands of clients across the globe. Other than managing tickets and travel itineraries, the agency also keeps a record of passports and visas of their clients to ensure that customers have valid documents at the time of travel.

Most countries require that a foreigner’s passport must be valid for at least six months from the date of entry. The US government, therefore, recommends that you renew your passport at least nine months before it expires.

Send Automatic Emails with Google Sheets

John’s agency is looking for a reminder system that will automatically send an email notification to their customers when their passports have expired or are due for renewal in the next few months. Let’s see how they can build such a workflow in 10 minutes with the help of Mail Merge for Gmail.

The idea is simple.

We have the customer data in a Google Sheet or a Microsoft Excel spreadsheet. The “Expiry Date” column in the spreadsheet contains the date when the passport is set to expire. We setup a cron job that runs in the background and monitors the expiry date. If any date in the sheet is less than, say, 12 months from today, an automatic email reminder is sent to the customer.

Create the Reminder Email Workflow

To get started, install the Mail Merge for Gmail add-on for Google Sheets. If you have never used the merge add-on earlier, please watch the Mail Merge tutorial for a quick overview.

Email Reminders Sheet

Next, create a new Google Sheet and choose Addons > Mail Merge with Attachments > Create Merge Template. If you have your customer data in an Excel sheet, you can easily import the records into this Google sheet using the File > Import menu.

Next, we’ll use the Array Formulas to populate the Scheduled Date column based on the date in the Expiry Date column. Go to row #2 of the scheduled date column and paste this formula:

=ArrayFormula(IF(ISBLANK(E2:E),"",E2:E-365))

The date in the Scheduled Date column will automatically be filled with a date that is 12 months before the date in the Expiry Date column. Thus if the passport expiration date is set to July 12, 2021, the follow-up reminder email would be sent exactly a year earlier on July 12, 2020.

Reminder Dates

Open the Gmail website, compose a new email message that will be the reminder template and save it in your drafts folder. The email body and subject can include column titles, enclosed inside double-curly braces and these will be replaced with actual values from the Google Sheet when the email is sent.

Auto Expiry Reminder Email

Here’s how are sample reminder email template looks like. You can also include emojis, images, and file attachments in your email drafts.

Automatic Email Reminder

Now that our customer data is ready to be merged, go to the Addons menu in the sheet and choose Configure Mail Merge.

Here follow the step-by-step wizard to add your sender’s name and also specify addresses that you wish to CC/BCC in every merged message.

In the Create Email Template section, choose “Use a Gmail Draft” and select the draft template that you’ve created in the previous step.

Send Date-based Reminder Emails

Expand the “Send Email Campaign” section and choose “Send a Test Email” to preview your message before it gets sent to external users. If all looks good, choose “Run Mail Merge” and hit “Go”.

That’s it. Mail Merge will setup a background task that will continuously run in the background and whenever a passport is due to expire, an email reminder is automatically sent to the client based on the date in the Scheduled Date column.

Send Reminder Emails

You can check the “Mail Merge Logs” sheet to track progress and a copy of all emails will also be saved in your Gmail Sent Items folder.

The reminder emails are sent based on the timezone of your spreadsheet. If you would like to send emails in a different timezone, go to the File menu inside Google Sheet, choose Spreadsheet Settings and update the timezone.

You can also make use of Filters in Google Sheets to send automatic emails to rows that meet specific criteria - when the country is “India” or when a cell value contains “Follow-up” and so on.

The same date-based workflow can be utilized to automate email sending in multiple scenarios like sending personalized wishes on birthdays and anniversaries, domain renewal reminders, fee payment reminders, appointments and more.

See the Mail Merge section for help.

Invoking Stored Procedure With Oracle Abstract Data Type Parameters in Mule 4

This article describes the steps that need to be followed in order to invoke a stored procedure with complex Abstract Data Type as IN, OUT, and IN OUT parameter in Mule 4.

The lack of documentation to handle ADT payloads while invoking stored procedures and technical issues while retrieving the ADT response in mule run time 4.x.x discouraged developers using mulesoft for the purpose.

Knowledge Graphs Power Scientific Research and Business Use Cases: Year of the Graph Newsletter, April/March 2020

Is there life after COVID-19? Of course there is, even though it may be quite different, and it may be hard to get there. But there's one thing in common in the "before" and "after" pictures: science and technology as the cornerstones of modern society, for better or worse.

We have argued before that Knowledge Graph is a technology that enables other technologies to accelerate their growth, and it also enables humans to take stock of their own knowledge. This is why the future is Knowledge Graph.

Creating a Non-English Chatbot Solution in Teneo

When you created your first solution you chose English as the bot’s language and the tutorials on this site assume your bot understands English. However, Teneo supports many more languages, which you can read about here: Languages.

The evaluation environment that is created for you when you sign up contains the resources needed that offer advanced support for Dutch, English, French, German, Norwegian and Swedish. On this page we will show you how you can create a German solution, but the same principle applies to French as well.

Watch the Women of React Conference for Free on Saturday, April 25

While much of the world is in lockdown, public gatherings and conferences have been cancelled, leaving a void in the lives of people who enjoy meeting their fellow open source contributors and colleagues in person throughout the year. Virtual events, which were already on the rise, are enjoying a bit of a renaissance by necessity.

On Saturday, April 25, the Women of React conference will stream live with seven speakers, along with Q&A and lightning sessions from React core contributors and leaders in the community. The event will include a single-stream of talks with breaks for socializing and connecting with other attendees, as well as an invite-only Discord chat server.

Women of React was organized as a sort of pop-up tech event in response to current events. Co-organizers Rachel Nabors, Kevin Lewis, Sara Vieira, and Jenn Creighton did not put out a request for speakers but rather opted to invite women from around the world who would provide quality presentations on diverse topics of interest to the React community.

“I think I woke up one morning and was watching the pandemic news and realized all the cool women I would usually see on the conference circuit cannot give their talks and I’m not going to see them,” Rachel Nabors said on a recent episode of the Inside Facebook Mobile podcast. “I’m not going to see any of my favorite women in the React community this year and it was super depressing.” She contacted her colleagues and together they quickly spun up a conference that would allow women in React to connect online.

Last week the organizers reported more than 1,000 registered attendees. They expect that number to be over 2,000 on the day of the conference. Fortunately, they don’t have to have a hard count on attendees ahead of time, since virtual events don’t have a limited number of seats. Organizers have even created printable swag for all who attend.

Women of React will run from 12:30pm—8:00pm EST. Attendees can sign up on the website and will receive a link for the livestream. Organizers are also planning to record the sessions so that people who are unable to attend can watch it at a later time.

How to Make a CSS-Only Carousel

We mentioned a way to make a CSS-only carousel in a recent issue of the newsletter and I thought that a more detailed write up would be interesting and capture some of my thoughts on making one.

So, here’s what we’re making today:

There’s no JavaScript here, whatsoever! No jQuery plugins. No trickiness. Just a couple of new-ish CSS properties that I’ve been experimenting with as well as some basic HTML.

OK to start, we need to focus on the markup. The design includes a left navigation made up of images and a large image gallery on the right that lets us scroll through each image individually. We’ll also need a wrapper to help us organize the layout:

<div class="wrapper">
  <nav class="lil-nav"></nav>
  <div class="gallery"></div>
</div>

Next, we can add images! For this little example, I checked out our list of sites with high quality images that you can use for free and went with Unsplash.

After saving images with the CodePen asset manager, I started adding the URLs to the nav element:

<nav class="lil-nav">
  <a href="#image-1">
    <img class="lil-nav__img" src="..." alt="Yosemite" />
  </a>
  <a href="#image-2">
    <img class="lil-nav__img" src="..." alt="Basketball hoop" />
  </a>
  <!-- more images go here --> 
</nav>

See that the href to each of these links is pointing to an ID? That’s because if we look at the demo again, we want to be able to click an image and then we want to it to hop to the larger version of that image in the gallery to the right.

So, now we can start to add these images to the large gallery, too…

<div class="gallery">
  <img class="gallery__img" id="image-1" src="..." alt="Yosemite" />
  <img class="gallery__img" id="image-2" src="..." alt="Basketball hoop" />
  <!-- more images go here --> 
</div>

Nifty. Next is the fun part: styling this bad boy. We can use a grid layout the parent .wrapper and set some smart defaults for the img element:

img {
  display: block;
  max-width: 100%;
}

.wrapper {
  display: grid;
  grid-template-columns: 1fr 5fr;
  grid-gap: 20px;
}

So far, we have our layout sorted and our links set up. Next, let’s any any overflow that might spill outside our wrapper and make sure that the nav and the gallery are scrollable:

.wrapper {
  display: grid;
  grid-template-columns: 1fr 5fr;
  grid-gap: 10px;
  overflow: hidden;
  height: 100vh; 
}

.gallery {
  overflow: scroll;
}

.lil-nav {
  overflow-y: scroll;
  overflow-x: hidden;
}

We can scroll through each image in the gallery now, but if this was a production website we’d probably want to make sure that folks can scroll passed this carousel a bit more easily. Trent Walton wrote about this very problem several years ago and I think it’s always worth keeping in mind.

Next up, let’s focus on the carousel snap of each image in the gallery. To do that we’ll need to use the scroll-snap-type and scroll-snap-align property like this:

.gallery {
  overflow: scroll;
  scroll-snap-type: x mandatory;
}

.gallery__img {
  scroll-snap-align: start;
  margin-bottom: 10px;
}

Now try scrolling through the gallery on the right-hand side again:

If you want to learn more about these properties I’d highly recommend this piece about practical CSS scroll snapping which digs into the nitty-gritty of these properties.

We have a pretty dang usable carousel! From here, all we have to do is tidy up the design because the gallery image isn’t the full height of the screen. To do that we can use object-fit and give each image a min-height with the vh unit, just like this:

.gallery__img {
  scroll-snap-align: start;
  margin-bottom: 10px;
  min-height: 100vh;
  object-fit: cover;
}

Now the big gallery images will always be the full size of the screen and will scale to take up the width and height. Let’s move on and tackle the style of the little navigation images:

.lil-nav {
  overflow-y: scroll;
  overflow-x: hidden;
}

.lil-nav a {
  height: 200px;
  display: flex;
  margin-bottom: 10px;
}

.lil-nav__img {
  object-fit: cover;
}

At first, I made this little nav act like a carousel too, but it felt really weird. I’m just keeping the default scroll behavior for now. In that demo above, though, try clicking an image. Notice how it jumps to that image in the carousel immediately? It would be nice if we could animate that transition a bit — and we can!

.gallery {
  overflow: scroll;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
}

That scroll-behavior CSS property is super handy for this and so now the whole thing will animate if you click one of the nav items:

Nifty, eh? One more tiny thing we could do here is throw a filter on the nav items to make them black and white and then animate them on hover:

.lil-nav__img {
  object-fit: cover;
  filter: saturate(0);
  transition: 0.3s ease all;
}

.lil-nav__img:hover {
  transform: scale(1.05);
  filter: saturate(1);
}

I’m sure there’s a lot more we could do here but I think this works quite nicely!

We could even throw a tiny bit of JavaScript into the mix to show which image is active, but I reckon that folks know that just from looking at the gallery.

That’s it! We now have a carousel that’s pretty dang good for progressive enhancement and it means we don’t have to load a library of JavaScript or write a bunch more code than we really need to.

Making the carousel responsive…

Let’s go one step further though and make this chap responsive. What we want to do is reverse the order of our grid by moving all of our current styles into a media query that is only activated at larger screens.

You might want to open up this demo in a new tab and decrease/increase the size of the browser to see the changes take place:

If you load this demo on a mobile device you should see how the layout switches between the two modes. This is done by using a single media query on the .wrapper element. Note that we’re using Sass:

$large: 1200px;

.wrapper {
  overflow: hidden;
  height: 100vh;
  display: grid;
  grid-template-rows: 2fr 1fr;
  grid-gap: 10px;

  @media screen and (min-width: $large) {
    grid-template-columns: 1fr 5fr;
    grid-template-rows: auto;
  }
}

Let’s add one on the navigation, too. But this time, we need to tell the navigation to start on the second row so it moves to the bottom of the screen:

.lil-nav {
  overflow-x: scroll;
  overflow-y: hidden;
  display: flex;
  grid-row-start: 2;

  @media screen and (min-width: $large) {
    overflow-y: scroll;
    overflow-x: hidden;
    display: block;
    grid-row-start: auto;
  }
}

With the gallery we need to switch around the scroll-type for larger screens and reverse the overflow property as well:

.gallery {
  overflow-x: scroll;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  display: flex;

  @media screen and (min-width: $large) {
    display: block;
    overflow-y: scroll;
    overflow-x: hidden;
    scroll-snap-type: y mandatory;
  }
}

That’s the bulk of the changes we’ve had to make and I quite like it! If we wanted to make this production-ready, we would think about accessibility (e.g. we probably don’t want screen readers to read out all the images in both the nav and gallery). Then there’s performance — we might consider lazy-loading so the images are only rendered when they’re needed.

Either way, this is a good start !

The post How to Make a CSS-Only Carousel appeared first on CSS-Tricks.

Testing a console input/output

Hi guys, I was trying to test a method which takes a user input, does something and then returns that input but I'm having some issues with it. I've attempted a few solutions, mostly described in SE, I will leaave them out of this
post and discuss instead the one that seemed the most likely to work instead.
This is the method that I'm trying to test (other code omitted for brevity):

public int getUserInput() {
        int choice = 0;
        boolean isValidInput = false;
        System.out.printf("Welcome. Select action: %d for READ, %d for CREATE, %d for UPDATE, %d for DELETE, %d for EXIT.", OperationOptions.READ.getValue(), OperationOptions.CREATE.getValue(), OperationOptions.UPDATE.getValue(), OperationOptions.DELETE.getValue(), OperationOptions.EXIT.getValue());
        while(!isValidInput)
            try {                 
                choice = scanner.nextInt();
                if(choice == OperationOptions.READ.getValue() || choice == OperationOptions.CREATE.getValue() || choice == OperationOptions.UPDATE.getValue() || choice == OperationOptions.DELETE.getValue() || choice == OperationOptions.EXIT.getValue())
                {
                    isValidInput = true;
                }
                else
                {
                    isValidInput = false;
                    System.out.println(String.format(Messages.NOT_ALLOWED_VALUES, OperationOptions.READ.getValue(), OperationOptions.CREATE.getValue(), OperationOptions.UPDATE.getValue(), OperationOptions.DELETE.getValue(), OperationOptions.EXIT.getValue()));
                }

                scanner.hasNextLine();
            }
            catch(InputMismatchException e) {
                 System.out.println(Messages.NOT_NUMERICAL_ERROR);
                 isValidInput = false;
                 scanner.nextLine();                 
            }
        return choice;
    }

A word about the test. What I had in mind was to test the actual input, so have a test that fakes the input, then calls the method and check that the fake input is the same as the one returned from that method. That would be
the first test, then chose another input and make sure it generates an exception and so on.

So this is my test class

package com.test.userInteraction;

import static org.junit.Assert.assertEquals;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.PrintStream;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class UserInputTest {
    UserInput userInput;
    private final InputStream systemIn = System.in;
    private final PrintStream systemOut = System.out;

    private ByteArrayInputStream testIn;
    private ByteArrayOutputStream testOut;

    @Before
    public void setUpOutput() {
        testOut = new ByteArrayOutputStream();
        System.setOut(new PrintStream(testOut));
    }
    private String getOutput() {
        return testOut.toString();
    }

    @After
    public void restoreSystemInputOutput() {
        System.setIn(systemIn);
        System.setOut(systemOut);
    }

    @Test
    public void testCase1() {
          int testString = 3;

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutput out;
        try {
            out = new ObjectOutputStream(bos);
            out.writeInt(testString);
            out.close();
            byte[] int_bytes = bos.toByteArray();
            provideInput(int_bytes);
            userInput = new UserInput();
            int userInput2 = userInput.getUserInput();
            assertEquals(testString, userInput2);

            bos.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private void provideInput(byte[] int_bytes) {
        testIn = new ByteArrayInputStream(int_bytes);
        System.setIn(testIn);

    }
}

So the problem is that it fails when it reachesint userInput2 = userInput.getUserInput(); inside getUserInput when it reaches choice = scanner.nextInt(); it generates a InputMismatchException and then controls goes back to choice = scanner.nextInt(); and then fails but I can't quite figure out why
The stack trace in the test is

java.util.NoSuchElementException
    at java.util.Scanner.throwFor(Scanner.java:862)
    at java.util.Scanner.next(Scanner.java:1485)
    at java.util.Scanner.nextInt(Scanner.java:2117)
    at java.util.Scanner.nextInt(Scanner.java:2076)
    at com.test.userInteraction.UserInput.getUserInput(UserInput.java:34)
    at com.test.userInteraction.UserInputTest.testCase1(UserInputTest.java:69)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)

Any idea what is going on? It's like it doesn't like the fake input somehow

Elevated Signals Shows How Technology Provides Great Benefits to Agriculture

When you think of agricultural technology (agtech), it seems something of a contradiction. Agriculture involves growing crops. There’s no real-world shortcut or fast track in that plants require planting in appropriate seasons with access to light, water, nutrients, and time to grow. By comparison, tech is about speed, rapid prototyping, and timely deployment. But today's cannabis farmers are using technological innovation to improve the health of their crops, effectively monitor their yield, and comply with government regulations. Today's crop grower is more likely to carry an iPad than a pitchfork and consult a data platform instead of an almanac.

One company leading the way is Canada's Elevated Signals. The company has created a digital production management platform that leverages wireless IoT (Internet of Things) sensors and modern software tools to help optimize crop production and manage complex compliance requirements. 

WP Feedback Kicks off Free Virtual Summit for WordPress Professionals on April 27

Decorative image for the WP Feedback Virtual Summit

WP Feedback is running a virtual event from April 27 – May 1. The event is primarily geared toward WordPress professionals who are looking to scale their business. It will feature CEOs, designers, freelancers, and more from the WordPress space. Between five and seven video sessions will be available each new day of the event.

The sessions are free to watch for the full 24-hour period on the day they are scheduled. Once that window closes, visitors must purchase an all-access pass to view them, which is currently available for $67 but will go up to $97 once the event begins. A one-time purchase provides lifetime access.

“Due to the outbreak of Coronavirus, otherwise known as COVID-19, every event has been postponed or outright canceled for the foreseeable future,” said Vito Peleg, founder of WP Feedback. “Seeing that the opportunity to learn and network with like-minded professionals was taken away from us at the last second, we decided to step in to provide the true conference experience all without leaving your desk.”

The goal of the summit is provide value by teaching attendees how to scale their agency or freelance business by having experts in their respective fields share advice.

“Above all, the best part is that it’s completely free to attend, and although some of us can’t wait to get out, I’m sure others will agree it’s also really nice that you can attend all from the comfort of your home office — or living rooms!” said Peleg.

The WP Feedback team hopes that everyone from freelancers to large agencies and businesses can learn something. “So to that end, the event is geared towards WordPress professionals who are looking to scale their business beyond themselves (without losing all of their hair), people struggling during the quarantine/lockdown as a result of an impact that this has had on their business, and people who are just looking to meet and network with other like-minded people in the community,” said Peleg.

The goal for WP Feedback is to help WordPress professionals succeed and scale their business via the site’s network and feedback plugin. “This effort is two-fold,” said Peleg. “We primarily do this with our software that simplifies and organizes client communication for web designers. But, we also do so with summits just like this one, educating people through our content and community platform.”

For those interested in seeing what type of content the summit offers, Piccia Neri’s session from 2019, The Main Ingredient of Great UX, is available to watch for free.

Continuation of WP Agency Summit

Last December, before joining the WP Feedback team, Jan Koch launched the first version of this event. Over 2,000 attendees registered and recorded 15,000 session views. Strictly by the numbers, the event was successful.

“Measuring the success of the 2019 summit event in numbers would not even tell half of the story,” said Peleg. “Most exciting were all the ripple effects the event caused. So many new connections were made not just from Jan’s perspective but also in the community that formed around the event on Facebook. We’re all still leveraging these new friendships and hope that, with the improved networking area for the new summit, we’ll see even more connections being made.”

With Koch joining WP Feedback, the team felt like it was a natural move to continue the event. “One of the main reasons Jan joined the team was to be heavily involved with our summit plans due to his experience and success with the WP Agency Summit last year,” said Peleg. “As this is WP FeedBack’s first summit, having Jan on the team has made it possible for us to organize it in such a short amount of time. He’s taught us a lot and we will 100% be using everything we’ve learned to do more like this in the future.”

One of the issues with the 2019 event was the lack of gender diversity. There was a 20:4 male-to-female speaker ratio. The team has attempted to address this for the 2020 event by adding more women to the lineup.

“Yes, that was a hard lesson learned for Jan,” Peleg said in response to the low number of women speakers. “He and the entire team at WP FeedBack leveraged our connections to get a more even ratio this time. Obviously, there are many successful women in the WordPress space, and now we were able to bring a few of our friends on thanks to our combined networks.”

The WP Feedback team has been collectively working to make this year’s event a success. Peleg said that many on the team have had to quickly adapt and learn how to run such an event. “Thankfully, Jan’s experience has massively helped in how we have been planning everything, and he is the one heading up all of the sessions too,” he said. “The vision was to create a summit experience online that replicates how it feels to go to a summit in real life, and we are really taking huge steps to provide that experience for all of our attendees.”

jQuery .stop() all animation

How can I use jQuery's .stop() to stop all animations and not just for one specific selector.

In my use case, I don't know the element being animated.

Does this function bubble? Can I do something like $(document).stop(true, false); ??

“The title ‘Front-End Developer’ is obsolete.”

That title is from the opening tweet of a thread from Benjamin De Cock. I wouldn’t go that far, myself. What I like about the term is that ‘Front-End’ literally means the browser, and while the job has been changing quite a lot — and is perhaps fracturing before our eyes — the fact that the job is about doing browser work is still true. We’re browser people. This was a point I tried to make in my “Ooooops I guess we’re full-stack developers now” talk.

I really like Benjamin’s sentiment though. There is a scourge of implementations of things on the web that are both heavier and worse because they re-implement something that the browser offers better and “for free.” Think sliders: scrolling behavior, snap points, fixed/sticky positioning, form controls, animation, etc.

Our industry seems to have acknowledged that backend and frontend developers require very different skills (even though they often use the exact same language), and yet it’s struggling to see there’s too much bundled into the term “front-end developer”.

That’s the tricky part. That’s at the heart of The Great Divide. There’s an awful lot of front-end developers where their job solely focuses on JavaScript. You could call them “JavaScript Engineers” or “JavaScript Developers,” and that feels OK. However, I’m not sure what you call someone who’s a great front-end developer, not particularly focused on JavaScript, but is on other aspects of the front end.

The modern frontend developer is most often than not a “Jack of all trades” mastering JS (or even just a framework) and barely tolerating HTML/CSS as a necessary evil. That’s understandable. I strongly think it’s a different specialization, and it’s too much for a single person.

Yep, it’s OK! The divide isn’t a bad thing; it’s just a thing. Front-end teams need JavaScript specialists and CSS specialists and accessibility specialists and performance specialists and animation specialists and internationalization specialists and, and, and, and. They don’t have to all be separate people. People can be good at multiple things. It’s just exceptionally rare that people are good at everything, even when scoped only to front-end skills.

The post “The title ‘Front-End Developer’ is obsolete.” appeared first on CSS-Tricks.

Python question.

In python
how to write a program which takes a number of days from now - 100 days, and find in which month that future day is.

Mule 4: Dynamically Call Multiple Subflows With One Flow-Ref

In this tutorial, we will see how we can call multiple subflows dynamically with the help of single flow reference component. 

As a first step, let's create a new Mule project using Anypoint Studio. After  creating the project, we need to have all the subflow details listed under .properties/.yaml file.

Developing Reactive REST APIs With Quarkus

This article describes how to implement reactive REST APIs in Java with Quarkus rather than using synchronous endpoints. In order to do this, the Java classes CompletableFuture and CompletionStage are needed. The article explains how to use these classes and how to chain asynchronous method invocations including exception handling and timeouts.

Why Use Reactive REST APIs?

The first question you probably ask is, why should you change old habits and not use imperative code? After all implementing asynchronous code is rather unusual for some Java developers and requires a new thinking.

Square Announces Terminal API Beta

Square has announced the beta release of its new Square Terminal API. Through the API, developers can integrate the Square Terminal with their own POS systems. That includes mobile platforms, web, desktop, anything. All payment types are supported, including touchless, NFC technology.

Getting Started With MariaDB SkySQL for Analytics

MariaDB recently announced SkySQL, the first DBaaS (database-as-a-service) to unlock the power of the MariaDB Platform. You’re likely familiar with the traditional row-based storage that RDBMS platforms offer, and while MariaDB SkySQL certainly offers that approach, it also provides much more.

MariaDB Platform for Analytics leverages the columnar capabilities of MariaDB ColumnStore with data placed on object storage in the cloud. With this functionality, you not only get the high-performance analytical benefits of columnar storage, but you eliminate the need to pre-allocate storage for growth. MariaDB Platform for Analytics allows you to perform real-time ad hoc queries on big data using inexpensive pay-as-you-go object storage.