FOOApp
The FOOApp: A complete Classified Ads application showing how to use Active Server Pages' ADO database techniques, SQL techniques, cookies for "remembering", VBScript client-side field validation, and much more. FREE!
AI
AI Samenvatting: This codebase represents a historical implementation of the logic described in the metadata. Our preservation engine analyzes the structure to provide context for modern developers.
Broncode
<p><font size="2" face="Verdana">The most common approach to teaching the fundamentals of any programming language is to start with theory, then the features, the basic concepts, some techniques, and finally, finishing with a glimpse of the guts of a real application. I, on the other hand, learn best by taking something functional and dissecting it into little lessons that expose the integration of those concepts, techniques, and features of the language. The undestanding of the interplay of these dissections is what seems most important to me in becoming a better programmer. This is the way I learn best, and this is also the approach I will use for teaching you some of the cool things you can quickly replicate on your own with Active Server Pages.</font></p> <p><font size="2" face="Verdana">I designed the FooApp (Forum for Online Opportunities) to "show-off" how simple it is to build a self-maintaining database application with ASP. People set up their own passwords; maintain their own member profiles; they can add, edit, or delete, information they "own"; they can search etc. The application will run on any machine that supports active server pages and an Access database. Converting the application for use with SQL is a matter of pointing your datasource to an SQL server whose table names and fields are the same as those that exist in the Access dabase. This application is designed for beggining to intermediate ASP'ers who have at least perused the tutorials found elsewhere on the site. It is also good for advanced ASP'ers interested in learning a few tricks etc. but remember the application is not perfect. If you want to make any additions to the application for others to benefit from, please <a href="mailto:[email protected]"><font color="mediumblue">e-mail me</font></a>.</font> <hr> <p> </p> <p><strong><font size="2" face="Verdana">*IMPORTANT</font></strong></p> <p><font size="2" face="Verdana">1. If you download the source code all I ask is that you take five seconds out of your surfing schedule and visit at least one of our sponsors- it's an extremely fair trade don't you think? Now that we have that out of the way, just <a href="http://www.aspalliance.com/glenncook/foocode.zip"><font color="mediumblue">download</font></a>the complete application's source code! This is the exact source code that is running on DataReturn's server at the ASPAlliance. I am telling you this because I don't want anyone "testing" a childish prank on the application that many people will be counting on to help them learn. C'mon I am giving away the source-code for free- please don't abuse this opportunity!</font></p> <p><font size="2" face="Verdana">2. The application will not run right "out-of-the-box." The first thing you want to do is delete all instances of "<!--#include virtual = /adshow.asp-->"(This is the banner rotator for the site) You will also have to set-up a DSN to point to the Access database that is included, and you will have to edit the cookie information properly. The DSN name is called "ClassyAds" and the information about how to edit your own cookie can be found <a href="http://www.aspalliance.com/glenncook/cookiecode.asp" target><font color="mediumblue">here</font></a>. If you don't know how to set up a DSN there is a brief explanation at the <a href="http://www.aspalliance.com/glenncook/searchcode.asp"><font color="mediumblue">search tutorial</font></a>. The application has been installed successfully on hundreds of machines now so if you are receiving errors, check for typos and editing problems.</font></p> <p><font size="2" face="Verdana">3. Your frame of reference for these tutorials should be the the <a href="http://www.aspalliance.com/glenncook/aspjobs/chill.asp"><font color="mediumblue">working example in the ASP Trenches</font></a>. Try to mentally figure out how the application is doing this work before digging into the source code explanations. Visit the application several times and see how it remembers you? Try to search for your information several ways, and edit your profile. Important: Look at the asp page names in your browser as you interface with it. Also as you dig into the source code you will notice the unconventional variable names that I use- Simpsons characters. This is a way for me to keep laughing while I program. You should see the faces on management when I present them with the documented source code for the projects I've done for them. Now that's REAL funny!</font></p> <p><font size="2" face="Verdana">4. Ok. Let's start the dissection process- Your fetal pig is waiting....Have Fun!</font></p> <p><font size="2" face="Verdana">Go to the<a href="http://www.aspalliance.com/glenncook/aspjobs/chill.asp"><font color="mediumblue">TESTING GROUND!!!!</font></a></font></p> <hr> <p><strong><font size="4" face="Verdana">Cookielog.asp</font></strong></p> <table border="1" cellPadding="7" cellSpacing="1" width="685"> <tbody> <tr> <td vAlign="top" width="61%"><font size="2"> <p><font color="green" face="Verdana"><%Response.Buffer = true %></font></p> <p><font face="Verdana"> </font></font></p> </td> <td vAlign="top" width="39%"><font size="2"> <p><font face="Verdana">The <%Response.Buffer = True %> line is the way to tell ASP to execute the entire page before sending anything back to the client. Otherwise it will just start streaming stuff as it executes. You'll find that you need this quite often when Redirecting clients to different pages.</font></p> <p><font face="Verdana"> </font></font></p> </td> </tr> <tr> <td vAlign="top" width="61%"> <p><font color="green" size="2" face="Verdana"><!--#INCLUDE file="adovbs.inc"--></font></p> </td> <td vAlign="top" width="39%"><font size="2"> <p><font face="Verdana">The "adovbs.inc" file is a collection of VB constants that we can use for accessing a database via ADO. It's a header file that gives us tools to connect to a database, recordset, etc. and it also gives us little useful functions like RecordCount.</font></p> </font></td> </tr> <tr> <td vAlign="top" width="61%"><font size="2"> <p><font color="green" face="Verdana"><% <font color="black">If </font>Request.Cookies("Shaft").HasKeys <font color="black">Then</font></font></p> <p><font face="Verdana"> </font></font></p> </td> <td vAlign="top" width="39%"><font size="2"> <p><font face="Verdana">This line Requests the client's browser for the Shaft cookie! I use HasKeys to validate whether that cookie exists. If the person has the "Shaft" cookie then HasKeys will be equal to "true" and the next line will execute.</font></font></p> </td> </tr> <tr> <td vAlign="top" width="61%"> <p><font color="green" size="2" face="Verdana">Response.Redirect "memberpage.asp"%></font></p> </td> <td vAlign="top" width="39%"><font size="2"> <p><font face="Verdana">Here's how you magically transport the user to a new page, and the reason why I set the Buffers to True. I didn't want to send any data to the client until I was sure that this was the page I was actually going to send to the client. Since the user already has the Shaft cookie, they've obviously already signed up as a member and I will redirect them to the Member Login page-"memberpage.asp". For kicks go ahead and take set the buffers property to False. Does that error code look familiar?</font></font></p> </td> </tr> <tr> <td vAlign="top" width="61%"><font size="2"> <p><font face="Verdana"><%Else%></font></font></p> </td> <td vAlign="top" width="39%"><font size="2"> <p><font face="Verdana">This is the starting point for users that have never visited the site before. They don't have the "Shaft" cookie- the HasKeys property was equal to "False"!</font></font></p> </td> </tr> <tr> <td vAlign="top" width="61%"><font size="2"> <p><font color="green" face="Verdana"><%</font></p> <p><font color="green" face="Verdana"><font color="black">If </font>"BadMutha" = Request("ActionType") <font color="black">Then</font></font></p> <p><font color="green" face="Verdana">TheContactName=Request("ContactName")</font></p> <p><font color="green" face="Verdana">TheComany=Request("Company")</font></p> <p><font color="green" face="Verdana">ThePassword=Request("Password")</font></p> <p><font color="green" face="Verdana">TheEmail=Request("Email")</font></p> <p><font color="green" face="Verdana">TheStatus=Request("Status")</font></p> <p><font color="green" face="Verdana">TheDomain=".www.aspalliance.com"</font></p> <p><font color="green" face="Verdana">ThePath="/glenncook/aspjobs"</font></p> <p><font color="green" face="Verdana">Response.Cookies("Shaft")("ContactName") = TheContactName</font></p> <p><font color="green" face="Verdana">Response.Cookies("Shaft")("Company") = TheCompany</font></p> <p><font color="green" face="Verdana">Response.Cookies("Shaft")("Password") = ThePassword</font></p> <p><font color="green" face="Verdana">Response.Cookies("Shaft")("Email") = TheEmail</font></p> <p><font color="green" face="Verdana">Response.Cookies("Shaft")("Status") = TheStatus</font></p> <p><font color="green" face="Verdana">Response.Cookies("Shaft").Expires = #September 3, 1999#</font></p> <p><font color="green" face="Verdana">Response.Cookies("Shaft").Domain = TheDomain</font></p> <p><font color="green" face="Verdana">Response.Cookies("Shaft").Path = ThePath</font></p> <p><font color="green" face="Verdana">%></font></font></p> </td> <td vAlign="top" width="39%"><font size="2"> <p><font face="Verdana">This is where this page gets cool!<br> <In the voice of an Infomercial host.><br> Not only does it check for an existing cookie, but it also posts its own form data to itself , collects the data, and writes the information onto the user's system in the form of a cookie! But wait there's more: It also writes that information to a database!</font></p> <p><font face="Verdana"><End Infomercial Voice></font></p> <p><font face="Verdana">Notice that the first line checks to see if the person is posting any information to the page. It just simply Requests to see if there was a variable sent called ("ActionType") and if it is equal to a string called "BadMutha". If the statement is equal to true, then the page starts executing all of the cookie code you see in this block.</font></p> <p><font face="Verdana">The first little paragraph Requests/extracts and collects the data that has been posted to it. Each variable is given a name that the page can use later on.</font></p> <p><font face="Verdana">The second paragraph uses the Response object to stick each of those variables that it just collected into contents/Keys of a cookie I call "Shaft." The reponse object literally sends that cookie and its keys to the client's machine. (For an in-depth cookie tutorial please visit </font></font><font face="Verdana"><a href="http://www.aspalliance.com/glenncook/cookiecode.asp"><font size="2">The Cheesy Cookie</font></a><font size="2">!!!</font></font></p> </td> </tr> <tr> <td vAlign="top" width="61%"><font size="2"> <p><font color="green" face="Verdana"><%</font></p> <p><font color="green" face="Verdana">dim Status</font></p> <p><font color="green" face="Verdana">dim Address</font></p> <p> </p> <p><font color="green" face="Verdana">Status = Request("Status")</font></p> <p><font color="green" face="Verdana">Session("Status") = Status</font></p> <p><font size="+0" color="green" face="Verdana">Address = Request("EMail")</font></p> <p> </p> <p><font face="Verdana"> </font></p> <p></font></p> </td> <td vAlign="top" width="39%"><font size="2"> <p><font face="Verdana">Remember the if statement from the block above? Well it's still got work to do. This is where I start the process of creating a Member Profile in a database using ADO and SQL.</font></p> <p><font face="Verdana">The first thing that I do is create a couple of variables:</font></p> <p><font face="Verdana">The "Status" variable I use for sticking the information collected from the form about wheteher they are an "Employer" "Developer" etc. into the Session("Status") variable that was created in the global.asa file. Remember the global.asa file is where we can create variables to use across the entire time the user is visiting our site. Any other variables "die" as soon as the page is done executing.</font></p> <p><font face="Verdana">The "Address" variable is what I will use to build my SQL statement. I collect the data by Requesting the individual's e-mail address from the posting form.</font></font></p> </td> </tr> <tr> <td vAlign="top" width="61%"><font size="2"> <p><font face="Verdana">1 <font color="green">Set Conn = Server.CreateObject("ADODB.Connection")</font></font></p> <p><font face="Verdana">2 <font color="darkgreen">Set NewCust = Server.CreateObject("ADODB.RecordSet")</font></font></p> <p> </p> <p><font face="Verdana">3 <font color="darkgreen">Conn.Open "ClassyAds","sa",""</font></font></p> <p><font face="Verdana">4 <font color="green">NewCust.Open "SELECT * FROM ASPLoginUserTbl WHERE _</font></font></p> <p><font color="green" face="Verdana">EMail = '" & Address & "'", Conn , adOpenKeyset , adLockOptimistic</font></p> <p> </p> <p><font face="Verdana"> </font></p> <p> </p> <p><font face="Verdana"> </font></font></p> </td> <td vAlign="top" width="39%"><font size="2"> <p> </p> <p><font face="Verdana">Here's where we make a connection to the database, build an SQL statement and execute it!</font></p> <ol> <li><font face="Verdana">Create an ADODB connection object.</font> <li><font face="Verdana">Create a recordset object.</font> <li><font face="Verdana">Open a connection to the DSN called Classy ads. (The server must have a Data Source Name created in the control panel's ODBC icon.)</font> <li><font face="Verdana">SQL statement: where I basically say, SELECT everything FROM the ASPLoginUserTbl Table WHERE the Email field in that table is equal to the contents the Address variable. The other "Conn, AdOpenKeyset,.." things are properties of the statement's interaction with the database that you can read up on in <a href="http://www.activeserverpages.com/tutorials">Charles Carol's</a> massive database tutorial pages!</font></li> </ol> <p><font face="Verdana">*The most common mistake that I run into with database programming is an SQL statement typo. If any of the & "'", stuff is driving you nuts you need an SQL primer!</font></font></p> </td> </tr> <tr> <td vAlign="top" width="61%"><font size="2"> <p><font face="Verdana">If <font color="green">NewCust.RecordCount = 0 </font>Then</font></p> <p> </p> <p><font color="green" face="Verdana">NewCust.AddNew</font></p> <p><font face="Verdana">If <font color="darkgreen">Request("ContactName") <> "" </font>Then</font></p> <p><font color="green" face="Verdana">NewCust("ContactName") = Request("ContactName")</font></p> <p><font face="Verdana">End If</font></p> <p><font color="green" face="Verdana"><font color="black">If </font>Request("Company") <> "" <font color="black">Then</font></font></p> <p><font color="green" face="Verdana">NewCust("Company") = Request("Company")</font></p> <p><font face="Verdana">End If</font></p> <p><font face="Verdana">If <font color="green">Request("Email") <> "" </font>Then</font></p> <p><font color="green" face="Verdana">NewCust("Email") = Request("Email")</font></p> <p><font face="Verdana">End If</font></p> <p><font face="Verdana">If <font color="green">Request("Password") <> "" </font>Then</font></p> <p><font color="green" face="Verdana">NewCust("Password") = Request("Password")</font></p> <p><font face="Verdana">End If</font></p> <p><font face="Verdana">If <font color="green">Request("Status") <> "" </font>Then</font></p> <p><font color="green" face="Verdana">NewCust("Status") = Request("Status")</font></p> <p><font face="Verdana">End If</font></p> <p> </p> </font></td> <td vAlign="top" width="39%"><font size="2"> <p><font face="Verdana"> </font></p> <p><font face="Verdana">Since the SQL statement has executed above, we can now see if the Recordset object we created, called "NewCust", has a RecordCount equal to 0. Logically, it should because we've already made the assumption that the individual has never been here before. Since we all know the evils of assumptions, this if statement covers our butt if the user has already filled out a member profile. So if our SQL query finds an e-mail address it will increment the record count by one. We should only have one member profile per E-mail address!</font></p> <p><font face="Verdana">The second line executes if there is no other e-mail address in the table that matches. This line actually adds a new row to the table. Each line that follows actually inserts the information it Requests from the posted form into the individual fields in the access table.</font></p> <p><font face="Verdana">*Again if the SQL statement references a field that doesn't exist in the table, ERROR!</font></p> <p><font face="Verdana"> </font></font></p> </td> </tr> <tr> <td vAlign="top" width="61%"><font size="2"> <p> </p> <p><font color="green" face="Verdana">NewCust.Update</font></p> <p><font color="green" face="Verdana">NewCust.Close</font></p> <p> </p> <p><font color="green" face="Verdana">Response.Redirect "memberpage.asp"</font></font></p> </td> <td vAlign="top" width="39%"><font size="2"> <p><font face="Verdana">This little section of code just does some basic administrative work . It updates/saves the new row in the Recordset called NewCust. And since we're done with it we close it.</font></p> <p><font face="Verdana">So at this point we&rsquo;ve written a cookie and stuck data into a database - now we want to direct them to the Member Login Page. If they have allowed us to use the "Shaft" cookie then their e-mail address and password are automatically extracted into the page- so they don't have to remember their password.</font></font></p> </td> </tr> <tr> <td vAlign="top" width="61%"><font size="2"> <p><font face="Verdana">Else</font></p> <p><font color="green" face="Verdana">Response.Cookies("JonShaft").Expires = Date - 2</font></p> <p><font color="green" face="Verdana">Response.Redirect "addresserr.htm"</font></p> <p><font face="Verdana">End If</font></p> <p><font color="green" face="Verdana">%></font></p> </font></td> <td vAlign="top" width="39%"><font size="2"> <p><font face="Verdana"> </font></p> <p><font face="Verdana">This little section basically references that if statement that checks to see if they have already entered a member profile before. If the RecordCount property equals anything other than "0" then this little section is executed.</font></p> <p><font face="Verdana">All it does is "kill" the Shaft cookie we just wrote to the user's system by setting it&rsquo;s Expires property to two days ago. Then we send them to a little page that says something like, "That e-mail address is already in the system" or something to that effect.</font></font></p> </td> </tr> <tr> <td vAlign="top" width="61%"><font size="2"> <p><font face="Verdana"><%Else%></font></p> <p><font color="navy" face="Verdana"><HTML></font></p> <p><font color="navy" face="Verdana"><HEAD></font></p> <p><font color="navy" face="Verdana"><TITLE>New Member Login Screen</TITLE></font></p> <p><font color="navy" face="Verdana"></HEAD></font></p> <p><font color="navy" face="Verdana"><body></font></p> <p><font face="Verdana"><font color="navy"><form METHOD="POST" ACTION="</font><font color="green"><%=Request.ServerVariables("SCRIPT_NAME<font size="+0" color="navy">")%></font></font><font color="navy" size="+0">" Name="MyForm"></font></font></p> <p><font color="navy" face="Verdana"><input type="hidden" name="ActionType" value="BadMutha"><p><font face="Verdana"</font></p> <p><font color="navy" face="Verdana">color="#408080"><big><strong>New Member Login</strong></big></font></p></font></p> <p><font color="navy" face="Verdana"><p><small><font face="Verdana">Our site does not recognize you as an existing member. If you do not have an account yet please fill in your</font></p> <p><font color="navy" face="Verdana">personal information below to recieve your "member cookie". If you have somehow</font></p> <p><font color="navy" face="Verdana">lost or deleted your "member cookie" and you remember your user name and password, you may</font></p> <p><font color="navy" face="Verdana">proceed to the member login page.</font></small></p></font></p> <p><font color="navy" face="Verdana"><table border="1" width="100%" bgcolor="#FFFFA2" style="border: 2px solid rgb(64,128,128)"></font></p> <p><font color="navy" face="Verdana"><tr></font></p> <p><font color="navy" face="Verdana"><td width="18%"><small><font face="Verdana">Contact Name(First&Last):</font></small></td></font></p> <p><font color="navy" face="Verdana"><td width="82%"><small><font face="Verdana"><input type="text" name="ContactName" size="30"><font</font></p> <p><font color="navy" face="Verdana">color="#FF0000">*</font></font></small></td></font></p> <p><font color="navy" face="Verdana"></tr></font></p> <p><font color="navy" face="Verdana"><tr></font></p> <p><font color="navy" face="Verdana"><td width="18%"><small><font face="Verdana">Company:</font></small></td></font></p> <p><font color="navy" face="Verdana"><td width="82%"><small><font face="Verdana"><input type="text" name="Company" size="30"><font</font></p> <p><font color="navy" face="Verdana">color="#FF0000">*</font></font></small></td></font></p> <p><font color="navy" face="Verdana"></tr></font></p> <p><font color="navy" face="Verdana"><tr></font></p> <p><font color="navy" face="Verdana"><td width="18%"><small><font face="Verdana">E-mail:</font></small></td></font></p> <p><font color="navy" face="Verdana"><td width="82%"><small><font face="Verdana"><input type="text" name="EMail" size="30"><font</font></p> <p><font color="navy" face="Verdana">color="#FF0000">*</font></font></small></td></font></p> <p><font color="navy" face="Verdana"></tr></font></p> <p><font color="navy" face="Verdana"><tr></font></p> <p><font color="navy" face="Verdana"><td width="18%"><small><font face="Verdana">Password:</font></small></td></font></p> <p><font color="navy" face="Verdana"><td width="82%"><small><font face="Verdana"><input type="password" name="Password"</font></p> <p><font color="navy" face="Verdana">size="10"><font color="#FF0000">*</font></small></td></font></p> <p><font color="navy" face="Verdana"></tr></font></p> <p><font color="navy" face="Verdana"><tr></font></p> <p><font color="navy" face="Verdana"><td width="18%"><small><font face="Verdana">Verify Password:</font></small></td></font></p> <p><font color="navy" face="Verdana"><td width="82%"><small><font face="Verdana"><input type="password" name="Password2"</font></p> <p><font color="navy" face="Verdana">size="10"><font color="#FF0000">*</font></small></td></font></p> <p><font color="navy" face="Verdana"></tr></font></p> <p><font color="navy" face="Verdana"><tr></font></p> <p><font color="navy" face="Verdana"><td width="18%"><strong><small><font face="Verdana">Membership category(Select a profile for your account):</font></small></strong></td></font></p> <p><font color="navy" face="Verdana"><td width="82%"><small><font face="Verdana"><select name="Status" size="1"></font></p> <p><font color="navy" face="Verdana"><option value="Employer">Employer</option></font></p> <p><font color="navy" face="Verdana"><option value="Developer">Developer</option></font></p> <p><font color="navy" face="Verdana"><option value="Graphic Designer">Graphic Designer</option></font></p> <p><font color="navy" face="Verdana"><option value="Contracts">Contract(s) To Post</option></font></p> <p><font color="navy" face="Verdana"></select></font></small></td></font></p> <p><font color="navy" face="Verdana"></tr></font></p> <p><font color="navy" face="Verdana"><tr></font></p> <p><font color="navy" face="Verdana"><td width="100%" colspan="2"><div align="left"><p><small><font face="Verdana"><input</font></p> <p><font color="navy" face="Verdana">type="reset" value="Clear Form" id="reset1" name="reset1"> <input TYPE="submit"</font></p> <p><font color="navy" face="Verdana">VALUE="Submit Info!" id="submit1" name="submit1"></form></font></p> <p><font color="navy" face="Verdana"><form METHOD="POST" ACTION="<font color="green"><%=Request.ServerVariables("SCRIPT_NAME")%></font>" Name="Form2"> <input TYPE="submit"</font></p> <p><font color="navy" face="Verdana">VALUE="Proceed to Login Screen" id="submit2" name="submit2"></form></font></small></td></font></p> <p><font color="navy" face="Verdana"></tr></font></p> <p><font color="navy" face="Verdana"></table></font></p> <p><font color="navy" face="Verdana"><p><font face="Verdana" color="#FF0000"><small><strong>* Required information for new</font></p> <p><font color="navy" face="Verdana">members. No information collected will be redistributed or used for spamming.</strong></small></font></p></font></p> <p><font color="navy" face="Verdana"></BODY></font></p> <p><font color="navy" face="Verdana"></HTML></font></p> <p><font face="Verdana"><%End If%></font></p> <p><font face="Verdana"><%End If%></font></p> </font></td> <td vAlign="top" width="39%"><font size="2"> <p><font face="Verdana"> </font></p> <p><font face="Verdana">Remember that "If" statement from way-back-when that checked to see if the user was posting a form that had an ActionType equal to the string "BadMutha"? Well, this is the HTML for the form!</font></p> <p><font face="Verdana">Please notice a couple things:</font></p> <ol> <li><font face="Verdana">Since I'm posting this form to this asp page I extract the pages name from itself by using the Request.ServerVariables object-Cool trick!</font> <li><font face="Verdana">I have a hidden input field called ActionType that I use for finding out if they are posting this form to this page-Cool Trick #2</font> <li><font face="Verdana">There is also a form that redirects the user to the login page. Just in case they don't have cookies enabled.</font></li> </ol> </font></td> </tr> <tr> <td vAlign="top" width="61%"><font size="2"> <p><font face="Verdana"><% If <font color="green">Request.Form("submit2") = "Proceed to Login Screen" </font>Then</font></p> <p><font color="green" face="Verdana">Response.Redirect "memberpage.asp"</font></p> <p><font face="Verdana">End If%></font></p> </font></td> <td vAlign="top" width="39%"><font size="2"> <p><font face="Verdana">This little section tests to see if the user has selected the "Proceed to login screen" button that I put there for people who don't want the cookie to remember their password information. It just Redirects them to the login page where they will need to provide their e-mail address and password information.</font></p> </font></td> </tr> <tr> <td colSpan="2" height="30" vAlign="top"><font size="2"> <p><font color="red" face="Verdana">The remaining portion of this ASP page is some advanced client-side VBScript that does some cool input field validation. If you don't have the source-code for the FOOApp, you can download it at the top of this article. VBScript tutorials will come at a later date.</font></p> </font></td> </tr> </tbody> </table>
Originele reacties (3)
Hersteld van de Wayback Machine