How To Build A Real-Time Commenting System

  • 25 minute read
  • Coding, CSS, JavaScript, HTML5, HTML
  • Share on Twitter, LinkedIn

Add Real content -Time functionality for an app can result in a more interactive and engaging user experience. However, configuring and maintaining real-time components on the server side can be an unwanted distraction. But don’t worry, there’s a solution.

Cloud-hosted web services and APIs have come to the rescue of many developers in recent years, and real-time functionality is no different. Pusher’s goal, for example, is to let you focus on building your real-time web apps by offering a hosted API that makes it quick and easy to add scalable real-time functionality to web and mobile apps.

Further reading on SmashingMag:

  • Improve user experience with real-time features
  • Real-time data and a more personalized web
  • Creating a Real-time Retrospective Dashboard with Videochat
  • Where did all the comments go?

In this tutorial, I’ll show you how to turn a basic blog commenting system into a an engaging real-time experience where you’ll see a comment made in one browser window “magically” appear in a second window.

Why should we care about the real-time web?

Although the real-time Web is a relatively recent buzzword, real-time Web technologies have been around for a long time. more than 10 years They were mainly used by companies building software targeted at the financial services industry or in web chat applications. These initial solutions were classified as “hacks”. In 2006, these solutions were given a general term called Comet, but even with a defined name, the solutions were still considered hacks. So what has changed?

In my opinion, there are a number of factors that have brought real-time web technologies to the forefront of web application development.

Social Media Data

Social media, and specifically Twitter, has meant that more and more data is instantly available. Gone are the days when we had to wait forever for Google to find our data (blog posts, status updates, images). There are now platforms that not only make our data instantly visible, but also deliver it instantly to those who have declared interest. This publish/subscribe idea is critical to the real-time web, especially when building web applications.

Increased user expectation

As more users move to applications like Twitter and Facebook , and the user experiences they offer, changed their perception of what to expect from a web application. Although applications had become more dynamic through the use of JavaScript, experiences were rarely truly interactive. Facebook, with its real-time wall (and later other real-time features) and Twitter with its stream-centric, conversation-focused user interface, demonstrated how engaging web apps can be.

WebSockets

HTML5 and WebSockets are great!

I previously said that previous solutions to allow servers to instantly send data to web browsers were considered “hacky”. But this didn’t remove the fact that there was a requirement to be able to do this in a standardized and cross-browser way. Our prayers have finally been answered with HTML5 WebSockets. WebSockets represent a standardized API and protocol that enable two-way communication between the server and the client (web browser) in real time over a single connection. Older solutions could only achieve two-way communication using two connections, so the fact that WebSockets use only one connection is really a big problem. It can be a huge resource saver for both the server and the client, and the latter is especially important for mobile devices where battery power is extremely precious.

How are technologies used in real-time?

Real-time web technologies are making it possible to create all kinds of compelling functionality, leading to better user experiences. Here are some common use cases:

  • Real-time statistics: Technology was first used in finance to display stock information, so it’s no surprise that now be used more than ever. It is also very beneficial for sports, betting and analysis.
  • Notifications – when something a user is interested in becomes available or changes.
  • Activity Streams: Activity streams from friends or projects. This is commonly seen in apps like Twitter, Facebook, Trello, Quora, and many more.
  • Chat: The 101 or real-time web technology, but it’s still a very valuable feature . It helps to offer instant interaction between friends, co-workers, customers and customer service, etc.
  • li>

  • Multiplayer Games: The ability to instantly deliver player moves, game state changes, and score updates is clearly important for multiplayer games.

< In the rest of this tutorial I'll cover creating a basic blog commenting system, how to progressively improve it using jQuery, and finally also progressively improve it using the real-time web service I work for, Pusher, which will demonstrate no not only how easy it can be to use real-time web technology, but also the value and increased engagement that a real-time factor can introduce.

Creating a Generic Commenting System for Blogs

Start from a pla ntilla

I want to focus on adding real-time comments to a blog post, so let’s start with a template.

This template reuses the defined HTML5 layout in the post Coding an HTML 5 Layout from Scratch and the file structure we’ll start with is as follows (with a few additions we don’t need to worry about at this point):

  • css ( dir)
    • global-forms.css
    • main.css
    • reset.css
  • images ( dir)
  • index.php

HTML

The HTML template, found in index. php, it has been changed from the HTML5 layout article to focus on content like a blog post with comments. You can see the HTML source here.

The main elements to consider are:

  • – the content of the blog post< /li

  • – where comments should appear. This is where most of our work will be done.

Comments

Now that we have the HTML code for our blog post and to display the comments, we also need a way for our readers to post comments, so let’s add a element to collect and send the comment details to post_comment.php. We’ll add this to the end of the

section wrapped in a

.

Leave a comment

CSS Comment Form

Let’s apply some CSS so that the Make things look a little better by adding the following to main.css:

#respond { margin top: 40px; } #responder input[type=’text’], #responder input[type=’email’], #responder textarea { margin-bottom: 10px; screen lock; width: 100%; border: 1px solid rgba(0, 0, 0, 0.1); -webkit-border-radius: 5px; -moz-border-radius: 5px; -o-border-radius: 5px; -ms-border-radius: 5px; -khtml-border-radius: 5px; border-radius: 5px; line height: 1.4 em; }

Once the HTML structure, comment form, and CSS are in place, our blogging system has started to look a bit more presentable.

Screenshot of blog post and the comment system

Handling the comment posting

The next step is to write the PHP form post handler that accepts the request and stores the comment, post_comment.php . You should create this file in the root of your application.

As I said before, I want to focus on realtime functionality, so there is a class within the template that you downloaded that encapsulates some of the functionality verification standard and data persistence. This class is defined in Persistence.php (you can view the source code here), is not production quality, and handles:

  • Basic validation
  • Basic data sanitization
  • Very simple persistence using a $_SESSION user. This means that a comment saved by one user will not be available to another user.

This also means that we don’t need to waste time setting up a database and all that goes with it. and makes post_comment.php very simple and clean. If you want to use this functionality in a production environment, you will need to rewrite the contents of Persistence.php. Here is the code for post_comment.php.

add_comment($_POST) ) { header( ‘Location: index.php’ ); } else { header( ‘Location: index.php?error=Your comment was not published due to errors in your form submission’ ); } ?>

The above code does the following:

  1. Includes the Persistence.php class that handles saving and getting comments.
  2. Creates a new instance of the Persistence object and assigns it to the variable $db.
  3. Tries to add the comment to $db. If the comment is added successfully, it is redirected to the blog post. If it fails, the redirect also occurs, but error text is added to an error query parameter.

Display comments with blog post

The last thing we need to do to get our Generic Blog Commenting System up and running is to update the blog page, index.php, to get and display the comments from the Persistence object.

  • Since this is not a blogging system we will hardcode the value of $comment_post_ID to be 1.
  • Include the Persistence.php class and get the comments from it. Comments are associated with a blog post by a unique $comment_post_ID.

get_comments($comment_post_ID); $has_comments = (count($comments) > 0); ?>

Since we now have $comment_post_ID accessible via PHP, we need to update the HTML for the comment form to use this value.

<input type="hidden" name="comment_post_ID" value=" ” id=”comment_post_ID” />

We now have all the comments related to the blog post referenced by the $comments variable and we need to display them on the page. To do this, we need to update PHP in index.php to loop through them and create the required HTML.

<ol id="posts-list" class="hfeed”>

  • Be the first to add a comment.
  • <article id= "comment_” class=”hentry”>
    <abbr class="published" title="”>

    By

  • You will notice that if the value of $has_comments is true, an additional CSS class is applied to the ordered list named has-comments. This is so we can hide the list item with the “Be the first to add a comment” message when the comments are displayed using CSS:

    #posts-list.has-comments li.no-comments { display : none ; }

    Now that all of this is in place, we have a working blog commenting system. If you want to start writing your code from this basic blog comment system, you can also download the completed code here.

    Screenshot of working blog comment system

    Progressive improvement with jQuery

    The first step in making our blog commenting system feel less like a web page and more like an app is to stop page reloads when a user posts a comment. We can do this by sending the comments to the server using an AJAX request. Since jQuery is probably the de facto standard for cross-browser JavaScript functionality, we’ll use it here. Although I’m using jQuery here, I’d also like to point out that it’s a good idea not to always use jQuery. Instead, look at your scenario and make a considered decision because there are some cases where it’s better not to.

    In an attempt to try to keep as much scripting as possible (PHP and JavaScript) from the index.php file we will create a new folder for our JavaScript and there a file for our JavaScript application. The path to this padding should be js/app.js. This file should be included after the jQuery include.

    Catch the comment form submission

    When the page is ready, bind it to the form’s submit event.

    $(function() { $ (‘#commentform’).submit(handleSubmit); });

    When the form is submitted and the handleSubmit function is called, the comment data that we want to submit to the server is pulled from the form. There are more elegant ways to get the form data, but this approach clearly shows where we’re getting the values ​​from and the data object we’re creating.

    function handleSubmit() { var form = $(this); var data = { “author_comment”: form.find(‘#author_comment’).val(), “email”: form.find(‘#email’).val(), “comment”: form.find(‘# comment’).val(), “comment_post_ID”: form.find(‘#comment_post_ID’).val() }; postComment(data); false return; } function postComment(data) { // send the data to the server }

    POST the comment with AJAX

    Inside the postComment function make a POST request to the server passing the data we retrieved from the form When the request is made, an additional HTTP header will be sent to identify the request as an AJAX request. We want to do this so that we can return a JSON response if it’s an AJAX request and keep our basic functionality if it’s not (for more on this, see AJAX events caught on the server). We also define two controllers; postSuccess to handle the stored comment successfully and postError to handle any failure.

    function postComment(data) { $.ajax({ type: ‘POST’, url: ‘post_comment.php’, data: data, headers: { ‘X-Requested-With’: ‘XMLHttpRequest’ }, success: postSuccess, error: postError }); } function postSuccess(data, textStatus, jqXHR) { // add comment to UI } function postError(jqXHR, textStatus, errorThrown) { // display error }

    Dynamic update of UI with comment

    At this point, the comment data is sent to the server and saved, but the AJAX response does not provide any meaningful feedback. Also, the comment section does not refresh to display the recently submitted comment, so the user would have to refresh the page to see it. Let’s start by writing the code to update the UI and test that functionality.

    If you’re thinking “Wait a minute! We don’t have all the data we need from the web server to display the comment”, then you’re right. However, this doesn’t stop us from writing the code to update the UI and also test that it works, here’s how:

    function postsuccess(data, statetext, jqXHR) { $(‘#comment form’) .get(0).reset(); showComment(data); } function showComment(data) { varHtmlComment = createComment(data); var CommentThe = $(HtmlComment); commentThe.hide(); var PostList = $ (‘#post-list’); postsList.addClass(‘has-comments’); postsList.prepend(commentEl); commentEl.slideDown(); } function createComment(data) { var html = ‘ + ‘

  • ‘ + ‘

    ‘ + ‘

    ‘ + ‘

    ‘ + data.comment + ‘

    ‘ + ‘

    ‘ + ‘

  • ‘; return html; } function parseDisplayDate(date) { date = (date instance of Date? date : new Date( Date.parse(date) ) ); var display = date.getDate() + ‘ ‘ + [‘January’, ‘February’, ‘March’, ‘April’, ‘May’, ‘June’, ‘July’, ‘August’, ‘September’, ‘ October’, ‘November’, ‘December’][date.getMonth()] + ‘ ‘ + date.getFullYear(); return screen; }

    The above code does the following:

    • Inside the postSuccess function we clear the form values ​​and call displayComment.
    • displayComment first calls the createComment function to create the HTML list (
    • ) element as a string.
    • We then convert the HTML to a jQuery object using $(commentHtml) and hide the element.
    • The element of the comment list is then prepended to the ordered list of comments (
        ). The list also has a class called has comments added so that we can hide the first item in the list that contains the “Be the first to comment” statement.
      1. Finally, we call commentEl.slideDown() so that have the comment displayed in what is becoming the standard “here’s a new item” form.

    The functionality is already implemented but we want to test it. This can be accomplished in two ways:

    • The displayComment is a global function so we can call it directly using the browser’s JavaScript console.
    • We can hook to an event in the page that triggers a fake update that calls the displayComment function

    Let’s go with the latter and bind to the “u” key that is released by binding to the keyup event. When it is, we’ll create a dummy data object containing all the information needed to create a new comment and pass it to the displayComment function. That comment will be displayed in the UI.

    Press the “u” key multiple times and you will see the comments appear.

    $(function() { $(document).keyup(function ( e) { e = e || window.event; if(e.keyCode === 85){ displayComment({ “id”: “comment_1”, “comment_post_ID”: 1, “date”:”Tue, Feb 21 2012 18:33:03 +0000″, “comment”: “The real-time web is great!”, “comment_author”: “Phil Leggetter” }); } }); });

    Great! We now know that our displayComment function works exactly as expected.Remember to remove the test function before posting or you will really confuse your user every time they press “u”.

    Screenshot of a bunch of fake comments

    Detect and respond to AJAX request

    All that’s left to do is update the post_comment.php file to detect the AJAX call and return information about the newly created comment.

    Detection of the AJAX request is done by checking the X-Requested-With header:

    $ajax = ($_SERVER[ ‘HTTP_X_REQUESTED_WITH’ ] === ‘XMLHttpRequest’);

    Once we know that the request is an AJAX Request, we can update the code to respond with an appropriate status code and the data representing the comment. We also need to make sure that the original functionality is maintained. The post_comment.php code now looks like this:

    add_comment($_POST); if($ajax) { sendAjaxResponse($added); } else { sendStandardResponse($added); } function sendAjaxResponse($added) { header(“Content-Type: application/x-javascript”); if ($added) { header(‘Status: 201’); echo( json_encode($added) ); } else { header(‘Status: 400’); } } function sendStandardResponse($added) { if($added) { header( ‘Location: index.php’ ); } else { header( ‘Location: index.php?error=Your comment was not published due to errors in your form submission’ ); } } ?>

    The key points of the above code are:

    • The $db->add_comment($_POST) call returns the data of the added comment that is assigned to the $added variable.
    • By setting the response content-type to “application/json”, we tell jQuery to convert the returned string to a JavaScript object. For more information on calling JSON web services, see the Beginner’s Guide to jQuery-Based JSON API Clients.
    • Status code 201 indicates a successful call and also that the call created a resource (the comment).

    The blog comment system now works in a much more dynamic way, instantly showing the user that their comment has been posted without refreshing the page. Also, the way we add JavaScript-based functionality to the page means that if JavaScript is disabled or a JavaScript file fails to load, the system will fall back to the standard functionality we first implemented.

    Get real time : finally!

    As with any “from scratch” tutorial, it can take a bit of time to get to the really interesting part, but we’re finally here. . However, all the work we have done has been worth it. Because we’ve built our commenting system in a progressively improved way, plugging Pusher into it is going to be a breeze.

    What is Pusher?

    At the beginning of the tutorial, it said that we would use Pusher to add real-time functionality to the app. But what is Pusher?

    Pusher is a hosted service for quickly and easily adding real-time features to web and mobile applications. It offers a RESTful API that makes it easy to post events from any application that can make an HTTP request, and a WebSocket API for real-time, two-way communication. You don’t even need to use the APIs directly, as there are server (PHP, Ruby, node.js, ASP.NET, Python, and more) and client (JavaScript, iOS, Android, .NET, ActionScript, Arduino, and more) libraries available at a host of technologies, which means you can add real-time functionality to an application in a matter of minutes. I’m sure you’ll be surprised how easy it is!

    Sign Up for Pusher and Get Your API Credentials

    To add Pusher-powered real-time functionality to a web application, You must first sign up for a free Sandbox account. Once you’ve signed up, you’ll be taken to the Pusher control panel, where you’ll see that a “Main” app has been created for you. You’ll also see that you’re in the “API Access” section for that app, where you can get your API credentials.

    Screenshot of API access section in Pusher Dashboard

    For easy access, create a file pusher_config.php and define the credentials there so we can refer to them later:

    In your version of pusherconfig.php, make sure to replace the values ​​that are ‘YOURS with your actual credentials.

    You should also request this in your index.php file. We should also make APP_KEY available to the JavaScript runtime, as we’ll need it to connect to Pusher.

    var APP_KEY = ”;

    Realtime JavaScript

    The first thing to do when adding Pusher to a web application is to include the Pusher JavaScript library and connect to Pusher. To connect, you will need to use the key you took from the Pusher dashboard. Below you can see everything that is required to connect your front-end app to Pusher.

    Include the Pusher JavaScript library after app.js include:

    Add Pusher functionality to app.js:

    var pusher = new Pusher(APP_KEY); var channel = pusher.subscribe(‘comments-‘ + $(‘#comment_post_ID’).val()); channel.bind(‘new_comment’, displayComment);

    This probably sounds too easy to be true, so here are the details on what the above code does:

    • var pusher = new Pusher(APPLICATION_KEY); Creates a new instance of a Pusher object, and in doing so connects it to the Pusher. The app to use is defined by the APP_KEY value you pass in that we set earlier.
    • var channel = pusher.subscribe(‘comments-‘ + $(‘#comment_post_ID’).val( )); Channels provide a great way to organize data streams in real time. Here we are subscribing to the comments of the current blog post, uniquely identified by the value of the hidden form input element comment_post_ID.
    • channel.bind(‘new_comment’, displayComment); Events are used to further filter data and are ideal for linking updates to UI changes. In this case, we want to bind to an event that fires every time a new comment is added and display it. Since we’ve already created the displayComment function, we can simply pass a reference to the call to bind to.

    Dispatching events in real time using the Event Builder

    We You can also test this functionality without writing any server-side code by using the Event Builder for your application, which can also be found in the Pusher panel. The Event Creator allows you to post events to a channel through a simple user interface. From the code above we can see that we want to post an event called “new_comment” to the channel “comments-1”. From the test function above we also have an example of the test data we can post.

    Screenshot of the event creator in Pusher Dashboard

    PHP real-time

    Once again, we have shown that our client-side functionality works without having to write any server-side code. Now let’s add the PHP code we need to fire the new comment event as soon as a comment is posted in our comment system.

    Pusher offers a number of server-side libraries that make posting events easy in addition to helping with functionality such as private channel authentication and providing user information for presence channels. We only want to use the basic event trigger functionality in the post_comment.php file, so we need to download the PHP Pusher library.

    Once you have downloaded this zip file, unzip it into the directory along with your other files. Your file structure will now look like this:

    • index.php
    • css (dir)
    • images (dir)
    • post_comment.php
    • pusher_config.php
    • Persistence.php
    • squeeks-Pusher-PHP (dir)
      • lib (dir)
        • Pusher.php

    An event can be triggered with just a few lines of code:

    trigger(‘comments-1’, ‘new_comment’, array( “post_ID_comment” => 1, “date” => “Tue, Feb 21 2012 18:33:03 +0000”, “comment” => “The real-time web is cool!”, “comment_author” => “Phil Leggetter” )); ?>

    However, we need to apply some additional logic before firing the event:

    • Verify that the comment has been added.
    • Extract the unique identifier of the comment from the $added array.
    • Create the text to identify a channel name for the submitted comment.
    • Fire a _newcomment event on the channel with the $added data. Note: The library automatically converts the $added array variable to JSON for sending via Pusher.

    So the entire post_comment.php file ends up looking like this:

    add_comment($_POST); if($added) { $channel_name = ‘comments-‘ .$added[‘comment_post_ID’]; $event_name = ‘new_comment’; $pusher = new pusher(APP_KEY, APP_SECRET, APP_ID); $pusher->trigger($channel_name, $event_name, $added); } if($ajax) { sendAjaxResponse($added); } else { sendStandardResponse($added); } function sendAjaxResponse($added) { header(“Content-Type: application/json”); if ($added) { header(‘Status: 201’); echo( json_encode($added) ); } else { header(‘Status: 400’); } } function sendStandardResponse($added) { if($added) { header( ‘Location: index.php’ ); } else { header( ‘Location: index.php?error=Your comment was not published due to errors in your form submission’ ); } } ?>

    If you run the application now in two different browser windows, you’ll see that as soon as you post a comment in one window, that comment will instantly (“magically”) appear in the second window. We now have a real-time commenting system!

    But&mldr;, we’re not done yet. You will also see that the comment is displayed twice in the window of the user who submitted it. This is because the comment has been added by the AJAX callback and the Pusher event. Because this is a very common scenario, especially if you’ve built an application in a progressively improved way like ours, the Pusher server libraries expose a way to exclude a connection/user from receiving the event via Pusher.

    To do this, you need to send a unique connection identifier called socket_id from the client to the server. This identifier can be used to define who will be excluded.

    function handleSubmit() { var form = $(this); var data = { “author_comment”: form.find(‘#author_comment’).val(), “email”: form.find(‘#email’).val(), “comment”: form.find(‘# comment’).val(), “comment_post_ID”: form.find(‘#comment_post_ID’).val() }; var socketId = getSocketId(); if(socketId !== null) { data.socket_id = socketId; } postComment(data); false return; } function getSocketId() { if(pusher && pusher.connection.state === ‘connected’) { return pusher.connection.socket_id; } returns null; }

    The changes we have made are:

    • A new function called getSocketId has been added to get the socket_id. Wraps a check to make sure the pusher variable is set and also that the client is connected to the pusher.
    • The handleSubmit has been updated to check if a socket_id is available. If so, this information is posted to the server along with the comment data.

    On the server, we need to use the socket_id parameter if it is present and thus exclude the connection and the user who posted the comment, or pass null if it isn’t:

    $channel_name = ‘comments-‘ . $added[‘comment_post_ID’]; $event_name = ‘new_comment’; $socket_id = (isset($_POST[‘socket_id’])?$_POST[‘socket_id’]:null); $pusher = new pusher(APP_KEY, APP_SECRET, APP_ID); $pusher->trigger($channel_name, $event_name, $added, $socket_id);

    And as simple as that, we have a fully enabled real-time blog commenting system and we only push messages to users who really need to see them. As with the AJAX functionality, the real-time functionality has been added in a progressively improved way, to ensure that it does not affect any other functionality. You can find a running demo here and the complete solution in the real-time feedback repository on github.

    Real-time application development best practices

    Developing applications in real-time realtime shares good common development practices with general web development. However, I thought I’d share a couple of tips that might be particularly helpful.

    Use the browser’s developer tools

    When you start doing a lot of JavaScript, the browser’s developer tools they become your best friend. It’s the same when adding real-time functionality to your web application, not only because you’re using JavaScript, but also because the JavaScript library you’re using is likely doing some pretty complex things internally. So the best way to understand what’s going on and if your code is using it as expected is to enable logging, which usually goes to the developer console. All major browser vendors now offer good developer tools including a console:

    • Firebug Add-on for Firefox
    • Internet Explorer F12 Developer Tools
    • Opera Dragonfly
    • Safari Developer Tools

    The Pusher JavaScript library provides a way to connect to the logging functionality. All you need to do is assign a function to the Pusher.log static property. This function will receive all log messages. You can do whatever you want inside the function, but the best practice is to log the messages in the developer console. You can do this as follows, making sure that the code executed after the Pusher JavaScript library includes:

    Pusher.log = function(msg) { if(window.console && window.console.log) { window. console.log(newdate()).getTime() + ‘: ‘ + message); } };

    The above code checks that the console and logging function are available (not in older browsers) and then logs the messages along with a timestamp to the JavaScript console. This can be incredibly useful for tracking down issues.

    Screenshot of Pusher login to Chrome Developer Tools Console

    Check connectivity

    Any good real-time technology will maintain a persistent connection between the client (web browser) and the server or web service. Sometimes the client will lose connectivity and when the client is not connected to the Internet, the real-time functionality will not work. This can happen a lot with apps running on mobile devices that rely on mobile networks. Therefore, if your application depends on such connectivity and functionality, it is important to deal with scenarios where the client is not connected. This could be by displaying a message to tell the user that they are offline, or perhaps you want to implement some alternative functionality.

    The Pusher JavaScript library exposes the connectivity state through the pusher.connection object, which we briefly looked at earlier when get the socket_id. Binding to state changes and implementing the required functionality is quite simple, as it follows the same mechanism as binding to events on channels:

    var pusher = new Pusher(APP_KEY); pusher.connection.bind(‘state_change’, function(states) { pusher.log(‘Connection state changed from: ‘ + previous.states + ‘ to ‘ + current.states); });

    Conclusion </h2

    We see real-time functionality appear in a lot of high-profile apps: some have it at the heart of what they offer, while others use it sparingly. No matter how it’s used, the end goal is generally the same; to improve the user experience and keep users engaged with an app. By turning a basic blog commenting system into a more engaging communication platform, I hope I’ve shown that the functionality and experience can be easily layered onto an existing application.

    The ease of access to this technology is relatively new. thing and we just touched on the potential uses of the technology. Real-time statistics, instant news updates, activity streams, social interaction, collaboration, and gaming are just some of the common uses, but as more developers become aware and comfortable with the technology, I’m sure we’ll see some truly amazing innovation. An “Internet of things in real time?”?

    .

    See Also:  How to create multiple pages on a website using wordpress

    Leave a Reply

    Your email address will not be published. Required fields are marked *