Tips for Proper English

January 29, 2010 12:00 by Rob

1. Avoid alliteration. Always.
2. Never use a long word when a diminutive one will do.
4. Employ the vernacular.
5. Eschew ampersands & abbreviations, etc.
6. Parenthetical remarks (however relevant) are unnecessary.
7. Remember to never split an infinitive.
8. Contractions aren't necessary.
9. Foreign words and phrases are not apropos.
10. One should never generalize.
11. Eliminate quotations. As Ralph Waldo Emerson said, "I hate quotations. Tell me what you know."
12. Comparisons are as bad as cliches.
13. Don't be redundant; don't use more words than necessary; it's highly superfluous.
14. Be more or less specific.
15. Understatement is always best.
16. One-word sentences? Eliminate.
17. Analogies in writing are like feathers on a snake.
18. The passive voice is to be avoided.
19. Go around the barn at high noon to avoid colloquialisms.
20. Even if a mixed metaphor sings, it should be derailed.
21. Who needs rhetorical questions?
22. Exaggeration is a billion times worse than understatement.
23. Don't never use a double negation.
24. capitalize every sentence and remember always end it with point
25. Do not put statements in the negative form.
26. Verbs have to agree with their subjects.
27. Proofread carefully to see if you words out.
28. If you reread your work, you can find on rereading a great deal
of repetition can be avoided by rereading and editing.
29. A writer must not shift your point of view.
30. And don't start a sentence with a conjunction. (Remember, too, a preposition is a terrible word to end a sentence with.)
31. Don't overuse exclamation marks!!
32. Place pronouns as close as possible, especially in long sentences,
as of 10 or more words, to their antecedents.
33. Writing carefully, dangling participles must be avoided.
34. If any word is improper at the end of a sentence, a linking verb is.
35. Take the bull by the hand and avoid mixing metaphors.
36. Avoid trendy locutions that sound flaky.
37. Everyone should be careful to use a singular pronoun with singular nouns in their writing.
38. Always pick on the correct idiom.
39. The adverb always follows the verb.
40. Last but not least, avoid cliches like the plague; They're old hat; seek viable alternatives.

Other Versions:


1.Don't abbrev.
2.Check to see if you any words out.
3.Be carefully to use adjectives and adverbs correct.
4.About sentence fragments.
5.When dangling, don't use participles.
6.Don't use no double negatives.
7.Each pronoun agrees with their antecedent.
8.Just between you and I, case is important.
9.Join clauses good, like a conjunction should.
10.Don't use commas, that aren't necessary.
11.Its important to use apostrophe's right.
12.It's better not to unnecessarily split an infinitive.
13.Never leave a transitive verb just lay there without an object.
14.Only Proper Nouns should be capitalized. also a sentence should begin with a capital and end with a period
15.Use hyphens in compound-words, not just in any two-word phrase.
16.In letters compositions reports and things like that we use commas
to keep a string of items apart.
17.Watch out for irregular verbs which have creeped into our language.
18.Verbs has to agree with their subjects.
19.Avoid unnecessary redundancy.
20.A writer mustn't shift your point of view.
21.Don't write a run-on sentence you've got to punctuate it.
22.A preposition isn't a good thing to end a sentence with.
23.Avoid cliches like the plague.
24.It is wrong to ever split an infinitive.
25.Profanity sucks.

 

(source)


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories: General
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

Bomb Proof Http Cache Utility?

September 9, 2009 16:38 by Rob

I’d like to share this piece of code with you all.

Usually, when you use the System.Web.Cache classes, you do something like:

object x = Cache[blabla];
if(x == null) //not in cache
{
    x = …..;
   
    // add to cache
    Cache.Add(x, …);
}
// do something with x here.

Now this is not very thread-safe, because when 2 threads arrive at the ‘if’ at the same time, the object is constructed twice. The second one to complete will just overwrite the cached result of the first one (get it?).

So, in order to avoid this you can add a ‘lock’ statement around this to avoid filling the cache twice.

lock(typeof(ClassName))
{
   …

}

This will essentially avoid that 2 threads will enter the same code at the same time.

The problem with this approach is that there is a significant amount of code for every time that you want to read or write to the cache. The code is very error-prone but it is basically the same pattern over and over.

With generics and delegates you can develop a function that behaves like so:

object x = Cached.Get<object>(“cacheKey”, TimeSpan.FromSeconds(5),
                            () => new object()
                       );

The lambda expression ()=> new object is the fragment of code that is executed to populate the cache. The “cacheKey” is some sort of string that uniquely defines what information you want to retrieve. The key should in theory contain all the parameters for your population method.

Now there is a huge potential problem inside the Get() method. The lock statement (typeof(ClassName)) inside is essentially the same one over and over, so *all* calls through this method will be blocked and serialized, thus reducing concurrency to zero. If you have long-running or expensive population methods (you will, because that is why you are caching) you’ll be slowing the system to a halt.In effect, you’d want a separate lock for every 'cache key’ literal.

To overcome this problem, I developed an implementation that generates a new lock for every key. However, when reading and updating the HttpUtility Cache you should be very careful for race conditions.

CacheUtility.cs (7,11 kb)

This class provides strongly-typed access to the HttpCache. It also provides helper methods to flush a single or all elements that were cached using this method, and also a way to determine groups of cached elements. This way you can flush only a subsection of your cache.


Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories: ASP.Net | C# | Software Engineering
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

Quotes and more quotes

July 17, 2009 13:36 by Rob

I just saw this article with computer quotes, and I found it to be quite hilarious.

“The Internet?  We are not interested in it.”
– Bill Gates, 1993

“Pessimists, we’re told, look at a glass containing 50% air and 50% water and see it as half empty.  Optimists, in contrast, see it as half full.  Engineers, of course, understand the glass is twice as big as it needs to be.”
– Bob Lewis

“It was a joke, okay?  If we thought it would actually be used, we wouldn’t have written it!”
– Mark Andreesen, speaking of the HTML tag BLINK

“Perl: The only language that looks the same before and after RSA encryption.”
– Keith Bostic

“Yes, we have a dress code. You have to dress.”
– Scott McNealy, co-founder of Sun Microsystems

And finally, since I’m working with UXP professionals:

“We have to stop optimizing for programmers and start optimizing for users.”
– Jeff Atwood

 

 

For more great quotes, check here.


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Large file uploading using Silverlight, ASP.Net and WCF Part 3

February 25, 2009 22:45 by Rob

Welcome to part 3 of my little series of creating an Asp.net component that allows to upload files of several megabytes without connection timeouts.

In part 1, I explained how the Silverlight component was built and in part 2 the backend service was discussed. In this third and last part I will explain the reusable ASP.Net server control that combines the features into a plug and play component.

The component will solve the following problems:

  • How do I host the SilverLight component?
  • How do I know when the upload has completed?
  • How do I retrieve the contents of the file?

Hosting the SilverLight component

The SilverLightUploader control overrides the CreateChildControls and embeds a System.Web.UI.SilverlightControls.Silverlight component to host the uploader. The control provides for a couple of properties and some are passed on to the silverlight component by providing some initialization parameters. These include:

  • The url of the webservice to be called
  • The location of the SilverLightUpload.xap package.
  • The filter that limits the extension of the files that can be uploaded.

image

I used a helper function to resolve the passed Url’s to absolute url’s because of some limitations I had in my library, but a simple ResolveUrl should be sufficient in most cases.

Also note the OnPluginLoaded hook. This hook is used to bind the event (that is raised when a file is uploaded) to JavaScript.

When a file upload is completed, the Silverlight component raises an event. This event is then catched by a JavaScript block which saves the token of the upload in a hidden field. The Silverlight component just displayed ‘Upload Completed’ and sits and waits until the page is submitted. (the script block is not shown here).

On postback of the page the control checks if the hidden field contains a valid token, and if this is the case, the asp.net component raises an event that can be caught by the page which contains the control.

The control implements IPostBackDataHandler, which means that on any postback the LoadPostData method of the control will be called.

image

The GUID of the upload is persisted in a ViewState-backed property. So even if a validation error occurs on postback, the upload is still safe. (Unfortunately, the Silverlight component does not reflect this yet). LoadPostData returns ‘true’ and the asp.net framework calls RaisePostDataChangedEvent after all the initialisation logic of the page have been completed:

image

 

 

The page that is subscribed to the FileUploadEvent can then call the UploadManager.GetUpload() with the ID that is provided in the event to retrieve the file.

Some tricks left

Instead of putting the SilverlightUpload.xap in /ClientBin, I have embedded the package in the web control by adding it as an embedded resource. I added this file to the project using ‘Add Existing Item’ and ‘Add as Link’ to the SilverlightUpload.xap from the web application. This last step saved me from manually copying the xap every time I created a new build.

image

In AssemblyInfo.cs I have added a declaration so that webresource.axd can be used to retrieve the xap:

image

Also, I moved the implemementation of the WCF UploadService.svc into the control DLL.

Now, to use this control:

  • Add the WebResource.axd handler declaration to the web.config of your web application,
  • Append the service EndPoint to the web.config,
  • Add the SilverlightUpload.dll to the bin directory (or add a reference)
  • Create a file that is a stub for the WCF service (this is the almost-empty UploadService.svc file),
  • Create a page that uses the control,
  • Add an eventhandler to the FileUploaded event

For your uploading pleasure, I’ve added the project with all code to this post.

That should be it!

SilverlightUpload.zip (73.54 kb)


Currently rated 5.0 by 4 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Large file uploading using Silverlight, ASP.Net and WCF Part 2

February 24, 2009 19:27 by Rob

This is the second part of a multi-part article about implementing large file upload for ASP.Net In my previous post I explained the Silverlight bit and this part will be about the WCF backend.

Curious enough, the WCF backend is actually extremely simple. The are only 3 methods that are exposed as a webservice. There 3 methods cover the 3 phases of the file upload process I explained in the previous post. But before I show the service I need to explain some thing else first.

In summary:

  • The client request an upload token.
  • The client sends the binary file in small blocks using the token.
  • After the file is complete, the client confirms the upload.

We took care of those steps with the Silverlight client. On the server side, we need to respond to those steps.

To maintain a record of all the uploads that are in progress, we need to maintain some sort of ‘memory’.  When an upload starts, a new UploadSession object is created. The UploadSession has a couple of properties:

  1. The Filename of the file that is being submitted,
  2. The ID or token of the session,
  3. The State that the upload is currently in (Created, Streaming, Completed or Failed), and finally:
  4. The binary Data of the transmitted file.

UploadManager class

To access a session, a singleton class is implemented.It has 3 methods: CreateSession and GetSession, and finally GetUpload():

image 

CreateSession will create a new session, GetSession retrieves a session. Both are declared internal because they are used by the WCF service (we will get to that in a minute). Third, the public GetUpload() is similar to GetSession but is used to retrieve a completed transfer.

UploadSessions

The UploadSessions class is a helper collection class that is used to store the current uploads. In a first version I was keeping all the uploads in a collection that had Timer events to purge old uploads, but later I decided to use the HttpRuntime.Cache. Here’s the collection class:

image

In essence, it provides strongly-typed access to the cache using the indexer operator. These getter and setter forwards all calls to the HttpRuntime Cache. If you didn't know, this cache is exactly the same class as the HttpContext.Current.Cache, only shorter.

I set the sliding expiration to 5 minutes. This means that the session will be removed is no block is received within 5 minutes, or when the file is not ‘picked up’ by the consuming client after 5 minutes of the upload. This should be sufficient in most cases.

Also, I use the priority to CacheItemPriority.NotRemovable so the server does not expire the session within the timeout period is it low on resources.

(I just noticed that the Remove method is empty…)

Calling the UploadManager from WCF

The WCF service itself is extremely simple. I just forwards all methods to the UploadManager:

image

Last, but not least

The last step for the service side is UploadSession class itself:

image

Again, no rocket science. The UploadSession class is just a wrapper class for a MemoryStream. I intend to expand this class so it flushes the buffer to a temp-file if the file becomes too large, but for now it works perfectly.

The reason I am using a in-memory buffer is a) memory is cheap and fast and b) I’m using the uploaded data in combination with Linq. And Linq stored binary data as a Binary() class, which is just a wrapper class for a byte[]. Therefore it has no use in streaming the file to disk first, and then completely loading it back into memory. The disk buffer approach is only handy when lots of file are uploaded at the same time. If a lot of files are uploaded simultaneously, the total memory usage would have been lower during the time of the uploads, at the cost of requiring temporary files and a lot of disk I/O.

Hosting the Service

Now, to host this WCF service, a basic endpoint must be configured in the web.config of the hosting application:

image

This configuration was generated automatically when I added the service in my project, so it is completely standard. No magic here. No streaming, no large buffers, nothing fancy.

The Silverlight client needs the Url of the WCF service, but I think that was already covered in the previous post.

Wrapping it all up

This is it for the WCF side of it all. As I mentioned before, we are not finished yet. We still need a way to host the Silverlight application, and tell Asp.net that we have received a file. After that we need to pickup the file from the UploadManager. I’ll be showing you a custom server control that does all three of these steps in a simple, reusable Asp.Net control. But that topic will have to wait until the next episode.

Happy uploading!


Currently rated 5.0 by 2 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories: ASP.Net | C# | Silverlight | Visual Studio
Actions: E-mail | Permalink | Comments (1) | Comment RSSRSS comment feed

Postpone CreateChildControls on Postback

February 22, 2009 23:28 by Rob

Let me explain the problem. A have a server control that really needs to serious context before it can render or process postback events. The context is set using a public property mysteriously called TypeToShow. The value of the property is a complex structure and cannot be persisted in ViewState. This all works fine when I do the initial load of the page, because the CreateChildControls of the control does not occur until I call DataBind() from the containing page.

However, when a postback occurs, the CreateChildControls() method is invoked before I get a chance to inject the meta data.

I know that Asp.Net delayes all events with child controls that are dynamically added using Controls.Add(…), so my work-around was to actually use a Placeholder and create the control until Page_Load was invoked.

There is a workaround, and here it is.:

First, you need to add a couple of statements to the beginning of CreateChildControls like so:

image

This will case CreateChildControls to fail if the property ‘_typeToShow’ was not set. Note that in my case, my control inherits from the 2.0 CompositeDataBoundControl class that does not require you to override CreateChildControls to create your controls. Instead you need to override an overload of this method. Check the SDK on the CompositeDataBoundControl for more info.

Next, you need to give the framework another chance to fire any events. The framework calls OnLoad of the child controls after the parent has been created. This includes Page_Load. To do this, override the OnLoad of the server control like so:

image

The framework detects that the controls have been created and starts raising any events you may have defined.

PS. I don’t know I anyone is reading this blog (except GoogleBot). Gimme a comment!


Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories: C# | ASP.Net | Tricks of the Trade
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

Large file upload using Silverlight, ASP.Net and WCF, Part 1

February 14, 2009 16:53 by Rob

In this article I would like to show you how I created a reusable ASP.Net component to handle large uploads using Silverlight 2.

The solution contains of 3 components:

  • A Silverlight control that allows the user to browse for files (this page)
  • A WCF service that receives the file data
  • An ASP.Net control that raises an event when the file has been uploaded.

I will discuss them one at a time. The code blocks are screenshots, but don’t worry because I attached the file below.

Edit: After posting this, somebody pointed out that Tim Heuer has a surprisingly similar screencast called Silverlight 2: OpenFileDialog and File Upload. The big difference is that Tim doesn’t support very large uploads.

The Silverlight Control

Using Visual Studio 2008, create a new Silverlight application,delete the standard Page, and add a control named ‘UploadControl’.

image

The control will look like this.

image

This control contains 2 buttons, a progress bar and a display message. The buttons are on top of each other and so are the progress bar and the message.

The magic of this control is in its code behind though. When the upload button is clicked i show a file selection dialog. After a file is selected, some housekeeping is done and a new instance of an UploadState class is initialized.

image

You will notice that 3 events are wired up:

  • One event is raised when the upload is completed
  • Another event is raised each time a block of data is transferred
  • And finally one event may be raised when the user has clicked the cancel button.

The rest of the event handling in this class is rather trivial. The UploadState class is where all the magic happens.

After creation and initialization of the UploadState instance I will start the upload:

image

This section of code needs some explanation, but before I do that, I need to tell you how to achieve large uploads.

Large Upload Intermezzo

IIS, Web services and pages don’t like large requests. Requests tend to time out and no progress can be shown. There have been lots and lots of solutions using ISAPI handlers, background processes and other weird solutions that all have their pros and cons.On Asp.Net forums there is actually a thread about large uploads which at time of writing consists of a massive 182 posts.

The approach presented here may not be unique, but I think it is a great alternative. The steps for large uploads in this solution are as follows:

  • The client requests an upload token from the server. I like Guid’s, to a Guid it is.
  • After the client has received the upload token (or handle as I call it), i can begin to send chunks of data to the server, 8kb at a time. Every chunk is a new http request so timeouts aren’t likely to occur.
  • The server will collect the chunks.The token is sent with the data chunk to the server knows what file the data belongs to.Since the chunks are numbered it can reassemble the entire file.
  • After the last chunk is sent, the client informs that all chunks have been sent.
  • The server receives the completion signal and will assemble all the chunks back into a single file.The server then sends an ‘All Ok’ back to the client.
  • The client has received word that the file has been stored on the server. The file can now be retrieved using all sorts of methods.

Back to Silverlight…

The Silverlight Control, continued

Here’s the ‘StartUpload’ method again.

image

Of course you know that all WCF communication in Silverlight must be asynchronous. This is what happens here. A WCF client is obtained, and a service call to ‘GetHandle’ is executed. The anonymous delegate is fired when a handle is obtained. After the block number and progress values are initialized, the first block is pushed.

Blocks are pushed using the PushBlock method. This method will read a chunk of data from the client’s file and send it asynchronously to the WCF service:

image

Problem with asynchronous calls is that it is impossible to use a standard while loop to enumerate all the blocks. But we can make another call to ‘PushBlock’ when this block is sent, using the anonymous method: (sender, e) => { PushBlock(); }

After every chunk is sent, the remote server is informed:

image

When the server has acknowledged the Complete method, the Completed event is raised from the UploadState class to the control in this method:

image

Again, more housekeeping. The final bit is at the end, where the FileID property is set and the FileUploaded event is raised. The FileUploaded event is a top-level event written for the client of the upload control. You can use this upload control in another Silverlight control, or you can expose it to the Html object model. In my project, i did it using the following code in  App.Xaml

image

The RegisterScriptableObject essentially exposes the UploadControl instance as an object named ‘uploadControl’ in JavaScript. We’ll come back to that later when I wrap the control into and ASP.Net component.

On the next part, I will dive into the implementation of the WCF service.

That’s it for now, keep tight. I need a break.

Rob.


Currently rated 5.0 by 3 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Give that man a cigar!

February 5, 2009 15:20 by Rob

I’ve never been so happy about a new feature in Office 2007 in all my life.

When pasting text, code and other stuff from within Office into a mail or some other editor, the layout always becomes a mess because Word, Excel or Outlook tries to copy the layout of the original document to the new document. I just want the text!

So, all the frustration can now be set aside, because there is a hidden feature in all office applications. I will explain by using some screenshots.

  • Click the round thingy in the top-left corner of your Office Application
    image

  • In the bottom-right corner of that menu there is a button labels ‘Editor Options’image
  • Go to ‘Advanced’ and scroll down a little.
    image 
  • Change your default paste options.

The developer that implemented this feature, and the UI designer that invented this feature and the product manager that approved the feature and the developer who bribed the product manager to approve the feature after he or she learnt from the UI designer that such a feature would actually be very welcome on his behalf, all should receive a ribbon, a bonus, a cigar or a double Latte Macchiato for doing so. Hurray!


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories:
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

Silverlight ImageSourceConverter

November 19, 2008 13:54 by Rob

The Silverlight 2 converter below will convert from a string to a absolute uri in order to stream the images from the website instead of retrieving them from the XAP file.

One of the reasons to do this was a side-effect in Silverlight. For example, when you have a folder within your silverlight project named 'Controls', and you bind an image path to 'Images/Test.png', the resulting image will be loaded from 'Controls/Images/Test'. To overcome this behaviour, I trim the folder name from the request path and transform the relative images to an absolute url.

 

Here's the code:

[code]

using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media.Imaging;
using System.Windows.Interop;

namespace Silverlight.Controls.Converters
{
    /// <summary>  
    /// A type converter for changing any image url to the root of the web application
    /// </summary>  
    public class ImageSourceConverter : IValueConverter
    {
        public object Convert(
            object value,
            Type targetType,
            object parameter,
            CultureInfo culture)
        {
            Uri hostUri = Application.Current.Host.Source;

            //first, get the host,
            string host = hostUri.GetComponents(UriComponents.SchemeAndServer, UriFormat.UriEscaped);

            string path = hostUri.GetComponents(UriComponents.PathAndQuery, UriFormat.UriEscaped);

            //remove /clientbin/...
            path = path.Substring(0, path.IndexOf("/ClientBin"));
            path = System.IO.Path.Combine(path, (string)value);

            //now combine host and path.
            Uri newUri = new Uri(new Uri(host), path);

            return new BitmapImage(newUri);
        }

        public object ConvertBack(
            object value,
            Type targetType,
            object parameter,
            CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }
}

[/code]


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories: C# | Silverlight
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

Drag and Drop Manager for Silverlight 2

October 29, 2008 11:50 by Rob

Preview

One thing that I found lacking in the current Silverlight distribution is the ability to quickly implement drag and drop. I have seen a couple of one-off implementations on the web, but they need a lot of coding every time drag and drop is required. So I came up with my own DragDrop toolkit.

For our drag-drop to work we need three components:

  1. The object to be dragged (one or more)
  2. The component that centralizes all drag and drop functionality
  3. The drop target (one or more).

For number one, I designed a Silverlight custom control that wraps around a FrameworkElement by inheriting from ContentControl. this control adds the drag possibility.

Number 2 is designed as a UI-less component that couples the drag with the drop. Since it is a container control, it also inherits from ControlControl

Number 3 is not designed, and can be any element on your page, as long as it is contained within number 2.

My trick for providing visual feedback on the dragdrop operation is by using a ControlTemplate that includes a Popup (to display the dragging content) and a ContentPresenter (that shows the draggable object). By mutating the position of the popup along with the mouse cursor you can get a nice drag/drop experience.

For example: the following XAML fragment allows me to drop an textblock on a listbox:

image

This effectively enables drag and drop from one of the buttons into the ListBox.

After you have given the DragDropManager an x:Name, you can hook into the 'drop' event and handle your logic there:

 

image

With the DragDropEventArgs, you get the DraggableItem that was dragged, the target control (which in this case can only be a ListBox) and the coordinates of the actual drop.

Drag Drop feedback is limited in this solution, but by applying new styles and templates you can do a lot. For example, the DraggableElement is fully skinnable using the Visual States that are defined in the default template. In the current version, this is the default template for a draggableElement:

image

As you can see there are states for MouseOver, Normal, Dragging and DropNotAllowed. Plenty to work with!

 

 

 

PS. I intend to release this code on codeplex, so I will have to find out how.


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:
Categories:
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed