[
  {
    "path": ".gitattributes",
    "content": "###############################################################################\n# Set default behavior to automatically normalize line endings.\n###############################################################################\n* text=auto\n\n###############################################################################\n# Set default behavior for command prompt diff.\n#\n# This is need for earlier builds of msysgit that does not have it on by\n# default for csharp files.\n# Note: This is only used by command line\n###############################################################################\n*.cs         text diff=csharp\n*.sln        text eol=crlf\n*.csproj     text eol=crlf\n###############################################################################\n# Set the merge driver for project and solution files\n#\n# Merging from the command prompt will add diff markers to the files if there\n# are conflicts (Merging from VS is not affected by the settings below, in VS\n# the diff markers are never inserted). Diff markers may cause the following \n# file extensions to fail to load in VS. An alternative would be to treat\n# these files as binary and thus will always conflict and require user\n# intervention with every merge. To do so, just uncomment the entries below\n###############################################################################\n#*.sln       merge=binary\n#*.csproj    merge=binary\n#*.vbproj    merge=binary\n#*.vcxproj   merge=binary\n#*.vcproj    merge=binary\n#*.dbproj    merge=binary\n#*.fsproj    merge=binary\n#*.lsproj    merge=binary\n#*.wixproj   merge=binary\n#*.modelproj merge=binary\n#*.sqlproj   merge=binary\n#*.wwaproj   merge=binary\n\n###############################################################################\n# behavior for image files\n#\n# image files are treated as binary by default.\n###############################################################################\n#*.jpg   binary\n#*.png   binary\n#*.gif   binary\n\n###############################################################################\n# diff behavior for common document formats\n# \n# Convert binary document formats to text before diffing them. This feature\n# is only available from the command line. Turn it on by uncommenting the \n# entries below.\n###############################################################################\n#*.doc   diff=astextplain\n#*.DOC   diff=astextplain\n#*.docx  diff=astextplain\n#*.DOCX  diff=astextplain\n#*.dot   diff=astextplain\n#*.DOT   diff=astextplain\n#*.pdf   diff=astextplain\n#*.PDF   diff=astextplain\n#*.rtf   diff=astextplain\n#*.RTF   diff=astextplain\n"
  },
  {
    "path": ".gitignore",
    "content": "bin/\nobj/\n*.user\n*.userprefs\n*.suo\n*.pidb\n_ReSharper*/\nTestResults/\n*.mdf\n*.psess\n*.vsp\n\n# StyleCop files\nStyleCop.Cache"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2013 Drew DeVault\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "README.md",
    "content": "# RedditSharp\n\nA partial implementation of the [Reddit](http://reddit.com) API. Includes support for many API endpoints, as well as\nLINQ-style paging of results.\n\n```csharp\nvar reddit = new Reddit();\nvar user = reddit.LogIn(\"username\", \"password\");\nvar subreddit = reddit.GetSubreddit(\"/r/example\");\nsubreddit.Subscribe();\nforeach (var post in subreddit.New.Take(25))\n{\n    if (post.Title == \"What is my karma?\")\n    {\n        // Note: This is an example. Bots are not permitted to cast votes automatically.\n        post.Upvote();\n        var comment = post.Comment(string.Format(\"You have {0} link karma!\", post.Author.LinkKarma));\n        comment.Distinguish(DistinguishType.Moderator);\n    }\n}\n```\n\n**Important note**: Make sure you use `.Take(int)` when working with pagable content. For example, don't do this:\n\n```csharp\nvar all = reddit.RSlashAll;\nforeach (var post in all) // BAD\n{\n    // ...\n}\n```\n\nThis will cause you to page through everything that has ever been posted on Reddit. Better:\n\n```csharp\nvar all = reddit.RSlashAll;\nforeach (var post in all.Take(25))\n{\n    // ...\n}\n```\n\n## Development\n\nRedditSharp is developed with the following workflow:\n\n1. Nothing happens for weeks/months/years\n2. Someone needs it to do something it doesn't already do\n3. That person implements that something and submits a pull request\n4. Repeat\n\nIf it doesn't have a feature that you want it to have, add it! The code isn't that scary.\n"
  },
  {
    "path": "RedditSharp/AuthProvider.cs",
    "content": "using System;\nusing System.Net;\nusing System.Security.Authentication;\nusing System.Text;\nusing Newtonsoft.Json.Linq;\nusing RedditSharp.Things;\n\nnamespace RedditSharp\n{\n    public class AuthProvider\n    {\n        private const string AccessUrl = \"https://ssl.reddit.com/api/v1/access_token\";\n        private const string OauthGetMeUrl = \"https://oauth.reddit.com/api/v1/me\";\n        private const string RevokeUrl = \"https://www.reddit.com/api/v1/revoke_token\";\n\n        public static string OAuthToken { get; set; }\n        public static string RefreshToken { get; set; }\n\n        [Flags]\n        public enum Scope\n        {\n            none = 0x0,\n            identity = 0x1,\n            edit = 0x2,\n            flair = 0x4,\n            history = 0x8,\n            modconfig = 0x10,\n            modflair = 0x20,\n            modlog = 0x40,\n            modposts = 0x80,\n            modwiki = 0x100,\n            mysubreddits = 0x200,\n            privatemessages = 0x400,\n            read = 0x800,\n            report = 0x1000,\n            save = 0x2000,\n            submit = 0x4000,\n            subscribe = 0x8000,\n            vote = 0x10000,\n            wikiedit = 0x20000,\n            wikiread = 0x40000\n        }\n        private IWebAgent _webAgent;\n        private readonly string _redirectUri;\n        private readonly string _clientId;\n        private readonly string _clientSecret;\n\n        /// <summary>\n        /// Allows use of reddit's OAuth interface, using an app set up at https://ssl.reddit.com/prefs/apps/.\n        /// </summary>\n        /// <param name=\"clientId\">Granted by reddit as part of app.</param>\n        /// <param name=\"clientSecret\">Granted by reddit as part of app.</param>\n        /// <param name=\"redirectUri\">Selected as part of app. Reddit will send users back here.</param>\n        public AuthProvider(string clientId, string clientSecret, string redirectUri)\n        {\n            _clientId = clientId;\n            _clientSecret = clientSecret;\n            _redirectUri = redirectUri;\n            _webAgent = new WebAgent();\n        }\n        /// <summary>\n        /// Allows use of reddit's OAuth interface, using an app set up at https://ssl.reddit.com/prefs/apps/.\n        /// </summary>\n        /// <param name=\"clientId\">Granted by reddit as part of app.</param>\n        /// <param name=\"clientSecret\">Granted by reddit as part of app.</param>\n        /// <param name=\"redirectUri\">Selected as part of app. Reddit will send users back here.</param>\n        /// <param name=\"agent\">Implementation of IWebAgent to use to make requests.</param>\n        public AuthProvider(string clientId, string clientSecret, string redirectUri,IWebAgent agent)\n        {\n            _clientId = clientId;\n            _clientSecret = clientSecret;\n            _redirectUri = redirectUri;\n            _webAgent = agent;\n        }\n\n        /// <summary>\n        /// Creates the reddit OAuth2 Url to redirect the user to for authorization. \n        /// </summary>\n        /// <param name=\"state\">Used to verify that the user received is the user that was sent</param>\n        /// <param name=\"scope\">Determines what actions can be performed against the user.</param>\n        /// <param name=\"permanent\">Set to true for access lasting longer than one hour.</param>\n        /// <returns></returns>\n        public string GetAuthUrl(string state, Scope scope, bool permanent = false)\n        {\n            return String.Format(\"https://ssl.reddit.com/api/v1/authorize?client_id={0}&response_type=code&state={1}&redirect_uri={2}&duration={3}&scope={4}\", _clientId, state, _redirectUri, permanent ? \"permanent\" : \"temporary\", scope.ToString().Replace(\" \",\"\"));\n        }\n\n        /// <summary>\n        /// Gets the OAuth token for the user associated with the provided code.\n        /// </summary>\n        /// <param name=\"code\">Sent by reddit as a parameter in the return uri.</param>\n        /// <param name=\"isRefresh\">Set to true for refresh requests.</param>\n        /// <returns></returns>\n        public string GetOAuthToken(string code, bool isRefresh = false)\n        {\n            if (Type.GetType(\"Mono.Runtime\") != null)\n                ServicePointManager.ServerCertificateValidationCallback = (s, c, ch, ssl) => true;\n            _webAgent.Cookies = new CookieContainer();\n\n            var request = _webAgent.CreatePost(AccessUrl);\n\n            request.Headers[\"Authorization\"] = \"Basic \" + Convert.ToBase64String(Encoding.Default.GetBytes(_clientId + \":\" + _clientSecret));\n            var stream = request.GetRequestStream();\n\n            if (isRefresh)\n            {\n                _webAgent.WritePostBody(stream, new\n                {\n                    grant_type = \"refresh_token\",\n                    refresh_token = code\n                });\n            }\n            else\n            {\n                _webAgent.WritePostBody(stream, new\n                {\n                    grant_type = \"authorization_code\",\n                    code,\n                    redirect_uri = _redirectUri\n                });\n            }\n\n            stream.Close();\n            var json = _webAgent.ExecuteRequest(request);\n            if (json[\"access_token\"] != null)\n            {\n                if (json[\"refresh_token\"] != null)\n                    RefreshToken = json[\"refresh_token\"].ToString();\n                OAuthToken = json[\"access_token\"].ToString();\n                return json[\"access_token\"].ToString();\n            }\n            throw new AuthenticationException(\"Could not log in.\");\n        }\n\n        /// <summary>\n        /// Gets the OAuth token for the user.\n        /// </summary>\n        /// <param name=\"username\">The username.</param>\n        /// <param name=\"password\">The user's password.</param>\n        /// <returns>The access token</returns>\n        public string GetOAuthToken(string username, string password)\n        {\n            if (Type.GetType(\"Mono.Runtime\") != null)\n                ServicePointManager.ServerCertificateValidationCallback = (s, c, ch, ssl) => true;\n            _webAgent.Cookies = new CookieContainer();\n\n            var request = _webAgent.CreatePost(AccessUrl);\n\n            request.Headers[\"Authorization\"] = \"Basic \" + Convert.ToBase64String(Encoding.Default.GetBytes(_clientId + \":\" + _clientSecret));\n            var stream = request.GetRequestStream();\n\n            _webAgent.WritePostBody(stream, new\n            {\n                grant_type = \"password\",\n                username,\n                password,\n                redirect_uri = _redirectUri\n            });\n\n            stream.Close();\n            var json = _webAgent.ExecuteRequest(request);\n            if (json[\"access_token\"] != null)\n            {\n                if (json[\"refresh_token\"] != null)\n                    RefreshToken = json[\"refresh_token\"].ToString();\n                OAuthToken = json[\"access_token\"].ToString();\n                return json[\"access_token\"].ToString();\n            }\n            throw new AuthenticationException(\"Could not log in.\");\n        }\n\t\t\n        public void RevokeToken(string token, bool isRefresh)\n        {\n            string tokenType = isRefresh ? \"refresh_token\" : \"access_token\";\n            var request = _webAgent.CreatePost(RevokeUrl);\n\n            request.Headers[\"Authorization\"] = \"Basic \" + Convert.ToBase64String(Encoding.Default.GetBytes(_clientId + \":\" + _clientSecret));\n\n            var stream = request.GetRequestStream();\n\n            _webAgent.WritePostBody(stream, new\n            {\n                token = token,\n                token_type = tokenType\n            });\n\n            stream.Close();\n\n            _webAgent.ExecuteRequest(request);\n\n        }\n        /// <summary>\n        /// Gets a user authenticated by OAuth2.\n        /// </summary>\n        /// <param name=\"accessToken\">Obtained using GetOAuthToken</param>\n        /// <returns></returns>\n        [Obsolete(\"Reddit.InitOrUpdateUser is preferred\")]\n        public AuthenticatedUser GetUser(string accessToken)\n        {\n            var request = _webAgent.CreateGet(OauthGetMeUrl);\n            request.Headers[\"Authorization\"] = String.Format(\"bearer {0}\", accessToken);\n            var response = (HttpWebResponse)request.GetResponse();\n            var result = _webAgent.GetResponseString(response.GetResponseStream());\n            var thingjson = \"{\\\"kind\\\": \\\"t2\\\", \\\"data\\\": \" + result + \"}\";\n            var json = JObject.Parse(thingjson);\n            return new AuthenticatedUser().Init(new Reddit(), json, _webAgent);\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/Captcha.cs",
    "content": "﻿using System;\n\nnamespace RedditSharp\n{\n    public struct Captcha\n    {\n        private const string UrlFormat = \"http://www.reddit.com/captcha/{0}\";\n\n        public readonly string Id;\n        public readonly Uri Url;\n\n        internal Captcha(string id)\n        {\n            Id = id;\n            Url = new Uri(string.Format(UrlFormat, Id), UriKind.Absolute);\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/CaptchaFailedException.cs",
    "content": "﻿using System;\n\nnamespace RedditSharp\n{\n    public class CaptchaFailedException : RedditException\n    {\n        public CaptchaFailedException()\n        {\n            \n        }\n\n        public CaptchaFailedException(string message)\n            : base(message)\n        {\n            \n        }\n\n        public CaptchaFailedException(string message, Exception inner)\n            : base(message, inner)\n        {\n            \n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/CaptchaResponse.cs",
    "content": "﻿namespace RedditSharp\n{\n    public class CaptchaResponse\n    {\n        public readonly string Answer;\n\n        public bool Cancel { get { return string.IsNullOrEmpty(Answer); } }\n\n        public CaptchaResponse(string answer = null)\n        {\n            Answer = answer;\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/ConsoleCaptchaSolver.cs",
    "content": "﻿using System;\n\nnamespace RedditSharp\n{\n    public class ConsoleCaptchaSolver : ICaptchaSolver\n    {\n        public CaptchaResponse HandleCaptcha(Captcha captcha)\n        {\n            Console.WriteLine(\"Captcha required! The captcha ID is {0}\", captcha.Id);\n            Console.WriteLine(\"You can find the captcha image at this url: {0}\", captcha.Url);\n            Console.WriteLine(\"Please input your captcha response or empty string to cancel:\");\n            var response = Console.ReadLine();\n            CaptchaResponse captchaResponse = new CaptchaResponse(string.IsNullOrEmpty(response) ? null : response);\n            return captchaResponse;\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/Domain.cs",
    "content": "using System;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing RedditSharp.Things;\n\nnamespace RedditSharp\n{\n    public class Domain\n    {\n        private const string DomainPostUrl = \"/domain/{0}.json\";\n        private const string DomainNewUrl = \"/domain/{0}/new.json?sort=new\";\n        private const string DomainHotUrl = \"/domain/{0}/hot.json\";\n        private const string FrontPageUrl = \"/.json\";\n\n        [JsonIgnore]\n        private Reddit Reddit { get; set; }\n\n        [JsonIgnore]\n        private IWebAgent WebAgent { get; set; }\n\n        [JsonIgnore]\n        public string Name { get; set; }\n\n        public Listing<Post> Posts\n        {\n            get\n            {\n                return new Listing<Post>(Reddit, string.Format(DomainPostUrl, Name), WebAgent);\n            }\n        }\n\n        public Listing<Post> New\n        {\n            get\n            {\n                return new Listing<Post>(Reddit, string.Format(DomainNewUrl, Name), WebAgent);\n            }\n        }\n\n        public Listing<Post> Hot\n        {\n            get\n            {\n                return new Listing<Post>(Reddit, string.Format(DomainHotUrl, Name), WebAgent);\n            }\n        }\n\n        protected internal Domain(Reddit reddit, Uri domain, IWebAgent webAgent)\n        {\n            Reddit = reddit;\n            WebAgent = webAgent;\n            Name = domain.Host;\n        }\n\n        public override string ToString()\n        {\n            return \"/domain/\" + Name;\n        }\n    }\n}\n\n"
  },
  {
    "path": "RedditSharp/DuplicateLinkException.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\n\nnamespace RedditSharp\n{\n    /// <summary>\n    /// Exception that gets thrown if you try and submit a duplicate link to a SubReddit\n    /// </summary>\n    public class DuplicateLinkException : RedditException\n    {\n        public DuplicateLinkException()\n        {\n        }\n\n        public DuplicateLinkException(string message)\n            : base(message)\n        {\n        }\n\n        public DuplicateLinkException(string message, Exception inner)\n            : base(message, inner)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/Extensions.cs",
    "content": "﻿using Newtonsoft.Json.Linq;\nusing System.Collections.Generic;\n\nnamespace RedditSharp\n{\n    public static class Extensions\n    {\n        public static T ValueOrDefault<T>(this IEnumerable<JToken> enumerable)\n        {\n            if (enumerable == null)\n                return default(T);\n            return enumerable.Value<T>();\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/FlairTemplate.cs",
    "content": "﻿namespace RedditSharp\n{\n    public class UserFlairTemplate // TODO: Consider using this class to set templates as well\n    {\n        public string Text { get; set; }\n        public string CssClass { get; set; }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/FlairType.cs",
    "content": "﻿namespace RedditSharp\n{\n    public enum FlairType\n    {\n        Link,\n        User\n    }\n}\n"
  },
  {
    "path": "RedditSharp/ICaptchaSolver.cs",
    "content": "﻿namespace RedditSharp\n{\n    public interface ICaptchaSolver\n    {\n        CaptchaResponse HandleCaptcha(Captcha captcha);\n    }\n}\n"
  },
  {
    "path": "RedditSharp/IWebAgent.cs",
    "content": "using System.IO;\nusing System.Net;\nusing Newtonsoft.Json.Linq;\n\nnamespace RedditSharp\n{\n    public interface IWebAgent\n    {\n        CookieContainer Cookies { get; set; }\n        string AuthCookie { get; set; }\n        string AccessToken { get; set; }\n        HttpWebRequest CreateRequest(string url, string method);\n        HttpWebRequest CreateGet(string url);\n        HttpWebRequest CreatePost(string url);\n        string GetResponseString(Stream stream);\n        void WritePostBody(Stream stream, object data, params string[] additionalFields);\n        JToken CreateAndExecuteRequest(string url);\n        JToken ExecuteRequest(HttpWebRequest request);\n    }\n}\n"
  },
  {
    "path": "RedditSharp/LinkData.cs",
    "content": "﻿namespace RedditSharp\n{\n    internal class LinkData : SubmitData\n    {\n        [RedditAPIName(\"extension\")]\n        internal string Extension { get; set; }\n        \n        [RedditAPIName(\"url\")]\n        internal string URL { get; set; }\n\n        internal LinkData()\n        {\n            Extension = \"json\";\n            Kind = \"link\";\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/Listing.cs",
    "content": "﻿using Newtonsoft.Json.Linq;\nusing System;\nusing System.Collections.Generic;\nusing RedditSharp.Things;\n\nnamespace RedditSharp\n{\n    public enum Sorting\n    {\n        Relevance,\n        New,\n        Top,\n        Comments\n    }\n\n    public enum TimeSorting\n    {\n        All,\n        Hour,\n        Day,\n        Week,\n        Month,\n        Year\n    }\n\n    public class Listing<T> : IEnumerable<T> where T : Thing\n    {\n        /// <summary>\n        /// Gets the default number of listings returned per request\n        /// </summary>\n        internal const int DefaultListingPerRequest = 25;\n\n        private IWebAgent WebAgent { get; set; }\n        private Reddit Reddit { get; set; }\n        private string Url { get; set; }\n\n        /// <summary>\n        /// Creates a new Listing instance\n        /// </summary>\n        /// <param name=\"reddit\"></param>\n        /// <param name=\"url\"></param>\n        /// <param name=\"webAgent\"></param>\n        internal Listing(Reddit reddit, string url, IWebAgent webAgent)\n        {\n            WebAgent = webAgent;\n            Reddit = reddit;\n            Url = url;\n        }\n\n        /// <summary>\n        /// Returns an enumerator that iterates through a collection, using the specified number of listings per\n        /// request and optionally the maximum number of listings\n        /// </summary>\n        /// <param name=\"limitPerRequest\">The number of listings to be returned per request</param>\n        /// <param name=\"maximumLimit\">The maximum number of listings to return</param>\n        /// <returns></returns>\n        public IEnumerator<T> GetEnumerator(int limitPerRequest, int maximumLimit = -1)\n        {\n            return new ListingEnumerator<T>(this, limitPerRequest, maximumLimit);\n        }\n\n        /// <summary>\n        /// Returns an enumerator that iterates through a collection, using the default number of listings per request\n        /// </summary>\n        /// <returns></returns>\n        public IEnumerator<T> GetEnumerator()\n        {\n            return GetEnumerator(DefaultListingPerRequest);\n        }\n\n        /// <summary>\n        /// Returns an enumerator that iterates through a collection\n        /// </summary>\n        /// <returns></returns>\n        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()\n        {\n            return GetEnumerator();\n        }\n\n        /// <summary>\n        /// Returns an IEnumerable instance which will return the specified maximum number of listings\n        /// </summary>\n        /// <param name=\"maximumLimit\"></param>\n        /// <returns></returns>\n        public IEnumerable<T> GetListing(int maximumLimit)\n        {\n            return GetListing(maximumLimit, DefaultListingPerRequest);\n        }\n\n        /// <summary>\n        /// Returns an IEnumerable instance which will return the specified maximum number of listings\n        /// with the limited number per request\n        /// </summary>\n        /// <param name=\"maximumLimit\"></param>\n        /// <param name=\"limitPerRequest\"></param>\n        /// <returns></returns>\n        public IEnumerable<T> GetListing(int maximumLimit, int limitPerRequest)\n        {\n            // Get the enumerator with the specified maximum and per request limits\n            var enumerator = GetEnumerator(limitPerRequest, maximumLimit);\n\n            return GetEnumerator(enumerator);\n        }\n\n        /// <summary>\n        /// Converts an IEnumerator instance to an IEnumerable\n        /// </summary>\n        /// <param name=\"enumerator\"></param>\n        /// <returns></returns>\n        private static IEnumerable<T> GetEnumerator(IEnumerator<T> enumerator)\n        {\n            while (enumerator.MoveNext())\n            {\n                yield return enumerator.Current;\n            }\n        }\n\n#pragma warning disable 0693\n        private class ListingEnumerator<T> : IEnumerator<T> where T : Thing\n        {\n            private Listing<T> Listing { get; set; }\n            private int CurrentPageIndex { get; set; }\n            private string After { get; set; }\n            private string Before { get; set; }\n            private Thing[] CurrentPage { get; set; }\n            private int Count { get; set; }\n            private int LimitPerRequest { get; set; }\n            private int MaximumLimit { get; set; }\n\n            /// <summary>\n            /// Creates a new ListingEnumerator instance\n            /// </summary>\n            /// <param name=\"listing\"></param>\n            /// <param name=\"limitPerRequest\">The number of listings to be returned per request. -1 will exclude this parameter and use the Reddit default (25)</param>\n            /// <param name=\"maximumLimit\">The maximum number of listings to return, -1 will not add a limit</param>\n            public ListingEnumerator(Listing<T> listing, int limitPerRequest, int maximumLimit)\n            {\n                Listing = listing;\n                CurrentPageIndex = -1;\n                CurrentPage = new Thing[0];\n\n                // Set the listings per page (if not specified, use the Reddit default of 25) and the maximum listings\n                LimitPerRequest = (limitPerRequest <= 0 ? DefaultListingPerRequest : limitPerRequest); \n                MaximumLimit = maximumLimit;\n            }\n\n            public T Current\n            {\n                get \n                {\n                    return (T)CurrentPage[CurrentPageIndex];\n                }\n            }\n\n            private void FetchNextPage()\n            {\n                var url = Listing.Url;\n\n                if (After != null)\n                {\n                    url += (url.Contains(\"?\") ? \"&\" : \"?\") + \"after=\" + After;\n                }\n\n                if (LimitPerRequest != -1)\n                {\n                    int limit = LimitPerRequest;\n\n                    if (limit > MaximumLimit)\n                    {\n                        // If the limit is more than the maximum number of listings, adjust\n                        limit = MaximumLimit;\n                    }\n                    else if (Count + limit > MaximumLimit)\n                    {\n                        // If a smaller subset of listings are needed, adjust the limit\n                        limit = MaximumLimit - Count;\n                    }\n\n                    if (limit > 0)\n                    {\n                        // Add the limit, the maximum number of items to be returned per page\n                        url += (url.Contains(\"?\") ? \"&\" : \"?\") + \"limit=\" + limit;\n                    }\n                }\n\n                if (Count > 0)\n                {\n                    // Add the count, the number of items already seen in this listing\n                    // The Reddit API uses this to determine when to give values for before and after fields                \n                    url += (url.Contains(\"?\") ? \"&\" : \"?\") + \"count=\" + Count;\n                }\n\n                var request = Listing.WebAgent.CreateGet(url);\n                var response = request.GetResponse();\n                var data = Listing.WebAgent.GetResponseString(response.GetResponseStream());\n                var json = JToken.Parse(data);\n                if (json[\"kind\"].ValueOrDefault<string>() != \"Listing\")\n                    throw new FormatException(\"Reddit responded with an object that is not a listing.\");\n                Parse(json);\n            }\n\n            private void Parse(JToken json)\n            {\n                var children = json[\"data\"][\"children\"] as JArray;\n                CurrentPage = new Thing[children.Count];\n                \n                for (int i = 0; i < CurrentPage.Length; i++)\n                    CurrentPage[i] = Thing.Parse<T>(Listing.Reddit, children[i], Listing.WebAgent);\n\n                // Increase the total count of items returned\n                Count += CurrentPage.Length;\n\n                After = json[\"data\"][\"after\"].Value<string>();\n                Before = json[\"data\"][\"before\"].Value<string>();\n            }\n\n            public void Dispose()\n            {\n                // ...\n            }\n\n            object System.Collections.IEnumerator.Current\n            {\n                get { return Current; }\n            }\n\n            public bool MoveNext()\n            {\n                CurrentPageIndex++;\n                if (CurrentPageIndex == CurrentPage.Length)\n                {\n                    if (After == null && CurrentPageIndex != 0)\n                    {\n                        // No more pages to return\n                        return false;\n                    }\n\n                    if (MaximumLimit != -1 && Count >= MaximumLimit)\n                    {\n                        // Maximum listing count returned\n                        return false;\n                    }\n\n                    // Get the next page\n                    FetchNextPage();\n                    CurrentPageIndex = 0;\n\n                    if (CurrentPage.Length == 0)\n                    {\n                        // No listings were returned in the page\n                        return false;\n                    }\n                }\n                return true;\n            }\n\n            public void Reset()\n            {\n                After = Before = null;\n                CurrentPageIndex = -1;\n                CurrentPage = new Thing[0];\n            }\n        }\n#pragma warning restore\n    }\n}\n"
  },
  {
    "path": "RedditSharp/ModActionType.cs",
    "content": "﻿using Newtonsoft.Json;\nusing System;\n\nnamespace RedditSharp\n{\n    public enum ModActionType\n    {\n        BanUser,\n        UnBanUser,\n        RemoveLink,\n        ApproveLink,\n        RemoveComment,\n        ApproveComment,\n        AddModerator,\n        InviteModerator,\n        UnInviteModerator,\n        AcceptModeratorInvite,\n        RemoveModerator,\n        AddContributor,\n        RemoveContributor,\n        EditSettings,\n        EditFlair,\n        Distinguish,\n        MarkNSFW,\n        WikiBanned,\n        WikiContributor,\n        WikiUnBanned,\n        WikiPageListed,\n        RemoveWikiContributor,\n        WikiRevise,\n        WikiPermlevel,\n        IgnoreReports,\n        UnIgnoreReports,\n        SetPermissions,\n        SetSuggestedsort,\n        Sticky,\n        UnSticky,\n        SetContestMode,\n        UnSetContestMode,\n        LockPost, //actual value is \"Lock\" but it's a reserved word\n        Unlock,\n        MuteUser,\n        UnMuteUser\n    }\n\n    public class ModActionTypeConverter : JsonConverter\n    {\n        /// <summary>\n        /// Replaces \"LockPost\" with \"lock\" since \"lock\" is a reserved word and can't be used in the enum\n        /// </summary>\n        /// <returns>String representation of enum value recognized by Reddit's api</returns>\n        public static string GetRedditParamName(ModActionType action)\n        {\n            if (action == ModActionType.LockPost) return \"lock\";\n            else return action.ToString(\"g\").ToLower();\n        }\n        public override bool CanConvert(Type objectType)\n        {\n            return objectType == typeof(ModActionType);\n        }\n\n        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)\n        {\n            string value = reader.Value.ToString();\n            if (value.ToLower() == \"lock\")\n            {\n                return ModActionType.LockPost;\n            }\n            else\n            {\n                return Enum.Parse(typeof(ModActionType), value, true);\n            }\n\n        }\n\n        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)\n        {\n            if (value == null) writer.WriteNull();\n            else writer.WriteValue(GetRedditParamName((ModActionType) value));\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/ModeratorPermission.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\n\nnamespace RedditSharp\n{\n    [Flags]\n    public enum ModeratorPermission\n    {\n        None   = 0x00,\n        Access = 0x01,\n        Config = 0x02,\n        Flair  = 0x04,\n        Mail   = 0x08,\n        Posts  = 0x10,\n        Wiki   = 0x20,\n        All    = Access | Config | Flair | Mail | Posts | Wiki\n    }\n\n    internal class ModeratorPermissionConverter : JsonConverter\n    {\n        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)\n        {\n            throw new NotImplementedException();\n        }\n\n        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)\n        {\n            var data = String.Join(\",\", JArray.Load(reader).Select(t => t.ToString()));\n\n            ModeratorPermission result;\n\n            var valid = Enum.TryParse(data, true, out result);\n\n            if (!valid)\n                result = ModeratorPermission.None;\n\n            return result;\n        }\n\n        public override bool CanConvert(Type objectType)\n        {\n            // NOTE: Not sure if this is what is supposed to be returned\n            // This method wasn't called in my (Sharparam) tests so unsure what it does\n            return objectType == typeof (ModeratorPermission);\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/ModeratorUser.cs",
    "content": "﻿using Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\n\nnamespace RedditSharp\n{\n    public class ModeratorUser\n    {\n        public ModeratorUser(Reddit reddit, JToken json)\n        {\n            JsonConvert.PopulateObject(json.ToString(), this, reddit.JsonSerializerSettings);\n        }\n\n        [JsonProperty(\"name\")]\n        public string Name { get; set; }\n\n        [JsonProperty(\"id\")]\n        public string Id { get; set; }\n\n        [JsonProperty(\"mod_permissions\")]\n        [JsonConverter(typeof (ModeratorPermissionConverter))]\n        public ModeratorPermission Permissions { get; set; }\n\n        public override string ToString()\n        {\n            return Name;\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/MultipartFormBuilder.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Net;\n\nnamespace RedditSharp\n{\n    public class MultipartFormBuilder\n    {\n        public HttpWebRequest Request { get; set; }\n\n        private string Boundary { get; set; }\n        private MemoryStream Buffer { get; set; }\n        private TextWriter TextBuffer { get; set; }\n\n        public MultipartFormBuilder(HttpWebRequest request)\n        {\n            // TODO: See about regenerating the boundary when needed\n            Request = request;\n            var random = new Random();\n            Boundary = \"----------\" + CreateRandomBoundary();\n            request.ContentType = \"multipart/form-data; boundary=\" + Boundary;\n            Buffer = new MemoryStream();\n            TextBuffer = new StreamWriter(Buffer);\n        }\n\n        private string CreateRandomBoundary()\n        {\n            // TODO: There's probably a better way to go about this\n            const string characters = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\n            string value = \"\";\n            var random = new Random();\n            for (int i = 0; i < 10; i++)\n                value += characters[random.Next(characters.Length)];\n            return value;\n        }\n\n        public void AddDynamic(object data)\n        {\n            var type = data.GetType();\n            var properties = type.GetProperties();\n            foreach (var property in properties)\n            {\n                var entry = Convert.ToString(property.GetValue(data, null));\n                AddString(property.Name, entry);\n            }\n        }\n\n        public void AddString(string name, string value)\n        {\n            TextBuffer.Write(\"{0}\\r\\nContent-Disposition: form-data; name=\\\"{1}\\\"\\r\\n\\r\\n{2}\\r\\n\",\n                \"--\" + Boundary, name, value);\n            TextBuffer.Flush();\n        }\n\n        public void AddFile(string name, string filename, byte[] value, string contentType)\n        {\n            TextBuffer.Write(\"{0}\\r\\nContent-Disposition: form-data; name=\\\"{1}\\\"; filename=\\\"{2}\\\"\\r\\nContent-Type: {3}\\r\\n\\r\\n\",\n                \"--\" + Boundary, name, filename, contentType);\n            TextBuffer.Flush();\n            Buffer.Write(value, 0, value.Length);\n            Buffer.Flush();\n            TextBuffer.Write(\"\\r\\n\");\n            TextBuffer.Flush();\n        }\n\n        public void Finish()\n        {\n            TextBuffer.Write(\"--\" + Boundary + \"--\");\n            TextBuffer.Flush();\n            var stream = Request.GetRequestStream();\n            Buffer.Seek(0, SeekOrigin.Begin);\n            Buffer.WriteTo(stream);\n            stream.Close();\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following \n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"RedditSharp\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"RedditSharp\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2012\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Setting ComVisible to false makes the types in this assembly not visible \n// to COM components.  If you need to access a type in this assembly from \n// COM, set the ComVisible attribute to true on that type.\n[assembly: ComVisible(false)]\n\n// The following GUID is for the ID of the typelib if this project is exposed to COM\n[assembly: Guid(\"5b1e351d-35b7-443e-9341-52c069a14886\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version \n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers \n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n"
  },
  {
    "path": "RedditSharp/RateLimitException.cs",
    "content": "using System;\n\nnamespace RedditSharp\n{\n    public class RateLimitException : Exception\n    {\n        public TimeSpan TimeToReset { get; set; }\n\n        public RateLimitException(TimeSpan timeToReset)\n        {\n            TimeToReset = timeToReset;\n        }\n    }\n}\n\n"
  },
  {
    "path": "RedditSharp/Reddit.cs",
    "content": "using Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing System;\nusing System.Linq;\nusing System.Net;\nusing System.Security.Authentication;\nusing RedditSharp.Things;\nusing System.Threading.Tasks;\nusing DefaultWebAgent = RedditSharp.WebAgent;\n\nnamespace RedditSharp\n{\n    /// <summary>\n    /// Class to communicate with Reddit.com\n    /// </summary>\n    public class Reddit\n    {\n        #region Constant Urls\n\n        private const string SslLoginUrl = \"https://ssl.reddit.com/api/login\";\n        private const string LoginUrl = \"/api/login/username\";\n        private const string UserInfoUrl = \"/user/{0}/about.json\";\n        private const string MeUrl = \"/api/me.json\";\n        private const string OAuthMeUrl = \"/api/v1/me.json\";\n        private const string SubredditAboutUrl = \"/r/{0}/about.json\";\n        private const string ComposeMessageUrl = \"/api/compose\";\n        private const string RegisterAccountUrl = \"/api/register\";\n        private const string GetThingUrl = \"/api/info.json?id={0}\";\n        private const string GetCommentUrl = \"/r/{0}/comments/{1}/foo/{2}\";\n        private const string GetPostUrl = \"{0}.json\";\n        private const string DomainUrl = \"www.reddit.com\";\n        private const string OAuthDomainUrl = \"oauth.reddit.com\";\n        private const string SearchUrl = \"/search.json?q={0}&restrict_sr=off&sort={1}&t={2}\";\n        private const string UrlSearchPattern = \"url:'{0}'\";\n        private const string NewSubredditsUrl = \"/subreddits/new.json\";\n        private const string PopularSubredditsUrl = \"/subreddits/popular.json\";\n        private const string GoldSubredditsUrl = \"/subreddits/gold.json\";\n        private const string DefaultSubredditsUrl = \"/subreddits/default.json\";\n        private const string SearchSubredditsUrl = \"/subreddits/search.json?q={0}\";\n\n\n        #endregion\n\n        #region Static Variables\n\n        static Reddit()\n        {\n            DefaultWebAgent.UserAgent = \"\";\n            DefaultWebAgent.RateLimit = DefaultWebAgent.RateLimitMode.Pace;\n            DefaultWebAgent.Protocol = \"https\";\n            DefaultWebAgent.RootDomain = \"www.reddit.com\";\n        }\n\n        #endregion\n        \n        internal IWebAgent WebAgent { get; set; }\n        /// <summary>\n        /// Captcha solver instance to use when solving captchas.\n        /// </summary>\n        public ICaptchaSolver CaptchaSolver;\n\n        /// <summary>\n        /// The authenticated user for this instance.\n        /// </summary>\n        public AuthenticatedUser User { get; set; }\n\n        /// <summary>\n        /// Sets the Rate Limiting Mode of the underlying WebAgent\n        /// </summary>\n        public DefaultWebAgent.RateLimitMode RateLimit\n        {\n            get { return DefaultWebAgent.RateLimit; }\n            set { DefaultWebAgent.RateLimit = value; }\n        }\n\n        internal JsonSerializerSettings JsonSerializerSettings { get; set; }\n\n        /// <summary>\n        /// Gets the FrontPage using the current Reddit instance.\n        /// </summary>\n        public Subreddit FrontPage\n        {\n            get { return Subreddit.GetFrontPage(this); }\n        }\n\n        /// <summary>\n        /// Gets /r/All using the current Reddit instance.\n        /// </summary>\n        public Subreddit RSlashAll\n        {\n            get { return Subreddit.GetRSlashAll(this); }\n        }\n\n        public Reddit()\n            : this(true) { }\n\n        public Reddit(bool useSsl)\n        {\n            DefaultWebAgent defaultAgent = new DefaultWebAgent();\n\n            JsonSerializerSettings = new JsonSerializerSettings\n                {\n                    CheckAdditionalContent = false,\n                    DefaultValueHandling = DefaultValueHandling.Ignore\n                };\n            DefaultWebAgent.Protocol = useSsl ? \"https\" : \"http\";\n            WebAgent = defaultAgent;\n            CaptchaSolver = new ConsoleCaptchaSolver();\n        }\n\n        public Reddit(DefaultWebAgent.RateLimitMode limitMode, bool useSsl = true)\n            : this(useSsl)\n        {\n            DefaultWebAgent.UserAgent = \"\";\n            DefaultWebAgent.RateLimit = limitMode;\n            DefaultWebAgent.RootDomain = \"www.reddit.com\";\n        }\n\n        public Reddit(string username, string password, bool useSsl = true)\n            : this(useSsl)\n        {\n            LogIn(username, password, useSsl);\n        }\n\n        public Reddit(string accessToken)\n            : this(true)\n        {\n            DefaultWebAgent.RootDomain = OAuthDomainUrl;\n            WebAgent.AccessToken = accessToken;\n            InitOrUpdateUser();\n        }\n        /// <summary>\n        /// Creates a Reddit instance with the given WebAgent implementation\n        /// </summary>\n        /// <param name=\"agent\">Implementation of IWebAgent interface. Used to generate requests.</param>\n        public Reddit(IWebAgent agent)\n        {\n            WebAgent = agent;\n            JsonSerializerSettings = new JsonSerializerSettings\n            {\n                CheckAdditionalContent = false,\n                DefaultValueHandling = DefaultValueHandling.Ignore\n            };\n            CaptchaSolver = new ConsoleCaptchaSolver();\n        }\n        /// <summary>\n        /// Creates a Reddit instance with the given WebAgent implementation\n        /// </summary>\n        /// <param name=\"agent\">Implementation of IWebAgent interface. Used to generate requests.</param>\n        /// <param name=\"initUser\">Whether to run InitOrUpdateUser, requires <paramref name=\"agent\"/> to have credentials first.</param>\n        public Reddit(IWebAgent agent, bool initUser)\n        {\n            WebAgent = agent;\n            JsonSerializerSettings = new JsonSerializerSettings\n            {\n                CheckAdditionalContent = false,\n                DefaultValueHandling = DefaultValueHandling.Ignore\n            };\n            CaptchaSolver = new ConsoleCaptchaSolver();\n            if(initUser) InitOrUpdateUser();\n        }\n\n        /// <summary>\n        /// Logs in the current Reddit instance.\n        /// </summary>\n        /// <param name=\"username\">The username of the user to log on to.</param>\n        /// <param name=\"password\">The password of the user to log on to.</param>\n        /// <param name=\"useSsl\">Whether to use SSL or not. (default: true)</param>\n        /// <returns></returns>\n        public AuthenticatedUser LogIn(string username, string password, bool useSsl = true)\n        {\n            if (Type.GetType(\"Mono.Runtime\") != null)\n                ServicePointManager.ServerCertificateValidationCallback = (s, c, ch, ssl) => true;\n            WebAgent.Cookies = new CookieContainer();\n            HttpWebRequest request;\n            if (useSsl)\n                request = WebAgent.CreatePost(SslLoginUrl);\n            else\n                request = WebAgent.CreatePost(LoginUrl);\n            var stream = request.GetRequestStream();\n            if (useSsl)\n            {\n                WebAgent.WritePostBody(stream, new\n                {\n                    user = username,\n                    passwd = password,\n                    api_type = \"json\"\n                });\n            }\n            else\n            {\n                WebAgent.WritePostBody(stream, new\n                {\n                    user = username,\n                    passwd = password,\n                    api_type = \"json\",\n                    op = \"login\"\n                });\n            }\n            stream.Close();\n            var response = (HttpWebResponse)request.GetResponse();\n            var result = WebAgent.GetResponseString(response.GetResponseStream());\n            var json = JObject.Parse(result)[\"json\"];\n            if (json[\"errors\"].Count() != 0)\n                throw new AuthenticationException(\"Incorrect login.\");\n\n            InitOrUpdateUser();\n\n            return User;\n        }\n\n        public RedditUser GetUser(string name)\n        {\n            var request = WebAgent.CreateGet(string.Format(UserInfoUrl, name));\n            var response = request.GetResponse();\n            var result = WebAgent.GetResponseString(response.GetResponseStream());\n            var json = JObject.Parse(result);\n            return new RedditUser().Init(this, json, WebAgent);\n        }\n\n        /// <summary>\n        /// Initializes the User property if it's null,\n        /// otherwise replaces the existing user object\n        /// with a new one fetched from reddit servers.\n        /// </summary>\n        public void InitOrUpdateUser()\n        {\n            var request = WebAgent.CreateGet(string.IsNullOrEmpty(WebAgent.AccessToken) ? MeUrl : OAuthMeUrl);\n            var response = (HttpWebResponse)request.GetResponse();\n            var result = WebAgent.GetResponseString(response.GetResponseStream());\n            var json = JObject.Parse(result);\n            User = new AuthenticatedUser().Init(this, json, WebAgent);\n        }\n\n        #region Obsolete Getter Methods\n\n        [Obsolete(\"Use User property instead\")]\n        public AuthenticatedUser GetMe()\n        {\n            return User;\n        }\n\n        #endregion Obsolete Getter Methods\n\n        public Subreddit GetSubreddit(string name)\n        {\n            if (name.StartsWith(\"r/\"))\n                name = name.Substring(2);\n            if (name.StartsWith(\"/r/\"))\n                name = name.Substring(3);\n            name = name.TrimEnd('/');\n            return GetThing<Subreddit>(string.Format(SubredditAboutUrl, name));\n        }\n\n        /// <summary>\n        /// Returns the subreddit. \n        /// </summary>\n        /// <param name=\"name\">The name of the subreddit</param>\n        /// <returns>The Subreddit by given name</returns>\n        public async Task<Subreddit> GetSubredditAsync(string name)\n        {\n            if (name.StartsWith(\"r/\"))\n                name = name.Substring(2);\n            if (name.StartsWith(\"/r/\"))\n                name = name.Substring(3);\n            name = name.TrimEnd('/');\n            return await GetThingAsync<Subreddit>(string.Format(SubredditAboutUrl, name));\n        }\n\n        public Domain GetDomain(string domain)\n        {\n            if (!domain.StartsWith(\"http://\") && !domain.StartsWith(\"https://\"))\n                domain = \"http://\" + domain;\n            var uri = new Uri(domain);\n            return new Domain(this, uri, WebAgent);\n        }\n\n        public JToken GetToken(Uri uri)\n        {\n            var url = uri.AbsoluteUri;\n\n            if (url.EndsWith(\"/\"))\n                url = url.Remove(url.Length - 1);\n\n            var request = WebAgent.CreateGet(string.Format(GetPostUrl, url));\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            var json = JToken.Parse(data);\n\n            return json[0][\"data\"][\"children\"].First;\n        }\n\n        public Post GetPost(Uri uri)\n        {\n            return new Post().Init(this, GetToken(uri), WebAgent);\n        }\n\n        /// <summary>\n        /// \n        /// </summary>\n        /// <param name=\"subject\"></param>\n        /// <param name=\"body\"></param>\n        /// <param name=\"to\"></param>\n        /// <param name=\"fromSubReddit\">The subreddit to send the message as (optional).</param>\n        /// <param name=\"captchaId\"></param>\n        /// <param name=\"captchaAnswer\"></param>\n        /// <remarks>If <paramref name=\"fromSubReddit\"/> is passed in then the message is sent from the subreddit. the sender must be a mod of the specified subreddit.</remarks>\n        /// <exception cref=\"AuthenticationException\">Thrown when a subreddit is passed in and the user is not a mod of that sub.</exception>\n        public void ComposePrivateMessage(string subject, string body, string to, string fromSubReddit = \"\", string captchaId = \"\", string captchaAnswer = \"\")\n        {\n            if (User == null)\n                throw new Exception(\"User can not be null.\");\n\n            if (!String.IsNullOrWhiteSpace(fromSubReddit))\n            {\n                var subReddit = this.GetSubreddit(fromSubReddit);\n                var modNameList = subReddit.Moderators.Select(b => b.Name).ToList();\n\n                if (!modNameList.Contains(User.Name))\n                    throw new AuthenticationException(\n                        String.Format(\n                            @\"User {0} is not a moderator of subreddit {1}.\",\n                            User.Name,\n                            subReddit.Name));\n            }\n\n            var request = WebAgent.CreatePost(ComposeMessageUrl);\n            WebAgent.WritePostBody(request.GetRequestStream(), new\n            {\n                api_type = \"json\",\n                subject,\n                text = body,\n                to,\n                from_sr = fromSubReddit,\n                uh = User.Modhash,\n                iden = captchaId,\n                captcha = captchaAnswer\n            });\n            var response = request.GetResponse();\n            var result = WebAgent.GetResponseString(response.GetResponseStream());\n            var json = JObject.Parse(result);\n\n            ICaptchaSolver solver = CaptchaSolver; // Prevent race condition\n\n            if (json[\"json\"][\"errors\"].Any() && json[\"json\"][\"errors\"][0][0].ToString() == \"BAD_CAPTCHA\" && solver != null)\n            {\n                captchaId = json[\"json\"][\"captcha\"].ToString();\n                CaptchaResponse captchaResponse = solver.HandleCaptcha(new Captcha(captchaId));\n\n                if (!captchaResponse.Cancel) // Keep trying until we are told to cancel\n                    ComposePrivateMessage(subject, body, to, captchaId, captchaResponse.Answer);\n            }\n        }\n\n        /// <summary>\n        /// Registers a new Reddit user\n        /// </summary>\n        /// <param name=\"userName\">The username for the new account.</param>\n        /// <param name=\"passwd\">The password for the new account.</param>\n        /// <param name=\"email\">The optional recovery email for the new account.</param>\n        /// <returns>The newly created user account</returns>\n        public AuthenticatedUser RegisterAccount(string userName, string passwd, string email = \"\")\n        {\n            var request = WebAgent.CreatePost(RegisterAccountUrl);\n            WebAgent.WritePostBody(request.GetRequestStream(), new\n            {\n                api_type = \"json\",\n                email = email,\n                passwd = passwd,\n                passwd2 = passwd,\n                user = userName\n            });\n            var response = request.GetResponse();\n            var result = WebAgent.GetResponseString(response.GetResponseStream());\n            var json = JObject.Parse(result);\n            return new AuthenticatedUser().Init(this, json, WebAgent);\n            // TODO: Error\n        }\n\n        public Thing GetThingByFullname(string fullname)\n        {\n            var request = WebAgent.CreateGet(string.Format(GetThingUrl, fullname));\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            var json = JToken.Parse(data);\n            return Thing.Parse(this, json[\"data\"][\"children\"][0], WebAgent);\n        }\n\n        public Comment GetComment(string subreddit, string name, string linkName)\n        {\n            try\n            {\n                if (linkName.StartsWith(\"t3_\"))\n                    linkName = linkName.Substring(3);\n                if (name.StartsWith(\"t1_\"))\n                    name = name.Substring(3);\n\n                var url = string.Format(GetCommentUrl, subreddit, linkName, name);\n                return GetComment(new Uri(url));\n            }\n            catch (WebException)\n            {\n                return null;\n            }\n        }\n\n        public Comment GetComment(Uri uri)\n        {\n            var url = string.Format(GetPostUrl, uri.AbsoluteUri);\n            var request = WebAgent.CreateGet(url);\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            var json = JToken.Parse(data);\n\n            var sender = new Post().Init(this, json[0][\"data\"][\"children\"][0], WebAgent);\n            return new Comment().Init(this, json[1][\"data\"][\"children\"][0], WebAgent, sender);\n        }\n\n        public Listing<T> SearchByUrl<T>(string url) where T : Thing\n        {\n            var urlSearchQuery = string.Format(UrlSearchPattern, url);\n            return Search<T>(urlSearchQuery);\n        }\n\n        public Listing<T> Search<T>(string query, Sorting sortE = Sorting.Relevance, TimeSorting timeE = TimeSorting.All) where T : Thing\n        {\n            string sort = sortE.ToString().ToLower();\n            string time = timeE.ToString().ToLower();\n            return new Listing<T>(this, string.Format(SearchUrl, query, sort, time), WebAgent);\n        }\n\n        public Listing<T> SearchByTimestamp<T>(DateTime from, DateTime to, string query = \"\", string subreddit = \"\", Sorting sortE = Sorting.Relevance, TimeSorting timeE = TimeSorting.All) where T : Thing\n        {\n            string sort = sortE.ToString().ToLower();\n            string time = timeE.ToString().ToLower();\n\n            var fromUnix = (from - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds;\n            var toUnix = (to - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds;\n\n            string searchQuery = \"(and+timestamp:\" + fromUnix + \"..\" + toUnix + \"+'\" + query + \"'+\" + \"subreddit:'\" + subreddit + \"')&syntax=cloudsearch\";\n            return new Listing<T>(this, string.Format(SearchUrl, searchQuery, sort, time), WebAgent);\n        }\n\n\n        #region SubredditSearching\n\n        /// <summary>\n        /// Returns a Listing of newly created subreddits.\n        /// </summary>\n        /// <returns></returns>\n        public Listing<Subreddit> GetNewSubreddits()\n        {\n            return new Listing<Subreddit>(this, NewSubredditsUrl, WebAgent);\n        }\n\n        /// <summary>\n        /// Returns a Listing of the most popular subreddits.\n        /// </summary>\n        /// <returns></returns>\n        public Listing<Subreddit> GetPopularSubreddits()\n        {\n            return new Listing<Subreddit>(this, PopularSubredditsUrl, WebAgent);\n        }\n\n        /// <summary>\n        /// Returns a Listing of Gold-only subreddits. This endpoint will not return anything if the authenticated Reddit account does not currently have gold.\n        /// </summary>\n        /// <returns></returns>\n        public Listing<Subreddit> GetGoldSubreddits()\n        {\n            return new Listing<Subreddit>(this, GoldSubredditsUrl, WebAgent);\n        }\n\n        /// <summary>\n        /// Returns the Listing of default subreddits.\n        /// </summary>\n        /// <returns></returns>\n        public Listing<Subreddit> GetDefaultSubreddits()\n        {\n            return new Listing<Subreddit>(this, DefaultSubredditsUrl, WebAgent);\n        }\n\n        /// <summary>\n        /// Returns the Listing of subreddits related to a query.\n        /// </summary>\n        /// <returns></returns>\n        public Listing<Subreddit> SearchSubreddits(string query)\n        {\n            return new Listing<Subreddit>(this, string.Format(SearchSubredditsUrl, query), WebAgent);\n        }\n\n        #endregion SubredditSearching\n\n        #region Helpers\n\n        protected async internal Task<T> GetThingAsync<T>(string url) where T : Thing\n        {\n            var request = WebAgent.CreateGet(url);\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            var json = JToken.Parse(data);\n            var ret = await Thing.ParseAsync(this, json, WebAgent);\n            return (T)ret;\n        }\n\n        protected internal T GetThing<T>(string url) where T : Thing\n        {\n            var request = WebAgent.CreateGet(url);\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            var json = JToken.Parse(data);\n            return (T)Thing.Parse(this, json, WebAgent);\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "RedditSharp/RedditAPINameAttribute.cs",
    "content": "﻿using System;\n\nnamespace RedditSharp\n{\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]\n    internal class RedditAPINameAttribute : Attribute\n    {\n        internal string Name { get; private set; }\n\n        internal RedditAPINameAttribute(string name)\n        {\n            Name = name;\n        }\n\n        public override string ToString()\n        {\n            return Name;\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/RedditException.cs",
    "content": "using System;\nusing System.Runtime.Serialization;\n\nnamespace RedditSharp\n{\n    /// <summary>\n    /// Represents an error that occurred during accessing or manipulating data on Reddit.\n    /// </summary>\n    [Serializable]\n    public class RedditException : Exception\n    {\n        /// <summary>\n        /// Initializes a new instance of the RedditException class.\n        /// </summary>\n        public RedditException()\n        {\n        \n        }\n\n        /// <summary>\n        /// Initializes a new instance of the RedditException class with a specified error message.\n        /// </summary>\n        /// <param name=\"message\">The message that describes the error.</param>\n        public RedditException(string message)\n            : base(message)\n        {\n\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the RedditException class with a specified error message and\n        /// a referenced inner exception that is the cause of this exception.\n        /// </summary>\n        /// <param name=\"message\">The message that describes the error.</param>\n        /// <param name=\"inner\">The exception that is the cause of the current exception, or a null\n        /// reference (Nothing in Visual Basic) if no inner exception is specified.</param>\n        public RedditException(string message, Exception inner)\n            : base(message, inner)\n        {\n            \n        }\n\n        /// <summary>\n        /// Initializes a new instance of the RedditException class with serialized data.\n        /// </summary>\n        /// <param name=\"info\">The System.Runtime.Serialization.SerializationInfo that holds the\n        /// serialized object data about the exception being thrown.</param>\n        /// <param name=\"context\">The System.Runtime.Serialization.StreamingContext that contains\n        /// contextual information about the source or destination.</param>\n        /// <exception cref=\"System.ArgumentNullException\">The info parameter is null.</exception>\n        /// <exception cref=\"System.Runtime.Serialization.SerializationException\">The class name\n        /// is null or System.Exception.HResult is zero (0).</exception>\n        protected RedditException(SerializationInfo info, StreamingContext context)\n            : base(info, context)\n        {\n\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/RedditSharp.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"12.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <PropertyGroup>\r\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\r\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\r\n    <ProductVersion>8.0.30703</ProductVersion>\r\n    <SchemaVersion>2.0</SchemaVersion>\r\n    <ProjectGuid>{A368CB75-75F0-4489-904D-B5CEBB0FE624}</ProjectGuid>\r\n    <OutputType>Library</OutputType>\r\n    <AppDesignerFolder>Properties</AppDesignerFolder>\r\n    <RootNamespace>RedditSharp</RootNamespace>\r\n    <AssemblyName>RedditSharp</AssemblyName>\r\n    <FileAlignment>512</FileAlignment>\r\n    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>\r\n    <TargetFrameworkProfile />\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\r\n    <DebugSymbols>True</DebugSymbols>\r\n    <DebugType>full</DebugType>\r\n    <Optimize>False</Optimize>\r\n    <OutputPath>bin\\Debug\\</OutputPath>\r\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <WarningLevel>4</WarningLevel>\r\n    <Prefer32Bit>false</Prefer32Bit>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\r\n    <DebugType>pdbonly</DebugType>\r\n    <Optimize>True</Optimize>\r\n    <OutputPath>bin\\Release\\</OutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <WarningLevel>4</WarningLevel>\r\n    <Prefer32Bit>false</Prefer32Bit>\r\n  </PropertyGroup>\r\n  <PropertyGroup />\r\n  <ItemGroup>\r\n    <Reference Include=\"HtmlAgilityPack\">\r\n      <HintPath>..\\HtmlAgilityPack.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"Newtonsoft.Json\">\r\n      <HintPath>..\\Newtonsoft.Json.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"System\" />\r\n    <Reference Include=\"System.Core\" />\r\n    <Reference Include=\"System.Web\" />\r\n    <Reference Include=\"System.Xml.Linq\" />\r\n    <Reference Include=\"System.Data.DataSetExtensions\" />\r\n    <Reference Include=\"Microsoft.CSharp\" />\r\n    <Reference Include=\"System.Data\" />\r\n    <Reference Include=\"System.Xml\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Compile Include=\"ModActionType.cs\" />\r\n    <Compile Include=\"Things\\Contributor.cs\" />\r\n    <Compile Include=\"Things\\ModAction.cs\" />\r\n    <Compile Include=\"Utils\\DateTimeExtensions.cs\" />\r\n    <Compile Include=\"SpamFilterSettings.cs\" />\r\n    <Compile Include=\"Things\\AuthenticatedUser.cs\" />\r\n    <Compile Include=\"AuthProvider.cs\" />\r\n    <Compile Include=\"Captcha.cs\" />\r\n    <Compile Include=\"CaptchaFailedException.cs\" />\r\n    <Compile Include=\"CaptchaResponse.cs\" />\r\n    <Compile Include=\"ConsoleCaptchaSolver.cs\" />\r\n    <Compile Include=\"DuplicateLinkException.cs\" />\r\n    <Compile Include=\"ICaptchaSolver.cs\" />\r\n    <Compile Include=\"Things\\Comment.cs\" />\r\n    <Compile Include=\"Things\\CreatedThing.cs\" />\r\n    <Compile Include=\"Extensions.cs\" />\r\n    <Compile Include=\"FlairTemplate.cs\" />\r\n    <Compile Include=\"IWebAgent.cs\" />\r\n    <Compile Include=\"LinkData.cs\" />\r\n    <Compile Include=\"Listing.cs\" />\r\n    <Compile Include=\"ModeratorPermission.cs\" />\r\n    <Compile Include=\"ModeratorUser.cs\" />\r\n    <Compile Include=\"MultipartFormBuilder.cs\" />\r\n    <Compile Include=\"FlairType.cs\" />\r\n    <Compile Include=\"Things\\Post.cs\" />\r\n    <Compile Include=\"Things\\PrivateMessage.cs\" />\r\n    <Compile Include=\"Reddit.cs\" />\r\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\r\n    <Compile Include=\"RedditAPINameAttribute.cs\" />\r\n    <Compile Include=\"RedditException.cs\" />\r\n    <Compile Include=\"Things\\RedditUser.cs\" />\r\n    <Compile Include=\"SubmitData.cs\" />\r\n    <Compile Include=\"Things\\Subreddit.cs\" />\r\n    <Compile Include=\"SubredditImage.cs\" />\r\n    <Compile Include=\"SubredditSettings.cs\" />\r\n    <Compile Include=\"SubredditStyle.cs\" />\r\n    <Compile Include=\"TextData.cs\" />\r\n    <Compile Include=\"Things\\Thing.cs\" />\r\n    <Compile Include=\"UnixTimeStamp.cs\" />\r\n    <Compile Include=\"UnixTimestampConverter.cs\" />\r\n    <Compile Include=\"UrlParser.cs\" />\r\n    <Compile Include=\"Things\\VotableThing.cs\" />\r\n    <Compile Include=\"RateLimitException.cs\" />\r\n    <Compile Include=\"WebAgent.cs\" />\r\n    <Compile Include=\"Wiki.cs\" />\r\n    <Compile Include=\"WikiPage.cs\" />\r\n    <Compile Include=\"Things\\WikiPageRevision.cs\" />\r\n    <Compile Include=\"WikiPageSettings.cs\" />\r\n    <Compile Include=\"Domain.cs\" />\r\n    <Compile Include=\"TBUserNote.cs\" />\r\n    <Compile Include=\"ToolBoxUserNotes.cs\" />\r\n    <Compile Include=\"ToolBoxUserNotesException.cs\" />\r\n  </ItemGroup>\r\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\r\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \r\n       Other similar extension points exist, see Microsoft.Common.targets.\r\n  <Target Name=\"BeforeBuild\">\r\n  </Target>\r\n  <Target Name=\"AfterBuild\">\r\n  </Target>\r\n  -->\r\n</Project>"
  },
  {
    "path": "RedditSharp/SpamFilterSettings.cs",
    "content": "﻿namespace RedditSharp\n{\n    public class SpamFilterSettings\n    {\n        public SpamFilterStrength LinkPostStrength { get; set; }\n        public SpamFilterStrength SelfPostStrength { get; set; }\n        public SpamFilterStrength CommentStrength { get; set; }\n\n        public SpamFilterSettings()\n        {\n            LinkPostStrength = SpamFilterStrength.High;\n            SelfPostStrength = SpamFilterStrength.High;\n            CommentStrength = SpamFilterStrength.High;\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/SubmitData.cs",
    "content": "namespace RedditSharp\n{\n    internal abstract class SubmitData\n    {\n        [RedditAPIName(\"api_type\")]\n        internal string APIType { get; set; }\n\n        [RedditAPIName(\"kind\")]\n        internal string Kind { get; set; }\n\n        [RedditAPIName(\"sr\")]\n        internal string Subreddit { get; set; }\n\n        [RedditAPIName(\"uh\")]\n        internal string UserHash { get; set; }\n\n        [RedditAPIName(\"title\")]\n        internal string Title { get; set; }\n\n        [RedditAPIName(\"iden\")]\n        internal string Iden { get; set; }\n\n        [RedditAPIName(\"captcha\")]\n        internal string Captcha { get; set; }\n\n        [RedditAPIName(\"resubmit\")]\n        internal bool Resubmit { get; set; }\n\n        protected SubmitData()\n        {\n            APIType = \"json\";\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/SubredditImage.cs",
    "content": "﻿using System;\nnamespace RedditSharp\n{\n    public class SubredditImage\n    {\n        private const string DeleteImageUrl = \"/api/delete_sr_img\";\n\n        private Reddit Reddit { get; set; }\n        private IWebAgent WebAgent { get; set; }\n\n        public SubredditImage(Reddit reddit, SubredditStyle subredditStyle,\n            string cssLink, string name, IWebAgent webAgent)\n        {\n            Reddit = reddit;\n            WebAgent = webAgent;\n            SubredditStyle = subredditStyle;\n            Name = name;\n            CssLink = cssLink;\n        }\n\n        public SubredditImage(Reddit reddit, SubredditStyle subreddit,\n            string cssLink, string name, string url, IWebAgent webAgent)\n            : this(reddit, subreddit, cssLink, name, webAgent)\n        {\n            Url = new Uri(url);\n            // Handle legacy image urls\n            // http://thumbs.reddit.com/FULLNAME_NUMBER.png\n            int discarded;\n            if (int.TryParse(url, out discarded))\n                Url = new Uri(string.Format(\"http://thumbs.reddit.com/{0}_{1}.png\", subreddit.Subreddit.FullName, url), UriKind.Absolute);\n        }\n\n        public string CssLink { get; set; }\n        public string Name { get; set; }\n        public Uri Url { get; set; }\n        public SubredditStyle SubredditStyle { get; set; }\n\n        public void Delete()\n        {\n            var request = WebAgent.CreatePost(DeleteImageUrl);\n            var stream = request.GetRequestStream();\n            WebAgent.WritePostBody(stream, new\n            {\n                img_name = Name,\n                uh = Reddit.User.Modhash,\n                r = SubredditStyle.Subreddit.Name\n            });\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            SubredditStyle.Images.Remove(this);\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/SubredditSettings.cs",
    "content": "﻿using System.Web;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing RedditSharp.Things;\n\nnamespace RedditSharp\n{\n    public class SubredditSettings\n    {\n        private const string SiteAdminUrl = \"/api/site_admin\";\n        private const string DeleteHeaderImageUrl = \"/api/delete_sr_header\";\n\n        private Reddit Reddit { get; set; }\n        private IWebAgent WebAgent { get; set; }\n\n        [JsonIgnore]\n        public Subreddit Subreddit { get; set; }\n\n        public SubredditSettings(Reddit reddit, Subreddit subreddit, IWebAgent webAgent)\n        {\n            Subreddit = subreddit;\n            Reddit = reddit;\n            WebAgent = webAgent;\n            // Default settings, for use when reduced information is given\n            AllowAsDefault = true;\n            Domain = null;\n            Sidebar = string.Empty;\n            Language = \"en\";\n            Title = Subreddit.DisplayName;\n            WikiEditKarma = 100;\n            WikiEditAge = 10;\n            UseDomainCss = false;\n            UseDomainSidebar = false;\n            HeaderHoverText = string.Empty;\n            NSFW = false;\n            PublicDescription = string.Empty;\n            WikiEditMode = WikiEditMode.None;\n            SubredditType = SubredditType.Public;\n            ShowThumbnails = true;\n            ContentOptions = ContentOptions.All;\n            SpamFilter = new SpamFilterSettings();\n        }\n\n        public SubredditSettings(Subreddit subreddit, Reddit reddit, JObject json, IWebAgent webAgent) : this(reddit, subreddit, webAgent)\n        {\n            var data = json[\"data\"];\n            AllowAsDefault = data[\"default_set\"].ValueOrDefault<bool>();\n            Domain = data[\"domain\"].ValueOrDefault<string>();\n            Sidebar = HttpUtility.HtmlDecode(data[\"description\"].ValueOrDefault<string>() ?? string.Empty);\n            Language = data[\"language\"].ValueOrDefault<string>();\n            Title = data[\"title\"].ValueOrDefault<string>();\n            WikiEditKarma = data[\"wiki_edit_karma\"].ValueOrDefault<int>();\n            UseDomainCss = data[\"domain_css\"].ValueOrDefault<bool>();\n            UseDomainSidebar = data[\"domain_sidebar\"].ValueOrDefault<bool>();\n            HeaderHoverText = data[\"header_hover_text\"].ValueOrDefault<string>();\n            NSFW = data[\"over_18\"].ValueOrDefault<bool>();\n            PublicDescription = HttpUtility.HtmlDecode(data[\"public_description\"].ValueOrDefault<string>() ?? string.Empty);\n            SpamFilter = new SpamFilterSettings\n            {\n                LinkPostStrength = GetSpamFilterStrength(data[\"spam_links\"].ValueOrDefault<string>()),\n                SelfPostStrength = GetSpamFilterStrength(data[\"spam_selfposts\"].ValueOrDefault<string>()),\n                CommentStrength = GetSpamFilterStrength(data[\"spam_comments\"].ValueOrDefault<string>())\n            };\n            if (data[\"wikimode\"] != null)\n            {\n                var wikiMode = data[\"wikimode\"].ValueOrDefault<string>();\n                switch (wikiMode)\n                {\n                    case \"disabled\":\n                        WikiEditMode = WikiEditMode.None;\n                        break;\n                    case \"modonly\":\n                        WikiEditMode = WikiEditMode.Moderators;\n                        break;\n                    case \"anyone\":\n                        WikiEditMode = WikiEditMode.All;\n                        break;\n                }\n            }\n            if (data[\"subreddit_type\"] != null)\n            {\n                var type = data[\"subreddit_type\"].ValueOrDefault<string>();\n                switch (type)\n                {\n                    case \"public\":\n                        SubredditType = SubredditType.Public;\n                        break;\n                    case \"private\":\n                        SubredditType = SubredditType.Private;\n                        break;\n                    case \"restricted\":\n                        SubredditType = SubredditType.Restricted;\n                        break;\n                }\n            }\n            ShowThumbnails = data[\"show_media\"].ValueOrDefault<bool>();\n            WikiEditAge = data[\"wiki_edit_age\"].ValueOrDefault<int>();\n            if (data[\"content_options\"] != null)\n            {\n                var contentOptions = data[\"content_options\"].ValueOrDefault<string>();\n                switch (contentOptions)\n                {\n                    case \"any\":\n                        ContentOptions = ContentOptions.All;\n                        break;\n                    case \"link\":\n                        ContentOptions = ContentOptions.LinkOnly;\n                        break;\n                    case \"self\":\n                        ContentOptions = ContentOptions.SelfOnly;\n                        break;\n                }\n            }\n        }\n\n        public bool AllowAsDefault { get; set; }\n        public string Domain { get; set; }\n        public string Sidebar { get; set; }\n        public string Language { get; set; }\n        public string Title { get; set; }\n        public int WikiEditKarma { get; set; }\n        public bool UseDomainCss { get; set; }\n        public bool UseDomainSidebar { get; set; }\n        public string HeaderHoverText { get; set; }\n        public bool NSFW { get; set; }\n        public string PublicDescription { get; set; }\n        public WikiEditMode WikiEditMode { get; set; }\n        public SubredditType SubredditType { get; set; }\n        public bool ShowThumbnails { get; set; }\n        public int WikiEditAge { get; set; }\n        public ContentOptions ContentOptions { get; set; }\n        public SpamFilterSettings SpamFilter { get; set; }\n\n        public void UpdateSettings()\n        {\n            var request = WebAgent.CreatePost(SiteAdminUrl);\n            var stream = request.GetRequestStream();\n            string link_type;\n            string type;\n            string wikimode;\n            switch (ContentOptions)\n            {\n                case ContentOptions.All:\n                    link_type = \"any\";\n                    break;\n                case ContentOptions.LinkOnly:\n                    link_type = \"link\";\n                    break;\n                default:\n                    link_type = \"self\";\n                    break;\n            }\n            switch (SubredditType)\n            {\n                case SubredditType.Public:\n                    type = \"public\";\n                    break;\n                case SubredditType.Private:\n                    type = \"private\";\n                    break;\n                default:\n                    type = \"restricted\";\n                    break;\n            }\n            switch (WikiEditMode)\n            {\n                case WikiEditMode.All:\n                    wikimode = \"anyone\";\n                    break;\n                case WikiEditMode.Moderators:\n                    wikimode = \"modonly\";\n                    break;\n                default:\n                    wikimode = \"disabled\";\n                    break;\n            }\n            WebAgent.WritePostBody(stream, new\n            {\n                allow_top = AllowAsDefault,\n                description = Sidebar,\n                domain = Domain,\n                lang = Language,\n                link_type,\n                over_18 = NSFW,\n                public_description = PublicDescription,\n                show_media = ShowThumbnails,\n                sr = Subreddit.FullName,\n                title = Title,\n                type,\n                uh = Reddit.User.Modhash,\n                wiki_edit_age = WikiEditAge,\n                wiki_edit_karma = WikiEditKarma,\n                wikimode,\n                spam_links = SpamFilter == null ? null : SpamFilter.LinkPostStrength.ToString().ToLowerInvariant(),\n                spam_selfposts = SpamFilter == null ? null : SpamFilter.SelfPostStrength.ToString().ToLowerInvariant(),\n                spam_comments = SpamFilter == null ? null : SpamFilter.CommentStrength.ToString().ToLowerInvariant(),\n                api_type = \"json\"\n            }, \"header-title\", HeaderHoverText);\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n        }\n\n        /// <summary>\n        /// Resets the subreddit's header image to the Reddit logo\n        /// </summary>\n        public void ResetHeaderImage()\n        {\n            var request = WebAgent.CreatePost(DeleteHeaderImageUrl);\n            var stream = request.GetRequestStream();\n            WebAgent.WritePostBody(stream, new\n            {\n                uh = Reddit.User.Modhash,\n                r = Subreddit.Name\n            });\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n        }\n\n        private SpamFilterStrength GetSpamFilterStrength(string rawValue)\n        {\n            switch(rawValue)\n            {\n                case \"low\":\n                    return SpamFilterStrength.Low;\n                case \"high\":\n                    return SpamFilterStrength.High;\n                case \"all\":\n                    return SpamFilterStrength.All;\n                default:\n                    return SpamFilterStrength.High;\n            }\n        }\n    }\n\n    public enum WikiEditMode\n    {\n        None,\n        Moderators,\n        All\n    }\n\n    public enum SubredditType\n    {\n        Public,\n        Restricted,\n        Private\n    }\n\n    public enum ContentOptions\n    {\n        All,\n        LinkOnly,\n        SelfOnly\n    }\n\n    public enum SpamFilterStrength\n    {\n        Low,\n        High,\n        All\n    }\n}\n"
  },
  {
    "path": "RedditSharp/SubredditStyle.cs",
    "content": "﻿using System.Collections.Generic;\nusing Newtonsoft.Json.Linq;\nusing System.Web;\nusing RedditSharp.Things;\n\nnamespace RedditSharp\n{\n    public class SubredditStyle\n    {\n        private const string UploadImageUrl = \"/api/upload_sr_img\";\n        private const string UpdateCssUrl = \"/api/subreddit_stylesheet\";\n\n        private Reddit Reddit { get; set; }\n        private IWebAgent WebAgent { get; set; }\n\n        public SubredditStyle(Reddit reddit, Subreddit subreddit, IWebAgent webAgent)\n        {\n            Reddit = reddit;\n            Subreddit = subreddit;\n            WebAgent = webAgent;\n        }\n\n        public SubredditStyle(Reddit reddit, Subreddit subreddit, JToken json, IWebAgent webAgent) : this(reddit, subreddit, webAgent)\n        {\n            Images = new List<SubredditImage>();\n            var data = json[\"data\"];\n            CSS = HttpUtility.HtmlDecode(data[\"stylesheet\"].Value<string>());\n            foreach (var image in data[\"images\"])\n            {\n                Images.Add(new SubredditImage(\n                    Reddit, this, image[\"link\"].Value<string>(),\n                    image[\"name\"].Value<string>(), image[\"url\"].Value<string>(), WebAgent));\n            }\n        }\n\n        public string CSS { get; set; }\n        public List<SubredditImage> Images { get; set; }\n        public Subreddit Subreddit { get; set; }\n\n        public void UpdateCss()\n        {\n            var request = WebAgent.CreatePost(UpdateCssUrl);\n            var stream = request.GetRequestStream();\n            WebAgent.WritePostBody(stream, new\n            {\n                op = \"save\",\n                stylesheet_contents = CSS,\n                uh = Reddit.User.Modhash,\n                api_type = \"json\",\n                r = Subreddit.Name\n            });\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            var json = JToken.Parse(data);\n        }\n\n        public void UploadImage(string name, ImageType imageType, byte[] file)\n        {\n            var request = WebAgent.CreatePost(UploadImageUrl);\n            var formData = new MultipartFormBuilder(request);\n            formData.AddDynamic(new\n                {\n                    name,\n                    uh = Reddit.User.Modhash,\n                    r = Subreddit.Name,\n                    formid = \"image-upload\",\n                    img_type = imageType == ImageType.PNG ? \"png\" : \"jpg\",\n                    upload = \"\"\n                });\n            formData.AddFile(\"file\", \"foo.png\", file, imageType == ImageType.PNG ? \"image/png\" : \"image/jpeg\");\n            formData.Finish();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            // TODO: Detect errors\n        }\n    }\n\n    public enum ImageType\n    {\n        PNG,\n        JPEG\n    }\n}\n"
  },
  {
    "path": "RedditSharp/TBUserNote.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace RedditSharp\n{\n    public class TBUserNote\n    {\n        public int NoteTypeIndex { get; set; }\n        public string NoteType { get; set; }\n        public string SubName { get; set; }\n        public string Submitter { get; set; }\n        public int SubmitterIndex { get; set; }\n        public string Message { get; set; }\n        public string AppliesToUsername { get; set; }\n        public string Url { get; set; }\n        private DateTime _timestamp;\n        public DateTime Timestamp\n        {\n            get { return _timestamp; }\n            set\n            {\n                _timestamp = DateTime.SpecifyKind(value, DateTimeKind.Utc);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/TextData.cs",
    "content": "﻿namespace RedditSharp\n{\n    internal class TextData : SubmitData\n    {\n        [RedditAPIName(\"text\")]\n        internal string Text { get; set; }\n\n        internal TextData()\n        {\n            Kind = \"self\";\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/Things/AuthenticatedUser.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\n\nnamespace RedditSharp.Things\n{\n    public class AuthenticatedUser : RedditUser\n    {\n        private const string ModeratorUrl = \"/reddits/mine/moderator.json\";\n        private const string UnreadMessagesUrl = \"/message/unread.json?mark=true&limit=25\";\n        private const string ModQueueUrl = \"/r/mod/about/modqueue.json\";\n        private const string UnmoderatedUrl = \"/r/mod/about/unmoderated.json\";\n        private const string ModMailUrl = \"/message/moderator.json\";\n        private const string MessagesUrl = \"/message/messages.json\";\n        private const string InboxUrl = \"/message/inbox.json\";\n        private const string SentUrl = \"/message/sent.json\";\n\n        public new AuthenticatedUser Init(Reddit reddit, JToken json, IWebAgent webAgent)\n        {\n            CommonInit(reddit, json, webAgent);\n            JsonConvert.PopulateObject(json[\"name\"] == null ? json[\"data\"].ToString() : json.ToString(), this,\n                reddit.JsonSerializerSettings);\n            return this;\n        }\n        public async new Task<AuthenticatedUser> InitAsync(Reddit reddit, JToken json, IWebAgent webAgent)\n        {\n            CommonInit(reddit, json, webAgent);\n            await Task.Factory.StartNew(() => JsonConvert.PopulateObject(json[\"name\"] == null ? json[\"data\"].ToString() : json.ToString(), this,\n                reddit.JsonSerializerSettings));\n            return this;\n        }\n\n        private void CommonInit(Reddit reddit, JToken json, IWebAgent webAgent)\n        {\n            base.Init(reddit, json, webAgent);\n        }\n\n        public Listing<Subreddit> ModeratorSubreddits\n        {\n            get\n            {\n                return new Listing<Subreddit>(Reddit, ModeratorUrl, WebAgent);\n            }\n        }\n\n        public Listing<Thing> UnreadMessages\n        {\n            get\n            {\n                return new Listing<Thing>(Reddit, UnreadMessagesUrl, WebAgent);\n            }\n        }\n\n        public Listing<VotableThing> ModerationQueue\n        {\n            get\n            {\n                return new Listing<VotableThing>(Reddit, ModQueueUrl, WebAgent);\n            }\n        }\n\n        public Listing<Post> UnmoderatedLinks\n        {\n            get\n            {\n                return new Listing<Post>(Reddit, UnmoderatedUrl, WebAgent);\n            }\n        }\n\n        public Listing<PrivateMessage> ModMail\n        {\n            get\n            {\n                return new Listing<PrivateMessage>(Reddit, ModMailUrl, WebAgent);\n            }\n        }\n\n        public Listing<PrivateMessage> PrivateMessages\n        {\n            get\n            {\n                return new Listing<PrivateMessage>(Reddit, MessagesUrl, WebAgent);\n            }\n        }\n\n        public Listing<PrivateMessage> Inbox\n        {\n            get\n            {\n                return new Listing<PrivateMessage>(Reddit, InboxUrl, WebAgent);\n            }\n        }\n\n        public Listing<PrivateMessage> Sent\n        {\n            get\n            {\n                return new Listing<PrivateMessage>(Reddit, SentUrl, WebAgent);\n            }\n        }\n\n        #region Obsolete Getter Methods\n\n        [Obsolete(\"Use ModeratorSubreddits property instead\")]\n        public Listing<Subreddit> GetModeratorReddits()\n        {\n            return ModeratorSubreddits;\n        }\n\n        [Obsolete(\"Use UnreadMessages property instead\")]\n        public Listing<Thing> GetUnreadMessages()\n        {\n            return UnreadMessages;\n        }\n\n        [Obsolete(\"Use ModerationQueue property instead\")]\n        public Listing<VotableThing> GetModerationQueue()\n        {\n            return new Listing<VotableThing>(Reddit, ModQueueUrl, WebAgent);\n        }\n\n        public Listing<Post> GetUnmoderatedLinks()\n        {\n            return new Listing<Post>(Reddit, UnmoderatedUrl, WebAgent);\n        }\n\n        [Obsolete(\"Use ModMail property instead\")]\n        public Listing<PrivateMessage> GetModMail()\n        {\n            return new Listing<PrivateMessage>(Reddit, ModMailUrl, WebAgent);\n        }\n\n        [Obsolete(\"Use PrivateMessages property instead\")]\n        public Listing<PrivateMessage> GetPrivateMessages()\n        {\n            return new Listing<PrivateMessage>(Reddit, MessagesUrl, WebAgent);\n        }\n\n        [Obsolete(\"Use Inbox property instead\")]\n        public Listing<PrivateMessage> GetInbox()\n        {\n            return new Listing<PrivateMessage>(Reddit, InboxUrl, WebAgent);\n        }\n\n        #endregion Obsolete Getter Methods\n\n        [JsonProperty(\"modhash\")]\n        public string Modhash { get; set; }\n\n        [JsonProperty(\"has_mail\")]\n        public bool HasMail { get; set; }\n\n        [JsonProperty(\"has_mod_mail\")]\n        public bool HasModMail { get; set; }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/Things/Comment.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing System.Net;\nusing System.Security.Authentication;\nusing System.Threading.Tasks;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\n\nnamespace RedditSharp.Things\n{\n    public class Comment : VotableThing\n    {\n        private const string CommentUrl = \"/api/comment\";\n        private const string EditUserTextUrl = \"/api/editusertext\";\n        private const string RemoveUrl = \"/api/remove\";\n        private const string DelUrl = \"/api/del\";\n        private const string SetAsReadUrl = \"/api/read_message\";\n\n        [JsonIgnore]\n        private Reddit Reddit { get; set; }\n        [JsonIgnore]\n        private IWebAgent WebAgent { get; set; }\n\n        public Comment Init(Reddit reddit, JToken json, IWebAgent webAgent, Thing sender)\n        {\n            var data = CommonInit(reddit, json, webAgent, sender);\n            ParseComments(reddit, json, webAgent, sender);\n            JsonConvert.PopulateObject(data.ToString(), this, reddit.JsonSerializerSettings);\n            return this;\n        }\n        public async Task<Comment> InitAsync(Reddit reddit, JToken json, IWebAgent webAgent, Thing sender)\n        {\n            var data = CommonInit(reddit, json, webAgent, sender);\n            await ParseCommentsAsync(reddit, json, webAgent, sender);\n            await Task.Factory.StartNew(() => JsonConvert.PopulateObject(data.ToString(), this, reddit.JsonSerializerSettings));\n            return this;\n        }\n\n        private JToken CommonInit(Reddit reddit, JToken json, IWebAgent webAgent, Thing sender)\n        {\n            base.Init(reddit, webAgent, json);\n            var data = json[\"data\"];\n            Reddit = reddit;\n            WebAgent = webAgent;\n            this.Parent = sender;\n\n            // Handle Reddit's API being horrible\n            if (data[\"context\"] != null)\n            {\n                var context = data[\"context\"].Value<string>();\n                LinkId = context.Split('/')[4];\n            }\n         \n            return data;\n        }\n\n        private void ParseComments(Reddit reddit, JToken data, IWebAgent webAgent, Thing sender)\n        {\n            // Parse sub comments\n            var replies = data[\"data\"][\"replies\"];\n            var subComments = new List<Comment>();\n            if (replies != null && replies.Count() > 0)\n            {\n                foreach (var comment in replies[\"data\"][\"children\"])\n                    subComments.Add(new Comment().Init(reddit, comment, webAgent, sender));\n            }\n            Comments = subComments.ToArray();\n        }\n\n        private async Task ParseCommentsAsync(Reddit reddit, JToken data, IWebAgent webAgent, Thing sender)\n        {\n            // Parse sub comments\n            var replies = data[\"data\"][\"replies\"];\n            var subComments = new List<Comment>();\n            if (replies != null && replies.Count() > 0)\n            {\n                foreach (var comment in replies[\"data\"][\"children\"])\n                    subComments.Add(await new Comment().InitAsync(reddit, comment, webAgent, sender));\n            }\n            Comments = subComments.ToArray();            \n        }\n\n        [JsonProperty(\"author\")]\n        public string Author { get; set; }\n        [JsonProperty(\"banned_by\")]\n        public string BannedBy { get; set; }\n        [JsonProperty(\"body\")]\n        public string Body { get; set; }\n        [JsonProperty(\"body_html\")]\n        public string BodyHtml { get; set; }\n        [JsonProperty(\"parent_id\")]\n        public string ParentId { get; set; }\n        [JsonProperty(\"subreddit\")]\n        public string Subreddit { get; set; }\n        [JsonProperty(\"approved_by\")]\n        public string ApprovedBy { get; set; }\n        [JsonProperty(\"author_flair_css_class\")]\n        public string AuthorFlairCssClass { get; set; }\n        [JsonProperty(\"author_flair_text\")]\n        public string AuthorFlairText { get; set; }\n        [JsonProperty(\"gilded\")]\n        public int Gilded { get; set; }\n        [JsonProperty(\"link_id\")]\n        public string LinkId { get; set; }\n        [JsonProperty(\"link_title\")]\n        public string LinkTitle { get; set; }\n        [JsonProperty(\"num_reports\")]\n        public int? NumReports { get; set; }\n\n        [JsonIgnore]\n        public IList<Comment> Comments { get; private set; }\n\n        [JsonIgnore]\n        public Thing Parent { get; internal set; }\n\n        public override string Shortlink\n        {\n            get\n            {\n                // Not really a \"short\" link, but you can't actually use short links for comments\n                string linkId = \"\";\n                int index = this.LinkId.IndexOf('_');\n                if (index > -1)\n                {\n                    linkId = this.LinkId.Substring(index + 1);\n                }\n\n                return String.Format(\"{0}://{1}/r/{2}/comments/{3}/_/{4}\",\n                                     RedditSharp.WebAgent.Protocol, RedditSharp.WebAgent.RootDomain,\n                                     this.Subreddit, this.Parent != null ? this.Parent.Id : linkId, this.Id);\n            }\n        }\n\n        public Comment Reply(string message)\n        {\n            if (Reddit.User == null)\n                throw new AuthenticationException(\"No user logged in.\");\n            var request = WebAgent.CreatePost(CommentUrl);\n            var stream = request.GetRequestStream();\n            WebAgent.WritePostBody(stream, new\n            {\n                text = message,\n                thing_id = FullName,\n                uh = Reddit.User.Modhash,\n                api_type = \"json\"\n                //r = Subreddit\n            });\n            stream.Close();\n            try\n            {\n                var response = request.GetResponse();\n                var data = WebAgent.GetResponseString(response.GetResponseStream());\n                var json = JObject.Parse(data);\n                if (json[\"json\"][\"ratelimit\"] != null)\n                    throw new RateLimitException(TimeSpan.FromSeconds(json[\"json\"][\"ratelimit\"].ValueOrDefault<double>()));\n                return new Comment().Init(Reddit, json[\"json\"][\"data\"][\"things\"][0], WebAgent, this);\n            }\n            catch (WebException ex)\n            {\n                var error = new StreamReader(ex.Response.GetResponseStream()).ReadToEnd();\n                return null;\n            }\n        }\n\n        /// <summary>\n        /// Replaces the text in this comment with the input text.\n        /// </summary>\n        /// <param name=\"newText\">The text to replace the comment's contents</param>        \n        public void EditText(string newText)\n        {\n            if (Reddit.User == null)\n                throw new Exception(\"No user logged in.\");\n\n            var request = WebAgent.CreatePost(EditUserTextUrl);\n            WebAgent.WritePostBody(request.GetRequestStream(), new\n            {\n                api_type = \"json\",\n                text = newText,\n                thing_id = FullName,\n                uh = Reddit.User.Modhash\n            });\n            var response = request.GetResponse();\n            var result = WebAgent.GetResponseString(response.GetResponseStream());\n            JToken json = JToken.Parse(result);\n            if (json[\"json\"].ToString().Contains(\"\\\"errors\\\": []\"))\n                Body = newText;\n            else\n                throw new Exception(\"Error editing text.\");\n        }\n\n        private string SimpleAction(string endpoint)\n        {\n            if (Reddit.User == null)\n                throw new AuthenticationException(\"No user logged in.\");\n            var request = WebAgent.CreatePost(endpoint);\n            var stream = request.GetRequestStream();\n            WebAgent.WritePostBody(stream, new\n            {\n                id = FullName,\n                uh = Reddit.User.Modhash\n            });\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            return data;\n        }\n\n        public void Del()\n        {\n            var data = SimpleAction(DelUrl);\n        }\n\n        public void Remove()\n        {\n            RemoveImpl(false);\n        }\n\n        public void RemoveSpam()\n        {\n            RemoveImpl(true);\n        }\n\n        private void RemoveImpl(bool spam)\n        {\n            var request = WebAgent.CreatePost(RemoveUrl);\n            var stream = request.GetRequestStream();\n            WebAgent.WritePostBody(stream, new\n            {\n                id = FullName,\n                spam = spam,\n                uh = Reddit.User.Modhash\n            });\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n        }\n\n        public void SetAsRead()\n        {\n            var request = WebAgent.CreatePost(SetAsReadUrl);\n            WebAgent.WritePostBody(request.GetRequestStream(), new\n                                 {\n                                     id = FullName,\n                                     uh = Reddit.User.Modhash,\n                                     api_type = \"json\"\n                                 });\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/Things/Contributor.cs",
    "content": "﻿using System;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\n\nnamespace RedditSharp.Things \n{\n    public class Contributor : Thing \n    {\n        [JsonProperty(\"name\")]\n        public string Name { get; set; }\n\n        [JsonProperty(\"date\")]\n        [JsonConverter(typeof(UnixTimestampConverter))]\n        public DateTime DateAdded { get; set; }\n\n        public Contributor Init(Reddit reddit, JToken json, IWebAgent webAgent) \n        {\n            CommonInit(json);\n            JsonConvert.PopulateObject(json.ToString(), this, reddit.JsonSerializerSettings);\n            return this;\n        }\n\n        private void CommonInit(JToken json) \n        {\n            base.Init(json);\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/Things/CreatedThing.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\n\nnamespace RedditSharp.Things\n{\n    public class CreatedThing : Thing\n    {\n        private Reddit Reddit { get; set; }\n\n        protected CreatedThing Init(Reddit reddit, JToken json)\n        {\n            CommonInit(reddit, json);\n            JsonConvert.PopulateObject(json[\"data\"].ToString(), this, reddit.JsonSerializerSettings);\n            return this;\n        }\n        protected async Task<CreatedThing> InitAsync(Reddit reddit, JToken json)\n        {\n            CommonInit(reddit, json);\n            await Task.Factory.StartNew(() => JsonConvert.PopulateObject(json[\"data\"].ToString(), this, reddit.JsonSerializerSettings));\n            return this;\n        }\n\n        private void CommonInit(Reddit reddit, JToken json)\n        {\n            base.Init(json);\n            Reddit = reddit;\n        }\n\n\n        [JsonProperty(\"created\")]\n        [JsonConverter(typeof(UnixTimestampConverter))]\n        public DateTime Created { get; set; }\n\n        [JsonProperty(\"created_utc\")]\n        [JsonConverter(typeof(UnixTimestampConverter))]\n        public DateTime CreatedUTC { get; set; }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/Things/ModAction.cs",
    "content": "﻿using Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace RedditSharp.Things\n{\n    public class ModAction : Thing\n    {\n\n        [JsonProperty(\"action\")]\n        [JsonConverter(typeof(ModActionTypeConverter))]\n        public ModActionType Action { get; set; }\n\n        [JsonProperty(\"created_utc\")]\n        [JsonConverter(typeof(UnixTimestampConverter))]\n        public DateTime? TimeStamp { get; set; }\n\n        [JsonProperty(\"details\")]\n        public string Details { get; set; }\n\n        [JsonProperty(\"mod\")]\n        public string ModeratorName { get; set; }\n\n        [JsonProperty(\"target_author\")]\n        public string TargetAuthorName { get; set; }\n\n        [JsonProperty(\"target_fullname\")]\n        public string TargetThingFullname { get; set; }\n\n        [JsonProperty(\"target_permalink\")]\n        public string TargetThingPermalink { get; set; }\n\n        [JsonIgnore]\n        public RedditUser TargetAuthor\n        {\n            get\n            {\n                return Reddit.GetUser(TargetAuthorName);\n            }\n        }\n\n        [JsonIgnore]\n        public Thing TargetThing\n        {\n            get\n            {\n                return Reddit.GetThingByFullname(TargetThingFullname);\n            }\n        }\n\n        [JsonIgnore]\n        private Reddit Reddit { get; set; }\n\n        [JsonIgnore]\n        private IWebAgent WebAgent { get; set; }\n\n        public ModAction Init(Reddit reddit, JToken json, IWebAgent webAgent)\n        {\n            CommonInit(reddit, json, webAgent);\n            JsonConvert.PopulateObject(json[\"data\"].ToString(), this, reddit.JsonSerializerSettings);\n            return this;\n        }\n        public async Task<ModAction> InitAsync(Reddit reddit, JToken post, IWebAgent webAgent)\n        {\n            CommonInit(reddit, post, webAgent);\n            await Task.Factory.StartNew(() => JsonConvert.PopulateObject(post[\"data\"].ToString(), this, reddit.JsonSerializerSettings));\n            return this;\n        }\n\n        private void CommonInit(Reddit reddit, JToken json, IWebAgent webAgent)\n        {\n            base.Init(json);\n            Reddit = reddit;\n            WebAgent = webAgent;\n        }\n\n    }\n}\n"
  },
  {
    "path": "RedditSharp/Things/Post.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Security.Authentication;\nusing System.Threading.Tasks;\nusing System.Web;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\n\nnamespace RedditSharp.Things\n{\n    public class Post : VotableThing\n    {\n        private const string CommentUrl = \"/api/comment\";\n        private const string RemoveUrl = \"/api/remove\";\n        private const string DelUrl = \"/api/del\";\n        private const string GetCommentsUrl = \"/comments/{0}.json\";\n        private const string ApproveUrl = \"/api/approve\";\n        private const string EditUserTextUrl = \"/api/editusertext\";\n        private const string HideUrl = \"/api/hide\";\n        private const string UnhideUrl = \"/api/unhide\";\n        private const string SetFlairUrl = \"/r/{0}/api/flair\";\n        private const string MarkNSFWUrl = \"/api/marknsfw\";\n        private const string UnmarkNSFWUrl = \"/api/unmarknsfw\";\n        private const string ContestModeUrl = \"/api/set_contest_mode\";\n        private const string StickyModeUrl = \"/api/set_subreddit_sticky\";\n\n        [JsonIgnore]\n        private Reddit Reddit { get; set; }\n\n        [JsonIgnore]\n        private IWebAgent WebAgent { get; set; }\n\n        public Post Init(Reddit reddit, JToken post, IWebAgent webAgent)\n        {\n            CommonInit(reddit, post, webAgent);\n            JsonConvert.PopulateObject(post[\"data\"].ToString(), this, reddit.JsonSerializerSettings);\n            return this;\n        }\n        public async Task<Post> InitAsync(Reddit reddit, JToken post, IWebAgent webAgent)\n        {\n            CommonInit(reddit, post, webAgent);\n            await Task.Factory.StartNew(() => JsonConvert.PopulateObject(post[\"data\"].ToString(), this, reddit.JsonSerializerSettings));\n            return this;\n        }\n\n        private void CommonInit(Reddit reddit, JToken post, IWebAgent webAgent)\n        {\n            base.Init(reddit, webAgent, post);\n            Reddit = reddit;\n            WebAgent = webAgent;\n        }\n\n        [JsonProperty(\"author\")]\n        public string AuthorName { get; set; }\n\n        [JsonIgnore]\n        public RedditUser Author\n        {\n            get\n            {\n                return Reddit.GetUser(AuthorName);\n            }\n        }\n\n        public Comment[] Comments\n        {\n            get\n            {\n                return ListComments().ToArray();\n            }\n        }\n\n        [JsonProperty(\"approved_by\")]\n        public string ApprovedBy { get; set; }\n\n        [JsonProperty(\"author_flair_css_class\")]\n        public string AuthorFlairCssClass { get; set; }\n\n        [JsonProperty(\"author_flair_text\")]\n        public string AuthorFlairText { get; set; }\n\n        [JsonProperty(\"banned_by\")]\n        public string BannedBy { get; set; }\n\n        [JsonProperty(\"domain\")]\n        public string Domain { get; set; }\n\n        [JsonProperty(\"edited\")]\n        public bool Edited { get; set; }\n\n        [JsonProperty(\"is_self\")]\n        public bool IsSelfPost { get; set; }\n\n        [JsonProperty(\"link_flair_css_class\")]\n        public string LinkFlairCssClass { get; set; }\n\n        [JsonProperty(\"link_flair_text\")]\n        public string LinkFlairText { get; set; }\n\n        [JsonProperty(\"num_comments\")]\n        public int CommentCount { get; set; }\n\n        [JsonProperty(\"over_18\")]\n        public bool NSFW { get; set; }\n\n        [JsonProperty(\"permalink\")]\n        [JsonConverter(typeof(UrlParser))]\n        public Uri Permalink { get; set; }\n\n        [JsonProperty(\"score\")]\n        public int Score { get; set; }\n\n        [JsonProperty(\"selftext\")]\n        public string SelfText { get; set; }\n\n        [JsonProperty(\"selftext_html\")]\n        public string SelfTextHtml { get; set; }\n\n        [JsonProperty(\"thumbnail\")]\n        [JsonConverter(typeof(UrlParser))]\n        public Uri Thumbnail { get; set; }\n\n        [JsonProperty(\"title\")]\n        public string Title { get; set; }\n\n        [JsonProperty(\"subreddit\")]\n        public string SubredditName { get; set; }\n\n        [JsonIgnore]\n        public Subreddit Subreddit\n        {\n            get\n            {\n                return Reddit.GetSubreddit(\"/r/\" + SubredditName);\n            }\n        }\n\n        [JsonProperty(\"url\")]\n        [JsonConverter(typeof(UrlParser))]\n        public Uri Url { get; set; }\n\n        [JsonProperty(\"num_reports\")]\n        public int? Reports { get; set; }\n\n        public Comment Comment(string message)\n        {\n            if (Reddit.User == null)\n                throw new AuthenticationException(\"No user logged in.\");\n            var request = WebAgent.CreatePost(CommentUrl);\n            var stream = request.GetRequestStream();\n            WebAgent.WritePostBody(stream, new\n                {\n                    text = message,\n                    thing_id = FullName,\n                    uh = Reddit.User.Modhash,\n                    api_type = \"json\"\n                });\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            var json = JObject.Parse(data);\n            if (json[\"json\"][\"ratelimit\"] != null)\n                throw new RateLimitException(TimeSpan.FromSeconds(json[\"json\"][\"ratelimit\"].ValueOrDefault<double>()));\n            return new Comment().Init(Reddit, json[\"json\"][\"data\"][\"things\"][0], WebAgent, this);\n        }\n\n        private string SimpleAction(string endpoint)\n        {\n            if (Reddit.User == null)\n                throw new AuthenticationException(\"No user logged in.\");\n            var request = WebAgent.CreatePost(endpoint);\n            var stream = request.GetRequestStream();\n            WebAgent.WritePostBody(stream, new\n            {\n                id = FullName,\n                uh = Reddit.User.Modhash\n            });\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            return data;\n        }\n\n        private string SimpleActionToggle(string endpoint, bool value, bool requiresModAction = false)\n        {\n            if (Reddit.User == null)\n                throw new AuthenticationException(\"No user logged in.\");\n\n            var modNameList = this.Subreddit.Moderators.Select(b => b.Name).ToList();\n\n            if (requiresModAction && !modNameList.Contains(Reddit.User.Name))\n                throw new AuthenticationException(\n                    String.Format(\n                        @\"User {0} is not a moderator of subreddit {1}.\", \n                        Reddit.User.Name,\n                        this.Subreddit.Name));\n\n            var request = WebAgent.CreatePost(endpoint);\n            var stream = request.GetRequestStream();\n            WebAgent.WritePostBody(stream, new\n            {\n                id = FullName,\n                state = value,\n                uh = Reddit.User.Modhash\n            });\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            return data;\n        }\n\n        public void Approve()\n        {\n            var data = SimpleAction(ApproveUrl);\n        }\n\n        public void Remove()\n        {\n            RemoveImpl(false);\n        }\n\n        public void RemoveSpam()\n        {\n            RemoveImpl(true);\n        }\n\n        private void RemoveImpl(bool spam)\n        {\n            var request = WebAgent.CreatePost(RemoveUrl);\n            var stream = request.GetRequestStream();\n            WebAgent.WritePostBody(stream, new\n            {\n                id = FullName,\n                spam = spam,\n                uh = Reddit.User.Modhash\n            });\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n        }\n\n        public void Del()\n        {\n            var data = SimpleAction(DelUrl);\n        }\n\n        public void Hide()\n        {\n            var data = SimpleAction(HideUrl);\n        }\n\n        public void Unhide()\n        {\n            var data = SimpleAction(UnhideUrl);\n        }\n\n        public void MarkNSFW()\n        {\n            var data = SimpleAction(MarkNSFWUrl);\n        }\n\n        public void UnmarkNSFW()\n        {\n            var data = SimpleAction(UnmarkNSFWUrl);\n        }\n\n        public void ContestMode(bool state)\n        {\n            var data = SimpleActionToggle(ContestModeUrl, state);\n        }\n\n        public void StickyMode(bool state)\n        {\n            var data = SimpleActionToggle(StickyModeUrl, state, true);\n        }\n\n        #region Obsolete Getter Methods\n\n        [Obsolete(\"Use Comments property instead\")]\n        public Comment[] GetComments()\n        {\n            return Comments;\n        }\n\n        #endregion Obsolete Getter Methods\n\n        /// <summary>\n        /// Replaces the text in this post with the input text.\n        /// </summary>\n        /// <param name=\"newText\">The text to replace the post's contents</param>\n        public void EditText(string newText)\n        {\n            if (Reddit.User == null)\n                throw new Exception(\"No user logged in.\");\n            if (!IsSelfPost)\n                throw new Exception(\"Submission to edit is not a self-post.\");\n\n            var request = WebAgent.CreatePost(EditUserTextUrl);\n            WebAgent.WritePostBody(request.GetRequestStream(), new\n            {\n                api_type = \"json\",\n                text = newText,\n                thing_id = FullName,\n                uh = Reddit.User.Modhash\n            });\n            var response = request.GetResponse();\n            var result = WebAgent.GetResponseString(response.GetResponseStream());\n            JToken json = JToken.Parse(result);\n            if (json[\"json\"].ToString().Contains(\"\\\"errors\\\": []\"))\n                SelfText = newText;\n            else\n                throw new Exception(\"Error editing text.\");\n        }\n        public void Update()\n        {\n            JToken post = Reddit.GetToken(this.Url);\n            JsonConvert.PopulateObject(post[\"data\"].ToString(), this, Reddit.JsonSerializerSettings);\n        }\n\n        public void SetFlair(string flairText, string flairClass)\n        {\n            if (Reddit.User == null)\n                throw new Exception(\"No user logged in.\");\n\n            var request = WebAgent.CreatePost(string.Format(SetFlairUrl,SubredditName));\n            WebAgent.WritePostBody(request.GetRequestStream(), new\n            {\n                api_type = \"json\",\n                css_class = flairClass,\n                link = FullName,\n                name = Reddit.User.Name,\n                text = flairText,\n                uh = Reddit.User.Modhash\n            });\n            var response = request.GetResponse();\n            var result = WebAgent.GetResponseString(response.GetResponseStream());\n            var json = JToken.Parse(result);\n            LinkFlairText = flairText;\n        }\n\n        public List<Comment> ListComments(int? limit = null)\n        {\n            var url = string.Format(GetCommentsUrl, Id);\n\n            if (limit.HasValue)\n            {\n                var query = HttpUtility.ParseQueryString(string.Empty);\n                query.Add(\"limit\", limit.Value.ToString());\n                url = string.Format(\"{0}?{1}\", url, query);\n            }\n\n            var request = WebAgent.CreateGet(url);\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            var json = JArray.Parse(data);\n            var postJson = json.Last()[\"data\"][\"children\"];\n\n            var comments = new List<Comment>();\n            foreach (var comment in postJson)\n            {\n                comments.Add(new Comment().Init(Reddit, comment, WebAgent, this));\n            }\n\n            return comments;\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/Things/PrivateMessage.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Security.Authentication;\nusing System.Threading.Tasks;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\n\nnamespace RedditSharp.Things\n{\n    public class PrivateMessage : Thing\n    {\n        private const string SetAsReadUrl = \"/api/read_message\";\n        private const string CommentUrl = \"/api/comment\";\n\n        private Reddit Reddit { get; set; }\n        private IWebAgent WebAgent { get; set; }\n\n        [JsonProperty(\"body\")]\n        public string Body { get; set; }\n\n        [JsonProperty(\"body_html\")]\n        public string BodyHtml { get; set; }\n\n        [JsonProperty(\"was_comment\")]\n        public bool IsComment { get; set; }\n\n        [JsonProperty(\"created\")]\n        [JsonConverter(typeof(UnixTimestampConverter))]\n        public DateTime Sent { get; set; }\n\n        [JsonProperty(\"created_utc\")]\n        [JsonConverter(typeof(UnixTimestampConverter))]\n        public DateTime SentUTC { get; set; }\n\n        [JsonProperty(\"dest\")]\n        public string Destination { get; set; }\n\n        [JsonProperty(\"author\")]\n        public string Author { get; set; }\n\n        [JsonProperty(\"subreddit\")]\n        public string Subreddit { get; set; }\n\n        [JsonProperty(\"new\")]\n        public bool Unread { get; set; }\n\n        [JsonProperty(\"subject\")]\n        public string Subject { get; set; }\n\n        [JsonProperty(\"parent_id\")]\n        public string ParentID { get; set; }\n\n        [JsonProperty(\"first_message_name\")]\n        public string FirstMessageName { get; set; }\n\n        [JsonIgnore]\n        public PrivateMessage[] Replies { get; set; }\n\n        [JsonIgnore]\n        public PrivateMessage Parent\n        {\n            get\n            {\n                if (string.IsNullOrEmpty(ParentID))\n                    return null;\n                var id = ParentID.Remove(0, 3);\n                var listing = new Listing<PrivateMessage>(Reddit, \"/message/messages/\" + id + \".json\", WebAgent);\n                var firstMessage = listing.First();\n                if (firstMessage.FullName == ParentID)\n                    return listing.First();\n                else\n                    return firstMessage.Replies.First(x => x.FullName == ParentID);\n            }\n        }\n\n        public Listing<PrivateMessage> Thread\n        {\n            get\n            {\n                if (string.IsNullOrEmpty(ParentID))\n                    return null;\n                var id = ParentID.Remove(0, 3);\n                return new Listing<PrivateMessage>(Reddit, \"/message/messages/\" + id + \".json\", WebAgent);\n            }\n        }\n\n        public PrivateMessage Init(Reddit reddit, JToken json, IWebAgent webAgent)\n        {\n            CommonInit(reddit, json, webAgent);\n            JsonConvert.PopulateObject(json[\"data\"].ToString(), this, reddit.JsonSerializerSettings);\n            return this;\n        }\n        public async Task<PrivateMessage> InitAsync(Reddit reddit, JToken json, IWebAgent webAgent)\n        {\n            CommonInit(reddit, json, webAgent);\n            await Task.Factory.StartNew(() => JsonConvert.PopulateObject(json[\"data\"].ToString(), this, reddit.JsonSerializerSettings));\n            return this;\n        }\n\n        private void CommonInit(Reddit reddit, JToken json, IWebAgent webAgent)\n        {\n            base.Init(json);\n            Reddit = reddit;\n            WebAgent = webAgent;\n            var data = json[\"data\"];\n            if (data[\"replies\"] != null && data[\"replies\"].Any())\n            {\n                if (data[\"replies\"][\"data\"] != null)\n                {\n                    if (data[\"replies\"][\"data\"][\"children\"] != null)\n                    {\n                        var replies = new List<PrivateMessage>();\n                        foreach (var reply in data[\"replies\"][\"data\"][\"children\"])\n                            replies.Add(new PrivateMessage().Init(reddit, reply, webAgent));\n                        Replies = replies.ToArray();\n                    }\n                }\n            }\n        }\n\n        #region Obsolete Getter Methods\n\n        [Obsolete(\"Use Thread property instead\")]\n        public Listing<PrivateMessage> GetThread()\n        {\n            return Thread;\n        }\n\n        #endregion Obsolete Gettter Methods\n\n        public void SetAsRead()\n        {\n            var request = WebAgent.CreatePost(SetAsReadUrl);\n            WebAgent.WritePostBody(request.GetRequestStream(), new\n            {\n                id = FullName,\n                uh = Reddit.User.Modhash,\n                api_type = \"json\"\n            });\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n        }\n\n        public void Reply(string message)\n        {\n            if (Reddit.User == null)\n                throw new AuthenticationException(\"No user logged in.\");\n            var request = WebAgent.CreatePost(CommentUrl);\n            var stream = request.GetRequestStream();\n            WebAgent.WritePostBody(stream, new\n            {\n                text = message,\n                thing_id = FullName,\n                uh = Reddit.User.Modhash\n            });\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            var json = JObject.Parse(data);\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/Things/RedditUser.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\n\nnamespace RedditSharp.Things\n{\n    public class RedditUser : Thing\n    {\n        private const string OverviewUrl = \"/user/{0}.json\";\n        private const string CommentsUrl = \"/user/{0}/comments.json\";\n        private const string LinksUrl = \"/user/{0}/submitted.json\";\n        private const string SubscribedSubredditsUrl = \"/subreddits/mine.json\";\n        private const string LikedUrl = \"/user/{0}/liked.json\";\n        private const string DislikedUrl = \"/user/{0}/disliked.json\";\n\n        private const int MAX_LIMIT = 100;\n\n        public RedditUser Init(Reddit reddit, JToken json, IWebAgent webAgent)\n        {\n            CommonInit(reddit, json, webAgent);\n            JsonConvert.PopulateObject(json[\"name\"] == null ? json[\"data\"].ToString() : json.ToString(), this,\n                reddit.JsonSerializerSettings);\n            return this;\n        }\n        public async Task<RedditUser> InitAsync(Reddit reddit, JToken json, IWebAgent webAgent)\n        {\n            CommonInit(reddit, json, webAgent);\n            await Task.Factory.StartNew(() => JsonConvert.PopulateObject(json[\"name\"] == null ? json[\"data\"].ToString() : json.ToString(), this,\n                reddit.JsonSerializerSettings));\n            return this;\n        }\n\n        private void CommonInit(Reddit reddit, JToken json, IWebAgent webAgent)\n        {\n            base.Init(json);\n            Reddit = reddit;\n            WebAgent = webAgent;\n        }\n\n        [JsonIgnore]\n        protected Reddit Reddit { get; set; }\n\n        [JsonIgnore]\n        protected IWebAgent WebAgent { get; set; }\n\n        [JsonProperty(\"name\")]\n        public string Name { get; set; }\n\n        [JsonProperty(\"is_gold\")]\n        public bool HasGold { get; set; }\n\n        [JsonProperty(\"is_mod\")]\n        public bool IsModerator { get; set; }\n\n        [JsonProperty(\"link_karma\")]\n        public int LinkKarma { get; set; }\n\n        [JsonProperty(\"comment_karma\")]\n        public int CommentKarma { get; set; }\n\n        [JsonProperty(\"created\")]\n        [JsonConverter(typeof(UnixTimestampConverter))]\n        public DateTime Created { get; set; }\n\n        public Listing<VotableThing> Overview\n        {\n            get\n            {\n                return new Listing<VotableThing>(Reddit, string.Format(OverviewUrl, Name), WebAgent);\n            }\n        }\n\n        public Listing<Post> LikedPosts\n        {\n            get\n            {\n                return new Listing<Post>(Reddit, string.Format(LikedUrl, Name), WebAgent);\n            }\n        }\n\n        public Listing<Post> DislikedPosts\n        {\n            get\n            {\n                return new Listing<Post>(Reddit, string.Format(DislikedUrl, Name), WebAgent);\n            }\n        }\n\n        public Listing<Comment> Comments\n        {\n            get\n            {\n                return new Listing<Comment>(Reddit, string.Format(CommentsUrl, Name), WebAgent);\n            }\n        }\n\n        public Listing<Post> Posts\n        {\n            get\n            {\n                return new Listing<Post>(Reddit, string.Format(LinksUrl, Name), WebAgent);\n            }\n        }\n\n        public Listing<Subreddit> SubscribedSubreddits\n        {\n            get\n            {\n                return new Listing<Subreddit>(Reddit, SubscribedSubredditsUrl, WebAgent);\n            }\n        }\n\n        /// <summary>\n        /// Get a listing of comments and posts from the user sorted by <paramref name=\"sorting\"/>, from time <paramref name=\"fromTime\"/>\n        /// and limited to <paramref name=\"limit\"/>.\n        /// </summary>\n        /// <param name=\"sorting\">How to sort the comments (hot, new, top, controversial).</param>\n        /// <param name=\"limit\">How many comments to fetch per request. Max is 100.</param>\n        /// <param name=\"fromTime\">What time frame of comments to show (hour, day, week, month, year, all).</param>\n        /// <returns>The listing of comments requested.</returns>\n        public Listing<VotableThing> GetOverview(Sort sorting = Sort.New, int limit = 25, FromTime fromTime = FromTime.All)\n        {\n            if ((limit < 1) || (limit > MAX_LIMIT))\n                throw new ArgumentOutOfRangeException(\"limit\", \"Valid range: [1,\" + MAX_LIMIT + \"]\");\n            string overviewUrl = string.Format(OverviewUrl, Name);\n            overviewUrl += string.Format(\"?sort={0}&limit={1}&t={2}\", Enum.GetName(typeof(Sort), sorting), limit, Enum.GetName(typeof(FromTime), fromTime));\n\n            return new Listing<VotableThing>(Reddit, overviewUrl, WebAgent);\n        }\n\n        /// <summary>\n        /// Get a listing of comments from the user sorted by <paramref name=\"sorting\"/>, from time <paramref name=\"fromTime\"/>\n        /// and limited to <paramref name=\"limit\"/>.\n        /// </summary>\n        /// <param name=\"sorting\">How to sort the comments (hot, new, top, controversial).</param>\n        /// <param name=\"limit\">How many comments to fetch per request. Max is 100.</param>\n        /// <param name=\"fromTime\">What time frame of comments to show (hour, day, week, month, year, all).</param>\n        /// <returns>The listing of comments requested.</returns>\n        public Listing<Comment> GetComments(Sort sorting = Sort.New, int limit = 25, FromTime fromTime = FromTime.All)\n        {\n            if ((limit < 1) || (limit > MAX_LIMIT))\n                throw new ArgumentOutOfRangeException(\"limit\", \"Valid range: [1,\" + MAX_LIMIT + \"]\");\n            string commentsUrl = string.Format(CommentsUrl, Name);\n            commentsUrl += string.Format(\"?sort={0}&limit={1}&t={2}\", Enum.GetName(typeof(Sort), sorting), limit, Enum.GetName(typeof(FromTime), fromTime));\n\n            return new Listing<Comment>(Reddit, commentsUrl, WebAgent);\n        }\n\n        /// <summary>\n        /// Get a listing of posts from the user sorted by <paramref name=\"sorting\"/>, from time <paramref name=\"fromTime\"/>\n        /// and limited to <paramref name=\"limit\"/>.\n        /// </summary>\n        /// <param name=\"sorting\">How to sort the posts (hot, new, top, controversial).</param>\n        /// <param name=\"limit\">How many posts to fetch per request. Max is 100.</param>\n        /// <param name=\"fromTime\">What time frame of posts to show (hour, day, week, month, year, all).</param>\n        /// <returns>The listing of posts requested.</returns>\n        public Listing<Post> GetPosts(Sort sorting = Sort.New, int limit = 25, FromTime fromTime = FromTime.All)\n        {\n            if ((limit < 1) || (limit > 100))\n                throw new ArgumentOutOfRangeException(\"limit\", \"Valid range: [1,100]\");\n            string linksUrl = string.Format(LinksUrl, Name);\n            linksUrl += string.Format(\"?sort={0}&limit={1}&t={2}\", Enum.GetName(typeof(Sort), sorting), limit, Enum.GetName(typeof(FromTime), fromTime));\n\n            return new Listing<Post>(Reddit, linksUrl, WebAgent);\n        }\n\n        public override string ToString()\n        {\n            return Name;\n        }\n\n        #region Obsolete Getter Methods\n\n        [Obsolete(\"Use Overview property instead\")]\n        public Listing<VotableThing> GetOverview()\n        {\n            return Overview;\n        }\n\n        [Obsolete(\"Use Comments property instead\")]\n        public Listing<Comment> GetComments()\n        {\n            return Comments;\n        }\n\n        [Obsolete(\"Use Posts property instead\")]\n        public Listing<Post> GetPosts()\n        {\n            return Posts;\n        }\n\n        [Obsolete(\"Use SubscribedSubreddits property instead\")]\n        public Listing<Subreddit> GetSubscribedSubreddits()\n        {\n            return SubscribedSubreddits;\n        }\n\n        #endregion Obsolete Getter Methods\n    }\n\n    public enum Sort\n    {\n        New,\n        Hot,\n        Top,\n        Controversial\n    }\n\n    public enum FromTime\n    {\n        All,\n        Year,\n        Month,\n        Week,\n        Day,\n        Hour\n    }\n}\n"
  },
  {
    "path": "RedditSharp/Things/Subreddit.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Security.Authentication;\nusing System.Threading.Tasks;\nusing HtmlAgilityPack;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing RedditSharp.Utils;\n\nnamespace RedditSharp.Things\n{\n    public class Subreddit : Thing\n    {\n        private const string SubredditPostUrl = \"/r/{0}.json\";\n        private const string SubredditNewUrl = \"/r/{0}/new.json?sort=new\";\n        private const string SubredditHotUrl = \"/r/{0}/hot.json\";\n        private const string SubredditRisingUrl = \"/r/{0}/rising.json\";\n        private const string SubredditTopUrl = \"/r/{0}/top.json?t={1}\";\n        private const string SubscribeUrl = \"/api/subscribe\";\n        private const string GetSettingsUrl = \"/r/{0}/about/edit.json\";\n        private const string GetReducedSettingsUrl = \"/r/{0}/about.json\";\n        private const string ModqueueUrl = \"/r/{0}/about/modqueue.json\";\n        private const string UnmoderatedUrl = \"/r/{0}/about/unmoderated.json\";\n        private const string FlairTemplateUrl = \"/api/flairtemplate\";\n        private const string ClearFlairTemplatesUrl = \"/api/clearflairtemplates\";\n        private const string SetUserFlairUrl = \"/api/flair\";\n        private const string StylesheetUrl = \"/r/{0}/about/stylesheet.json\";\n        private const string UploadImageUrl = \"/api/upload_sr_img\";\n        private const string FlairSelectorUrl = \"/api/flairselector\";\n        private const string AcceptModeratorInviteUrl = \"/api/accept_moderator_invite\";\n        private const string LeaveModerationUrl = \"/api/unfriend\";\n        private const string BanUserUrl = \"/api/friend\";\n        private const string AddModeratorUrl = \"/api/friend\";\n        private const string AddContributorUrl = \"/api/friend\";\n        private const string ModeratorsUrl = \"/r/{0}/about/moderators.json\";\n        private const string FrontPageUrl = \"/.json\";\n        private const string SubmitLinkUrl = \"/api/submit\";\n        private const string FlairListUrl = \"/r/{0}/api/flairlist.json\";\n        private const string CommentsUrl = \"/r/{0}/comments.json\";\n        private const string SearchUrl = \"/r/{0}/search.json?q={1}&restrict_sr=on&sort={2}&t={3}\";\n        private const string SearchUrlDate = \"/r/{0}/search.json?q=timestamp:{1}..{2}&restrict_sr=on&sort={3}&syntax=cloudsearch\";\n        private const string ModLogUrl = \"/r/{0}/about/log.json\";\n        private const string ContributorsUrl = \"/r/{0}/about/contributors.json\";\n\n        [JsonIgnore]\n        private Reddit Reddit { get; set; }\n\n        [JsonIgnore]\n        private IWebAgent WebAgent { get; set; }\n\n        [JsonIgnore]\n        public Wiki Wiki { get; private set; }\n\n        [JsonProperty(\"created\")]\n        [JsonConverter(typeof(UnixTimestampConverter))]\n        public DateTime? Created { get; set; }\n\n        [JsonProperty(\"description\")]\n        public string Description { get; set; }\n\n        [JsonProperty(\"description_html\")]\n        public string DescriptionHTML { get; set; }\n\n        [JsonProperty(\"display_name\")]\n        public string DisplayName { get; set; }\n\n        [JsonProperty(\"header_img\")]\n        public string HeaderImage { get; set; }\n\n        [JsonProperty(\"header_title\")]\n        public string HeaderTitle { get; set; }\n\n        [JsonProperty(\"over_18\")]\n        public bool NSFW { get; set; }\n\n        [JsonProperty(\"public_description\")]\n        public string PublicDescription { get; set; }\n\n        [JsonProperty(\"subscribers\")]\n        public int? Subscribers { get; set; }\n\n        [JsonProperty(\"accounts_active\")]\n        public int? ActiveUsers { get; set; }\n\n        [JsonProperty(\"title\")]\n        public string Title { get; set; }\n\n        [JsonProperty(\"url\")]\n        [JsonConverter(typeof(UrlParser))]\n        public Uri Url { get; set; }\n\n        /// <summary>\n        /// Property determining whether the current logged in user is a moderator on this subreddit.\n        /// </summary>\n        [JsonProperty(\"user_is_moderator\")]\n        public bool? UserIsModerator { get; set; }\n\n        /// <summary>\n        /// Property giving the moderator permissions of the logged in user on this subreddit.\n        /// </summary>\n        [JsonProperty(\"mod_permissions\")]\n        [JsonConverter(typeof(ModeratorPermissionConverter))]\n        public ModeratorPermission ModPermissions { get; set; }\n\n        /// <summary>\n        /// Property determining whether the current logged in user is banned from the subreddit.\n        /// </summary>\n        [JsonProperty(\"user_is_banned\")]\n        public bool? UserIsBanned { get; set; }\n\n        [JsonIgnore]\n        public string Name { get; set; }\n\n        public Listing<Post> GetTop(FromTime timePeriod)\n        {\n            if (Name == \"/\")\n            {\n                return new Listing<Post>(Reddit, \"/top.json?t=\" + Enum.GetName(typeof(FromTime), timePeriod).ToLower(), WebAgent);\n            }\n            return new Listing<Post>(Reddit, string.Format(SubredditTopUrl, Name, Enum.GetName(typeof(FromTime), timePeriod)).ToLower(), WebAgent);\n        }\n\n        public Listing<Post> Posts\n        {\n            get\n            {\n                if (Name == \"/\")\n                    return new Listing<Post>(Reddit, \"/.json\", WebAgent);\n                return new Listing<Post>(Reddit, string.Format(SubredditPostUrl, Name), WebAgent);\n            }\n        }\n\n        public Listing<Comment> Comments\n        {\n            get\n            {\n                if (Name == \"/\")\n                    return new Listing<Comment>(Reddit, \"/comments.json\", WebAgent);\n                return new Listing<Comment>(Reddit, string.Format(CommentsUrl, Name), WebAgent);\n            }\n        }\n\n        public Listing<Post> New\n        {\n            get\n            {\n                if (Name == \"/\")\n                    return new Listing<Post>(Reddit, \"/new.json\", WebAgent);\n                return new Listing<Post>(Reddit, string.Format(SubredditNewUrl, Name), WebAgent);\n            }\n        }\n\n        public Listing<Post> Hot\n        {\n            get\n            {\n                if (Name == \"/\")\n                    return new Listing<Post>(Reddit, \"/.json\", WebAgent);\n                return new Listing<Post>(Reddit, string.Format(SubredditHotUrl, Name), WebAgent);\n            }\n        }\n        public Listing<Post> Rising \n        {\n            get \n            {\n                if (Name == \"/\")\n                    return new Listing<Post>(Reddit, \"/.json\", WebAgent);\n                return new Listing<Post>(Reddit, string.Format(SubredditRisingUrl, Name), WebAgent);\n            }\n        }\n\n        public Listing<VotableThing> ModQueue\n        {\n            get\n            {\n                return new Listing<VotableThing>(Reddit, string.Format(ModqueueUrl, Name), WebAgent);\n            }\n        }\n\n        public Listing<Post> UnmoderatedLinks\n        {\n            get\n            {\n                return new Listing<Post>(Reddit, string.Format(UnmoderatedUrl, Name), WebAgent);\n            }\n        }\n\n        public Listing<Post> Search(string terms, Sorting sortE = Sorting.Relevance, TimeSorting timeE = TimeSorting.All)\n        {\n            string sort = sortE.ToString().ToLower();\n            string time = timeE.ToString().ToLower();\n\n            return new Listing<Post>(Reddit, string.Format(SearchUrl, Name, Uri.EscapeUriString(terms), sort, time), WebAgent);\n        }\n\n        public Listing<Post> Search(DateTime from, DateTime to, Sorting sortE = Sorting.New)\n        {\n            string sort = sortE.ToString().ToLower();\n\n            return new Listing<Post>(Reddit, string.Format(SearchUrlDate, Name, from.DateTimeToUnixTimestamp(), to.DateTimeToUnixTimestamp(), sort), WebAgent);\n        }\n        \n        public SubredditSettings Settings\n        {\n            get\n            {\n                if (Reddit.User == null)\n                    throw new AuthenticationException(\"No user logged in.\");\n                try\n                {\n                    var request = WebAgent.CreateGet(string.Format(GetSettingsUrl, Name));\n                    var response = request.GetResponse();\n                    var data = WebAgent.GetResponseString(response.GetResponseStream());\n                    var json = JObject.Parse(data);\n                    return new SubredditSettings(this, Reddit, json, WebAgent);\n                }\n                catch // TODO: More specific catch\n                {\n                    // Do it unauthed\n                    var request = WebAgent.CreateGet(string.Format(GetReducedSettingsUrl, Name));\n                    var response = request.GetResponse();\n                    var data = WebAgent.GetResponseString(response.GetResponseStream());\n                    var json = JObject.Parse(data);\n                    return new SubredditSettings(this, Reddit, json, WebAgent);\n                }\n            }\n        }\n\n        public UserFlairTemplate[] UserFlairTemplates // Hacky, there isn't a proper endpoint for this\n        {\n            get\n            {\n                var request = WebAgent.CreatePost(FlairSelectorUrl);\n                var stream = request.GetRequestStream();\n                WebAgent.WritePostBody(stream, new\n                {\n                    name = Reddit.User.Name,\n                    r = Name,\n                    uh = Reddit.User.Modhash\n                });\n                stream.Close();\n                var response = request.GetResponse();\n                var data = WebAgent.GetResponseString(response.GetResponseStream());\n                var document = new HtmlDocument();\n                document.LoadHtml(data);\n                if (document.DocumentNode.Descendants(\"div\").First().Attributes[\"error\"] != null)\n                    throw new InvalidOperationException(\"This subreddit does not allow users to select flair.\");\n                var templateNodes = document.DocumentNode.Descendants(\"li\");\n                var list = new List<UserFlairTemplate>();\n                foreach (var node in templateNodes)\n                {\n                    list.Add(new UserFlairTemplate\n                    {\n                        CssClass = node.Descendants(\"span\").First().Attributes[\"class\"].Value.Split(' ')[1],\n                        Text = node.Descendants(\"span\").First().InnerText\n                    });\n                }\n                return list.ToArray();\n            }\n        }\n\n        public SubredditStyle Stylesheet\n        {\n            get\n            {\n                var request = WebAgent.CreateGet(string.Format(StylesheetUrl, Name));\n                var response = request.GetResponse();\n                var data = WebAgent.GetResponseString(response.GetResponseStream());\n                var json = JToken.Parse(data);\n                return new SubredditStyle(Reddit, this, json, WebAgent);\n            }\n        }\n\n        public IEnumerable<ModeratorUser> Moderators\n        {\n            get\n            {\n                var request = WebAgent.CreateGet(string.Format(ModeratorsUrl, Name));\n                var response = request.GetResponse();\n                var responseString = WebAgent.GetResponseString(response.GetResponseStream());\n                var json = JObject.Parse(responseString);\n                var type = json[\"kind\"].ToString();\n                if (type != \"UserList\")\n                    throw new FormatException(\"Reddit responded with an object that is not a user listing.\");\n                var data = json[\"data\"];\n                var mods = data[\"children\"].ToArray();\n                var result = new ModeratorUser[mods.Length];\n                for (var i = 0; i < mods.Length; i++)\n                {\n                    var mod = new ModeratorUser(Reddit, mods[i]);\n                    result[i] = mod;\n                }\n                return result;\n            }\n        }\n\n        public IEnumerable<TBUserNote> UserNotes\n        {\n            get\n            {\n                return ToolBoxUserNotes.GetUserNotes(WebAgent, Name);\n            }\n        }\n\n        public Listing<Contributor> Contributors\n        {\n            get\n            {\n                return new Listing<Contributor>( Reddit, string.Format( ContributorsUrl, Name ), WebAgent );\n            }\n        }\n\n        public Subreddit Init(Reddit reddit, JToken json, IWebAgent webAgent)\n        {\n            CommonInit(reddit, json, webAgent);\n            JsonConvert.PopulateObject(json[\"data\"].ToString(), this, reddit.JsonSerializerSettings);\n            SetName();\n\n            return this;\n        }\n\n        public async Task<Subreddit> InitAsync(Reddit reddit, JToken json, IWebAgent webAgent)\n        {\n            CommonInit(reddit, json, webAgent);\n            await Task.Factory.StartNew(() => JsonConvert.PopulateObject(json[\"data\"].ToString(), this, reddit.JsonSerializerSettings));\n            SetName();\n\n            return this;\n        }\n\n        private void SetName()\n        {\n            Name = Url.ToString();\n            if (Name.StartsWith(\"/r/\"))\n                Name = Name.Substring(3);\n            if (Name.StartsWith(\"r/\"))\n                Name = Name.Substring(2);\n            Name = Name.TrimEnd('/');\n        }\n\n        private void CommonInit(Reddit reddit, JToken json, IWebAgent webAgent)\n        {\n            base.Init(json);\n            Reddit = reddit;\n            WebAgent = webAgent;\n            Wiki = new Wiki(reddit, this, webAgent);\n        }\n\n        public static Subreddit GetRSlashAll(Reddit reddit)\n        {\n            var rSlashAll = new Subreddit\n            {\n                DisplayName = \"/r/all\",\n                Title = \"/r/all\",\n                Url = new Uri(\"/r/all\", UriKind.Relative),\n                Name = \"all\",\n                Reddit = reddit,\n                WebAgent = reddit.WebAgent\n            };\n            return rSlashAll;\n        }\n\n        public static Subreddit GetFrontPage(Reddit reddit)\n        {\n            var frontPage = new Subreddit\n            {\n                DisplayName = \"Front Page\",\n                Title = \"reddit: the front page of the internet\",\n                Url = new Uri(\"/\", UriKind.Relative),\n                Name = \"/\",\n                Reddit = reddit,\n                WebAgent = reddit.WebAgent\n            };\n            return frontPage;\n        }\n\n        public void Subscribe()\n        {\n            if (Reddit.User == null)\n                throw new AuthenticationException(\"No user logged in.\");\n            var request = WebAgent.CreatePost(SubscribeUrl);\n            var stream = request.GetRequestStream();\n            WebAgent.WritePostBody(stream, new\n            {\n                action = \"sub\",\n                sr = FullName,\n                uh = Reddit.User.Modhash\n            });\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            // Discard results\n        }\n\n        public void Unsubscribe()\n        {\n            if (Reddit.User == null)\n                throw new AuthenticationException(\"No user logged in.\");\n            var request = WebAgent.CreatePost(SubscribeUrl);\n            var stream = request.GetRequestStream();\n            WebAgent.WritePostBody(stream, new\n            {\n                action = \"unsub\",\n                sr = FullName,\n                uh = Reddit.User.Modhash\n            });\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            // Discard results\n        }\n\n        public void ClearFlairTemplates(FlairType flairType)\n        {\n            var request = WebAgent.CreatePost(ClearFlairTemplatesUrl);\n            var stream = request.GetRequestStream();\n            WebAgent.WritePostBody(stream, new\n            {\n                flair_type = flairType == FlairType.Link ? \"LINK_FLAIR\" : \"USER_FLAIR\",\n                uh = Reddit.User.Modhash,\n                r = Name\n            });\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n        }\n\n        public void AddFlairTemplate(string cssClass, FlairType flairType, string text, bool userEditable)\n        {\n            var request = WebAgent.CreatePost(FlairTemplateUrl);\n            var stream = request.GetRequestStream();\n            WebAgent.WritePostBody(stream, new\n            {\n                css_class = cssClass,\n                flair_type = flairType == FlairType.Link ? \"LINK_FLAIR\" : \"USER_FLAIR\",\n                text = text,\n                text_editable = userEditable,\n                uh = Reddit.User.Modhash,\n                r = Name,\n                api_type = \"json\"\n            });\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            var json = JToken.Parse(data);\n        }\n\n        public string GetFlairText(string user)\n        {\n            var request = WebAgent.CreateGet(String.Format(FlairListUrl + \"?name=\" + user, Name));\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            var json = JToken.Parse(data);\n            return (string)json[\"users\"][0][\"flair_text\"];\n        }\n\n        public string GetFlairCssClass(string user)\n        {\n            var request = WebAgent.CreateGet(String.Format(FlairListUrl + \"?name=\" + user, Name));\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            var json = JToken.Parse(data);\n            return (string)json[\"users\"][0][\"flair_css_class\"];\n        }\n\n        public void SetUserFlair(string user, string cssClass, string text)\n        {\n            var request = WebAgent.CreatePost(SetUserFlairUrl);\n            var stream = request.GetRequestStream();\n            WebAgent.WritePostBody(stream, new\n            {\n                css_class = cssClass,\n                text = text,\n                uh = Reddit.User.Modhash,\n                r = Name,\n                name = user\n            });\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n        }\n\n        public void UploadHeaderImage(string name, ImageType imageType, byte[] file)\n        {\n            var request = WebAgent.CreatePost(UploadImageUrl);\n            var formData = new MultipartFormBuilder(request);\n            formData.AddDynamic(new\n            {\n                name,\n                uh = Reddit.User.Modhash,\n                r = Name,\n                formid = \"image-upload\",\n                img_type = imageType == ImageType.PNG ? \"png\" : \"jpg\",\n                upload = \"\",\n                header = 1\n            });\n            formData.AddFile(\"file\", \"foo.png\", file, imageType == ImageType.PNG ? \"image/png\" : \"image/jpeg\");\n            formData.Finish();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            // TODO: Detect errors\n        }\n\n        public void AddModerator(string user)\n        {\n            var request = WebAgent.CreatePost(AddModeratorUrl);\n            WebAgent.WritePostBody(request.GetRequestStream(), new\n            {\n                api_type = \"json\",\n                uh = Reddit.User.Modhash,\n                r = Name,\n                type = \"moderator\",\n                name = user\n            });\n            var response = request.GetResponse();\n            var result = WebAgent.GetResponseString(response.GetResponseStream());\n        }\n\n        public void AcceptModeratorInvite()\n        {\n            var request = WebAgent.CreatePost(AcceptModeratorInviteUrl);\n            WebAgent.WritePostBody(request.GetRequestStream(), new\n            {\n                api_type = \"json\",\n                uh = Reddit.User.Modhash,\n                r = Name\n            });\n            var response = request.GetResponse();\n            var result = WebAgent.GetResponseString(response.GetResponseStream());\n        }\n\n        public void RemoveModerator(string id)\n        {\n            var request = WebAgent.CreatePost(LeaveModerationUrl);\n            WebAgent.WritePostBody(request.GetRequestStream(), new\n            {\n                api_type = \"json\",\n                uh = Reddit.User.Modhash,\n                r = Name,\n                type = \"moderator\",\n                id\n            });\n            var response = request.GetResponse();\n            var result = WebAgent.GetResponseString(response.GetResponseStream());\n        }\n\n        public override string ToString()\n        {\n            return \"/r/\" + DisplayName;\n        }\n\n        public void AddContributor(string user)\n        {\n            var request = WebAgent.CreatePost(AddContributorUrl);\n            WebAgent.WritePostBody(request.GetRequestStream(), new\n            {\n                api_type = \"json\",\n                uh = Reddit.User.Modhash,\n                r = Name,\n                type = \"contributor\",\n                name = user\n            });\n            var response = request.GetResponse();\n            var result = WebAgent.GetResponseString(response.GetResponseStream());\n        }\n\n        public void RemoveContributor(string id)\n        {\n            var request = WebAgent.CreatePost(LeaveModerationUrl);\n            WebAgent.WritePostBody(request.GetRequestStream(), new\n            {\n                api_type = \"json\",\n                uh = Reddit.User.Modhash,\n                r = Name,\n                type = \"contributor\",\n                id\n            });\n            var response = request.GetResponse();\n            var result = WebAgent.GetResponseString(response.GetResponseStream());\n        }\n\n        public void BanUser(string user, string reason)\n        {\n            var request = WebAgent.CreatePost(BanUserUrl);\n            WebAgent.WritePostBody(request.GetRequestStream(), new\n            {\n                api_type = \"json\",\n                uh = Reddit.User.Modhash,\n                r = Name,\n                type = \"banned\",\n                id = \"#banned\",\n                name = user,\n                note = reason,\n                action = \"add\",\n                container = FullName\n            });\n            var response = request.GetResponse();\n            var result = WebAgent.GetResponseString(response.GetResponseStream());\n        }\n\n        private Post Submit(SubmitData data)\n        {\n            if (Reddit.User == null)\n                throw new RedditException(\"No user logged in.\");\n            var request = WebAgent.CreatePost(SubmitLinkUrl);\n\n            WebAgent.WritePostBody(request.GetRequestStream(), data);\n\n            var response = request.GetResponse();\n            var result = WebAgent.GetResponseString(response.GetResponseStream());\n            var json = JToken.Parse(result);\n\n            ICaptchaSolver solver = Reddit.CaptchaSolver;\n            if (json[\"json\"][\"errors\"].Any() && json[\"json\"][\"errors\"][0][0].ToString() == \"BAD_CAPTCHA\"\n                && solver != null)\n            {\n                data.Iden = json[\"json\"][\"captcha\"].ToString();\n                CaptchaResponse captchaResponse = solver.HandleCaptcha(new Captcha(data.Iden));\n\n                // We throw exception due to this method being expected to return a valid Post object, but we cannot\n                // if we got a Captcha error.\n                if (captchaResponse.Cancel)\n                    throw new CaptchaFailedException(\"Captcha verification failed when submitting \" + data.Kind + \" post\");\n\n                data.Captcha = captchaResponse.Answer;\n                return Submit(data);\n            }\n            else if (json[\"json\"][\"errors\"].Any() && json[\"json\"][\"errors\"][0][0].ToString() == \"ALREADY_SUB\")\n            {\n                throw new DuplicateLinkException(String.Format(\"Post failed when submitting.  The following link has already been submitted: {0}\", SubmitLinkUrl));\n            }\n\n            return new Post().Init(Reddit, json[\"json\"], WebAgent);\n        }\n\n        /// <summary>\n        /// Submits a link post in the current subreddit using the logged-in user\n        /// </summary>\n        /// <param name=\"title\">The title of the submission</param>\n        /// <param name=\"url\">The url of the submission link</param>\n        public Post SubmitPost(string title, string url, string captchaId = \"\", string captchaAnswer = \"\", bool resubmit = false)\n        {\n            return\n                Submit(\n                    new LinkData\n                    {\n                        Subreddit = Name,\n                        UserHash = Reddit.User.Modhash,\n                        Title = title,\n                        URL = url,\n                        Resubmit = resubmit,\n                        Iden = captchaId,\n                        Captcha = captchaAnswer\n                    });\n        }\n\n        /// <summary>\n        /// Submits a text post in the current subreddit using the logged-in user\n        /// </summary>\n        /// <param name=\"title\">The title of the submission</param>\n        /// <param name=\"text\">The raw markdown text of the submission</param>\n        public Post SubmitTextPost(string title, string text, string captchaId = \"\", string captchaAnswer = \"\")\n        {\n            return\n                Submit(\n                    new TextData\n                    {\n                        Subreddit = Name,\n                        UserHash = Reddit.User.Modhash,\n                        Title = title,\n                        Text = text,\n                        Iden = captchaId,\n                        Captcha = captchaAnswer\n                    });\n        }\n        /// <summary>\n        /// Gets the moderation log of the current subreddit\n        /// </summary>\n        public Listing<ModAction> GetModerationLog()\n        {\n            return new Listing<ModAction>(Reddit, string.Format(ModLogUrl, this.Name), WebAgent);\n        }\n        /// <summary>\n        /// Gets the moderation log of the current subreddit filtered by the action taken\n        /// </summary>\n        /// <param name=\"action\">ModActionType of action performed</param>\n        public Listing<ModAction> GetModerationLog(ModActionType action)\n        {\n            return new Listing<ModAction>(Reddit, string.Format(ModLogUrl + \"?type={1}\", Name, ModActionTypeConverter.GetRedditParamName(action)), WebAgent);\n        }\n        /// <summary>\n        /// Gets the moderation log of the current subreddit filtered by moderator(s) who performed the action\n        /// </summary>\n        /// <param name=\"mods\">String array of mods to filter by</param>\n        public Listing<ModAction> GetModerationLog(string[] mods)\n        {\n            return new Listing<ModAction>(Reddit, string.Format(ModLogUrl + \"?mod={1}\", Name, string.Join(\",\", mods)), WebAgent);\n        }\n        /// <summary>\n        /// Gets the moderation log of the current subreddit filtered by the action taken and moderator(s) who performed the action\n        /// </summary>\n        /// <param name=\"action\">ModActionType of action performed</param>\n        /// <param name=\"mods\">String array of mods to filter by</param>\n        /// <returns></returns>\n        public Listing<ModAction> GetModerationLog(ModActionType action, string[] mods)\n        {\n            return new Listing<ModAction>(Reddit, string.Format(ModLogUrl + \"?type={1}&mod={2}\", Name, ModActionTypeConverter.GetRedditParamName(action), string.Join(\",\", mods)), WebAgent);\n        }\n        #region Obsolete Getter Methods\n\n        [Obsolete(\"Use Posts property instead\")]\n        public Listing<Post> GetPosts()\n        {\n            return Posts;\n        }\n\n        [Obsolete(\"Use New property instead\")]\n        public Listing<Post> GetNew()\n        {\n            return New;\n        }\n\n        [Obsolete(\"Use Hot property instead\")]\n        public Listing<Post> GetHot()\n        {\n            return Hot;\n        }\n\n        [Obsolete(\"Use ModQueue property instead\")]\n        public Listing<VotableThing> GetModQueue()\n        {\n            return ModQueue;\n        }\n\n        [Obsolete(\"Use UnmoderatedLinks property instead\")]\n        public Listing<Post> GetUnmoderatedLinks()\n        {\n            return UnmoderatedLinks;\n        }\n\n        [Obsolete(\"Use Settings property instead\")]\n        public SubredditSettings GetSettings()\n        {\n            return Settings;\n        }\n\n        [Obsolete(\"Use UserFlairTemplates property instead\")]\n        public UserFlairTemplate[] GetUserFlairTemplates() // Hacky, there isn't a proper endpoint for this\n        {\n            return UserFlairTemplates;\n        }\n\n        [Obsolete(\"Use Stylesheet property instead\")]\n        public SubredditStyle GetStylesheet()\n        {\n            return Stylesheet;\n        }\n\n        [Obsolete(\"Use Moderators property instead\")]\n        public IEnumerable<ModeratorUser> GetModerators()\n        {\n            return Moderators;\n        }\n\n        #endregion Obsolete Getter Methods\n    }\n}\n"
  },
  {
    "path": "RedditSharp/Things/Thing.cs",
    "content": "using System;\nusing Newtonsoft.Json.Linq;\nusing System.Threading.Tasks;\n\nnamespace RedditSharp.Things\n{\n    public class Thing\n    {\n        public static Thing Parse(Reddit reddit, JToken json, IWebAgent webAgent)\n        {\n            var kind = json[\"kind\"].ValueOrDefault<string>();\n            switch (kind)\n            {\n                case \"t1\":\n                    return new Comment().Init(reddit, json, webAgent, null);\n                case \"t2\":\n                    return new RedditUser().Init(reddit, json, webAgent);\n                case \"t3\":\n                    return new Post().Init(reddit, json, webAgent);\n                case \"t4\":\n                    return new PrivateMessage().Init(reddit, json, webAgent);\n                case \"t5\":\n                    return new Subreddit().Init(reddit, json, webAgent);\n                case \"modaction\":\n                    return new ModAction().Init(reddit, json, webAgent);\n                default:\n                    return null;\n            }\n        }\n\n        // if we can't determine the type of thing by \"kind\", try by type\n        public static Thing Parse<T>(Reddit reddit, JToken json, IWebAgent webAgent) where T : Thing\n        {\n            Thing result = Parse(reddit, json, webAgent);\n            if (result == null)\n            {\n                if (typeof(T) == typeof(WikiPageRevision))\n                {\n                    return new WikiPageRevision().Init(reddit, json, webAgent);\n                }\n                else if (typeof(T) == typeof(ModAction))\n                {\n                    return new ModAction().Init(reddit, json, webAgent);\n                }\n                else if (typeof(T) == typeof(Contributor)) \n                {\n                    return new Contributor().Init(reddit, json, webAgent);\n                }\n            }\n            return result;\n        }\n\n        internal void Init(JToken json)\n        {\n            if (json == null)\n                return;\n            var data = json[\"name\"] == null ? json[\"data\"] : json;\n            FullName = data[\"name\"].ValueOrDefault<string>();\n            Id = data[\"id\"].ValueOrDefault<string>();\n            Kind = json[\"kind\"].ValueOrDefault<string>();\n            FetchedAt = DateTime.Now;\n        }\n\n        public virtual string Shortlink\n        {\n            get { return \"http://redd.it/\" + Id; }\n        }\n\n        public string Id { get; set; }\n        public string FullName { get; set; }\n        public string Kind { get; set; }\n\n        /// <summary>\n        /// The time at which this object was fetched from reddit servers.\n        /// </summary>\n        public DateTime FetchedAt { get; private set; }\n\n        /// <summary>\n        /// Gets the time since last fetch from reddit servers.\n        /// </summary>\n        public TimeSpan TimeSinceFetch\n        {\n            get\n            {\n                return DateTime.Now - FetchedAt;\n            }\n        }\n\n        public static async Task<Thing> ParseAsync(Reddit reddit, JToken json, IWebAgent webAgent)\n        {\n            var kind = json[\"kind\"].ValueOrDefault<string>();\n            switch (kind)\n            {\n                case \"t1\":\n                    return await new Comment().InitAsync(reddit, json, webAgent, null);\n                case \"t2\":\n                    return await new RedditUser().InitAsync(reddit, json, webAgent);\n                case \"t3\":\n                    return await new Post().InitAsync(reddit, json, webAgent);\n                case \"t4\":\n                    return await new PrivateMessage().InitAsync(reddit, json, webAgent);\n                case \"t5\":\n                    return await new Subreddit().InitAsync(reddit, json, webAgent);\n                case \"modaction\":\n                    return await new ModAction().InitAsync(reddit, json, webAgent);\n                default:\n                    return null;\n            }\n        }\n\n        // if we can't determine the type of thing by \"kind\", try by type\n        public static async Task<Thing> ParseAsync<T>(Reddit reddit, JToken json, IWebAgent webAgent) where T : Thing\n        {\n            Thing result = await ParseAsync(reddit, json, webAgent);\n            if (result == null)\n            {\n                if (typeof(T) == typeof(WikiPageRevision))\n                {\n                    return await new WikiPageRevision().InitAsync(reddit, json, webAgent);\n                }\n                else if (typeof(T) == typeof(ModAction))\n                {\n                    return await new ModAction().InitAsync(reddit, json, webAgent);\n                }\n            }\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/Things/VotableThing.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing System.Linq;\nusing System.Security.Authentication;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\n\nnamespace RedditSharp.Things\n{\n    public class VotableThing : CreatedThing\n    {\n        public enum VoteType\n        {\n            Upvote = 1,\n            None = 0,\n            Downvote = -1\n        }\n\n        public enum ReportType\n        {\n            Spam = 0,\n            VoteManipulation = 1,\n            PersonalInformation = 2,\n            SexualizingMinors = 3,\n            BreakingReddit = 4,\n            Other = 5\n        }\n\n        public enum DistinguishType\n        {\n            Moderator,\n            Admin,\n            Special,\n            None\n        }\n\n        private const string VoteUrl = \"/api/vote\";\n        private const string SaveUrl = \"/api/save\";\n        private const string UnsaveUrl = \"/api/unsave\";\n        private const string ReportUrl = \"/api/report\";\n        private const string DistinguishUrl = \"/api/distinguish\";\n\n        [JsonIgnore]\n        private IWebAgent WebAgent { get; set; }\n\n        [JsonIgnore]\n        private Reddit Reddit { get; set; }\n\n        protected VotableThing Init(Reddit reddit, IWebAgent webAgent, JToken json)\n        {\n            CommonInit(reddit, webAgent, json);\n            JsonConvert.PopulateObject(json[\"data\"].ToString(), this, Reddit.JsonSerializerSettings);\n            return this;\n        }\n        protected async Task<VotableThing> InitAsync(Reddit reddit, IWebAgent webAgent, JToken json)\n        {\n            CommonInit(reddit, webAgent, json);\n            await Task.Factory.StartNew(() => JsonConvert.PopulateObject(json[\"data\"].ToString(), this, Reddit.JsonSerializerSettings));\n            return this;\n        }\n\n        private void CommonInit(Reddit reddit, IWebAgent webAgent, JToken json)\n        {\n            base.Init(reddit, json);\n            Reddit = reddit;\n            WebAgent = webAgent;\n        }\n\n\n        [JsonProperty(\"downs\")]\n        public int Downvotes { get; set; }\n        [JsonProperty(\"ups\")]\n        public int Upvotes { get; set; }\n        [JsonProperty(\"score\")]\n        public int Score { get; set; }\n        [JsonProperty(\"saved\")]\n        public bool Saved { get; set; }\n        [JsonProperty(\"distinguished\")]\n        [JsonConverter(typeof(DistinguishConverter))]\n        public DistinguishType Distinguished { get; set; }\n\n        /// <summary>\n        /// True if the logged in user has upvoted this.\n        /// False if they have not.\n        /// Null if they have not cast a vote.\n        /// </summary>\n        [JsonProperty(\"likes\")]\n        public bool? Liked { get; set; }\n\n        /// <summary>\n        /// Gets or sets the vote for the current VotableThing.\n        /// </summary>\n        [JsonIgnore]\n        public VoteType Vote\n        {\n            get\n            {\n                switch (this.Liked)\n                {\n                    case true: return VoteType.Upvote;\n                    case false: return VoteType.Downvote;\n\n                    default: return VoteType.None;\n                }\n            }\n            set { this.SetVote(value); }\n        }\n\n        public void Upvote()\n        {\n            this.SetVote(VoteType.Upvote);\n        }\n\n        public void Downvote()\n        {\n            this.SetVote(VoteType.Downvote);\n        }\n\n        public void SetVote(VoteType type)\n        {\n            if (this.Vote == type) return;\n\n            var request = WebAgent.CreatePost(VoteUrl);\n            var stream = request.GetRequestStream();\n            WebAgent.WritePostBody(stream, new\n            {\n                dir = (int)type,\n                id = FullName,\n                uh = Reddit.User.Modhash\n            });\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n\n            if (Liked == true) Upvotes--;\n            if (Liked == false) Downvotes--;\n\n            switch(type)\n            {\n                case VoteType.Upvote: Liked = true; Upvotes++; return;\n                case VoteType.None: Liked = null; return;\n                case VoteType.Downvote: Liked = false; Downvotes++; return;\n            }\n        }\n\n        public void Save()\n        {\n            var request = WebAgent.CreatePost(SaveUrl);\n            var stream = request.GetRequestStream();\n            WebAgent.WritePostBody(stream, new\n            {\n                id = FullName,\n                uh = Reddit.User.Modhash\n            });\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            Saved = true;\n        }\n\n        public void Unsave()\n        {\n            var request = WebAgent.CreatePost(UnsaveUrl);\n            var stream = request.GetRequestStream();\n            WebAgent.WritePostBody(stream, new\n            {\n                id = FullName,\n                uh = Reddit.User.Modhash\n            });\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            Saved = false;\n        }\n\n        public void ClearVote()\n        {\n            var request = WebAgent.CreatePost(VoteUrl);\n            var stream = request.GetRequestStream();\n            WebAgent.WritePostBody(stream, new\n            {\n                dir = 0,\n                id = FullName,\n                uh = Reddit.User.Modhash\n            });\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n        }\n\n        public void Report(ReportType reportType, string otherReason = null)\n        {\n            var request = WebAgent.CreatePost(ReportUrl);\n            var stream = request.GetRequestStream();\n\n            string reportReason;\n            switch (reportType)\n            {\n                case ReportType.Spam:\n                    reportReason = \"spam\"; break;\n                case ReportType.VoteManipulation:\n                    reportReason = \"vote manipulation\"; break;\n                case ReportType.PersonalInformation:\n                    reportReason = \"personal information\"; break;\n                case ReportType.BreakingReddit:\n                    reportReason = \"breaking reddit\"; break;\n                case ReportType.SexualizingMinors:\n                    reportReason = \"sexualizing minors\"; break;\n                default:\n                    reportReason = \"other\"; break;\n            }\n\n            WebAgent.WritePostBody(stream, new\n            {\n                api_type = \"json\",\n                reason = reportReason,\n                other_reason = otherReason ?? \"\",\n                thing_id = FullName,\n                uh = Reddit.User.Modhash\n            });\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n        }\n\n        public void Distinguish(DistinguishType distinguishType)\n        {\n            if (Reddit.User == null)\n                throw new AuthenticationException(\"No user logged in.\");\n            var request = WebAgent.CreatePost(DistinguishUrl);\n            var stream = request.GetRequestStream();\n            string how;\n            switch (distinguishType)\n            {\n                case DistinguishType.Admin:\n                    how = \"admin\";\n                    break;\n                case DistinguishType.Moderator:\n                    how = \"yes\";\n                    break;\n                case DistinguishType.None:\n                    how = \"no\";\n                    break;\n                default:\n                    how = \"special\";\n                    break;\n            }\n            WebAgent.WritePostBody(stream, new\n            {\n                how,\n                id = Id,\n                uh = Reddit.User.Modhash\n            });\n            stream.Close();\n            var response = request.GetResponse();\n            var data = WebAgent.GetResponseString(response.GetResponseStream());\n            var json = JObject.Parse(data);\n            if (json[\"jquery\"].Count(i => i[0].Value<int>() == 11 && i[1].Value<int>() == 12) == 0)\n                throw new AuthenticationException(\"You are not permitted to distinguish this comment.\");\n        }\n\n        internal class DistinguishConverter : JsonConverter\n        {\n            public override bool CanConvert(Type objectType)\n            {\n                return objectType == typeof(DistinguishType) || objectType == typeof(string);\n            }\n\n            public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)\n            {\n                var token = JToken.Load(reader);\n                var value = token.Value<string>();\n                if (value == null)\n                    return DistinguishType.None;\n                switch (value)\n                {\n                    case \"moderator\": return DistinguishType.Moderator;\n                    case \"admin\": return DistinguishType.Admin;\n                    case \"special\": return DistinguishType.Special;\n                    default: return DistinguishType.None;\n                }\n            }\n\n            public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)\n            {\n                var d = (DistinguishType)value;\n                if (d == DistinguishType.None)\n                {\n                    writer.WriteNull();\n                    return;\n                }\n                writer.WriteValue(d.ToString().ToLower());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/Things/WikiPageRevision.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\n\nnamespace RedditSharp.Things\n{\n    public class WikiPageRevision : Thing\n    {\n        [JsonProperty(\"id\")]\n        new public string Id { get; private set; }\n\n        [JsonProperty(\"timestamp\")]\n        [JsonConverter(typeof(UnixTimestampConverter))]\n        public DateTime? TimeStamp { get; set; }\n\n        [JsonProperty(\"reason\")]\n        public string Reason { get; private set; }\n\n        [JsonProperty(\"page\")]\n        public string Page { get; private set; }\n\n        [JsonIgnore]\n        public RedditUser Author { get; set; }\n\n        protected internal WikiPageRevision() { }\n\n        internal WikiPageRevision Init(Reddit reddit, JToken json, IWebAgent webAgent)\n        {\n            CommonInit(reddit, json, webAgent);\n            JsonConvert.PopulateObject(json.ToString(), this, reddit.JsonSerializerSettings);\n            return this;\n        }        \n\n        internal async Task<WikiPageRevision> InitAsync(Reddit reddit, JToken json, IWebAgent webAgent)\n        {\n            CommonInit(reddit, json, webAgent);\n            await Task.Factory.StartNew(() => JsonConvert.PopulateObject(json.ToString(), this, reddit.JsonSerializerSettings));\n            return this;\n        }\n\n        private void CommonInit(Reddit reddit, JToken json, IWebAgent webAgent)\n        {\n            base.Init(json);\n            Author = new RedditUser().Init(reddit, json[\"author\"], webAgent);\n        }\n    }\n}"
  },
  {
    "path": "RedditSharp/ToolBoxUserNotes.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Newtonsoft.Json.Linq;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\nusing System.IO.Compression;\n\nnamespace RedditSharp\n{\n    public static class ToolBoxUserNotes\n    {\n        private const string ToolBoxUserNotesWiki = \"/r/{0}/wiki/usernotes\";\n        public static IEnumerable<TBUserNote> GetUserNotes(IWebAgent webAgent, string subName)\n        {\n            var request = webAgent.CreateGet(String.Format(ToolBoxUserNotesWiki, subName));\n            var reqResponse = webAgent.ExecuteRequest(request);\n            var response = JObject.Parse(reqResponse[\"data\"][\"content_md\"].Value<string>());\n\n            int version = response[\"ver\"].Value<int>();\n            string[] mods = response[\"constants\"][\"users\"].Values<string>().ToArray();\n\n            string[] warnings = response[\"constants\"][\"warnings\"].Values<string>().ToArray();\n\n            if (version < 6) throw new ToolBoxUserNotesException(\"Unsupported ToolBox version\");\n\n            try\n            {\n                var data = Convert.FromBase64String(response[\"blob\"].Value<string>());\n\n                string uncompressed;\n                using (System.IO.MemoryStream compressedStream = new System.IO.MemoryStream(data))\n                {\n                    compressedStream.ReadByte();\n                    compressedStream.ReadByte(); //skips first to bytes to fix zlib block size\n                    using (DeflateStream blobStream = new DeflateStream(compressedStream, CompressionMode.Decompress))\n                    {\n                        using (var decompressedReader = new System.IO.StreamReader(blobStream))\n                        {\n                            uncompressed = decompressedReader.ReadToEnd();\n                        }\n\n                    }\n                }\n\n                JObject users = JObject.Parse(uncompressed);\n\n                List<TBUserNote> toReturn = new List<TBUserNote>();\n                foreach (KeyValuePair<string, JToken> user in users)\n                {\n                    var x = user.Value;\n                    foreach (JToken note in x[\"ns\"].Children())\n                    {\n\n                        TBUserNote uNote = new TBUserNote();\n                        uNote.AppliesToUsername = user.Key;\n                        uNote.SubName = subName;\n                        uNote.SubmitterIndex = note[\"m\"].Value<int>();\n                        uNote.Submitter = mods[uNote.SubmitterIndex];\n                        uNote.NoteTypeIndex = note[\"w\"].Value<int>();\n                        uNote.NoteType = warnings[uNote.NoteTypeIndex];\n                        uNote.Message = note[\"n\"].Value<string>();\n                        uNote.Timestamp = UnixTimeStamp.UnixTimeStampToDateTime(note[\"t\"].Value<long>());\n                        uNote.Url = UnsquashLink(subName, note[\"l\"].ValueOrDefault<string>());\n\n                        toReturn.Add(uNote);\n                    }\n                }\n                return toReturn;\n            }\n            catch (Exception e)\n            {\n                throw new ToolBoxUserNotesException(\"An error occured while processing Usernotes wiki. See inner exception for details\", e);\n            }\n        }\n        public static string UnsquashLink(string subreddit, string permalink)\n        {\n            var link = \"https://reddit.com/r/\" + subreddit + \"/\";\n            if (string.IsNullOrEmpty(permalink))\n            {\n                return link;\n            }\n            var linkParams = permalink.Split(',');\n\n            if (linkParams[0] == \"l\")\n            {\n                link += \"comments/\" + linkParams[1] + \"/\";\n                if (linkParams.Length > 2)\n                    link += \"-/\" + linkParams[2] + \"/\";\n            }\n            else if (linkParams[0] == \"m\")\n            {\n                link += \"message/messages/\" + linkParams[1];\n            }\n            return link;\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/ToolBoxUserNotesException.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace RedditSharp\n{\n    class ToolBoxUserNotesException : Exception\n    {\n        public ToolBoxUserNotesException()\n        {\n        }\n\n        public ToolBoxUserNotesException(string message)\n            : base(message)\n        {\n        }\n\n        public ToolBoxUserNotesException(string message, Exception inner)\n            : base(message, inner)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/UnixTimeStamp.cs",
    "content": "﻿using System;\n\nnamespace RedditSharp\n{\n    public static class UnixTimeStamp\n    {\n        public static DateTime UnixTimeStampToDateTime(this long unixTimeStamp)\n        {\n            // Unix timestamp is seconds past epoch\n            var dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);\n            dtDateTime = dtDateTime.AddSeconds(unixTimeStamp);\n            return dtDateTime;\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/UnixTimestampConverter.cs",
    "content": "﻿using Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing System;\n\nnamespace RedditSharp\n{\n    public class UnixTimestampConverter : JsonConverter\n    {\n        public override bool CanConvert(Type objectType)\n        {\n            return objectType == typeof(double) || objectType == typeof(DateTime);\n        }\n\n        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)\n        {\n            var token = JToken.Load(reader);\n            return token.Value<long>().UnixTimeStampToDateTime();\n        }\n\n        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)\n        {\n            writer.WriteValue(value);\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/UrlParser.cs",
    "content": "﻿using Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing System;\n\nnamespace RedditSharp\n{\n    class UrlParser : JsonConverter\n    {\n        public override bool CanConvert(Type objectType)\n        {\n            return objectType == typeof(String) || objectType == typeof(Uri);\n        }\n\n        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)\n        {\n            var token = JToken.Load(reader);\n\n            if (token.Type == JTokenType.String)\n            {\n                if (Type.GetType(\"Mono.Runtime\") == null)\n                    return new Uri(token.Value<string>(), UriKind.RelativeOrAbsolute);\n                if (token.Value<string>().StartsWith(\"/\"))\n                    return new Uri(token.Value<string>(), UriKind.Relative);\n                return new Uri(token.Value<string>(), UriKind.RelativeOrAbsolute);\n            }\n            else\n                return token.Value<Uri>();\n        }\n\n        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)\n        {\n            writer.WriteValue(value);\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/Utils/DateTimeExtensions.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace RedditSharp.Utils\n{\n    internal static class DateTimeExtensions\n    {\n        public static double DateTimeToUnixTimestamp(this DateTime dateTime)\n        {\n            double time = (dateTime - new DateTime(1970, 1, 1).ToLocalTime()).TotalSeconds;\n\n            return Convert.ToInt32(time);\n        }\n    }\n}"
  },
  {
    "path": "RedditSharp/WebAgent.cs",
    "content": "using System;\nusing System.Dynamic;\nusing System.IO;\nusing System.Linq;\nusing System.Net;\nusing System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Text;\nusing System.Threading;\nusing System.Web;\nusing Newtonsoft.Json.Linq;\n\nnamespace RedditSharp\n{\n    public class WebAgent : IWebAgent\n    {\n        /// <summary>\n        /// Additional values to append to the default RedditSharp user agent.\n        /// </summary>\n        public static string UserAgent { get; set; }\n\n        /// <summary>\n        /// It is strongly advised that you leave this enabled. Reddit bans excessive\n        /// requests with extreme predjudice.\n        /// </summary>\n        public static bool EnableRateLimit { get; set; }\n\n        public static string Protocol { get; set; }\n\n        /// <summary>\n        /// It is strongly advised that you leave this set to Burst or Pace. Reddit bans excessive\n        /// requests with extreme predjudice.\n        /// </summary>\n        public static RateLimitMode RateLimit { get; set; }\n\n        /// <summary>\n        /// The method by which the WebAgent will limit request rate\n        /// </summary>\n        public enum RateLimitMode\n        {\n            /// <summary>\n            /// Limits requests to one every two seconds\n            /// </summary>\n            Pace,\n            /// <summary>\n            /// Restricts requests to five per ten seconds\n            /// </summary>\n            SmallBurst,\n            /// <summary>\n            /// Restricts requests to thirty per minute\n            /// </summary>\n            Burst,\n            /// <summary>\n            /// Does not restrict request rate. ***NOT RECOMMENDED***\n            /// </summary>\n            None\n        }\n\n        /// <summary>\n        /// The root domain RedditSharp uses to address Reddit.\n        /// www.reddit.com by default\n        /// </summary>\n        public static string RootDomain { get; set; }\n\n        /// <summary>\n        /// Used to make calls against Reddit's API using OAuth23\n        /// </summary>\n        public string AccessToken { get; set; }\n\n        public CookieContainer Cookies { get; set; }\n        public string AuthCookie { get; set; }\n\n        private static DateTime _lastRequest;\n        private static DateTime _burstStart;\n        private static int _requestsThisBurst;\n        /// <summary>\n        /// UTC DateTime of last request made to Reddit API\n        /// </summary>\n        public DateTime LastRequest \n        {\n            get { return _lastRequest; }\n        }\n        /// <summary>\n        /// UTC DateTime of when the last burst started\n        /// </summary>\n        public DateTime BurstStart \n        {\n            get { return _burstStart; }\n        }\n        /// <summary>\n        /// Number of requests made during the current burst \n        /// </summary>\n        public int RequestsThisBurst \n        {\n            get { return _requestsThisBurst; }\n        }\n\n\n        public virtual JToken CreateAndExecuteRequest(string url)\n        {\n            Uri uri;\n            if (!Uri.TryCreate(url, UriKind.Absolute, out uri))\n            {\n                if (!Uri.TryCreate(String.Format(\"{0}://{1}{2}\", Protocol, RootDomain, url), UriKind.Absolute, out uri))\n                    throw new Exception(\"Could not parse Uri\");\n            }\n            var request = CreateGet(uri);\n            try { return ExecuteRequest(request); }\n            catch (Exception)\n            {\n                var tempProtocol = Protocol;\n                var tempRootDomain = RootDomain;\n                Protocol = \"http\";\n                RootDomain = \"www.reddit.com\";\n                var retval = CreateAndExecuteRequest(url);\n                Protocol = tempProtocol;\n                RootDomain = tempRootDomain;\n                return retval;\n            }\n        }\n\n        /// <summary>\n        /// Executes the web request and handles errors in the response\n        /// </summary>\n        /// <param name=\"request\"></param>\n        /// <returns></returns>\n        public virtual JToken ExecuteRequest(HttpWebRequest request)\n        {\n            EnforceRateLimit();\n            HttpWebResponse response = (HttpWebResponse)request.GetResponse();\n            var result = GetResponseString(response.GetResponseStream());\n\n            JToken json;\n            if (!string.IsNullOrEmpty(result))\n            {\n                json = JToken.Parse(result);\n                try\n                {\n                    if (json[\"json\"] != null)\n                    {\n                        json = json[\"json\"]; //get json object if there is a root node\n                    }\n                    if (json[\"error\"] != null)\n                    {\n                        switch (json[\"error\"].ToString())\n                        {\n                            case \"404\":\n                                throw new Exception(\"File Not Found\");\n                            case \"403\":\n                                throw new Exception(\"Restricted\");\n                            case \"invalid_grant\":\n                                //Refresh authtoken\n                                //AccessToken = authProvider.GetRefreshToken();\n                                //ExecuteRequest(request);\n                                break;\n                        }\n                    }\n                }\n                catch\n                {\n                }\n            }\n            else\n            {\n                json = JToken.Parse(\"{'method':'\" + response.Method + \"','uri':'\" + response.ResponseUri.AbsoluteUri + \"','status':'\" + response.StatusCode.ToString() + \"'}\");\n            }\n            return json;\n\n        }\n\n        [MethodImpl(MethodImplOptions.Synchronized)]\n        protected virtual void EnforceRateLimit()\n        {\n            switch (RateLimit)\n            {\n                case RateLimitMode.Pace:\n                    while ((DateTime.UtcNow - _lastRequest).TotalSeconds < 2)// Rate limiting\n                        Thread.Sleep(250);\n                    _lastRequest = DateTime.UtcNow;\n                    break;\n                case RateLimitMode.SmallBurst:\n                    if (_requestsThisBurst == 0 || (DateTime.UtcNow - _burstStart).TotalSeconds >= 10) //this is first request OR the burst expired\n                    {\n                        _burstStart = DateTime.UtcNow;\n                        _requestsThisBurst = 0;\n                    }\n                    if (_requestsThisBurst >= 5) //limit has been reached\n                    {\n                        while ((DateTime.UtcNow - _burstStart).TotalSeconds < 10)\n                            Thread.Sleep(250);\n                        _burstStart = DateTime.UtcNow;\n                        _requestsThisBurst = 0;\n                    }\n                    _lastRequest = DateTime.UtcNow;\n                    _requestsThisBurst++;\n                    break;\n                case RateLimitMode.Burst:\n                    if (_requestsThisBurst == 0 || (DateTime.UtcNow - _burstStart).TotalSeconds >= 60) //this is first request OR the burst expired\n                    {\n                        _burstStart = DateTime.UtcNow;\n                        _requestsThisBurst = 0;\n                    }\n                    if (_requestsThisBurst >= 30) //limit has been reached\n                    {\n                        while ((DateTime.UtcNow - _burstStart).TotalSeconds < 60)\n                            Thread.Sleep(250);\n                        _burstStart = DateTime.UtcNow;\n                        _requestsThisBurst = 0;\n                    }\n                    _lastRequest = DateTime.UtcNow;\n                    _requestsThisBurst++;\n                    break;\n            }\n        }\n\n        public virtual HttpWebRequest CreateRequest(string url, string method)\n        {\n            EnforceRateLimit();\n            bool prependDomain;\n            // IsWellFormedUriString returns true on Mono for some reason when using a string like \"/api/me\"\n            if (Type.GetType(\"Mono.Runtime\") != null)\n                prependDomain = !url.StartsWith(\"http://\") && !url.StartsWith(\"https://\");\n            else\n                prependDomain = !Uri.IsWellFormedUriString(url, UriKind.Absolute);\n\n            HttpWebRequest request;\n            if (prependDomain)\n                request = (HttpWebRequest)WebRequest.Create(String.Format(\"{0}://{1}{2}\", Protocol, RootDomain, url));\n            else\n                request = (HttpWebRequest)WebRequest.Create(url);\n            request.CookieContainer = Cookies;\n            if (Type.GetType(\"Mono.Runtime\") != null)\n            {\n                var cookieHeader = Cookies.GetCookieHeader(new Uri(\"http://reddit.com\"));\n                request.Headers.Set(\"Cookie\", cookieHeader);\n            }\n            if (RootDomain == \"oauth.reddit.com\")// use OAuth\n            {\n                request.Headers.Set(\"Authorization\", \"bearer \" + AccessToken);//Must be included in OAuth calls\n            }\n            request.Method = method;\n            request.UserAgent = UserAgent + \" - with RedditSharp by /u/sircmpwn\";\n            return request;\n        }\n\n        protected virtual HttpWebRequest CreateRequest(Uri uri, string method)\n        {\n            EnforceRateLimit();\n            var request = (HttpWebRequest)WebRequest.Create(uri);\n            request.CookieContainer = Cookies;\n            if (Type.GetType(\"Mono.Runtime\") != null)\n            {\n                var cookieHeader = Cookies.GetCookieHeader(new Uri(\"http://reddit.com\"));\n                request.Headers.Set(\"Cookie\", cookieHeader);\n            }\n            if (RootDomain == \"oauth.reddit.com\")// use OAuth\n            {\n                request.Headers.Set(\"Authorization\", \"bearer \" + AccessToken);//Must be included in OAuth calls\n            }\n            request.Method = method;\n            request.UserAgent = UserAgent + \" - with RedditSharp by /u/sircmpwn\";\n            return request;\n        }\n\n        public virtual HttpWebRequest CreateGet(string url)\n        {\n            return CreateRequest(url, \"GET\");\n        }\n\n        private HttpWebRequest CreateGet(Uri url)\n        {\n            return CreateRequest(url, \"GET\");\n        }\n\n        public virtual HttpWebRequest CreatePost(string url)\n        {\n            var request = CreateRequest(url, \"POST\");\n            request.ContentType = \"application/x-www-form-urlencoded\";\n            return request;\n        }\n\n        public virtual string GetResponseString(Stream stream)\n        {\n            var data = new StreamReader(stream).ReadToEnd();\n            stream.Close();\n            return data;\n        }\n\n        public virtual void WritePostBody(Stream stream, object data, params string[] additionalFields)\n        {\n            var type = data.GetType();\n            var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);\n            string value = \"\";\n            foreach (var property in properties)\n            {\n                var attr = property.GetCustomAttributes(typeof(RedditAPINameAttribute), false).FirstOrDefault() as RedditAPINameAttribute;\n                string name = attr == null ? property.Name : attr.Name;\n                var entry = Convert.ToString(property.GetValue(data, null));\n                value += name + \"=\" + HttpUtility.UrlEncode(entry).Replace(\";\", \"%3B\").Replace(\"&\", \"%26\") + \"&\";\n            }\n            for (int i = 0; i < additionalFields.Length; i += 2)\n            {\n                var entry = Convert.ToString(additionalFields[i + 1]) ?? string.Empty;\n                value += additionalFields[i] + \"=\" + HttpUtility.UrlEncode(entry).Replace(\";\", \"%3B\").Replace(\"&\", \"%26\") + \"&\";\n            }\n            value = value.Remove(value.Length - 1); // Remove trailing &\n            var raw = Encoding.UTF8.GetBytes(value);\n            stream.Write(raw, 0, raw.Length);\n            stream.Close();\n        }\n    }\n}\n"
  },
  {
    "path": "RedditSharp/Wiki.cs",
    "content": "﻿using Newtonsoft.Json.Linq;\nusing System.Collections.Generic;\nusing System.Linq;\nusing RedditSharp.Things;\n\nnamespace RedditSharp\n{\n    using System;\n\n    public class Wiki\n    {\n        private Reddit Reddit { get; set; }\n        private Subreddit Subreddit { get; set; }\n        private IWebAgent WebAgent { get; set; }\n\n        private const string GetWikiPageUrl = \"/r/{0}/wiki/{1}.json?v={2}\";\n        private const string GetWikiPagesUrl = \"/r/{0}/wiki/pages.json\";\n        private const string WikiPageEditUrl = \"/r/{0}/api/wiki/edit\";\n        private const string HideWikiPageUrl = \"/r/{0}/api/wiki/hide\";\n        private const string RevertWikiPageUrl = \"/r/{0}/api/wiki/revert\";\n        private const string WikiPageAllowEditorAddUrl = \"/r/{0}/api/wiki/alloweditor/add\";\n        private const string WikiPageAllowEditorDelUrl = \"/r/{0}/api/wiki/alloweditor/del\";\n        private const string WikiPageSettingsUrl = \"/r/{0}/wiki/settings/{1}.json\";\n        private const string WikiRevisionsUrl = \"/r/{0}/wiki/revisions.json\";\n        private const string WikiPageRevisionsUrl = \"/r/{0}/wiki/revisions/{1}.json\";\n        private const string WikiPageDiscussionsUrl = \"/r/{0}/wiki/discussions/{1}.json\";\n\n        public IEnumerable<string> PageNames\n        {\n            get\n            {\n                var request = WebAgent.CreateGet(string.Format(GetWikiPagesUrl, Subreddit.Name));\n                var response = request.GetResponse();\n                string json = WebAgent.GetResponseString(response.GetResponseStream());\n                return JObject.Parse(json)[\"data\"].Values<string>();\n            }\n        }\n\n        public Listing<WikiPageRevision> Revisions\n        {\n            get\n            {\n                return new Listing<WikiPageRevision>(Reddit, string.Format(WikiRevisionsUrl, Subreddit.Name), WebAgent);\n            }\n        }\n\n        protected internal Wiki(Reddit reddit, Subreddit subreddit, IWebAgent webAgent)\n        {\n            Reddit = reddit;\n            Subreddit = subreddit;\n            WebAgent = webAgent;\n        }\n\n        public WikiPage GetPage(string page, string version = null)\n        {\n            var request = WebAgent.CreateGet(string.Format(GetWikiPageUrl, Subreddit.Name, page, version));\n            var response = request.GetResponse();\n            var json = JObject.Parse(WebAgent.GetResponseString(response.GetResponseStream()));\n            var result = new WikiPage(Reddit, json[\"data\"], WebAgent);\n            return result;\n        }\n\n        #region Settings\n        public WikiPageSettings GetPageSettings(string name)\n        {\n            var request = WebAgent.CreateGet(string.Format(WikiPageSettingsUrl, Subreddit.Name, name));\n            var response = request.GetResponse();\n            var json = JObject.Parse(WebAgent.GetResponseString(response.GetResponseStream()));\n            var result = new WikiPageSettings(Reddit, json[\"data\"], WebAgent);\n            return result;\n        }\n\n        public void SetPageSettings(string name, WikiPageSettings settings)\n        {\n            var request = WebAgent.CreatePost(string.Format(WikiPageSettingsUrl, Subreddit.Name, name));\n            WebAgent.WritePostBody(request.GetRequestStream(), new\n            {\n                page = name,\n                permlevel = settings.PermLevel,\n                listed = settings.Listed,\n                uh = Reddit.User.Modhash\n            });\n            var response = request.GetResponse();\n        }\n        #endregion\n\n        #region Revisions\n\n        public Listing<WikiPageRevision> GetPageRevisions(string page)\n        {\n            return new Listing<WikiPageRevision>(Reddit, string.Format(WikiPageRevisionsUrl, Subreddit.Name, page), WebAgent);\n        }\n        #endregion\n\n        #region Discussions\n        public Listing<Post> GetPageDiscussions(string page)\n        {\n            return new Listing<Post>(Reddit, string.Format(WikiPageDiscussionsUrl, Subreddit.Name, page), WebAgent);\n        }\n        #endregion\n\n        public void EditPage(string page, string content, string previous = null, string reason = null)\n        {\n            var request = WebAgent.CreatePost(string.Format(WikiPageEditUrl, Subreddit.Name));\n            dynamic param = new \n            {\n                content = content,\n                page = page,\n                uh = Reddit.User.Modhash\n            };\n            List<string> addParams = new List<string>();\n            if (previous != null) \n            {\n                addParams.Add(\"previous\");\n                addParams.Add(previous);\n            }\n            if (reason != null) \n            {\n                addParams.Add(\"reason\");\n                addParams.Add(reason);\n            }\n            WebAgent.WritePostBody(request.GetRequestStream(), param,addParams.ToArray());\n            var response = request.GetResponse();\n        }\n\n        public void HidePage(string page, string revision)\n        {\n            var request = WebAgent.CreatePost(string.Format(HideWikiPageUrl, Subreddit.Name));\n            WebAgent.WritePostBody(request.GetRequestStream(), new\n            {\n                page = page,\n                revision = revision,\n                uh = Reddit.User.Modhash\n            });\n            var response = request.GetResponse();\n        }\n\n        public void RevertPage(string page, string revision)\n        {\n            var request = WebAgent.CreatePost(string.Format(RevertWikiPageUrl, Subreddit.Name));\n            WebAgent.WritePostBody(request.GetRequestStream(), new\n            {\n                page = page,\n                revision = revision,\n                uh = Reddit.User.Modhash\n            });\n            var response = request.GetResponse();\n        }\n\n        public void SetPageEditor(string page, string username, bool allow)\n        {\n            var request = WebAgent.CreatePost(string.Format(allow ? WikiPageAllowEditorAddUrl : WikiPageAllowEditorDelUrl, Subreddit.Name));\n            WebAgent.WritePostBody(request.GetRequestStream(), new\n            {\n                page = page,\n                username = username,\n                uh = Reddit.User.Modhash\n            });\n            var response = request.GetResponse();\n        }\n\n        #region Obsolete Getter Methods\n\n        [Obsolete(\"Use PageNames property instead\")]\n        public IEnumerable<string> GetPageNames()\n        {\n            return PageNames;\n        }\n\n        [Obsolete(\"Use Revisions property instead\")]\n        public Listing<WikiPageRevision> GetRevisions()\n        {\n            return Revisions;\n        }\n\n        #endregion Obsolete Getter Methods\n    }\n}"
  },
  {
    "path": "RedditSharp/WikiPage.cs",
    "content": "﻿using Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing System;\nusing RedditSharp.Things;\n\nnamespace RedditSharp\n{\n    public class WikiPage\n    {\n        [JsonProperty(\"may_revise\")]\n        public string MayRevise { get; set; }\n\n        [JsonProperty(\"revision_date\")]\n        [JsonConverter(typeof(UnixTimestampConverter))]\n        public DateTime? RevisionDate { get; set; }\n\n        [JsonProperty(\"content_html\")]\n        public string HtmlContent { get; set; }\n\n        [JsonProperty(\"content_md\")]\n        public string MarkdownContent { get; set; }\n\n        [JsonIgnore]\n        public RedditUser RevisionBy { get; set; }\n\n        protected internal WikiPage(Reddit reddit, JToken json, IWebAgent webAgent)\n        {\n            RevisionBy = new RedditUser().Init(reddit, json[\"revision_by\"], webAgent);\n            JsonConvert.PopulateObject(json.ToString(), this, reddit.JsonSerializerSettings);\n        }\n    }\n}"
  },
  {
    "path": "RedditSharp/WikiPageSettings.cs",
    "content": "﻿using Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing System.Collections.Generic;\nusing System.Linq;\nusing RedditSharp.Things;\n\nnamespace RedditSharp\n{\n    public class WikiPageSettings\n    {\n        [JsonProperty(\"listed\")]\n        public bool Listed { get; set; }\n\n        [JsonProperty(\"permlevel\")]\n        public int PermLevel { get; set; }\n\n        [JsonIgnore]\n        public IEnumerable<RedditUser> Editors { get; set; }\n\n        public WikiPageSettings()\n        {\n        }\n\n        protected internal WikiPageSettings(Reddit reddit, JToken json, IWebAgent webAgent)\n        {\n            var editors = json[\"editors\"].ToArray();\n            Editors = editors.Select(x => new RedditUser().Init(reddit, x, webAgent));\n            JsonConvert.PopulateObject(json.ToString(), this, reddit.JsonSerializerSettings);\n        }\n    }\n}"
  },
  {
    "path": "RedditSharp.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 11.00\r\n# Visual Studio 2010\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"RedditSharp\", \"RedditSharp\\RedditSharp.csproj\", \"{A368CB75-75F0-4489-904D-B5CEBB0FE624}\"\r\nEndProject\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"TestRedditSharp\", \"TestRedditSharp\\TestRedditSharp.csproj\", \"{0101B252-0CCE-4572-8882-D5851FE41E4F}\"\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|Any CPU = Debug|Any CPU\r\n\t\tDebug|Mixed Platforms = Debug|Mixed Platforms\r\n\t\tDebug|x86 = Debug|x86\r\n\t\tRelease|Any CPU = Release|Any CPU\r\n\t\tRelease|Mixed Platforms = Release|Mixed Platforms\r\n\t\tRelease|x86 = Release|x86\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{0101B252-0CCE-4572-8882-D5851FE41E4F}.Debug|Any CPU.ActiveCfg = Debug|x86\r\n\t\t{0101B252-0CCE-4572-8882-D5851FE41E4F}.Debug|Any CPU.Build.0 = Debug|x86\r\n\t\t{0101B252-0CCE-4572-8882-D5851FE41E4F}.Debug|Mixed Platforms.ActiveCfg = Debug|x86\r\n\t\t{0101B252-0CCE-4572-8882-D5851FE41E4F}.Debug|Mixed Platforms.Build.0 = Debug|x86\r\n\t\t{0101B252-0CCE-4572-8882-D5851FE41E4F}.Debug|x86.ActiveCfg = Debug|x86\r\n\t\t{0101B252-0CCE-4572-8882-D5851FE41E4F}.Debug|x86.Build.0 = Debug|x86\r\n\t\t{0101B252-0CCE-4572-8882-D5851FE41E4F}.Release|Any CPU.ActiveCfg = Release|x86\r\n\t\t{0101B252-0CCE-4572-8882-D5851FE41E4F}.Release|Mixed Platforms.ActiveCfg = Release|x86\r\n\t\t{0101B252-0CCE-4572-8882-D5851FE41E4F}.Release|Mixed Platforms.Build.0 = Release|x86\r\n\t\t{0101B252-0CCE-4572-8882-D5851FE41E4F}.Release|x86.ActiveCfg = Release|x86\r\n\t\t{0101B252-0CCE-4572-8882-D5851FE41E4F}.Release|x86.Build.0 = Release|x86\r\n\t\t{A368CB75-75F0-4489-904D-B5CEBB0FE624}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{A368CB75-75F0-4489-904D-B5CEBB0FE624}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{A368CB75-75F0-4489-904D-B5CEBB0FE624}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU\r\n\t\t{A368CB75-75F0-4489-904D-B5CEBB0FE624}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU\r\n\t\t{A368CB75-75F0-4489-904D-B5CEBB0FE624}.Debug|x86.ActiveCfg = Debug|Any CPU\r\n\t\t{A368CB75-75F0-4489-904D-B5CEBB0FE624}.Debug|x86.Build.0 = Debug|Any CPU\r\n\t\t{A368CB75-75F0-4489-904D-B5CEBB0FE624}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{A368CB75-75F0-4489-904D-B5CEBB0FE624}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{A368CB75-75F0-4489-904D-B5CEBB0FE624}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU\r\n\t\t{A368CB75-75F0-4489-904D-B5CEBB0FE624}.Release|Mixed Platforms.Build.0 = Release|Any CPU\r\n\t\t{A368CB75-75F0-4489-904D-B5CEBB0FE624}.Release|x86.ActiveCfg = Release|Any CPU\r\n\t\t{A368CB75-75F0-4489-904D-B5CEBB0FE624}.Release|x86.Build.0 = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(MonoDevelopProperties) = preSolution\r\n\t\tStartupItem = TestRedditSharp\\TestRedditSharp.csproj\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "TestRedditSharp/App.config",
    "content": "<?xml version=\"1.0\"?>\n<configuration>\n    <startup> \n        <supportedRuntime version=\"v4.0\" sku=\".NETFramework,Version=v4.5\"/>\n    </startup>\n</configuration>\n"
  },
  {
    "path": "TestRedditSharp/Program.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing RedditSharp;\nusing System.Security.Authentication;\nusing RedditSharp.Things;\n\nnamespace TestRedditSharp\n{\n    class Program\n    {\n        static void Main(string[] args)\n        {\n            Reddit reddit = null;\n            var authenticated = false;\n            while (!authenticated)\n            {\n                Console.Write(\"OAuth? (y/n) [n]: \");\n                var oaChoice = Console.ReadLine();\n                if (!string.IsNullOrEmpty(oaChoice) && oaChoice.ToLower()[0] == 'y')\n                {\n                    Console.Write(\"OAuth token: \");\n                    var token = Console.ReadLine();\n                    reddit = new Reddit(token);\n                    reddit.InitOrUpdateUser();\n                    authenticated = reddit.User != null;\n                    if (!authenticated)\n                        Console.WriteLine(\"Invalid token\");\n                }\n                else\n                {\n                    Console.Write(\"Username: \");\n                    var username = Console.ReadLine();\n                    Console.Write(\"Password: \");\n                    var password = ReadPassword();\n                    try\n                    {\n                        Console.WriteLine(\"Logging in...\");\n                        reddit = new Reddit(username, password);\n                        authenticated = reddit.User != null;\n                    }\n                    catch (AuthenticationException)\n                    {\n                        Console.WriteLine(\"Incorrect login.\");\n                        authenticated = false;\n                    }\n                }\n            }\n            /*Console.Write(\"Create post? (y/n) [n]: \");\n            var choice = Console.ReadLine();\n            if (!string.IsNullOrEmpty(choice) && choice.ToLower()[0] == 'y')\n            {\n                Console.Write(\"Type a subreddit name: \");\n                var subname = Console.ReadLine();\n                var sub = reddit.GetSubreddit(subname);\n                Console.WriteLine(\"Making test post\");\n                var post = sub.SubmitTextPost(\"RedditSharp test\", \"This is a test post sent from RedditSharp\");\n                Console.WriteLine(\"Submitted: {0}\", post.Url);\n            }\n            else\n            {\n                Console.Write(\"Type a subreddit name: \");\n                var subname = Console.ReadLine();\n                var sub = reddit.GetSubreddit(subname);\n                foreach (var post in sub.GetTop(FromTime.Week).Take(10))\n                    Console.WriteLine(\"\\\"{0}\\\" by {1}\", post.Title, post.Author);\n            }*/\n            Comment comment = (Comment)reddit.GetThingByFullname(\"t1_ciif2g7\");\n            Post post = (Post)reddit.GetThingByFullname(\"t3_298g7j\");\n            PrivateMessage pm = (PrivateMessage)reddit.GetThingByFullname(\"t4_20oi3a\"); // Use your own PM here, as you don't have permission to view this one\n            Console.WriteLine(comment.Body);\n            Console.WriteLine(post.Title);\n            Console.WriteLine(pm.Body);\n            Console.WriteLine(post.Comment(\"test\").FullName);\n            Console.ReadKey(true);\n        }\n\n        public static string ReadPassword()\n        {\n            var passbits = new Stack<string>();\n            //keep reading\n            for (ConsoleKeyInfo cki = Console.ReadKey(true); cki.Key != ConsoleKey.Enter; cki = Console.ReadKey(true))\n            {\n                if (cki.Key == ConsoleKey.Backspace)\n                {\n                    if (passbits.Count() > 0)\n                    {\n                        //rollback the cursor and write a space so it looks backspaced to the user\n                        Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);\n                        Console.Write(\" \");\n                        Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);\n                        passbits.Pop();\n                    }\n                }\n                else\n                {\n                    Console.Write(\"*\");\n                    passbits.Push(cki.KeyChar.ToString());\n                }\n            }\n            string[] pass = passbits.ToArray();\n            Array.Reverse(pass);\n            Console.Write(Environment.NewLine);\n            return string.Join(string.Empty, pass);\n        }\n    }\n}\n"
  },
  {
    "path": "TestRedditSharp/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n// General Information about an assembly is controlled through the following \n// set of attributes. Change these attribute values to modify the information\n// associated with an assembly.\n[assembly: AssemblyTitle(\"TestRedditSharp\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"\")]\n[assembly: AssemblyProduct(\"TestRedditSharp\")]\n[assembly: AssemblyCopyright(\"Copyright ©  2012\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n\n// Setting ComVisible to false makes the types in this assembly not visible \n// to COM components.  If you need to access a type in this assembly from \n// COM, set the ComVisible attribute to true on that type.\n[assembly: ComVisible(false)]\n\n// The following GUID is for the ID of the typelib if this project is exposed to COM\n[assembly: Guid(\"ca7b9ba0-4e47-45d3-aeca-4665957ae929\")]\n\n// Version information for an assembly consists of the following four values:\n//\n//      Major Version\n//      Minor Version \n//      Build Number\n//      Revision\n//\n// You can specify all the values or you can default the Build and Revision Numbers \n// by using the '*' as shown below:\n// [assembly: AssemblyVersion(\"1.0.*\")]\n[assembly: AssemblyVersion(\"1.0.0.0\")]\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\n"
  },
  {
    "path": "TestRedditSharp/TestRedditSharp.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"12.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <PropertyGroup>\r\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\r\n    <Platform Condition=\" '$(Platform)' == '' \">x86</Platform>\r\n    <ProductVersion>8.0.30703</ProductVersion>\r\n    <SchemaVersion>2.0</SchemaVersion>\r\n    <ProjectGuid>{0101B252-0CCE-4572-8882-D5851FE41E4F}</ProjectGuid>\r\n    <OutputType>Exe</OutputType>\r\n    <AppDesignerFolder>Properties</AppDesignerFolder>\r\n    <RootNamespace>TestRedditSharp</RootNamespace>\r\n    <AssemblyName>TestRedditSharp</AssemblyName>\r\n    <FileAlignment>512</FileAlignment>\r\n    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>\r\n    <TargetFrameworkProfile />\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|x86' \">\r\n    <PlatformTarget>x86</PlatformTarget>\r\n    <DebugSymbols>True</DebugSymbols>\r\n    <DebugType>full</DebugType>\r\n    <Optimize>False</Optimize>\r\n    <OutputPath>bin\\Debug\\</OutputPath>\r\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <WarningLevel>4</WarningLevel>\r\n    <Externalconsole>true</Externalconsole>\r\n    <Prefer32Bit>false</Prefer32Bit>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|x86' \">\r\n    <PlatformTarget>x86</PlatformTarget>\r\n    <DebugType>pdbonly</DebugType>\r\n    <Optimize>True</Optimize>\r\n    <OutputPath>bin\\Release\\</OutputPath>\r\n    <DefineConstants>TRACE</DefineConstants>\r\n    <ErrorReport>prompt</ErrorReport>\r\n    <WarningLevel>4</WarningLevel>\r\n    <Prefer32Bit>false</Prefer32Bit>\r\n  </PropertyGroup>\r\n  <ItemGroup>\r\n    <Reference Include=\"Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL\" />\r\n    <Reference Include=\"System\" />\r\n    <Reference Include=\"System.Core\" />\r\n    <Reference Include=\"System.Xml.Linq\" />\r\n    <Reference Include=\"System.Data.DataSetExtensions\" />\r\n    <Reference Include=\"Microsoft.CSharp\" />\r\n    <Reference Include=\"System.Data\" />\r\n    <Reference Include=\"System.Xml\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Compile Include=\"Program.cs\" />\r\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"App.config\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ProjectReference Include=\"..\\RedditSharp\\RedditSharp.csproj\">\r\n      <Project>{A368CB75-75F0-4489-904D-B5CEBB0FE624}</Project>\r\n      <Name>RedditSharp</Name>\r\n    </ProjectReference>\r\n  </ItemGroup>\r\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\r\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \r\n       Other similar extension points exist, see Microsoft.Common.targets.\r\n  <Target Name=\"BeforeBuild\">\r\n  </Target>\r\n  <Target Name=\"AfterBuild\">\r\n  </Target>\r\n  -->\r\n</Project>"
  }
]