Node.js, Doctor’s Offices and Fast Food Restaurants – Understanding Event-driven Programming

The Frying Dutchman

Are you struggling to understand “event-driven” programming? Are you having trouble wrapping your brain around “blocking” vs “non-blocking” I/O? Or are you just trying to understand what makes Node.js different and why so many people are talking about it? (and why I keep writing about it?)

Try out one of these analogies…

The Doctor’s Office Reception Line Analogy

In the excellent episode 102 of the Herding Code podcast, Tim Caswell relates event-driven programming to standing in the line at a doctor’s office to see the receptionist. Inevitably, at least here in the USA, there are additional forms to fill out with insurance info, privacy releases, etc.

A Traditional Model

In a traditional thread-based system, when you get to the receptionist you stand at the counter for as long as it takes you to complete your transaction. If you have to fill out 3 forms, you would do so right there at the counter while the receptionist just sits there waiting for you. You are blocking her or him from servicing any other customers.

The only real way to scale a thread-based system is to add more receptionists. This, however, has financial implications in that you have to pay more people and physical implications in that you have to make the room for the additional receptionist windows.

Events To The Rescue

In an event-based system, when you get to the window and find out you had to complete additional forms, the receptionist gives you the forms, a clipboard and a pen and tells you to come back when you have completed the forms. You go sit down in the waiting and the receptionist helps the next person in line. You are not blocking her from servicing others.

When you are done with your forms, you get back in line and wait to speak with the receptionist again. If you have done something incorrectly or need to fill out another form, he or she will give you the new form or tell you the correction and you’ll repeat the process of going off, doing your work, and then waiting in line again.

This system is already highly scalable (and is in fact used in most doctor’s offices I visit). If the waiting line starts getting too long, you can certainly add an additional receptionist, but you don’t need to do so at quite the rate of a thread-based system.

The Fast Food Restaurant Analogy

It struck me that this is also very similar to ordering your food at a fast-food restaurant or street vendor.

The thread-based way would be to get to the front of the line, give your order to the cashier and then wait right there until your order was cooked and given to you. The cashier would not be able to help the next person until you got your food and went on your way. Need to service more customers… just add more cashiers!

Of course, we know that fast food restaurants don’t work that way. They are very much event-driven in that they try to make those cashiers as efficient as possible. As soon as you place your order, it’s sent off for someone to fulfill while the cashier is still taking your payment. When you are done paying, you have to step aside because the cashier is already looking to service the next customer. In some restaurants, you might even be given a pager that will flash and vibrate when your order is ready for pickup (My local Panera Bread does this).  The key point is that you are not blocking the receiving of new orders.

When your food is set, the cashier – or someone – will signal you by calling out your name, order number or triggering your pager.  The event of your order being ready causes the person to perform some function/action. (In programming lingo, this would be thought of as a “callback function“.)  You will then go up and get your food.

So What Does This Have To Do With Node.js?

The “traditional” mode of web servers[1] has always been one of the thread-based model. You launch Apache or any other web server and it starts receiving connections. When it receives a connection, it holds that connection open until it has performed the request for the page or whatever other transaction was sent. If it make take a few microseconds to retrieve a page from disk or write results to a database, the web server is blocking on that input/output operation. (This is referred to as “blocking I/O“.) To scale this type of web server, you need to launch additional copies of the server (referred to as “thread-based” because each copy typically requires another operating system thread).

In contrast, Node.js uses an event-driven model where the web server accepts the request, spins it off to be handled, and then goes on to service the next web request. When the original request is completed, it gets back in the processing queue and when it reaches the front of the queue the results are sent back (or whatever the next action is). This model is highly efficient and scalable because the web server is basically always accepting requests because it’s not waiting for any read or write operations. (This is referred to as “non-blocking I/O” or “event-driven I/O“.)

To put it a bit more concretely, consider this process:

  1. You use your web browser to make a request for “/about.html” on a Node.js web server.
  2. The Node server accepts your request and calls a function to retrieve that file from disk.
  3. While the Node server is waiting for the file to be retrieved, it services the next web request.
  4. When the file is retrieved, there is a callback function that is inserted in the Node servers queue.
  5. The Node server executes that function which in this case would render the “/about.html” page and send it back to your web browser.

Now, sure, in this case, it may only take microseconds for the server to retrieve the file, but..

microseconds matter!

Particularly when you are talking about highly-scalable web servers!

This is what makes Node.js different and of such interest right now. Add in the fact that it also uses the very common language of JavaScript, and it is a very easy way for developers to create very fast and very scalable servers.

Do these analogies help? Do have another analogy you use to explain “event-driven programming” or “event-driven I/O”?

[1] While I’m talking about “web servers” here, Node.js lets you write all sorts of different types of servers for many other protocols beyond HTTP. They all have similar issues (blocking vs non-blocking I/O).

Image credit: gerry balding on Flickr

80 thoughts on “Node.js, Doctor’s Offices and Fast Food Restaurants – Understanding Event-driven Programming

    1. Dan York Post author

      Caleb, Glad you liked it and MANY thanks for the catch on the URL! I’ve fixed it. (And it shows exactly why it’s so important to grab “.com” addresses as they are often inadvertently the “default” address people use… even for people who know better but make mistakes.)

      Thanks,
      Dan

      Reply
  1. Pingback: Slides: Node.js, Event Loops and How To Stop Writing Spaghetti Code | Code.DanYork.com

  2. chrelad

    Nice job, I like these analogies. I think I’ll refer people to this page when they ask about the event driven nature of node.js; because I just know I’ll mess up the analogy :)

    Reply
  3. Jay Godse

    Many folks say that this works with Javascript because of its callback functions. However, I have seen systems similar to these done 10 to 20 years ago in C++ and other languages. What is different about Javascript that enables this asynchronous event processing model? What prevents it from being done in Ruby, C#, Java or other languages?

    With node.js, is it possible to process more requests concurrently than the maximum number of simultaneous TCP connections allowed for an application server process? If so, how?

    Just curious.

    Reply
    1. Dan York Post author

      Jay,

      Thanks for the comment. You’re absolutely right… callback functions have been around for many years in many different languages. And the async event-driven model is already available in other languages. For instance Ruby has the “EventMachine” framework and python has the “Twisted” framework. So nothing prevents doing async event-driven programming in other languages.

      What perhaps has brought JavaScript so much into play is that: 1) developers using JavaScript on the client-side (web browser) are already used to event-driven programming because they are waiting for button presses, hovers, clicks, etc.; and 2) on the server-side there wasn’t really a set-in-stone way of working with server-side JavaScript, so in promoting event-driven programming through Node.js the folks involved weren’t swimming against the tide of common usage. The Register article about Node.js that I recently referenced included a bit of discussion with Ryan Dahl around this point.

      Another reason may simply be that Node.JS latched on to a blindingly fast JavaScript engine, which then helped on the performance front.

      On your second question, I can’t think of a way that Node.js could process more requests than the max number of simultaneous TCP connections… however, it’s probably going to process those requests much faster than other app environments, and so you’ll be able to handle a greater flow. (Others commenting may have better comments than I on this point…)

      Thanks,
      Dan

      Reply
  4. Pingback: ReadyState4 » Blog Archive » Event-driven programming vs traditional programming

  5. Sachin Pethani { Web-Farmer }

    Hi Dan,

    Nice explanation of event driven concept. I was so confused about blocking and non blocking IO. Since I have heard about node, i really could not get it functionally.

    But your real world example helped me to clear all those area.

    Keep writing node’s great tutorial….

    Thanks

    Reply
  6. Kernel Guru

    The current fascination with the event-driven model is sorta sad. It’s living proof that software developers these days know absolutely nothing about the fundamentals of how computers–and operating systems–work.

    Sigh.

    You see, operating systems themselves are “event driven” and while your thread may be blocked, the computer is not. The operating will do… exactly what your program will do. It will schedule in another thread to be executed when one is blocked waiting for IO. Operating systems have been doing this since the 1970s, and they have nicely optimized and hardened code to do this. The only benefit you get is that your effective thread weight is lighter, but most OS’s these days have VERY lightweight threads available to the tune of a few dozen K, making thread overhead memory usage meaningless in a system of 32GB of ram. Meanwhile you are reinventing the wheel to save a few K of thread weight.

    So, if your analogy were true, why, pray-tell, does the internet as we know it even work? The most popular web server is Apache, and it is thread-based. Some of the largest and most heavily trafficked sites in the world serve billions of hits per day on this model. So you suppose they are doing with with what, 500 million CPUs each? Maybe you’re missing something.

    So the event-driven thing is a handy language construct, and if that works for you, great, but it’s not some kind of performance miracle.

    KG

    Reply
    1. Jesse Sanford

      After having worked with both thread model httpd and process model httpd I can tell you that there is a heck of a lot more overhead than simply the thread local cache that you speak of. Of course most of that is not apache’s fault. 99% of the time it is the application server behind apache. The daemon’s that httpd fronts for normally are a) not thread safe (as is the case with PHP ) and there for have to use a process per request model (I can here you saying but… copy on write! true but there again you are only able to use that optimization of the daemon is written in a fashion that can use it) or b) use a virtual machine and thus suffer the greenthread issues (ahem ruby<1.9) that block ALL other threads in the VM while the single operating system thread they are mapped to does some i/o. The above example is a bit trivial in that it only speaks to servicing static file requests. Node is generally not used for such a purpose. In fact I think most people shy away from using it to serve static files.

      Reply
  7. Pingback: Event-driven http server in C# with Rx and HttpListener

  8. Enzo

    Nice overview. From what I understand, in order for node to take advantage of multiple processors, you need to have more than one instance of it running which is kind of lame.

    Reply
  9. Mahesh Venkat

    I am curious on how this works for a browser based Http client — for the server side callback function to write back the response data, a Http client connection has to be kept open per user. In the case of multiple http connections per page (large number of widgets per page), a large number of Http Connections should be available to receive the asynchronous response.
    On top of that how do you handle security needs in a asynchronous callback response?

    Reply
    1. Kernel Guru

      You are comparing apples and bowling balls. If you have an app framework like PHP or Ruby, then an event-driven approach is out of the question anyhow.

      If you did the exact same thing (without any sort of app server framework) in either model, the performance and memory usage would be approximately equal, but the threaded model would be me a million times easier to deal with in the long-run because you aren’t constantly re-inventing everything the OS already has been doing for decades.

      Saying “this other model is way lighter weight because there is no software written for it so there’s nothing to weigh it down” doesn’t make any sense at all. :-)

      Reply
      1. Mike Shugar

        I’m totally with KG here. I’ve been programming for 30 years and “non-blocking” sounds like someone thinks they invented something new becasue they never heard of asynchronous thread pooling and queuing (around since the ’80s).

        However it is kind of cool to have JavaScript on the server.

        Reply
  10. Stu

    Nice post, but I think the original (and maybe best) analogy goes back some time. Try searching ‘your coffee shop doesn’t use 2-phase commit’.

    Reply
  11. Pingback: Event-Driven Programming « IT Primer

  12. Pingback: NodeJS – initial thoughts « Missional Code

  13. Pingback: Callback in Node.js | Saturngod

  14. Pingback: Event-based programming vs Thread for High Concurrency Environments | Yodiaditya Research

  15. Pingback: An Introduction to Node.js | Object Partners Inc

  16. Martin

    I cannot see what makes the big difference:
    Node.js begins to serve the next request while the file for the previous is being fetched. The fetch is certainly happening in another thread, so the “event driven” model is in fact thread based, like the thread based one is event driven: While the receiving thread fetches the page in that model, no user is kept waiting since another thread immediately begins to serve the next request. What’s the big difference then?

    Also I wonder how the result is finally sent back over the net: How can that “callback” send the response to the requesting browser (or other client) if the network connection is not kept open? Is there an asynchronous I/O facility hidden inside that connection-less http protocol? And if not, what was again the big difference between “event driven” and “thread based”? Thanks for clarifying this.

    Reply
      1. Martin

        Thanks for the link. It leaves 3 things open to consider:

        1) The original socket connection must be kept open, since there is still no way visible how the response could reach the http-client otherwise. So there’s no benefit here.

        2) Any real gain seems to be coming from async I/O. And the strategy of not starting a thread for preparing the response but passing a callback is just needed for taking advantage of async I/O. This may work for file I/O but may fail on most other tasks. I know e.g. no way how to tell a database to “call my callback” when the result set is ready: all that async I/O facilities must support such a callback model! And since the callback must run in a thread again, it’s probably the thread of the main event loop that has to check for emerging callbacks at regular intervals (in some getNextRequest-function supposedly) and execute them (that part seems to be often skipped in explanations!)

        3) Note that async file I/O can benefit of “one thread less” just because it relies on hardware that performs I/O without the CPU’s help. A database server could benefit if it is running in another process (which is usually true: often on yet another physical machine) so again, there is some hardware working “asynchonously” (in another process) and if you can make it “call you back” somehow, your process uses one thread less for this operation. However, most of the benefit is just due to the operating systems doing such a bad job of handling threads:

        The waiting threads are just like waiting callbacks: they don’t need CPU time. It’s administrative overhead that makes an OS slow if you start “too many threads”. A package like Green Threads saves overhead since it maps all logical threads onto one OS-thread and just does very little administration. But that could not utilize multiple CPUs. JVMs have been implemented that limit the number of OS-Threads to some value N and map M logical threads to them even if M is greater than N. For JVMs that do 1:1 mapping, it should help to configure the servers’ thread pools: Every decent server should have a thread pool for taking care of the OS’s inefficiency. And mind you, the callback solution works only for async APIs; are there any for you trusty RDBMS? CLI, ODBC, JDBC or what? I don’t think so. And maybe the average database access is so much more complex than a file read that it does not matter much …

        By the way: The linked discussion thread mentions a trick of caching a file contents and let subsequent requests not read the file again. This has nothing to do with Node.js, callbacks and async I/O and would wor for any classic threaded solution as well, so that’s just a red herring and does not help to understand the matter.

        I conclude that 2) describes it best and that it all boils down to async I/O facilities and how to use them best to get around OS restrictions (the OSes of tomorrow should improve here!) and that it helps by far the most for simple things – like serving static files. It’s probably not intended to make classic webservers serving highly dynamic “computed” content obsolete, right?

        *) Note that usually a web application needs to do a lot of “computations” before preparing a response: it’s hardly ever the case that it knows “oh, I’m just going to read that single database record and send it back”. All computations can be done the “async” way only by …? Yes: by delegating to another thread again.

        Reply
  17. Jakob

    Why don’t ordinary webserver just use lightweigt threads (like earlang) instead?

    Those lightwight threads could then be scedueld to run on multiple real OS threads, non blocking so to say.
    Btw. thats probaly how Yaws works.

    Reply
  18. Jeff

    This article seems a little naive in the way of threaded app servers. The doctors office analogy only holds up if the app server has only one thread (the receptionist) which somewhat defeats the purpose of it being multithreaded. An app server such as Tomcat does not simply maintain one thread but has a pool of threads which are assigned to service requests as they come in, as if the doctors office had hundreds of receptionists which (unlike in a real world office) actually take up very little overhead. Yes the request queue will block when all the threads are busy and individual threads will block while doing I/O to the filesystem, DB or external resources but there are asynchronous ways to handle those situations if they become problematic and todays modern servers can handle thousands of simultaneous threads. This is how the current Internet keeps things moving. You do have to keep thread safe practices in mind when handling global resources but most of the time this isn’t much of an issue.

    The advantage of Node.js is not in its event driven nature, for me. Others have noted this pattern been around since the early days of OS development and I’ve worked with it quite a lot. Mostly what I love about Node.js is that it is a high level language offering a down-to-the-wire approach to TCP which is refreshing and allows me to craft specialized services quickly and with low overhead in a way that other systems make difficult, if not impossible. It’s like a TCP toy-box. Also its lack of threading is refreshing for someone who’s dealt with threading issues many times over the years. Knowing I can do x++ on a global or manipulate a collection without having to worry about locks is fun.

    For example I worked for a week or so making a high traffic long polling server in Tomcat 7 with Servlet 3, juggling reentrant read/write locks with aplomb, and got the whole thing stable only to have it start throwing occasional null pointer exceptions deep in the Tomcat engine under load testing. No doubt some kind of thread based race condition. I rewrote the system in Node.js over the weekend using pretty much the same design and patterns but tossing out all the unnecessary thread safety and it ran great under the same load test. And it’s only 600 lines of code (including lots of comments).

    No I would not use Node.js for a major web project or an enterprise class service, but for something like an RSS feed or messaging system backend it’s ideal. For me at least.

    Reply
    1. Oscar Goldman

      Good comment.

      I’m debating Node vs. Django, to serve up relatively simple results from DB queries that shouldn’t take very long. So far I don’t see any compelling reason to go with Node.js, except I could just learn JavaScript (which I need anyway) instead of JavaScript and Python. Node.js just seems too low-level for the tasks many Web apps face, as you point out in your conclusion.

      But Django offers so many convenient features, and in combination with the REST library, it can deliver data in multiple formats easily. To do the same thing with Node, I’d have to pore through dozens of libraries all claiming to do similar things, and cobble something together.

      Reply
  19. Pingback: Using Node.js in an ASP.NET MVC application with iisnode - Jon Galloway

  20. Pingback: Using Node.js in an ASP.NET MVC application with iisnode « Ocr Software « OCR Software

  21. Dimitris

    The examples were good and-at last-helped me understand what node.js is all about.

    Nonetheless i am lacking some knowledge about threaded servers so the next question popped in my mind after reading the article:

    Suppose that Apache has to deal with 2 connections for a site, as the incoming connection increase so does the latency. But since apache is installed in a machine(a server from the hardware point of view, which means that it accepts requests for other sites too), when requests for other sites(installed in the same-shared- server)
    come in, does the overhead increase or the discussion here focuses about requests that accumulate for the same site?

    When requests for other sites come in, does apache create a second thread?

    Which means that if this second thread has not many requests then there is not problem. I mean, when requests come in for the 2nd site do these “build upon” the request of the first one?

    Sorry if i confused you. I do not know how threaded servers work at all.

    Reply
  22. Pingback: Why So Many DevOps Tools Are Written in Node.js | ServicesANGLE

  23. Pingback: Node.js Project Leader Ryan Dahl Steps Down To Work On Research Projects | Code.DanYork.Com

  24. Pingback: Understanding Node.js « DotNetAdil

  25. Pingback: Node.js Journey Guide for Beginners Like Me « Muhammad Ghazali's Online Notes

  26. Javier Velez

    Nice metaphor!

    At least here in Spain, we can say that the event-driven model is implemented by Starbucks whilst the thread-based modes is implemented by McDonalds :P

    Reply
  27. Pingback: Visual Basic, PHP, Rails. Is Node.js next? — nPost

  28. Pingback: Visual Basic, PHP, Rails. Is Node.js next? | Web Help 101

  29. Pingback: Nginx Hosting Now Available | White Fire Web Design Salisbury Wiltshire

  30. Pingback: Pushing Data, Not Pages is the New Model for Application Development | DevOpsANGLE

  31. Pingback: Node for a novice « akhileshgodi

  32. Mike

    OS threads are expensive, but there are lots of thread-like constructs that have no more overhead than event driven programming and don’t require the control flow of the software to be completely rewritten. Event-driven programming is more of a workaround for languages and platforms that are so limited that they don’t provide such constructs.

    Reply
  33. michael

    when you say “threaded system”, do you mean “single threaded system”? threads can block if you dont spawn more threads

    Reply
  34. Aaron

    Great analogy to explain event-driven programming. I have been hearing a lot about Node.js lately and thought I would check it out, and it led me here. Thanks for the great explanation!

    Reply
  35. Pingback: Node.js | Skillcrush

  36. Pingback: Quora

  37. Pingback: Move Over Meteor: Derby Is The Other High Speed Node.js Framework In Town | TechCrunch

  38. Rick

    Thanks. Finally a refreshingly concise explanation. As a newbie struggling with jargon- ladened definitions and explanatons , I found this to be clear and easy to grasp. Thanks again!

    Reply
  39. Kent

    Good job! I am not a programmer and I hate programming, but with your explanation, I 100% understand what event-driven and node.js are.. :)

    Reply
  40. Marc

    The evented I/O model used by node is nothing new. It’s been around for decades. That’s not a slam on Node but there’s nothing revolutionary going on here. Also, you can debate the plusses and minuses of node’s architecture vs. the threaded model but performance-wise, the threaded model beats the living crap out of node’s model. Tomcat will destroy node in serving up web pages in any performance test. It’s not even a competition. Again, I’m not trying to attack node but this notion that it’s viable as a real web app server is pretty ridiculous for anything but low traffic stuff.

    I just wanted to put that out there because I think people are getting excited about node and getting the wrong idea about what it’s good for. If your goal is to serve up web pages, you’re going to be much better of with Apache or Tomcat.

    Reply
  41. Paul

    I think comment from Jeff (5.Oct.2011) sheds more light on the issue, than whole article, which is rather misleading. To say that Node.js is more effective because it is event-driven (vs. “thread-driven” for other webservers) is… harmful.

    Reply
  42. Rahul Dewan

    Thank you for the awesome layman explanation. As CXOs we have to make strategic decisions about the company’s future, and often are out of touch with technology while focussing on serving businesses. Such explanations really help.

    Reply
  43. Darron

    Thanks for the great explanation, and analogies of event driven, and thread based architecture. This single article helped me really soilidify my understanding of benefits of Node.js.

    Reply
  44. DjShinndig

    Awesome explanation. I’ve always had difficulty wrapping my head around the concept of callback functions but the analogy you gave is spot on. Totally makes sense and now I feel like coding!

    Reply
  45. Pingback: Quora

  46. Steven

    Is using node.js a practical solution to replace an Apache server? Are there newer servers that exist that are coded using node.js? If so, what are they? What are pros/cons?

    Reply
  47. http://tinyurl.com/pikelions19062

    “Node.js, Doctor’s Offices and Fast Food Restaurants – Understanding Event-driven Programming | Code.DanYork.ComCode.DanYork.Com” was a great blog post, can not wait to look at alot more of your postings. Time to waste several time on the internet haha. Thanks ,Gonzalo

    Reply
  48. Pingback: Weekly Updates and Worthwhile Reads - mmhan

  49. Pingback: Learning Node.js: Introduction | Karl Monson

  50. Fred Haegele

    While so many people question and scrutinize Node.JS, I see it as an opportunity to do something new with a language I already know.

    I wonder how many critics in the above comments are running a service that actually serve 1/10 of the pages they claim their application can serve up. So many questions surround the performance aspects of Node.JS, but in reality there are only a handful of websites/apps that require such laborious performance considerations.

    The reality is, that 99% if the internet can be run with Node.Js directly out of the box, and that fact is phenomenal. Can the same be said for Java or PHP four years after their inception? I think not.

    Reply
  51. Leo

    I wonder how new is event driven programming is, and why thread based models were used in web servers instead of event based ones? Also, why are web servers still using thread based models?

    Reply
  52. Pingback: Node.js and Non-Blocking I/O - Technical Blogs : Technical Blogs

  53. Amit

    I don’t completely understand the difference between thread-based and event-based model. In case of an event based server (node.js), doesn’t it spawn threads (O.S threads) which perform the io operations in parallel?

    I would appreciate if you could detail a bit on this.

    Reply
  54. Michael Long

    Since this article is still getting passed around and referenced, I just wanted to reply to Marc’s comment above and say that node is NOT recommended as a replacement for Apache, nor is it the best way to serve up static resources.

    Now, if you’re serving up dynamic pages, or if you’re servicing JSON requests, or if you need something really, really fast to handle backend requests for Backbone or Angular, then you need to look at node.

    Reply
  55. Adam Krouskop

    I’d love to see the author update this blog post to incorporate what “Jeff” commented back in October 2011.

    What gets called the “thread-based” model in this post describes a single-process, single-thread, blocks-for-a-single-connection model. That’s not the model used by multi-threaded servers. (I doubt that model is used by any real world servers…). It would be better to call it something like the “blocking model”.

    Actual thread-based models, as well as event-loop-models, (and even models that spawn a new process per request) can all handle servicing multiple requests concurrently just fine. This post suggests only the event-loop-model can.

    Reply
  56. Pingback: Introducing AppDynamics Node.js Agent now in Beta - Application Performance Monitoring Blog from AppDynamics

  57. Pingback: Why Node.js is a Great New Technology for the Cloud | CloCOM Tech

  58. Diego

    I seems that some comments are tendentious to one or another mode (like football team)l, but only few comments really explain the difference between both models, pros and cons. To me the async I/O model is the key concept and that belongs 30 years ago more or less. The assumption of the world wide web in the late 90′s and many many http connections requesting page and resources nowadays I think gives the popularity and the needs of that model…

    Reply

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>