Blogengine.NET – reCaptcha 0.93 Installation Instructions

by Filip Stanek 26. February 2010 01:33

These installation instructions now apply to version 0.95

First, the linked ZIP file contains the updated files for installing the Recaptcha control.

UPDATES:

  • Version 0.95 – Changed initial loading method to fix error that occurred in certain cases in IE. If upgrading from 0.94, you only need to replace the Recaptcha.cs file.
  • Version 0.94 – Logging fixes
  • Version 0.93 – Added logging.
  • Version 0.92 - The recaptcha will no longer get focus after it has been loaded. Install procedure is unchanged from version 0.91.
  • Version 0.91 - Changed the way that Recaptcha is verified.  It should no longer be possible to bypass the recaptcha by manually executing JavaScript on the page.
  • Version 0.9 - Initial Version

Quick Installation

First, back up your files in case you need to revert for any reason. If you have not modified any of the BlogEngine files, you can extract the ZIP linked to above and place all of the files into their proper locations ( the unzipped files should contain a folder structure ). There is no need to recompile.

You may need to force a refresh of your browser on the site, since there is a JavaScript file updated, and most browsers like to cache these files.

Manual Installation

Below is a complete summary of what needs to be altered to make the Recaptcha control work.  You’ll need to do this for any files manually modified in your BlogEngine.NET instance.

/App_Code/Controls/Recaptcha.cs
/admin/Pages/RecaptchaLogViewer.aspx
/admin/Pages/RecaptchaLogViewer.aspx.cs

These files were not included in the BlogEngine.NET installation, and should be placed in their respective folders.

/blog.js

There are three functions in this file that need to be updated to the following:

onCommentError: function(error, context) {
        BlogEngine.toggleCommentSavingIndicators(false);
        error = error || "Unknown error occurred.";
        var iDelimiterPos = error.indexOf("|");
        if (iDelimiterPos > 0) {
            error = error.substr(0, iDelimiterPos);
            // Remove numbers from end of error message.
            while (error.length > 0 && error.substr(error.length - 1, 1).match(/\d/)) {
                error = error.substr(0, error.length - 1);
            }
        }
        
        if( document.getElementById('recaptcha_response_field') )
        {
           Recaptcha.reload();
        }
 
        alert("Sorry, the following error occurred while processing your comment:\n\n" + error);
    }
addComment: function(preview) {
        var isPreview = preview == true;
        if (!isPreview) {
            BlogEngine.toggleCommentSavingIndicators(true);
            this.$("status").innerHTML = BlogEngine.i18n.savingTheComment;
        }
 
        var author = BlogEngine.comments.nameBox.value;
        var email = BlogEngine.comments.emailBox.value;
        var website = BlogEngine.comments.websiteBox.value;
        var country = BlogEngine.comments.countryDropDown ? BlogEngine.comments.countryDropDown.value : "";
        var content = BlogEngine.comments.contentBox.value;
        var notify = BlogEngine.$("cbNotify").checked;
        var captcha = BlogEngine.comments.captchaField.value;
        var replyToId = BlogEngine.comments.replyToId ? BlogEngine.comments.replyToId.value : "";
        
        var recaptchaResponseField = document.getElementById('recaptcha_response_field');        
        var recaptchaResponse = recaptchaResponseField ? recaptchaResponseField.value : "";
        
        var recaptchaChallengeField = document.getElementById('recaptcha_challenge_field');
        var recaptchaChallenge = recaptchaChallengeField ? recaptchaChallengeField.value : "";
 
        var avatarInput = BlogEngine.$("avatarImgSrc");
        var avatar = (avatarInput && avatarInput.value) ? avatarInput.value : "";
 
        var callback = isPreview ? BlogEngine.endShowPreview : BlogEngine.appendComment;
        var argument = author + "-|-" + email + "-|-" + website + "-|-" + country + "-|-" + content + "-|-" + notify + "-|-" + isPreview + "-|-" + captcha + "-|-" + replyToId + "-|-" + avatar + "-|-" + recaptchaResponse + "-|-" + recaptchaChallenge;
 
        WebForm_DoCallback(BlogEngine.comments.controlId, argument, callback, 'comment', BlogEngine.onCommentError, false);
 
        if (!isPreview && typeof (OnComment) != "undefined")
            OnComment(author, email, website, country, content);
    }
appendComment: function(args, context) {
        if (context == "comment") {
        
            if( document.getElementById('recaptcha_response_field') )
            {
               Recaptcha.reload();
            }
        
            if( args == "RecaptchaIncorrect" )
            {
               if( document.getElementById("spnCaptchaIncorrect") ) document.getElementById("spnCaptchaIncorrect").style.display = "";
               BlogEngine.toggleCommentSavingIndicators(false);
            }
            else
            {
            
                if( document.getElementById("spnCaptchaIncorrect") ) document.getElementById("spnCaptchaIncorrect").style.display = "none";
 
                var commentList = BlogEngine.$("commentlist");
                if (commentList.innerHTML.length < 10)
                    commentList.innerHTML = "<h1 id='comment'>" + BlogEngine.i18n.comments + "</h1>"
 
                // add comment html to the right place
                var id = BlogEngine.comments.replyToId ? BlogEngine.comments.replyToId.value : '';
 
                if (id != '') {
                    var replies = BlogEngine.$('replies_' + id);
                    replies.innerHTML += args;
                } else {
                    commentList.innerHTML += args;
                    commentList.style.display = 'block';
                }
 
                // reset form values
                BlogEngine.comments.contentBox.value = "";
                BlogEngine.comments.contentBox = BlogEngine.$(BlogEngine.comments.contentBox.id);
                BlogEngine.toggleCommentSavingIndicators(false);
                BlogEngine.$("status").className = "success";
 
                if (!BlogEngine.comments.moderation)
                    BlogEngine.$("status").innerHTML = BlogEngine.i18n.commentWasSaved;
                else
                    BlogEngine.$("status").innerHTML = BlogEngine.i18n.commentWaitingModeration;
 
                // move form back to bottom
                var commentForm = BlogEngine.$('comment-form');
                commentList.appendChild(commentForm);
                // reset reply to
                if (BlogEngine.comments.replyToId) BlogEngine.comments.replyToId.value = '';
                if (BlogEngine.$('cancelReply')) BlogEngine.$('cancelReply').style.display = 'none';
            
            }
        }
 
        BlogEngine.$("btnSaveAjax").disabled = false;
    }

/User controls/CommentView.ascx.cs

One method in this file needs to be updated:

/// <summary>
/// Processes a callback event that targets a control.
/// </summary>
/// <param name="eventArgument">A string that represents an event argument to pass to the event handler.</param>
public void RaiseCallbackEvent(string eventArgument)
{
    if (!BlogSettings.Instance.IsCommentsEnabled)
        return;
 
    string[] args = eventArgument.Split(new string[] { "-|-" }, StringSplitOptions.None);
    string author = args[0];
    string email = args[1];
    string website = args[2];
    string country = args[3];
    string content = args[4];
    bool notify = bool.Parse(args[5]);
    bool isPreview = bool.Parse(args[6]);
    string sentCaptcha = args[7];
    //If there is no "reply to" comment, args[8] is empty
    Guid replyToCommentID = String.IsNullOrEmpty(args[8]) ? Guid.Empty : new Guid(args[8]);
    string avatar = args[9];
 
    string recaptchaResponse = args[10];
    string recaptchaChallenge = args[11];
 
    recaptcha.UserUniqueIdentifier = hfCaptcha.Value;
    if (!isPreview && recaptcha.RecaptchaEnabled && recaptcha.RecaptchaNecessary)
    {
        if (!recaptcha.ValidateAsync(recaptchaResponse, recaptchaChallenge))
        {
            _Callback = "RecaptchaIncorrect";
            return;
        }
    }
 
    string storedCaptcha = hfCaptcha.Value;
 
    if (sentCaptcha != storedCaptcha)
        return;
 
    Comment comment = new Comment();
    comment.Id = Guid.NewGuid();
    comment.ParentId = replyToCommentID;
    comment.Author = Server.HtmlEncode(author);
    comment.Email = email;
    comment.Content = Server.HtmlEncode(content);
    comment.IP = Request.UserHostAddress;
    comment.Country = country;
    comment.DateCreated = DateTime.Now;
    comment.Parent = Post;
    comment.IsApproved = !BlogSettings.Instance.EnableCommentsModeration;
    comment.Avatar = avatar.Trim();
 
    if (Page.User.Identity.IsAuthenticated)
        comment.IsApproved = true;
 
    if (website.Trim().Length > 0)
    {
        if (!website.ToLowerInvariant().Contains("://"))
            website = "http://" + website;
 
        Uri url;
        if (Uri.TryCreate(website, UriKind.Absolute, out url))
            comment.Website = url;
    }
 
    if (!isPreview)
    {
        if (notify && !Post.NotificationEmails.Contains(email))
            Post.NotificationEmails.Add(email);
        else if (!notify && Post.NotificationEmails.Contains(email))
            Post.NotificationEmails.Remove(email);
 
        Post.AddComment(comment);
        SetCookie(author, email, website, country);
        recaptcha.UpdateLog(comment);
    }
 
    string path = Utils.RelativeWebRoot + "themes/" + BlogSettings.Instance.Theme + "/CommentView.ascx";
 
    CommentViewBase control = (CommentViewBase)LoadControl(path);
    control.Comment = comment;
    control.Post = Post;
 
    using (StringWriter sw = new StringWriter())
    {
        control.RenderControl(new HtmlTextWriter(sw));
        _Callback = sw.ToString();
    }
}

/User controls/CommentView.ascx

Finally, the following line needs to be added to this file, at the location you would like the Recaptcha control to appear. Remember to update your TabIndexes for proper tab button navigation.

<blog:RecaptchaControl ID="recaptcha" runat="server" TabIndex="8" />

 

Recaptcha Settings

You can edit the Recaptcha settings via the Extension Manager. You probably should enter in your own Public and Private keys, as the provided keys are for this site ( they are global, so they will work on other sites ).

Recaptcha Theming

There are 4 built-in themes that you can change via the ExtensionManager. You can also create your own theme by adding it in the following way to the Recaptcha control:

<blog:RecaptchaControl ID="recaptcha" runat="server" TabIndex="8" Theme="MyCustomTheme" />

For detailed instructions on what your theme needs to look like, visit the Recaptcha site.

Known Issues

  • None ATM

Tags: , , , , , ,

Web Development

Comments

  • Trackbacks (7)
  • Comments (47)

+0 Vote Up     Vote Down # CreepinJesus Australia on 2/28/2010 4:52:23 AM

CreepinJesus

I'm getting a "The captcha text was not valid. Please try again." error every time I try using reCaptcha on my site.  My site is not online yet - could this be why?

Thanks.

Reply

+0 Vote Up     Vote Down # Filip United States on 2/28/2010 11:09:34 PM

Filip

As mentioned in this thread [ blogengine.codeplex.com/.../View.aspx ], try not to use a private key on localhost. You can try to do one of three things:

- Create a global key at http://recaptcha.net
- Use the global key that came with the control for testing, and use a private key once you upload to your site
- You can try modifying your hosts on your local machine to make it think you are actually on your web server.

Reply

+0 Vote Up     Vote Down # adrian on 3/1/2010 5:40:16 AM

adrian

I'm using keys for my domain on my blog. I tested locally on my laptop from VS successfully with those keys(after building 1.6.0.1). As long as the server is specified as localhost or 127.0.0.1, I think recaptcha does not mind(see the documentation), it will do a POST for:
privatekey='...'&remoteip=127.0.0.1&challenge='...'...

Reply

+0 Vote Up     Vote Down # Abe United States on 3/2/2010 12:19:23 AM

Abe

Any suggestions for someone who has a precompiled site?

Reply

+0 Vote Up     Vote Down # Filip United States on 3/2/2010 1:41:49 AM

Filip

Abe:
I'm pretty sure you would need to download the non-precompiled web and either upload that, or compile it yourself and then upload the files.

Or maybe BE.NET will include this control or some version of it in a future release. Sorry!

Reply

+0 Vote Up     Vote Down # Abe United States on 3/2/2010 11:57:40 PM

Abe

Decided to go ahead and upgrade to 1.6 (was running 1.5) and use the non precompiled version.  I'll let you know how it goes.

Reply

+0 Vote Up     Vote Down # Abe United States on 3/3/2010 1:29:21 AM

Abe

Got it working.  Great post, thanks for the help!  Hopefully this will keep the spammers at bay.

Reply

+0 Vote Up     Vote Down # Pravesh India on 3/3/2010 12:09:38 AM

Pravesh

This is not working for me as I'm using DbBlogProvider for my data store.  Gives the following error



Line 195:            {
Line 196:                ExtensionSettings Settings = ExtensionManager.GetSettings("Recaptcha");
Line 197:                return Convert.ToInt32(Settings.GetSingleValue("MaxLogEntries"));
Line 198:            }
Line 199:        }



Any clue?

Reply

+0 Vote Up     Vote Down # Filip United States on 3/3/2010 3:03:20 AM

Filip

Pravesh: Could you go in your database and open the 'DataStoreSettings' table.  In that table, look for 'Recaptcha' in the 'ExtensionId' [edit: previously said 'eid'] field. If it is there, then delete that record, and restart  your blog.

The only time I've seen this error come up was during development, when I had created a setting value but not refreshed the cache or deleted my old settings which did not contain the setting.  I'm really not sure what could be causing this on your system, unless you had an extension before called 'Recaptcha' and it had a greater version number than 0.94.

Also, I'm assuming you did not modify anything in the Recaptcha.cs file, as that could also result in this error.

Reply

+0 Vote Up     Vote Down # Web Timesheet Blog United States on 3/6/2010 11:21:33 AM

Web Timesheet Blog

okay tested it on my blog and it works fine so far! This is the easiest implementation I have seen so far! Why not contribute this to the blogengine.net extensions? We ought to have it integrated in the next version!

Reply

+0 Vote Up     Vote Down # Filip United States on 3/6/2010 6:39:20 PM

Filip

There's a thread going about this extension on the BlogEngine forums [ blogengine.codeplex.com/.../View.aspx ]. As you'll see from the version number, I'm not yet confident enough to call it a "final" release.

At this point, there are no issues with the current implementation that I know of. If enough time goes by without any issues being reported, I'll promote this to version 1.  I also wouldn't be surprised to see this extension or some form of it in the next BlogEngine.NET release. I have no control over that though.

Reply

+0 Vote Up     Vote Down # Peter Australia on 3/8/2010 11:40:04 PM

Peter

Great...thanks

Reply

+0 Vote Up     Vote Down # Dean United Kingdom on 3/20/2010 5:31:37 AM

Dean

This is brilliant - I just copied the files onto my BlogEngine directory and it worked like a charm Smile

The only glitch was that I previously had the comments set to 'moderate' which caused an error with the ajax. I set comment approval to 'automatic' and the error dissapeared.

I was quite happy because the whole point of doing the reCaptcha thing was so that I didnt have to spend 20 minutes a day deleting comments from people from 'the big dick pills' company who found my blog about software development 'the best blog they've ever seen'

Thanks again

Reply

+0 Vote Up     Vote Down # Filip United States on 3/22/2010 11:47:26 AM

Filip

Glad you like it. I'll take a look at the "manual" moderation bug: I'm just probably missing a check if moderation is set to manual, so it shouldn't be too difficult to fix.  Thanks for the feedback!

Reply

+0 Vote Up     Vote Down # rtur.net United States on 3/23/2010 5:51:09 PM

rtur.net

Hey Philip, I've sent you email few days back but not sure if you got it. It will be shame if all hard work you put into recaptcha will only be used by some of BE users - we want to add this to the core so anybody can turn it on with a check box click. I'm evaluating it on my blog and planning start moving it into code base this weekend. If you don't want it moved to the core, please let me know. If you want to do it yourself by branching code - that works too, we can pull it in when you done. Let me know whatever you decide.

Ruslan

Reply

+0 Vote Up     Vote Down # Filip United States on 3/23/2010 11:23:53 PM

Filip

Oops, sorry, but I haven't been checking my personal email for a few days. I don't mind at all if you guys integrate this in BE.NET.

Reply

+0 Vote Up     Vote Down # rtur.net United States on 3/23/2010 5:53:45 PM

rtur.net

Forgot to tell "tank you" - sorry, rough day in the office Smile

Reply

+0 Vote Up     Vote Down # Alex Meyer-Gleaves Australia on 3/30/2010 10:59:58 AM

Alex Meyer-Gleaves

Hi Filip,

Thanks for sharing your great work. I had to make a couple of changes to get the extension (V0.95) working with the DbBlogProvider. If you are interested, the changes I made are outlined in the post below.

alexmg.com/.../...for-Comment-Spam-protection.aspx

These changes do not make the extension work with both the XmlBlogProvider and DbBlogProvider, though you could no doubt easily add support for both.

Cheers,

Alex.

Reply

+0 Vote Up     Vote Down # Tim Bailey New Zealand on 4/24/2010 6:33:33 AM

Tim Bailey

Great, was getting flooded with spam comments. Solved in 5 mins.  Thanks a bunch.

Reply

+0 Vote Up     Vote Down # Krystian United Kingdom on 6/2/2010 3:02:33 AM

Krystian

Yeah, I've had same problem as Tim above, on one of my test blogs, I'm still to choose the platform I'll use for my proper blogging, but I'm one step closer now thanks to your post.

Reply

+0 Vote Up     Vote Down # Pat United States on 6/11/2010 1:17:08 AM

Pat

This sounds so nice and easy but it doesn't work for me.
I upgraded BE to 1.6 so I could use recaptcha.
Put up the files available at the time.
Now I downloaded this package and put the files in place on the (shared hosting) folders.
Site failed.
Looked for and deleted previous recaptcha files on the server since this should be the complete package (right?) and site loaded ok again.
But NEVER a recaptcha image with the comments form.
I have enabled it in extensions.  On the first try, I registered a key and entered it in extensions manager.
When I go to extensions mgr and click to view the source of recaptcha extension, I get a page saying that source for App_Code\Extensions\Recaptcha.cs cannot be found.  But the file structure in this download has recaptchaa just in App_Code\Controls folder.  If I copy the file to the Extensions folder, the site fails.
I don't know what to do.  Am ready to abandon Blog Engine because of spam.  Seems the choice is either tons of spam or no comments at all.  Not acceptable.  Very sad.  Help?

Reply

+0 Vote Up     Vote Down # Elam Demelo United States on 6/28/2010 4:19:48 AM

Elam Demelo

This seems like a pretty useful tutorial . Thanks for posting it for us noobs Smile

Reply

+0 Vote Up     Vote Down # emlak Turkey on 7/9/2010 1:00:39 PM

emlak

Great, was getting flooded with spam comments. Thanks a bunch.

Reply

+0 Vote Up     Vote Down # Giochi Italy on 7/21/2010 8:30:29 AM

Giochi

I am trying to insall reCaptcha but i always get error
The captcha text was not valid. Please try again

i also tried not to use a private key

Reply

+0 Vote Up     Vote Down # plc United States on 7/24/2010 10:33:01 AM

plc

Thanks for the script code.
I had to download it and tomorrow I will try

Reply

+0 Vote Up     Vote Down # Iran Canada on 8/28/2010 1:26:45 AM

Iran

This blog is really meant for delivering excellent information i will bookmark your blog.

Reply

+0 Vote Up     Vote Down # electronic signature United States on 8/28/2010 6:17:58 AM

electronic signature

This is my first time i visit here. I found so many interesting stuff in your blog, especially its discussion. From the tons of comments on your articles, I guess I am not the only one having all the enjoyment here! Keep up the good work.

Reply

+0 Vote Up     Vote Down # seo minneapolis United States on 8/28/2010 6:21:13 AM

seo minneapolis

I was very pleased to find this site. I wanted to thank you for this great read!! I definitely enjoying every little bit of it and I have you bookmarked to check out new stuff you post.

Reply

+0 Vote Up     Vote Down # Canadian Genealogy New Zealand on 8/28/2010 7:25:53 AM

Canadian Genealogy

I so like Canada, I have never visited myself but really want to one day! Thanks for the good post.

Reply

+0 Vote Up     Vote Down # white label seo United States on 8/29/2010 11:06:17 AM

white label seo

This was a brilliant post. In theory I would like to write like this too. It takes time to create that informative and additionally lots of effort to write a good post.

Reply

+0 Vote Up     Vote Down # investing in london United States on 8/29/2010 11:10:05 AM

investing in london

I like the part where you say you are doing this to give back but I would assume by all the comments that this is working for you as well.Thanks

Reply

+0 Vote Up     Vote Down # per dm Sweden on 8/30/2010 5:37:31 AM

per dm

I wanted to thank you for this great read!! I definitely enjoying every little bit of it I have you bookmarked to check out new stuff you post.

Reply

+0 Vote Up     Vote Down # Carpet Cleaner Raleigh United States on 9/1/2010 4:07:32 AM

Carpet Cleaner Raleigh

Thanks for providing the installation techniques of the .NET re-captcha. It is very useful post for me. It is a good post.

Reply

+0 Vote Up     Vote Down # Talk Dirty Sri Lanka on 9/1/2010 4:09:05 AM

Talk Dirty

I feel strongly about it and will love to learning more on this at future. If possible, as you gain expertise, would you mind updating your blog more often with more useful information? Honestly It is extremely helpful for me.

Reply

+0 Vote Up     Vote Down # Talk Dirty Sri Lanka on 9/1/2010 4:16:01 AM

Talk Dirty

Awesome blog. I enjoyed reading your articles. This is truly a great read for me. I have bookmarked it and I am looking forward to reading new articles. Keep up the good work.

Reply

+0 Vote Up     Vote Down # wireless doorbell United States on 9/1/2010 4:18:53 AM

wireless doorbell

This site is really very nice with lot of blogs, all blogs are very informative and very interesting to read and enjoy.

Reply

+0 Vote Up     Vote Down # HostGator United States on 9/3/2010 2:14:40 AM

HostGator

This is the easiest implementation I have seen so far! Why not contribute this to the blogengine.net extensions?

Reply

+0 Vote Up     Vote Down # Downtown Short Sale United States on 9/3/2010 4:27:21 AM

Downtown Short Sale

Your site is really very rich with lot of different blogs,they are very informative,i got lot of information from this site.

Reply

+0 Vote Up     Vote Down # seattle movers United States on 9/3/2010 5:46:08 AM

seattle movers

Very smart ideas from this post. It contains a lot of valuable information which i really appreciate and adore. Thanks for letting me leave my comments here. Smile

Reply

+0 Vote Up     Vote Down # Casino Reviews 7 United States on 9/3/2010 1:47:02 PM

Casino Reviews 7

If you take part in the similar type of poker, your prediction will be parallel.
  

Reply

+0 Vote Up     Vote Down # Downtown Short Sale Sri Lanka on 9/4/2010 2:58:41 AM

Downtown Short Sale

This is my first time i visit here. I found so many interesting stuff in your blog, especially its discussion. From the tons of comments on your articles, I guess I am not the only one having all the enjoyment here! Keep up the good work.

Reply

+0 Vote Up     Vote Down # cctv lens selection Qatar on 9/4/2010 3:01:27 AM

cctv lens selection

The site is good in providing the short cuts in the M.S.office and also the designing of the site is excellent. Keep posting the valuable information.

Reply

+0 Vote Up     Vote Down # how to stop hair loss, how to stop hair fall, prevent hair loss, prevent hair fall United States on 9/7/2010 5:10:13 AM

how to stop hair loss, how to stop hair fall, prevent hair loss, prevent hair fall

Too much valuable things are shared here,I really appreciated form above information,In past I was searching like that,now I caught all the inforamtion which I want,So thanks for sharing
pretty good post.

Reply

+0 Vote Up     Vote Down # products for natural hair United States on 9/9/2010 2:28:29 AM

products for natural hair

Good blog, where it taught me a lot! Thank you! The hope of improving the content!

Reply

+0 Vote Up     Vote Down # Property Management Minneapolis United States on 9/9/2010 4:40:18 AM

Property Management Minneapolis

The site was informative and contain useful content for the visitors. It got good posts as well. I will bookmark this site for future viewing.

Reply

+0 Vote Up     Vote Down # As built services United States on 9/9/2010 4:45:51 AM

As built services

I wanted to thank you for this great read!! I definitely enjoying every little bit of it I have you bookmarked to check out new stuff you post.

Reply

+0 Vote Up     Vote Down # Seo Specialist United States on 9/9/2010 5:10:10 AM

Seo Specialist

Its like you read my mind! You seem to know so much about this, like you wrote the book in it or something. I think that you could do with some pics to drive the message home a bit, but other than that, this is great blog.
A great read. Ill definitely be back.

Reply

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading




Tag cloud

About Filip Stanek

Death Note Pic I'm a developer at ACG Multimedia in Cincinnati, OH. Besides working with ASP.NET, Flash, and other web technologies, I enjoy playing chess, video games, etc.

Currently playing:
- Final Fantasy XIII
E-mail me Send mail

Recent Comments

Comment RSS

Month List

Page List