ASP Live Help

johna by | August 6, 2007 | Classic ASP Web Development

I developed this application for an on-line store. The code is quite messy because it took me lots of attempts to get right but it now operates almost perfectly.

Live Help is a messenger type application written mostly in ASP but with lots of JavaScript. It uses the ASP Application object to store information.

Click for full size Live Help screenshot

An operator (or multiple operators) can sign in then bring up a messenger type window which displays the status of conversations and requests. They enter their name which is shown to the other party during conversations.

Someone using the web site can see the status of Live Help - either available or not available. If available they can click the link to request a conversation with an operator.

To initiate the conversation they enter their name which is shown to the operator.

The operator(s) will hear a ringing sound to indicate an incoming conversation request. They can either accept the request, ignore it or decline it. If the request is ignored it will eventually expire and (or if cancelled, will occur immediately) the user will be prompted to try again later or leave a messge (which is delivered via normal email).

If the request is accepted a two-way conversation can take place in a messenger style environoment. The system displays messages from both the operator and user including the time of last message received and plays a sound to indicate a message received. The conversation can be ended by either party at any time. It will also display a message if the other party is typing a message.

Download the sample and give it a try on any ASP server.

Installation

Unzip the file into your root web folder. All files will then be unzipped into a foler called 'livehelp'. It will not operate correctly if in any other folder without modification.

The system will now work as is for demonstration/test purposes. If you wish to integrate into a web site then changes are neccessary.

'request.asp' contains an email address where any messages are sent if a user cannot contact Live Help. This should be changed to an email address of your choice. It may also require changes if CDOSYS is not available or if you need to specify a mail server.

'Default.asp' and 'user.asp' are required only for demonstration/testing and should be removed prior to proper use in your own web site. They do contain functions and procedures which will need to be used in your own scripts and pages.

You will need to incorporate the JavaScript functions and operator link contained in 'default.asp' into your own administration or web site back end. The operator pages should only be able to be accessed by authorised persons so you will need to implement your own security. At present these scripts check for a session variable 'admin' being true.

In any web page where you wish for users to be able to use Live Help from you will ned to include the JavaScript function and VB Script Sub contained within 'user.asp'. Then simply call 'LiveHelpStatus' where you would like the status image/link to be displayed.

Demonstration

Simply unzip the file in the root of your web or localhost web folder.

Open the 'default.asp' page.

Click sign in as operator and enter a name for yourself.

Then you can sign in as a user either on the same or another computer and enter a name for yourself to request a conversation.

You should hear a ringing noise and in your operator messenger window you can accept the request.

Conversation windows will then pop-up and you can converse as required.

Download Live Help (updated 16-Jul-2008)

License: Freeware

Updates

16-Nov-2007: There has been reports of the chat application not scrolling down automatically to show messages. 'chat.asp' has been updated which seems to have solved the problem.

20-Nov-2007: I have found the issue causing problems with Firefox. Download the following file for the fix. Unfortunately in Firefox it doesn't display "...is typing a message" or play sounds but at least now it works.

16-Jan-2008: I have fixed a few bugs including the non-functioning decline chat function. If you click the download Live Help link above you will receive the latest version of all parts of Live Help. Changes are to request.asp, getusers,asp, messenger.asp.

16-Jul-2008: I was advised that LiveHelp wasn't working with Safari so I have had to make some modifications for it to work. Click the download link above for the latest version.

Related Posts

Web Development Retro Computing

Converting dBase IV programs to run in the browser

by johna | September 13, 2024
Some pointless entertainment trying to get some old dBase programs running in the browser.

Web Development

How to set up a debugging using the Turnkey Linux LAMP stack and VS Code

by johna | December 19, 2023
The second part in my guide to setting up a website and database using the Turnkey Linux LAMP stack.

Website Hosting Web Development

How to set up a website and database using the Turnkey Linux LAMP stack

by johna | November 18, 2023
If you need to host your own website for the purposes of web development, Turnkey Linux LAMP Stack is an easy to install all-in-one solution that you can set up on a spare computer or a VM (Virtual Machine).

Comments

by Dario Italy | September 6, 2007

VERY NICE CODE!
All the functions are ok .
Thanks

Dario

Reply

John Avis

by John Avis | September 7, 2007

The application uses CDONTS for email but can be easily changed to CDOSYS.

In "request.asp" you need to change line 198 to 207 to the following:

Set objCDOMail = Server.CreateObject("CDO.Message")
objCDOMail.From = strEml
objCDOMail.To = "you@youremail.com"
objCDOMail.Subject = "Message sent when Live Help! was offline"
objCDOMail.TextBody = strMsg
objCDOMail.Send
Set objCDOMail = Nothing

Reply

by Darann | September 10, 2007

Hello John,
this is the correct code in CDOSYS that works!
Thank you very much for your suggestions.

Line : 198->213

Set objMail = Server.createObject("CDO.Message")
Set objConfig = Server.createObject ("CDO.Configuration")
With objConfig
.Fields("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "mail.coretech.it" 'your mail server
.Fields("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
.Fields("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
.Fields("http://schemas.microsoft.com/cdo/configuration/smtpconnectiontimeout") = 60
.Fields.update
End With
Set objMail.Configuration = objConfig
objMail.From = strEml
objMail.To = "mail@youremail.com"
objMail.Subject = "Message sent when Live Help! was offline"
objMail.HTMLBody = strMsg
objMail.Send()
Set objMail = Nothing

Reply

by Darann Bis Cdosys | September 11, 2007

I'm sorry, the lines to be replaced are 198 until 207, with the code written above..

Bye

Reply

by Bijoy Philipose | September 14, 2007

Dear John,
Thank you very much!!!! Excellet code and we use it.... Congratulations!!! We were looking for similar kind of code for 3 days... We are IMPRESSED!!! GREAT WORK...

Reply

by Ignacio | September 26, 2007

Has this script been tested on Firefox? It doesn't work on firefox for me, has anybody else had the same problem?

I can't hear the ring either...

Reply

John Avis

by John Avis | October 17, 2007

Unfortunately I have not tested this on Firefox. If you wish to modify it to suit and share it with others I will be happy to include your changes. Thank you.

Reply

by Marty | November 15, 2007

Cool appz, but chat window not scrolling in IE7 (problem with scrollTop)

Reply

John Avis

by John Avis | November 15, 2007

I haven't been able to work out why it is not scrolling properly in IE7 but I have produced a quick work-around (see above, end of article). The faulty JavaScript code is as follows:

document.getElementById('chatBox').scrollTop=document.getElementById('chatBox').scrollHeight;

If anyone has any suggestions on how to resolve this problem, and as these properties are IE only, offer any alternatives for other browsers, please let me know. Thanks.

Reply

by Andy | November 18, 2007

Really good job here John.

It's a shame about the compatibility with firefox. i am really keen to use this code, but can anybody see any reason to why the chatbox will not show any text firefox?

Reply

John Avis

by John Avis | November 19, 2007

Firefox problem solved. Download the updated chat.asp - see the end of the blog entry above (chat2.zip).

Reply

by Andy | November 24, 2007

Thanks John, works great!

Reply

by kike | January 1, 2008

yesss!! i was previously using another chat system which, in my opinion, had way too many features and settings. it was however very similar to your script. (crafty syntax)

on a side note, for some reason the sound features were not working for me (IE7) so i modified your script a little incorporating soundmanager2 which uses flash and javascript to play the sound. now it works like a charm in firefox and ie7.

anyways thank you for this script. its awesome.

Reply

by Joao | January 15, 2008

I'm having a problem on the decline conversation. It doesn't work. I've checked the code and the link is kinda empty. Any sugestion how to solve this?

Thanks in advance

Reply

John Avis

by John Avis | January 15, 2008

Joao: you are right - the decline function doesn't seem to have any code to it. I have fixed that problem and solved a few other minor issues. You can download the latest version at the link above. Thank you.

Reply

by Joao | January 18, 2008

Hi again John,
thanks for you quick fix and reply but it seems to me that the chat stoped working since the decline was fixed. I tried to fix myself but this goes a little bit out of my knowledges.
If you could have a look at that I would be extremely thankfull.

Thank you

Reply

John Avis

by John Avis | January 18, 2008

Hi Joao: Sorry about that error, it is fixed now.

Reply

by Ivan | February 7, 2008

thanks for letting me view your guest book and giving me all the information

Reply

by Eric | February 9, 2008

Incredible! I do not hear the sound to notify that person is calling. This is wonderful work!

Reply

by Erden | February 15, 2008

We cant hear the conversation start ring! What could be the problem?

Reply

by Andy | March 1, 2008

I was looking for something like this for quite some time. Fantastic work John!.

Reply

by steve | March 12, 2008

Kudo! Nice to see others still working in classic ASP! And great job, I had been working on something similar now I can merge your work with mine. I will gladly send you a zip once complete, I am adding chat logging, operator transfers, and a few other tidbits. Let me know you can reach me at: sts <at> jsta.com

Reply

by Nikolet | March 19, 2008

Nice site!

Reply

by Tom | April 24, 2008

Was wondering if Kike would be kind enough to share his soundmanager2 fix for us?

Reply

by Ozzie | June 11, 2008

i have a problem that has stumped me

im trying to include the status.asp page into a main page and when i do that it finds the file ok but i get this error message

ADODB.Stream error '800a0bba'

File could not be opened.

/files/asp/status.asp, line 20

it cant open the image that is needed

any ideas what could solve this

if i run the status file on its own the images show up just fine.

Side not this is a noce app very simple straight forward i just cant seem to have it included on other pages

Reply

John Avis

by John Avis | June 12, 2008

Hi Ozzie. Your problem is most likely due to the paths in status.asp not being correct in your situation. Change part of line 18 and 12 from "../livehelp/img/" to an absolute path (eg to "/livehelp/img/" if the livehelp folder is located in the root directory) and you should solve the problem.

Reply

by Ozzie | June 13, 2008

thats what i thought as well but that did not do it, so i went a different direction, i put it in a frame and it works but now i cant seem to put a background on the status page without generating errors causing the page to fail to load, you would think this would not be complicated nor am i new to making simple changes like this but i guess im still very green

Reply

by Ozzie | June 13, 2008

sorry to keep bring this up

all im trying to do is put the info inside a table so i have control as to where the image gets placed and i get errors i really dont get issues like this with other mods can someone tell me why this is failing

this is from the status.asp file

<head>
<style type="text/css">
.style1 {
border-style: solid;
border-width: 1px;
}
</style>
</head>

<table style="width: 400px" cellspacing="0" cellpadding="0" class="style1">
<tr>
<td><%

blnOperator = False
If IsArray(Application("lhuser")) Then
arrUser = Application("lhuser")
For intCount = 1 To UBound(arrUser, 2)
If arrUser(2, intCount) = True And arrUser(4, intCount) >= DateAdd("s", -20, Now()) Then
blnOperator = True
End If
Next
End If
Response.Buffer = True
Dim objStream
Set objStream = Server.CreateObject("ADODB.Stream")
objStream.Type = 1 'adTypeBinary
objStream.Open
If blnOperator Then
objStream.LoadFromFile(Server.Mappath("img/online.gif"))
Else
'objStream.LoadFromFile(Server.Mappath("img/offline.gif"))
objStream.LoadFromFile(Server.Mappath("img/offline.gif"))

End If
Response.ContentType = "image/gif"
Response.BinaryWrite objStream.Read
objStream.Close
Set objStream = Nothing
%></td>
</tr>
</table>


Reply

John Avis

by John Avis | June 13, 2008

status.asp returns an GIF image file. It is used so that you can call a picture on your website that shows whether an operator is online or not. You cannot put any html in status.asp otherwise it will not work as it changes the content type to a gif image. See the sample user.asp for other ways you can show the operator status.

Reply

chris

by chris | June 27, 2008

Awesome Script! Unbelivable! I love it!

I have installed it and am playing around with the script but I was thinking of modifying it to accept departments. A user clicks on the chat link and then enters their name and what department they would like to talk with, then the operator at that dept. is rung.

Any suggestions on where to start on this adventure?

I could be easy and install two different chats in different directories and change the chat link to go to a page that they select which dept and then chat, but wanted to do it a little better.

thanks for a great script!!

Reply

Christian

by Christian | July 11, 2008

Great Script, I have one question though, the operator sees the typing message but the user does not see it. Using IE 7 on both sides, what could be wrong?

Reply

Michelle

by Michelle | July 14, 2008

I have made some modifications to it so it is now Operator password protected, but great script to "start" off with (and by start I mean have 90% of it done when I wouldn't have known where to begin!).

But, my issue is that it seems to time out on Operators if they don't do anything after 20 minutes (give or take). Is this the way you had it set up?

Does is have to do with this part of your code:
var exp=new Date();
exp.setTime(exp.getTime() + 365 * 24 * 60 * 60 * 1000);

function setCookie(name, value, expires, path, domain, secure)
{
var curCookie = name + '=' +
escape(value) +
((expires) ? '; expires=' + expires.toGMTString() : '') +
((path) ? '; path=' + path : '') +
((domain) ? '; domain=' + domain : '') +
((secure) ? '; secure' : '');

document.cookie = curCookie;
}

Thanks!

Reply

John Avis

by John Avis | July 14, 2008

The code uses ASP sessions to manage the Operator. The default session timeout is 20 minutes but you can change increase it by adding the following to any of the scripts called by the operator (eg. messenger.asp) or to your global.asa. Keep in mind that this setting will effect all sessions on the website.

Session.Timeout = x

(Where x is the number of minutes of inactivity a session should last)

Reply

Chris

by Chris | July 15, 2008

Just wanted to add some changes that I made to the script in case anyone else would find them useful.

I wanted a simple "Canned Response" for the operators to use so I did the following in the server.asp file:

After Line 253 I added:
'start of canned-also see javascript in head section
If Session("lhadmin") then
Response.Write("<td><strong><font size=2 face=verdana,arial,helvetica color=#FFFFFF>Canned: </font></strong></td>" & vbCrLf)
Response.Write("<td><img height=30 src=img/spacer.gif width=5></td> <td>" & vbCrLf)
Response.Write("<SELECT onChange=UpdateField(this.selectedIndex); NAME=canned>" &vbCrLf)
Response.Write("<option value= ></option>" & vbCrLf)
Response.Write("<option value='Hello "& strOther &" , How Can I Help You?'>Intro Greeting</option>" & vbCrLf)
Response.Write("<option value='Hello "& strOther &" , I will be right with you.'>Right With You </option>" & vbCrLf)
Response.Write("<option value='Okay, Just a moment.'>Okay, Just a moment.</option>" & vbCrLf)
Response.Write("<option value='Still Searching . .'>Still Searching . .</option>" & vbCrLf)
Response.Write("<option value='May I have your email address to send more information to you?'>Email Address?</option>" & vbCrLf)
Response.Write("<option value='Is there anything else I can help you with?'>Anything Else?</option>" & vbCrLf)
Response.Write("<option value='Thanks for visiting "& strOther &", look forward to speaking to you again!'>Thanks for Visiting</option>" & vbCrLf)
Response.Write("</select></td>" & vbCrLf)
End If
'end of canned
(just before the submit)

and also added:
'canned javascript
Response.Write("<SCRIPT LANGUAGE=JavaScript>" & vbCrLf)
Response.Write("function UpdateField(index) {" & vbCrLf)
Response.Write("form=document.frmMessage;" & vbCrLf)
Response.Write("form.msg.value = form.canned.options[index].value" & vbCrLf)
Response.Write("}" & vbCrLf)
Response.Write("</script>" &vbCrLf)
Response.Write("</head>" & vbCrLf)
(after line 236-Response.Write("window.onblur = BlurTrigger;" & vbCrLf)

Response.Write("</script>" & vbCrLf))

line numbers may be a little inaccurate as i changed a few other small items but its better than starting from the beginning. I love this script though, its awesome!

Reply

chris

by chris | July 15, 2008

what my mod does concerning the canned response is:
1. Only displays the canned response pull down in the operator's window.
2. When selected, it puts the value in the msg text box, the operator then presses submit, and thats it.

Reply

Michelle

by Michelle | July 18, 2008

Any idea on how to deal with load balance when adding Sessions to your app?

Reply

Rolf

by Rolf | August 17, 2008

Great script! i was looking for this for a long time.
All the changes mentioned above are in the new ZIP file?

Reply

John Avis

by John Avis | August 18, 2008

All the changes are in the Zip file. Thanks!

Reply

Rolf

by Rolf | August 18, 2008

Hi John, 2 questions:
Is it possible to log the conversations?
How can you see if there are more operators logged in?

Reply

Juan Carlos

by Juan Carlos | September 26, 2008

Hi John

I have a question:

How can i do to call the function from diferent sites that are hosted on diferent machines, i want to have the livehelp on the main site but be able to call for help from other sites, is this posible?

Reply

by nawaf | October 1, 2008

Greate !! It is working with me fine,,
but still have problem in the voice??

please need help to have it working with the voice,

waiting..

Reply

chris

by chris | October 7, 2008

I found a little bug I can't seem to figure out how to correct.

When the messenger is open and the operator is surfing the internet, if they click on a link that opens a new window, it opens in the operator console, thus logs them out.

Is there any way to make the operator console not be replaced when clicking on a window that opens a pop-up?

Thanks!

Reply

John Avis

by John Avis | October 7, 2008

You could try changing the name of the admin window from 'messenger' to something else and see if that solves the issue. This can be found in the 'openMessenger' function which, in the sample, is in 'default.asp'. Change the name 'messenger' to something else in the following line...

Response.Write(" window.open('../livehelp/messenger.asp','messenger','toolbar=0,location=0,status=0,menubar=0,scrollbars=0,resizable=1,width='+lw+',height='+lh+',top='+lt+',left='+ll);" & vbCrLf)

Reply

by Nawaf | October 12, 2008

please (John Avis)
i liked your script, but can u solve the sound problem, it is not working ???

Reply

John Avis

by John Avis | October 16, 2008

In reply to message posted by Juan Carlos, September 26, 2008:

You can use the script status.asp to generate an online of offline image and call this image from any website.

Eg:



And make sure you include the following Javascript function on any page that has this link:

function openChat(varUrl) {
var winleft=(screen.width-700)/2;
var wintop=(screen.height-450)/2;
window.open(varUrl,'chat','toolbar=0,location=0,status=1,menubar=0,scrollbars=0,resizable=1,width=700,height=450,top='+wintop+',left='+winleft);
}

Reply

Full

by Full | October 23, 2008

Hi, This script is very usefull.
I have only the same problem as mentioned before. I work with 2 pc's and 2 MAC's Only in 1 pc the sound is working with this script.
Is there allready a solution for this?

Reply

by Nawaf | October 24, 2008

is there any other way than the sound to know if a new custoer need a live chat help ? like a popup window or msgbox??

Reply

John Tse

by John Tse | October 28, 2008

It will be more perfect if the audio is added to the chat.

Reply

John Tse

by John Tse | October 31, 2008

This is a very nice and usefull ASP code. But, I think it will works better with audio/video chat option. I integrated it with Skype, using java script. The live demo is posted at http://arcoplaza.com/database/home/project/pcall.asp



Reply

John Avis

by John Avis | October 31, 2008

In reply to message posted by Nawaf, October 24, 2008:

With a little JavaScript knowledge you could easily add a JavaScript msgbox to warn you of an incoming call.

Reply

by Nawaf | November 3, 2008

Thank you John for your reply,,

I am expert in VB, but very bad in JAVA,,

can you please help me to have the javascript msgbox and where to put it in the code ?? i need it highly pls.
thank you in advanced >>

Reply

by Tony | November 14, 2008

Brilliant script, but I can't hear any sounds?

Reply

Kjell

by Kjell | November 15, 2008

Got it to work an asp pages, but would love to have java or other call from a html page, I assume the ref a href="#" onClick="openChat('http://www.yoursite.com/livehelp/request.asp');"><img src="http://www.yoursite.com/livehelp/status.asp"></a

And make sure you include the following Javascript function on any page that has this link:

function openChat(varUrl) {
var winleft=(screen.width-700)/2;
var wintop=(screen.height-450)/2;
window.open(varUrl,'chat','toolbar=0,location=0,status=1,menubar=0,scrollbars=0,resizable=1,width=700,height=450,top='+wintop+',left='+winleft);
} "
and the "I am expert in VB, but very bad in JAVA,,

can you please help me to have the javascript msgbox and where to put it in the code ?? i need it highly pls.
thank you in advanced" comment is about the same. Would be nice if anyone could tell me how to write a function to be included as a ref in a HTML page, if so I could use same help for my two sites.

Reply

by Nawaf | November 28, 2008

can someone help regarding the old post:

Thank you John for your reply,,

I am expert in VB, but very bad in JAVA,,

can you please help me to have the javascript msgbox and where to put it in the code ?? i need it highly pls.
thank you in advanced >>
Posted by Nawaf | November 3, 2008

Reply

Robert Moore

by Robert Moore | December 15, 2008

I have been paying monthly for live help and now want to create my own, maybe by using this free live help. I would like to make it work like the one i have. The one i have is installed on my desktop and always runs. My asp pages point to the vendors website. When i get a call my computer rings and a form pops up on my desktop, which means the vendors code is notifying my desktop code. The part i don't get is how to make a button click notify the file on my desktop. I write vb6 code and could create a desktop .exe to open if i knew how to call it. Does anyone know?

Reply

John Avis

by John Avis | December 16, 2008

Robert:

Live Help is written in such a way that it is the clients (admin users and customers) that are constantly checking for communication rather than the server notifying clients of communication. If you wanted to integrate with Live Help you could write a VB application that constantly checks the server for communication, just as the ASP scripts do.

Reply

gozdemir

by gozdemir | February 18, 2009

hi john, your code is very nice, thank you so much,
i need your help,
i want user ip see in operator window.because i want some dirty peoples banned.
i try but unsuccesful.
can u help me ?
thnx...

Reply

by craig | April 28, 2009

Did anyone ever get the DECLINE to actually work? Ive also gave up on getting the sound to work for now! Thanks.

Reply

by Craig | May 5, 2009

ok - still cant get the decline to work at all but, I got the sound to finally work using flash! If anyone is interested, here it is....

In 'getusers.asp' Replace the line beginning:
Response.Write("<td><img alt=needaction height=18 src=img/needaction.gif width=19></td>")

With this line:
response.Write("<td><object type=""application/x-shockwave-flash"" data=""http://www.rolica.co.uk/livehelp/snd/needaction.swf"" width=""18"" height=""19"">" &_
"<param name=""movie"" value=""/snd/needaction.swf"" />" &_
"</object></td> " &_
" " &_
" ")

If you want my swf sound - you can get it here:
http://www.rolica.co.uk/livehelp/snd/needaction.swf

Reply

Noah Bardach

by Noah Bardach | May 20, 2009

John, great work! Thanks!

I'm trying to add additional details to the user name displayed to the operator. I'm passing along these details in session variables from a secure Portal where the user's chat will be launched. I need the operator to see the user's full name, role, institution and email address. This is in order to prevent identity confusion that could result in problems for our customers.

Has anyone tried to modify this part of John's script? If so, how/where did you make the changes?

Please advise. Thanks in advance! N

Reply

Noah Bardach

by Noah Bardach | May 22, 2009

Craig,
Thanks for the code. I've tried implementing it but it doesn't display and no sound is produced.

I've commented out the line that reads:
Response.Write("<td><img alt=needaction height=18 src=img/needaction.gif width=19></td>")

and added your code:
Response.Write("<td><object type=""application/x-shockwave-flash"" data=""/snd/needaction.swf"" width=""18"" height=""19""><param name=""movie"" value=""/snd/needaction.swf""></object></td>")

The swf object doesn't display but a SWL placeholder is there that says "Movie not loaded..." when I right-click.

Any ideas? Please advis.e Thanks! N

Reply

Thomas

by Thomas | June 5, 2009

Thanks for the nice code but i cannot seem to get this below to work.

E.G [a href="#" onClick="openChat('http://www.yoursite.com/livehelp/request.asp');"><img src="http://www.yoursite.com/livehelp/status.asp"></a>]

Reply

John Avis

by John Avis | June 5, 2009

Hi Thomas - please post any error messages you receive so that we can help you.

Reply

Thomas

by Thomas | June 5, 2009

Hi,
there are no error messages, i just can't get the gif file to display the status. If I click on the link everything works ok, its just the various online/offline gif file.

Thankz so much for your reply

Reply

by Bryan | August 5, 2009

Hi Guys, Has anyone got this to work with ASPMAIL? Any code available :-O .... thank you!

Reply

Saravanan G

by Saravanan G | July 21, 2010

Thanks for your code !!!

Reply

Leave a Comment

About

...random postings about web development and programming, Internet, computers and electronics topics.

I recommend ASPnix for web hosting and Crazy Domains for domain registration.

Subscribe

Get the latest posts delivered to your inbox.