context: using System;
  using System.Net;
  using System.IO;
  using System.Xml;
  using System.Xml.XPath;
  using System.Xml.Serialization;
  using System.Text;
  using System.Threading;
  using System.Collections;
  using System.Collections.Specialized;
  
  namespace RtmNet
  {
  	/// <summary>
  	/// The main Rtm class.
  	/// </summary>
  	/// <remarks>
  	/// Create an instance of this class and then call its methods to perform methods on Rtm.
  	/// </remarks>
  	/// <example>
  	/// <code>RtmNet.Rtm Rtm = new RtmNet.Rtm ();
  	/// User user = Rtm.PeopleFindByEmail ("cal@iamcal.com");
  	/// Console.WriteLine ("User Id is " + u.UserId);</code>
  	/// </example>
  	//[System.Net.WebPermission (System.Security.Permissions.SecurityAction.Demand, ConnectPattern="http://www.Rtm.com/.*")]
  	public class Rtm
  	{
  		#region [ Private Variables ]
  		private const string AuthUrl = "http://api.rememberthemilk.com/services/auth/";
  		private const string BaseUrl = "http://api.rememberthemilk.com/services/rest/";
  		
  		private object throttlingLock;
  		private string apiKey;
  		private string apiToken;
  		private string sharedSecret;
  		private int timeout = 30000;
  		private const string UserAgent = "Mozilla/4.0 FlickrNet API (compatible; MSIE 6.0; Windows NT 5.1)";
  		private string lastRequest;
  		private string lastResponse;
  		private DateTime lastRequestTime;
  		private TimeSpan throttling;
  		
  		private WebProxy proxy;// = WebProxy.GetDefaultProxy();
  		
  		#endregion
  		
  		#region [ Public Properties ]
  		/// <summary>
  		/// Get or set the API Key to be used by all calls. API key is mandatory for all 
  		/// calls to Rtm.
  		/// </summary>
  		public string ApiKey  { 
  			get { return apiKey; } 
  			set { apiKey = (value == null || value.Length == 0 ? null : value); }
  		}
  		
  		/// <summary>
  		/// API shared secret is required for all calls that require signing, which includes
  		/// all methods that require authentication, as well as the actual Rtm.auth.* calls.
  		/// </summary>
  		public string ApiSecret {
  			get { return sharedSecret; }
  			set { sharedSecret = (value == null || value.Length == 0 ? null : value); }
  		}
  		
  		/// <summary>
  		/// The API token is required for all calls that require authentication.
  		/// A <see cref="RtmException"/> will be raised by Rtm if the API token is
  		/// not set when required.
  		/// </summary>
  		/// <remarks>
  		/// It should be noted that some methods will work without the API token, but
  		/// will return different results if used with them (such as group pool requests, 
  		/// and results which include private pictures the authenticated user is allowed to see
  		/// (their own, or others).
  		/// </remarks>
  		[Obsolete("Renamed to AuthToken to be more consistent with the Rtm API")]
  		public string ApiToken {
  			get { return apiToken; }
  			set { apiToken = (value == null || value.Length == 0 ? null : value); }
  		}
  		
  		/// <summary>
  		/// The authentication token is required for all calls that require authentication.
  		/// A <see cref="RtmException"/> will be raised by Rtm if the authentication token is
  		/// not set when required.
  		/// </summary>
  		/// <remarks>
  		/// It should be noted that some methods will work without the authentication token, but
  		/// will return different results if used with them (such as group pool requests, 
  		/// and results which include private pictures the authenticated user is allowed to see
  		/// (their own, or others).
  		/// </remarks>
  		public string AuthToken {
  			get { return apiToken; }
  			set { apiToken = (value == null || value.Length == 0 ? null : value); }
  		}
  		
  		/// <summary>
  		/// The default service to use for new Rtm instances
  		/// </summary>
  		public static SupportedService DefaultService {
  			get { return SupportedService.Rtm; }
  		}
  		
  		/// <summary>
  		/// The current service that the Rtm API is using.
  		/// </summary>
  		public SupportedService CurrentService {
  			get { return SupportedService.Rtm; } 
  		}
  		
  		/// <summary>
  		/// Internal timeout for all web requests in milliseconds. Defaults to 30 seconds.
  		/// </summary>
  		public int HttpTimeout {
  			get { return timeout; } 
  			set { timeout = value; }
  		}
  		
  		/// <summary>
  		/// Checks to see if a shared secret and an api token are stored in the object.
  		/// Does not check if these values are valid values.
  		/// </summary>
  		public bool IsAuthenticated {
  			get { return (sharedSecret != null && apiToken != null); }
  		}
  		
  		/// <summary>
  		/// Returns the raw XML returned from the last response.
  		/// Only set it the response was not returned from cache.
  		/// </summary>
  		public string LastResponse {
  			get { return lastResponse; }
  		}
  		
  		/// <summary>
  		/// Returns the last URL requested. Includes API signing.
  		/// </summary>
  		public string LastRequest {
  			get { return lastRequest; }
  		}
  		
  		/// <summary>
  		/// You can set the <see cref="WebProxy"/> or alter its properties.
  		/// It defaults to your internet explorer proxy settings.
  		/// </summary>
  		public WebProxy Proxy {
  			get { return proxy; } 
  			set { proxy = value; } 
  		}
  		#endregion
  		
  		#region [ Constructors ]
  		
  		/// <summary>
  		/// Constructor loads configuration settings from app.config or web.config file if they exist.
  		/// </summary>
  		public Rtm()
  		{
  		}
  		
  		/// <summary>
  		/// Create a new instance of the <see cref="Rtm"/> class with no authentication.
  		/// </summary>
  		/// <param name="apiKey">Your Rtm API Key.</param>
  		public Rtm (string apiKey) : this (apiKey, "", "")
  		{
  		}
  		
  		/// <summary>
  		/// Creates a new instance of the <see cref="Rtm"/> class with an API key and a Shared Secret.
  		/// This is only useful really useful for calling the Auth functions as all other
  		/// authenticationed methods also require the API Token.
  		/// </summary>
  		/// <param name="apiKey">Your Rtm API Key.</param>
  		/// <param name="sharedSecret">Your Rtm Shared Secret.</param>
  		public Rtm (string apiKey, string sharedSecret) : this (apiKey, sharedSecret, "")
  		{
  		}
  		
  		/// <summary>
  		/// Create a new instance of the <see cref="Rtm"/> class with the email address and password given
  		/// </summary>
  		/// <param name="apiKey">Your Rtm API Key</param>
  		/// <param name="sharedSecret">Your Rtm Shared Secret.</param>
  		/// <param name="token">The token for the user who has been authenticated.</param>
  		public Rtm (string apiKey, string sharedSecret, string token) : this ()
  		{
  			this.apiKey = apiKey;
  			this.sharedSecret = sharedSecret;
  			this.apiToken = token;
  			this.lastRequestTime = DateTime.MinValue;
  			this.throttlingLock = new object ();
  			this.throttling = TimeSpan.FromSeconds (1.0);
  		}
  		#endregion
  		
  		#region [ Private Methods ]
  		/// <summary>
  		/// A private method which performs the actual HTTP web request if
  		/// the details are not found within the cache.
  		/// </summary>
  		/// <param name="url">The URL to download.</param>
  		/// <param name="variables">The query string parameters to be added to the end of the URL.</param>
  		/// <returns>A <see cref="RtmNet.Response"/> object.</returns>
  		/// <remarks>If the final length of the URL would be greater than 2000 characters 
  		/// then they are sent as part of the body instead.</remarks>
  		private string DoGetResponse (string url, string variables)
  		{
  			HttpWebRequest req = null;
  			HttpWebResponse res = null;
  			
  			if (variables.Length < 2000) {
  				url += "?" + variables;
  				variables = "";
  			}
  			
  			// Initialise the web request
  			req = (HttpWebRequest) HttpWebRequest.Create (url);
  			req.Method = "POST";
  			
  			if (req.Method == "POST") req.ContentLength = variables.Length;
  			
  			req.UserAgent = UserAgent;
  			if (Proxy != null) req.Proxy = Proxy;
  			req.Timeout = HttpTimeout;
  			req.KeepAlive = false;
  			if (variables.Length > 0) {
  				req.ContentType = "application/x-www-form-urlencoded";
  				StreamWriter sw = null;
  				try {
  					sw = new StreamWriter (req.GetRequestStream ());
  					sw.Write (variables);
  					sw.Close ();
  				} catch(WebException ex) {
  					throw new RtmWebException (ex.Message, ex);
  				} finally {
  					if (sw != null)
  						sw.Close ();
  				}
  			} else {
  				// This is needed in the Compact Framework
  				// See for more details: http://msdn2.microsoft.com/en-us/library/1afx2b0f.aspx
  				try {
  					req.GetRequestStream ().Close ();
  				} catch (WebException ex) {
  					throw new RtmWebException (ex.Message, ex);
  				}
  			}
  			
  			try {
  				// Get response from the internet
  
gt: 				res = (HttpWebResponse)req.GetResponse();