[
  {
    "path": ".gitignore",
    "content": "#Autosave files\r\n*~\r\n\r\n#build\r\n[Oo]bj/\r\n[Bb]in/\r\npackages/\r\nTestResults/\r\n\r\n# globs\r\nMakefile.in\r\n*.DS_Store\r\n*.sln.cache\r\n*.suo\r\n*.cache\r\n*.pidb\r\n*.userprefs\r\n*.usertasks\r\nconfig.log\r\nconfig.make\r\nconfig.status\r\naclocal.m4\r\ninstall-sh\r\nautom4te.cache/\r\n*.user\r\n*.tar.gz\r\ntarballs/\r\ntest-results/\r\nThumbs.db\r\n\r\n#Mac bundle stuff\r\n*.dmg\r\n*.app\r\n\r\n#resharper\r\n*_Resharper.*\r\n*.Resharper\r\n\r\n#dotCover\r\n*.dotCover\r\n"
  },
  {
    "path": "Auth/FirebaseAuth.cs",
    "content": "﻿namespace Firebase.Xamarin.Auth\n{\n    using Newtonsoft.Json;\n\n    /// <summary>\n    /// The firebase auth.\n    /// </summary>\n    public class FirebaseAuth\n    {\n        /// <summary>\n        /// Gets or sets the firebase token which can be used for authenticated queries. \n        /// </summary>\n        [JsonProperty(\"idToken\")]\n        public string FirebaseToken\n        {\n            get;\n            set;\n        }\n\n        /// <summary>\n        /// Gets or sets the refresh token of the underlying service which can be used to get a new access token. \n        /// </summary>\n        [JsonProperty(\"refreshToken\")]\n        public string RefreshToken\n        {\n            get;\n            set;\n        }\n\n        /// <summary>\n        /// Gets or sets the numbers of seconds until the token expires.\n        /// </summary>\n        [JsonProperty(\"expiresIn\")]\n        public int ExpiresIn\n        {\n            get;\n            set;\n        }\n\n        /// <summary>\n        /// Gets or sets the user.\n        /// </summary>\n        public User User\n        {\n            get;\n            set;\n        }\n    }\n}\n"
  },
  {
    "path": "Auth/FirebaseAuthException.cs",
    "content": "﻿using System;\nusing System.Runtime.Serialization;\n\nnamespace Firebase.Xamarin.Auth\n{\n\t/*\n\t * Sign In Exceptions \n\t */\n\tpublic class FirebaseIncorrectPasswordException : Exception\n\t{\n\t\t/// <summary>\n\t\t/// Default constructor\n\t\t/// </summary>\n\t\tpublic FirebaseIncorrectPasswordException() : base()\n\t\t{\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Argument constructor\n\t\t/// </summary>\n\t\t/// <param name=\"message\">This is the description of the exception</param>\n\t\tpublic FirebaseIncorrectPasswordException(String message) : base(message)\n\t\t{\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Argument constructor with inner exception\n\t\t/// </summary>\n\t\t/// <param name=\"message\">This is the description of the exception</param>\n\t\t/// <param name=\"innerException\">Inner exception</param>\n\t\tpublic FirebaseIncorrectPasswordException(String message, Exception innerException) : base(message, innerException)\n\t\t{\n\t\t}\n\t}\n\n\tpublic class FirebaseInvalidEmailException : Exception\n\t{\n\t\t/// <summary>\n\t\t/// Default constructor\n\t\t/// </summary>\n\n\t\tpublic FirebaseInvalidEmailException() : base()\n\t\t{\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Argument constructor\n\t\t/// </summary>\n\t\t/// <param name=\"message\">This is the description of the exception</param>\n\n\t\tpublic FirebaseInvalidEmailException(String message) : base(message)\n\t\t{\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Argument constructor with inner exception\n\t\t/// </summary>\n\t\t/// <param name=\"message\">This is the description of the exception</param>\n\t\t/// <param name=\"innerException\">Inner exception</param>\n\n\t\tpublic FirebaseInvalidEmailException(String message, Exception innerException) : base(message, innerException)\n\t\t{\n\t\t}\n\t}\n\n\t/*\n\t * Create User Exceptions\n\t */\n\tpublic class FirebaseUsedEmailException : Exception\n\t{\n\t\t/// <summary>\n\t\t/// Default constructor\n\t\t/// </summary>\n\n\t\tpublic FirebaseUsedEmailException() : base()\n\t\t{\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Argument constructor\n\t\t/// </summary>\n\t\t/// <param name=\"message\">This is the description of the exception</param>\n\n\t\tpublic FirebaseUsedEmailException(String message) : base(message)\n\t\t{\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Argument constructor with inner exception\n\t\t/// </summary>\n\t\t/// <param name=\"message\">This is the description of the exception</param>\n\t\t/// <param name=\"innerException\">Inner exception</param>\n\n\t\tpublic FirebaseUsedEmailException(String message, Exception innerException) : base(message, innerException)\n\t\t{\n\t\t}\n\t}\n\n\tpublic class FirebaseWeakPasswordException : Exception\n\t{\n\t\t/// <summary>\n\t\t/// Default constructor\n\t\t/// </summary>\n\n\t\tpublic FirebaseWeakPasswordException() : base()\n\t\t{\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Argument constructor\n\t\t/// </summary>\n\t\t/// <param name=\"message\">This is the description of the exception</param>\n\n\t\tpublic FirebaseWeakPasswordException(String message) : base(message)\n\t\t{\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Argument constructor with inner exception\n\t\t/// </summary>\n\t\t/// <param name=\"message\">This is the description of the exception</param>\n\t\t/// <param name=\"innerException\">Inner exception</param>\n\n\t\tpublic FirebaseWeakPasswordException(String message, Exception innerException) : base(message, innerException)\n\t\t{\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "Auth/FirebaseAuthLink.cs",
    "content": "﻿namespace Firebase.Xamarin.Auth\n{\n    using System.Threading.Tasks;\n\n    /// <summary>\n    /// The firebase auth which can be linked to another credentials.\n    /// </summary>\n    public class FirebaseAuthLink : FirebaseAuth\n    {\n        internal FirebaseAuthLink()\n        {\n        }\n\n        internal FirebaseAuthProvider AuthProvider \n        {\n            get;\n            set;\n        }\n\n        /// <summary>\n        /// Links the user with an email and password.  \n        /// </summary>\n        /// <param name=\"email\"> The email. </param>\n        /// <param name=\"password\"> The password. </param>\n        /// <returns> The <see cref=\"FirebaseAuthLink\"/>. </returns>\n        public Task<FirebaseAuthLink> LinkToAsync(string email, string password)\n        {\n            return this.AuthProvider.LinkAccountsAsync(this, email, password);\n        }\n\n        /// <summary>\n        /// Links the this user with and account from a third party provider.\n        /// </summary> \n        /// <param name=\"authType\"> The auth type.  </param>\n        /// <param name=\"oauthAccessToken\"> The access token retrieved from login provider of your choice. </param>\n        /// <returns> The <see cref=\"FirebaseAuthLink\"/>.  </returns>\n        public Task<FirebaseAuthLink> LinkToAsync(FirebaseAuthType authType, string oauthAccessToken)\n        {\n            return this.AuthProvider.LinkAccountsAsync(this, authType, oauthAccessToken);\n        }\n    }\n}\n"
  },
  {
    "path": "Auth/FirebaseAuthProvider.cs",
    "content": "﻿namespace Firebase.Xamarin.Auth\n{\n\tusing System;\n\tusing System.Linq;\n\tusing System.Net.Http;\n\tusing System.Text;\n\tusing System.Threading.Tasks;\n\n\tusing Newtonsoft.Json;\n\tusing Newtonsoft.Json.Linq;\n\n\t/// <summary>\n\t/// The auth token provider.\n\t/// </summary>\n\tpublic class FirebaseAuthProvider : IDisposable, IFirebaseAuthProvider\n\t{\n\t\tprivate const string GoogleIdentityUrl = \"https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyAssertion?key={0}\";\n\t\tprivate const string GoogleSignUpUrl = \"https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key={0}\";\n\t\tprivate const string GooglePasswordUrl = \"https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key={0}\";\n\t\tprivate const string GooglePasswordResetUrl = \"https://www.googleapis.com/identitytoolkit/v3/relyingparty/getOobConfirmationCode?key={0}\";\n\t\tprivate const string GoogleSetAccountUrl = \"https://www.googleapis.com/identitytoolkit/v3/relyingparty/setAccountInfo?key={0}\";\n\n\t\tprivate readonly FirebaseConfig authConfig;\n\t\tprivate readonly HttpClient client;\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the <see cref=\"FirebaseAuthProvider\"/> class.\n\t\t/// </summary>\n\t\t/// <param name=\"authConfig\"> The auth config. </param>\n\t\tpublic FirebaseAuthProvider(FirebaseConfig authConfig)\n\t\t{\n\t\t\tthis.authConfig = authConfig;\n\t\t\tthis.client = new HttpClient();\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Using the provided access token from third party auth provider (google, facebook...), get the firebase auth with token and basic user credentials.\n\t\t/// </summary>\n\t\t/// <param name=\"authType\"> The auth type. </param>\n\t\t/// <param name=\"oauthAccessToken\"> The access token retrieved from login provider of your choice. </param>\n\t\t/// <returns> The <see cref=\"FirebaseAuth\"/>. </returns>\n\t\tpublic async Task<FirebaseAuthLink> SignInWithOAuthAsync(FirebaseAuthType authType, string oauthAccessToken)\n\t\t{\n\t\t\tvar providerId = this.GetProviderId(authType);\n\t\t\tvar content = $\"{{\\\"postBody\\\":\\\"access_token={oauthAccessToken}&providerId={providerId}\\\",\\\"requestUri\\\":\\\"http://localhost\\\",\\\"returnSecureToken\\\":true}}\";\n\n\t\t\treturn await this.SignInWithPostContentAsync(GoogleIdentityUrl, content).ConfigureAwait(false);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Sign in user anonymously. He would still have a user id and access token generated, but name and other personal user properties will be null.\n\t\t/// </summary>\n\t\t/// <returns> The <see cref=\"FirebaseAuth\"/>. </returns>\n\t\tpublic async Task<FirebaseAuthLink> SignInAnonymouslyAsync()\n\t\t{\n\t\t\tvar content = $\"{{\\\"returnSecureToken\\\":true}}\";\n\n\t\t\treturn await this.SignInWithPostContentAsync(GoogleSignUpUrl, content).ConfigureAwait(false);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Using the provided email and password, get the firebase auth with token and basic user credentials.\n\t\t/// </summary>\n\t\t/// <param name=\"email\"> The email. </param>\n\t\t/// <param name=\"password\"> The password. </param>\n\t\t/// <returns> The <see cref=\"FirebaseAuth\"/>. </returns>\n\t\tpublic async Task<FirebaseAuthLink> SignInWithEmailAndPasswordAsync(string email, string password)\n\t\t{\n\t\t\tvar content = $\"{{\\\"email\\\":\\\"{email}\\\",\\\"password\\\":\\\"{password}\\\",\\\"returnSecureToken\\\":true}}\";\n\n\t\t\treturn await this.SignInWithPostContentAsync(GooglePasswordUrl, content).ConfigureAwait(false);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Creates new user with given credentials.\n\t\t/// </summary>\n\t\t/// <param name=\"email\"> The email. </param>\n\t\t/// <param name=\"password\"> The password. </param>\n\t\t/// <returns> The <see cref=\"FirebaseAuth\"/>. </returns>\n\t\tpublic async Task<FirebaseAuthLink> CreateUserWithEmailAndPasswordAsync(string email, string password)\n\t\t{\n\t\t\tvar content = $\"{{\\\"email\\\":\\\"{email}\\\",\\\"password\\\":\\\"{password}\\\",\\\"returnSecureToken\\\":true}}\";\n\n\t\t\treturn await this.SignInWithPostContentAsync(GoogleSignUpUrl, content).ConfigureAwait(false);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Sends user an email with a link to reset his password.\n\t\t/// </summary>\n\t\t/// <param name=\"email\"> The email. </param>\n\t\tpublic async Task SendPasswordResetEmailAsync(string email)\n\t\t{\n\t\t\tvar content = $\"{{\\\"requestType\\\":\\\"PASSWORD_RESET\\\",\\\"email\\\":\\\"{email}\\\"}}\";\n\n\t\t\tvar response = await this.client.PostAsync(new Uri(string.Format(GooglePasswordResetUrl, this.authConfig.ApiKey)), new StringContent(content, Encoding.UTF8, \"application/json\")).ConfigureAwait(false);\n\n\t\t\tresponse.EnsureSuccessStatusCode();\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Links the authenticated user represented by <see cref=\"auth\"/> with an email and password. \n\t\t/// </summary>\n\t\t/// <param name=\"auth\"> The authenticated user to link with specified email and password. </param>\n\t\t/// <param name=\"email\"> The email. </param>\n\t\t/// <param name=\"password\"> The password. </param>\n\t\t/// <returns> The <see cref=\"FirebaseAuthLink\"/>. </returns>\n\t\tpublic async Task<FirebaseAuthLink> LinkAccountsAsync(FirebaseAuth auth, string email, string password)\n\t\t{\n\t\t\tvar content = $\"{{\\\"idToken\\\":\\\"{auth.FirebaseToken}\\\",\\\"email\\\":\\\"{email}\\\",\\\"password\\\":\\\"{password}\\\",\\\"returnSecureToken\\\":true}}\";\n\n\t\t\treturn await this.SignInWithPostContentAsync(GoogleSetAccountUrl, content).ConfigureAwait(false);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Links the authenticated user represented by <see cref=\"auth\"/> with and account from a third party provider.\n\t\t/// </summary>\n\t\t/// <param name=\"auth\"> The auth. </param>\n\t\t/// <param name=\"authType\"> The auth type.  </param>\n\t\t/// <param name=\"oauthAccessToken\"> The access token retrieved from login provider of your choice. </param>\n\t\t/// <returns> The <see cref=\"FirebaseAuthLink\"/>.  </returns>\n\t\tpublic async Task<FirebaseAuthLink> LinkAccountsAsync(FirebaseAuth auth, FirebaseAuthType authType, string oauthAccessToken)\n\t\t{\n\t\t\tvar providerId = this.GetProviderId(authType);\n\t\t\tvar content = $\"{{\\\"idToken\\\":\\\"{auth.FirebaseToken}\\\",\\\"postBody\\\":\\\"access_token={oauthAccessToken}&providerId={providerId}\\\",\\\"requestUri\\\":\\\"http://localhost\\\",\\\"returnSecureToken\\\":true}}\";\n\n\t\t\treturn await this.SignInWithPostContentAsync(GoogleIdentityUrl, content).ConfigureAwait(false);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Disposes all allocated resources. \n\t\t/// </summary>\n\t\tpublic void Dispose()\n\t\t{\n\t\t\tthis.client.Dispose();\n\t\t}\n\n\t\tprivate async Task<FirebaseAuthLink> SignInWithPostContentAsync(string googleUrl, string postContent)\n\t\t{\n\t\t\tvar response = await this.client.PostAsync(new Uri(string.Format(googleUrl, this.authConfig.ApiKey)), new StringContent(postContent, Encoding.UTF8, \"application/json\")).ConfigureAwait(false);\n\t\t\tvar responseData = await response.Content.ReadAsStringAsync().ConfigureAwait(false);\n\n\t\t\tif (!response.IsSuccessStatusCode)\n\t\t\t{\n\t\t\t\tvar jsonReturn = JObject.Parse(responseData);\n\t\t\t\tvar message = (string)jsonReturn[\"error\"][\"message\"];\n\n\t\t\t\t// Login\n\t\t\t\t// Email address not found in database\n\t\t\t\tif (message.Equals(\"EMAIL_NOT_FOUND\"))\n\t\t\t\t{\n\t\t\t\t\tthrow new FirebaseInvalidEmailException(\"Email address not found\");\n\t\t\t\t}\n\t\t\t\t// Login\n\t\t\t\t// Invalid password supplied\n\t\t\t\telse if (message.Equals(\"INVALID_PASSWORD\"))\n\t\t\t\t{\n\t\t\t\t\tthrow new FirebaseIncorrectPasswordException(\"Incorrect passord\");\n\t\t\t\t}\n\t\t\t\t// New User\n\t\t\t\t// Email address already exists\n\t\t\t\telse if (message.Equals(\"EMAIL_EXISTS\"))\n\t\t\t\t{\n\t\t\t\t\tthrow new FirebaseUsedEmailException(\"Email address already exists\");\n\t\t\t\t}\n\t\t\t\t// New User\n\t\t\t\t// Week Password\n\t\t\t\telse if (message.Contains(\"WEAK_PASSWORD\"))\n\t\t\t\t{\n\t\t\t\t\tthrow new FirebaseWeakPasswordException(\"Weak password, must be at least 6 characters\");\n\t\t\t\t}\n\t\t\t\t// Just end on default status check\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tresponse.EnsureSuccessStatusCode();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar user = JsonConvert.DeserializeObject<User>(responseData);\n\t\t\tvar auth = JsonConvert.DeserializeObject<FirebaseAuthLink>(responseData);\n\n\t\t\tauth.User = user;\n\t\t\tauth.AuthProvider = this;\n\n\t\t\treturn auth;\n\t\t}\n\n\t\tprivate string GetProviderId(FirebaseAuthType authType)\n\t\t{\n\t\t\tswitch (authType)\n\t\t\t{\n\t\t\t\tcase FirebaseAuthType.Facebook:\n\t\t\t\t\treturn \"facebook.com\";\n\t\t\t\tcase FirebaseAuthType.Google:\n\t\t\t\t\treturn \"google.com\";\n\t\t\t\tcase FirebaseAuthType.Github:\n\t\t\t\t\treturn \"github.com\";\n\t\t\t\tcase FirebaseAuthType.Twitter:\n\t\t\t\t\treturn \"twitter.com\";\n\t\t\t\tdefault: throw new NotImplementedException(\"\");\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "Auth/FirebaseAuthType.cs",
    "content": "﻿namespace Firebase.Xamarin.Auth\n{\n    /// <summary>\n    /// The type of authentication. \n    /// </summary>\n    public enum FirebaseAuthType\n    {\n        /// <summary>\n        /// The facebook auth.\n        /// </summary>\n        Facebook,\n\n        /// <summary>\n        /// The google auth.\n        /// </summary>\n        Google,\n\n        /// <summary>\n        /// The github auth.\n        /// </summary>\n        Github,\n\n        /// <summary>\n        /// The twitter auth. \n        /// </summary> \n        Twitter\n    } \n}\n"
  },
  {
    "path": "Auth/FirebaseConfig.cs",
    "content": "namespace Firebase.Xamarin.Auth\n{\n    /// <summary>\n    /// The auth config. \n    /// </summary>\n    public class FirebaseConfig\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FirebaseConfig\"/> class.\n        /// </summary>\n        /// <param name=\"apiKey\"> The api key of your Firebase app. </param>\n        public FirebaseConfig(string apiKey)\n        {\n            this.ApiKey = apiKey;\n        }\n        \n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"T:FirebaseConfig\"/> class.\n        /// </summary>\n        /// <param name=\"apiKey\">API key.</param>\n        /// <param name=\"apiKeyForPushNotification\">API key for push notification.</param>\n        public FirebaseConfig(string apiKey, string apiKeyForPushNotification)\n        {\n            this.ApiKey = apiKey;\n            this.ApiKeyForPushNotification = apiKeyForPushNotification;\n        }\n\n        /// <summary>\n        /// Gets or sets the api key of your Firebase app. \n        /// </summary>\n        public string ApiKey \n        {\n            get;\n            set;\n        }\n\n        /// <summary>\n        /// Gets or sets the API key for push notification.\n        /// </summary>\n        /// <value>The API key for push notification.</value>\n        public string ApiKeyForPushNotification\n        {\n            get;\n            set;\n        }\n    }\n}\n"
  },
  {
    "path": "Auth/IFirebaseAuthProvider.cs",
    "content": "﻿namespace Firebase.Xamarin.Auth\n{\n    using System.Threading.Tasks;\n\n    /// <summary>\n    /// The auth token provider.\n    /// </summary>\n    public interface IFirebaseAuthProvider\n    {\n        /// <summary>\n        /// Creates new user with given credentials.\n        /// </summary>\n        /// <param name=\"email\"> The email. </param>\n        /// <param name=\"password\"> The password. </param>\n        /// <returns> The <see cref=\"FirebaseAuthLink\"/>. </returns>\n        Task<FirebaseAuthLink> CreateUserWithEmailAndPasswordAsync(string email, string password);\n        \n        /// <summary>\n        /// Sends user an email with a link to reset his password.\n        /// </summary>\n        /// <param name=\"email\"> The email.  </param>\n        /// <returns> The <see cref=\"Task\"/>. </returns>\n        Task SendPasswordResetEmailAsync(string email);\n\n        /// <summary>\n        /// Sign in user anonymously. He would still have a user id and access token generated, but name and other personal user properties will be null.\n        /// </summary>\n        /// <returns> The <see cref=\"FirebaseAuthLink\"/>. </returns>\n        Task<FirebaseAuthLink> SignInAnonymouslyAsync();\n\n        /// <summary>\n        /// Using the provided email and password, get the firebase auth with token and basic user credentials.\n        /// </summary>\n        /// <param name=\"email\"> The email. </param>\n        /// <param name=\"password\"> The password. </param>\n        /// <returns> The <see cref=\"FirebaseAuthLink\"/>. </returns>\n        Task<FirebaseAuthLink> SignInWithEmailAndPasswordAsync(string email, string password);\n\n        /// <summary>\n        /// Using the provided access token from third party auth provider (google, facebook...), get the firebase auth with token and basic user credentials.\n        /// </summary>\n        /// <param name=\"authType\"> The auth type. </param>\n        /// <param name=\"oauthAccessToken\"> The access token retrieved from login provider of your choice. </param>\n        /// <returns> The <see cref=\"FirebaseAuthLink\"/>. </returns>\n        Task<FirebaseAuthLink> SignInWithOAuthAsync(FirebaseAuthType authType, string oauthAccessToken);\n\n        /// <summary>\n        /// Links the authenticated user represented by <see cref=\"auth\"/> with an email and password. \n        /// </summary>\n        /// <param name=\"auth\"> The authenticated user to link with specified email and password. </param>\n        /// <param name=\"email\"> The email. </param>\n        /// <param name=\"password\"> The password. </param>\n        /// <returns> The <see cref=\"FirebaseAuthLink\"/>. </returns>\n        Task<FirebaseAuthLink> LinkAccountsAsync(FirebaseAuth auth, string email, string password);\n\n        /// <summary>\n        /// Links the authenticated user represented by <see cref=\"auth\"/> with and account from a third party provider.\n        /// </summary>\n        /// <param name=\"auth\"> The auth. </param>\n        /// <param name=\"authType\"> The auth type.  </param>\n        /// <param name=\"oauthAccessToken\"> The access token retrieved from login provider of your choice. </param>\n        /// <returns> The <see cref=\"FirebaseAuthLink\"/>.  </returns>\n        Task<FirebaseAuthLink> LinkAccountsAsync(FirebaseAuth auth, FirebaseAuthType authType, string oauthAccessToken);\n    }\n}"
  },
  {
    "path": "Auth/User.cs",
    "content": "﻿namespace Firebase.Xamarin.Auth\n{\n    using System.ComponentModel;\n\n    using Newtonsoft.Json;\n\n    /// <summary>\n    /// Basic information about the logged in user.\n    /// </summary>\n    public class User\n    {\n        /// <summary>\n        /// Gets or sets the local id.\n        /// </summary>\n        [JsonProperty(\"localId\", DefaultValueHandling = DefaultValueHandling.Populate)]\n        [DefaultValue(\"\")]\n        public string LocalId\n        {\n            get;\n            set;\n        }\n\n        /// <summary>\n        /// Gets or sets the federated id.\n        /// </summary>\n        [JsonProperty(\"federatedId\", DefaultValueHandling = DefaultValueHandling.Populate)]\n        [DefaultValue(\"\")]\n        public string FederatedId\n        {\n            get;\n            set;\n        }\n\n        /// <summary>\n        /// Gets or sets the first name.\n        /// </summary>\n        [JsonProperty(\"firstName\", DefaultValueHandling = DefaultValueHandling.Populate)] \n        [DefaultValue(\"\")]\n        public string FirstName\n        {\n            get;\n            set;\n        }\n\n        /// <summary>\n        /// Gets or sets the last name.\n        /// </summary>\n        [JsonProperty(\"lastName\", DefaultValueHandling = DefaultValueHandling.Populate)]\n        [DefaultValue(\"\")]\n        public string LastName\n        {\n            get;\n            set;\n        }\n\n        /// <summary>\n        /// Gets or sets the display name.\n        /// </summary>\n        [JsonProperty(\"displayName\", DefaultValueHandling = DefaultValueHandling.Populate)]\n        [DefaultValue(\"\")]\n        public string DisplayName\n        {\n            get;\n            set;\n        }\n\n        /// <summary>\n        /// Gets or sets the email.\n        /// </summary>\n        [JsonProperty(\"email\", DefaultValueHandling = DefaultValueHandling.Populate)]\n        [DefaultValue(\"\")]\n        public string Email\n        {\n            get;\n            set;\n        }\n\n        /// <summary>\n        /// Gets or sets the photo url.\n        /// </summary>\n        [JsonProperty(\"photoUrl\", DefaultValueHandling = DefaultValueHandling.Populate)]\n        [DefaultValue(\"\")]\n        public string PhotoUrl\n        {\n            get;\n            set;\n        }\n    }\n}\n"
  },
  {
    "path": "Database/FirebaseClient.cs",
    "content": "namespace Firebase.Xamarin.Database\n{\n    using System;\n    using System.Collections.Generic;\n    using System.Threading.Tasks;\n\n    using Firebase.Xamarin.Database.Offline;\n    using Firebase.Xamarin.Database.Query;\n\n    /// <summary>\n    /// Firebase client which acts as an entry point to the online database.\n    /// </summary>\n    public class FirebaseClient\n    {\n        internal readonly Func<Type, string, IDictionary<string, OfflineEntry>> OfflineDatabaseFactory;\n        internal readonly Func<Task<string>> AuthTokenAsyncFactory;\n\n        private readonly string baseUrl;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FirebaseClient\"/> class.\n        /// </summary>\n        /// <param name=\"baseUrl\"> The base url. </param>\n        public FirebaseClient(string baseUrl) : this(baseUrl, (t, s) => new Dictionary<string, OfflineEntry>())\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FirebaseClient\"/> class.\n        /// </summary>\n        /// <param name=\"baseUrl\"> The base url. </param>\n        /// <param name=\"offlineDatabaseFactory\"> Offline database. </param>  \n        public FirebaseClient(string baseUrl, Func<Type, string, IDictionary<string, OfflineEntry>> offlineDatabaseFactory)\n        {\n            this.OfflineDatabaseFactory = offlineDatabaseFactory;\n\n            this.baseUrl = baseUrl;\n\n            if (!this.baseUrl.EndsWith(\"/\"))\n            {\n                this.baseUrl += \"/\";\n            }\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FirebaseClient\"/> class.\n        /// </summary>\n        /// <param name=\"baseUrl\"> The base url. </param>\n        /// <param name=\"authTokenAsyncFactory\"> Factory which returns valid firebase auth token. </param>\n        public FirebaseClient(string baseUrl, Func<Task<string>> authTokenAsyncFactory) \n            : this(baseUrl, authTokenAsyncFactory, (t, s) => new Dictionary<string, OfflineEntry>())\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FirebaseClient\"/> class.\n        /// </summary>\n        /// <param name=\"baseUrl\"> The base url. </param>\n        /// <param name=\"authTokenAsyncFactory\"> Factory which returns valid firebase auth token. </param>\n        /// <param name=\"offlineDatabaseFactory\"> Offline database. </param>   \n        public FirebaseClient(string baseUrl, Func<Task<string>> authTokenAsyncFactory, Func<Type, string, IDictionary<string, OfflineEntry>> offlineDatabaseFactory) \n            : this(baseUrl, offlineDatabaseFactory)\n        {\n            this.AuthTokenAsyncFactory = authTokenAsyncFactory;\n        }\n\n        /// <summary>\n        /// Queries for a child of the data root.\n        /// </summary>\n        /// <param name=\"resourceName\"> Name of the child. </param>\n        /// <returns> <see cref=\"ChildQuery\"/>. </returns>\n        public ChildQuery Child(string resourceName)\n        {\n            return new ChildQuery(this, () => this.baseUrl + resourceName);\n        }\n    }\n}\n"
  },
  {
    "path": "Database/FirebaseKeyGenerator.cs",
    "content": "namespace Firebase.Xamarin.Database\n{\n    using System;\n    using System.Text;\n\n    /// <summary>\n    /// Offline key generator which mimics the official Firebase generators. \n    /// Credit: https://github.com/bubbafat/FirebaseSharp/blob/master/src/FirebaseSharp.Portable/FireBasePushIdGenerator.cs\n    /// </summary>\n    public class FirebaseKeyGenerator \n    {\n        // Modeled after base64 web-safe chars, but ordered by ASCII.\n        private const string PushCharsString = \"-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz\";\n        private static readonly char[] PushChars;\n        private static readonly DateTimeOffset Epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, 0, TimeSpan.Zero);\n\n        private static readonly Random random = new Random();\n        private static readonly byte[] lastRandChars = new byte[12];\n\n        // Timestamp of last push, used to prevent local collisions if you push twice in one ms.\n        private static long lastPushTime;\n\n        static FirebaseKeyGenerator()\n        {\n            PushChars = Encoding.UTF8.GetChars(Encoding.UTF8.GetBytes(PushCharsString));\n        }\n\n        /// <summary>\n        /// Returns next firebase key based on current time.  \n        /// </summary>\n        /// <returns>\n        /// The <see cref=\"string\"/>. </returns>\n        public static string Next()\n        {\n            // We generate 72-bits of randomness which get turned into 12 characters and\n            // appended to the timestamp to prevent collisions with other clients. We store the last\n            // characters we generated because in the event of a collision, we'll use those same\n            // characters except \"incremented\" by one.\n            var id = new StringBuilder(20);\n            var now = (long)(DateTimeOffset.Now - Epoch).TotalMilliseconds;\n            var duplicateTime = now == lastPushTime;\n            lastPushTime = now;\n\n            var timeStampChars = new char[8];\n            for (int i = 7; i >= 0; i--)\n            {\n                var index = (int)(now % PushChars.Length);\n                timeStampChars[i] = PushChars[index];\n                now = (long)Math.Floor((double)now / PushChars.Length);\n            }\n\n            if (now != 0)\n            {\n                throw new Exception(\"We should have converted the entire timestamp.\");\n            }\n\n            id.Append(timeStampChars);\n\n            if (!duplicateTime)\n            {\n                for (int i = 0; i < 12; i++)\n                {\n                    lastRandChars[i] = (byte)random.Next(0, PushChars.Length);\n                }\n            }\n            else\n            {\n                // If the timestamp hasn't changed since last push, use the same random number,\n                // except incremented by 1.\n                var lastIndex = 11;\n                for (; lastIndex >= 0 && lastRandChars[lastIndex] == PushChars.Length - 1; lastIndex--)\n                {\n                    lastRandChars[lastIndex] = 0;\n                }\n\n                lastRandChars[lastIndex]++;\n            }\n\n            for (int i = 0; i < 12; i++)\n            {\n                id.Append(PushChars[lastRandChars[i]]);\n            }\n\n            if (id.Length != 20)\n            {\n                throw new Exception(\"Length should be 20.\");\n            }\n\n            return id.ToString();\n        }\n    }\n}\n"
  },
  {
    "path": "Database/FirebaseObject.cs",
    "content": "namespace Firebase.Xamarin.Database\n{\n    /// <summary>\n    /// Holds the object of type <typeparam name=\"T\" /> along with its key. \n    /// </summary>\n    /// <typeparam name=\"T\"> Type of the underlying object. </typeparam> \n    public class FirebaseObject<T> \n    {\n        internal FirebaseObject(string key, T obj)\n        {\n            this.Key = key;\n            this.Object = obj;\n        }\n\n        /// <summary>\n        /// Gets the key of <see cref=\"Object\"/>.\n        /// </summary>\n        public string Key\n        {\n            get;\n        }\n\n        /// <summary>\n        /// Gets the underlying object.\n        /// </summary>\n        public T Object\n        {\n            get;\n        }\n    }\n}\n"
  },
  {
    "path": "Database/GlobalSuppressions.cs",
    "content": "﻿\n// This file is used by Code Analysis to maintain SuppressMessage \n// attributes that are applied to this project.\n// Project-level suppressions either have no target or are given \n// a specific target and scoped to a namespace, type, member, etc.\n\n"
  },
  {
    "path": "Database/Http/HttpClientExtensions.cs",
    "content": "namespace Firebase.Xamarin.Database.Http\n{\n    using System;\n    using System.Collections;\n    using System.Collections.Generic;\n    using System.Linq;\n    using System.Net.Http;\n    using System.Threading.Tasks;\n\n    using Newtonsoft.Json;\n\n    /// <summary>\n    /// The http client extensions for object deserializations.\n    /// </summary>\n    internal static class HttpClientExtensions\n    {\n        /// <summary>\n        /// The get object collection async.\n        /// </summary>\n        /// <param name=\"client\"> The client. </param>\n        /// <param name=\"requestUri\"> The request uri. </param>  \n        /// <typeparam name=\"T\"> The type of entities the collection should contain. </typeparam>\n        /// <returns> The <see cref=\"Task\"/>. </returns>\n        public static async Task<IReadOnlyCollection<FirebaseObject<T>>> GetObjectCollectionAsync<T>(this HttpClient client, string requestUri)\n        {\n            var data = await client.GetStringAsync(requestUri).ConfigureAwait(false);\n            var dictionary = JsonConvert.DeserializeObject<Dictionary<string, T>>(data);\n\n            if (dictionary == null)\n            {\n                return new FirebaseObject<T>[0];\n            }\n\n            return dictionary.Select(item => new FirebaseObject<T>(item.Key, item.Value)).ToList();\n        }\n\n        /// <summary>\n        /// The get object collection async.\n        /// </summary>\n        /// <param name=\"data\"> The json data. </param>\n        /// <param name=\"elementType\"> The type of entities the collection should contain. </param>\n        /// <returns> The <see cref=\"Task\"/>.  </returns>\n        public static IEnumerable<FirebaseObject<object>> GetObjectCollection(this string data, Type elementType)\n        {\n            var dictionaryType = typeof(Dictionary<,>).MakeGenericType(typeof(string), elementType);\n            var dictionary = JsonConvert.DeserializeObject(data, dictionaryType) as IDictionary;\n\n            if (dictionary == null)\n            {\n                yield break;\n            }\n\n            foreach (DictionaryEntry item in dictionary)\n            {\n                yield return new FirebaseObject<object>((string)item.Key, item.Value);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Database/Http/PostResult.cs",
    "content": "namespace Firebase.Xamarin.Database.Http\n{\n    /// <summary>\n    /// Represents data returned after a successful POST to firebase server.\n    /// </summary>\n    public class PostResult\n    {\n        /// <summary>\n        /// Gets or sets the generated key after a successful post. \n        /// </summary>\n        public string Name\n        {\n            get;\n            set;\n        }\n    }\n}\n"
  },
  {
    "path": "Database/ObservableExtensions.cs",
    "content": "﻿namespace Firebase.Xamarin.Database\n{\n    using System;\n    using System.Collections.ObjectModel;\n\n    using Firebase.Xamarin.Database.Streaming;\n\n    /// <summary>\n    /// Extensions for <see cref=\"IObservable{T}\"/>.\n    /// </summary>\n    public static class ObservableExtensions\n    {\n        /// <summary>\n        /// Starts observing on given firebase observable and propagates event into an <see cref=\"ObservableCollection{T}\"/>.\n        /// </summary>\n        /// <param name=\"observable\"> The observable. </param>\n        /// <typeparam name=\"T\"> Type of entity. </typeparam>\n        /// <returns> The <see cref=\"ObservableCollection{T}\"/>. </returns> \n        public static ObservableCollection<T> AsObservableCollection<T>(this IObservable<FirebaseEvent<T>> observable)\n        {\n            var collection = new ObservableCollection<T>();\n\n            observable.Subscribe(f =>\n            {\n                if (f.EventType == FirebaseEventType.InsertOrUpdate)\n                {\n                    var i = collection.IndexOf(f.Object);\n                    if (i >= 0)\n                    {\n                        collection.RemoveAt(i);\n                    }\n\n                    collection.Add(f.Object);\n                }\n                else\n                {\n                    collection.Remove(f.Object);\n                }\n            });\n\n            return collection;\n        }\n    }\n}\n"
  },
  {
    "path": "Database/Offline/ExceptionEventArgs.cs",
    "content": "﻿namespace Firebase.Xamarin.Database.Offline\n{\n    using System;\n\n    /// <summary>\n    /// Event args holding the <see cref=\"Exception\"/> object.\n    /// </summary>\n    public class ExceptionEventArgs : EventArgs\n    {\n        public readonly Exception Exception;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ExceptionEventArgs\"/> class.\n        /// </summary>\n        /// <param name=\"exception\"> The exception. </param>\n        public ExceptionEventArgs(Exception exception)\n        {\n            this.Exception = exception;\n        }\n    }\n}\n"
  },
  {
    "path": "Database/Offline/OfflineCacheAdapter.cs",
    "content": "﻿namespace Firebase.Xamarin.Database.Offline\n{\n    using System;\n    using System.Collections;\n    using System.Collections.Generic;\n    using System.Linq;\n\n    internal class OfflineCacheAdapter<TKey, T> : IDictionary<string, T>, IDictionary \n    {\n        private readonly IDictionary<string, OfflineEntry> database;\n\n        public OfflineCacheAdapter(IDictionary<string, OfflineEntry> database)\n        {\n            this.database = database;\n        }\n\n        public void CopyTo(Array array, int index)\n        {\n            throw new NotImplementedException();\n        }\n\n        public int Count => this.database.Count;\n\n        public bool IsSynchronized { get; }\n\n        public object SyncRoot { get; }\n\n        public bool IsReadOnly => this.database.IsReadOnly;\n\n        object IDictionary.this[object key]\n        {\n            get\n            {\n                return this.database[key.ToString()].Deserialize<T>();\n            }\n\n            set\n            {\n                this.database[key.ToString()] = new OfflineEntry(key.ToString(), value, 1, SyncOptions.None);\n            }\n        }\n\n        public ICollection<string> Keys => this.database.Keys;\n\n        ICollection IDictionary.Values { get; }\n\n        ICollection IDictionary.Keys { get; }\n\n        public ICollection<T> Values => this.database.Values.Select(o => o.Deserialize<T>()).ToList();\n\n        public T this[string key]\n        {\n            get\n            {\n                return this.database[key].Deserialize<T>();\n            }\n\n            set\n            {\n                this.database[key] = new OfflineEntry(key, value, 1, SyncOptions.None);\n            }\n        }\n\n        public bool Contains(object key)\n        {\n            return this.ContainsKey(key.ToString());\n        }\n\n        IDictionaryEnumerator IDictionary.GetEnumerator()\n        {\n            throw new NotImplementedException();\n        }\n\n        public void Remove(object key)\n        {\n            this.Remove(key.ToString());\n        }\n\n        public bool IsFixedSize => false;\n\n        public IEnumerator<KeyValuePair<string, T>> GetEnumerator()\n        {\n            return this.database.Select(d => new KeyValuePair<string, T>(d.Key, d.Value.Deserialize<T>())).GetEnumerator();\n        }\n\n        IEnumerator IEnumerable.GetEnumerator()\n        {\n            return this.GetEnumerator();\n        }\n\n        public void Add(KeyValuePair<string, T> item)\n        {\n            this.Add(item.Key, item.Value);\n        }\n\n        public void Add(object key, object value)\n        {\n            this.Add(key.ToString(), (T)value);\n        }\n\n        public void Clear()\n        {\n            this.database.Clear();\n        }\n\n        public bool Contains(KeyValuePair<string, T> item)\n        {\n            return this.ContainsKey(item.Key);\n        }\n\n        public void CopyTo(KeyValuePair<string, T>[] array, int arrayIndex)\n        {\n            throw new NotImplementedException();\n        }\n\n        public bool Remove(KeyValuePair<string, T> item)\n        {\n            return this.database.Remove(item.Key);\n        }\n\n        public void Add(string key, T value)\n        {\n            this.database.Add(key, new OfflineEntry(key, value, 1, SyncOptions.None));\n        }\n\n        public bool ContainsKey(string key)\n        {\n            return this.database.ContainsKey(key);\n        }\n\n        public bool Remove(string key)\n        {\n            return this.database.Remove(key);\n        }\n\n        public bool TryGetValue(string key, out T value)\n        {\n            OfflineEntry val;\n\n            if (this.database.TryGetValue(key, out val))\n            {\n                value = val.Deserialize<T>();\n                return true;\n            }\n\n            value = default(T);\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "Database/Offline/OfflineEntry.cs",
    "content": "﻿namespace Firebase.Xamarin.Database.Offline\n{\n    using System;\n\n    using Newtonsoft.Json;\n\n    /// <summary>\n    /// Represents an object stored in offline storage.\n    /// </summary>\n    public class OfflineEntry\n    {\n        private object dataInstance;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OfflineEntry\"/> class.\n        /// </summary>\n        /// <param name=\"key\"> The key. </param>\n        /// <param name=\"obj\"> The object. </param>\n        /// <param name=\"priority\"> The priority. Objects with higher priority will be synced first. Higher number indicates higher priority. </param>  \n        /// <param name=\"syncOptions\"> The sync options. </param>\n        public OfflineEntry(string key, object obj, int priority, SyncOptions syncOptions = SyncOptions.Push)\n        {\n            this.Key = key;\n            this.Priority = priority;\n            this.Data = JsonConvert.SerializeObject(obj);\n            this.Timestamp = DateTime.UtcNow;\n            this.SyncOptions = syncOptions;\n\n            this.dataInstance = obj;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OfflineEntry\"/> class.\n        /// </summary>\n        public OfflineEntry() \n        {\n        }\n\n        /// <summary>\n        /// Gets or sets the key of this entry.\n        /// </summary>\n        public string Key\n        {\n            get;\n            set;\n        }\n\n        /// <summary>\n        /// Gets or sets the priority. Objects with higher priority will be synced first. Higher number indicates higher priority. \n        /// </summary>\n        public int Priority \n        {\n            get;\n            set;\n        }\n\n        /// <summary>\n        /// Gets or sets the timestamp when this entry was last touched.\n        /// </summary>\n        public DateTime Timestamp\n        {\n            get;\n            set;\n        }\n\n        /// <summary>\n        /// Gets or sets the <see cref=\"SyncOptions\"/> which define what sync state this entry is in.\n        /// </summary>\n        public SyncOptions SyncOptions\n        {\n            get;\n            set;\n        }\n\n        /// <summary>\n        /// Gets or sets serialized JSON data. \n        /// </summary>\n        public string Data\n        {\n            get;\n            set;\n        }\n\n        /// <summary>\n        /// Deserializes <see cref=\"Data\"/> into <typeparamref name=\"T\"/>. The result is cached.\n        /// </summary>\n        /// <typeparam name=\"T\"> Type of object to deserialize into. </typeparam>\n        /// <returns> Instance of <typeparamref name=\"T\"/>. </returns>\n        public T Deserialize<T>()\n        {\n            return (T)(this.dataInstance ?? (this.dataInstance = JsonConvert.DeserializeObject<T>(this.Data)));\n        }\n    }\n}\n"
  },
  {
    "path": "Database/Offline/RealtimeDatabase.cs",
    "content": "﻿namespace Firebase.Xamarin.Database.Offline\n{\n    using System;\n    using System.Collections.Generic;\n    using System.Linq;\n    using System.Reactive.Linq;\n    using System.Reactive.Subjects;\n    using System.Threading;\n    using System.Threading.Tasks;\n\n    using Firebase.Xamarin.Database.Query;\n    using Firebase.Xamarin.Database.Streaming;\n\n    /// <summary>\n    /// The real-time database which synchronizes online and offline data. \n    /// </summary>\n    /// <typeparam name=\"T\"> Type of entities. </typeparam>\n    public partial class RealtimeDatabase<T> where T : class\n    {\n        private readonly ChildQuery childQuery;\n        private readonly bool streamChanges;\n        private readonly IDictionary<string, OfflineEntry> database;\n        private readonly string elementRoot;\n        private readonly Subject<FirebaseEvent<T>> subject;\n\n        private IObservable<FirebaseEvent<T>> observable;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"RealtimeDatabase{T}\"/> class.\n        /// </summary>\n        /// <param name=\"childQuery\"> The child query.  </param>\n        /// <param name=\"elementRoot\"> The element Root. </param>\n        /// <param name=\"offlineDatabaseFactory\"> The offline database factory.  </param>\n        /// <param name=\"filenameModifier\"> Custom string which will get appended to the file name.  </param>\n        /// <param name=\"streamChanges\"> Specifies whether changes should be streamed from the server.  </param>\n        public RealtimeDatabase(ChildQuery childQuery, string elementRoot, Func<Type, string, IDictionary<string, OfflineEntry>> offlineDatabaseFactory, string filenameModifier, bool streamChanges)\n        {\n            this.childQuery = childQuery;\n            this.elementRoot = elementRoot;\n            this.streamChanges = streamChanges;\n            this.database = offlineDatabaseFactory(typeof(T), filenameModifier);\n            this.subject = new Subject<FirebaseEvent<T>>();\n\n            Task.Factory.StartNew(this.SynchronizeThread, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);\n        }\n\n        /// <summary>\n        /// Event raised whenever an exception is thrown in the synchronization thread. Exception thrown in there are swallowed, so this event is the only way to get to them. \n        /// </summary>\n        public event EventHandler<ExceptionEventArgs> SyncExceptionThrown;\n\n        /// <summary>\n        /// Overwrites existing object with given key.\n        /// </summary>\n        /// <param name=\"key\"> The key. </param>\n        /// <param name=\"obj\"> The object to set. </param>\n        /// <param name=\"priority\"> The priority. Objects with higher priority will be synced first. Higher number indicates higher priority. </param>\n        public void Put(string key, T obj, int priority = 1)\n        {\n            this.SetAndRaise(key, new OfflineEntry(key, obj, priority));\n        }\n\n        /// <summary>\n        /// Adds a new entity to the database.\n        /// </summary>\n        /// <param name=\"obj\"> The object to add.  </param>\n        /// <param name=\"priority\"> The priority. Objects with higher priority will be synced first. Higher number indicates higher priority. </param>\n        /// <returns> The generated key for this object. </returns>\n        public string Post(T obj, int priority = 1)\n        {\n            var key = FirebaseKeyGenerator.Next();\n\n            this.SetAndRaise(key, new OfflineEntry(key, obj, priority));\n\n            return key;\n        }\n\n        /// <summary>\n        /// Deletes the entity with the given key.\n        /// </summary>\n        /// <param name=\"key\"> The key. </param>\n        /// <param name=\"priority\"> The priority. Objects with higher priority will be synced first. Higher number indicates higher priority. </param> \n        public void Delete(string key, int priority = 1)\n        {\n            this.SetAndRaise(key, new OfflineEntry(key, null, priority));\n        }\n\n        /// <summary>\n        /// Fetches an object with the given key and adds it to the database.\n        /// </summary>\n        /// <param name=\"key\"> The key. </param>\n        /// <param name=\"priority\"> The priority. Objects with higher priority will be synced first. Higher number indicates higher priority. </param>\n        public void Pull(string key, int priority = 1)\n        {\n            if (!this.database.ContainsKey(key))\n            {\n                this.database[key] = new OfflineEntry(key, null, priority, SyncOptions.Pull);\n            }\n            else\n            {\n                this.database[key].SyncOptions = SyncOptions.Pull;\n            }\n        }\n\n        /// <summary> \n        /// Starts observing the real-time database. Events will be fired both when change is done locally and remotely.\n        /// </summary> \n        /// <returns> Stream of <see cref=\"FirebaseEvent{T}\"/>. </returns>\n        public IObservable<FirebaseEvent<T>> AsObservable()\n        {\n            if (this.observable == null)\n            { \n                var initialData = this.database\n                    .Where(kvp => !string.IsNullOrEmpty(kvp.Value.Data) && kvp.Value.Data != \"null\")\n                    .Select(kvp => new FirebaseEvent<T>(kvp.Key, kvp.Value.Deserialize<T>(), FirebaseEventType.InsertOrUpdate))\n                    .ToList().ToObservable();\n\n                this.observable = Observable\n                    .Create<FirebaseEvent<T>>(observer => this.InitializeStreamingSubscription(observer))\n                    .Merge(initialData)\n                    .Merge(this.subject)\n                    .Replay()\n                    .RefCount();\n            }\n\n            return this.observable;\n        }   \n\n        private IDisposable InitializeStreamingSubscription(IObserver<FirebaseEvent<T>> observer)\n        {\n            return this.streamChanges \n                ? new FirebaseSubscription<T>(observer, this.childQuery.OrderByKey().StartAt(() => this.GetLatestKey()), this.elementRoot, new FirebaseCache<T>(new OfflineCacheAdapter<string, T>(this.database))).Run() \n                : Observable.Never<string>().Subscribe();\n        }\n\n        private void SetAndRaise(string key, OfflineEntry obj)\n        {\n            this.database[key] = obj;\n            this.subject.OnNext(new FirebaseEvent<T>(key, obj?.Deserialize<T>(), string.IsNullOrEmpty(obj?.Data) ? FirebaseEventType.Delete : FirebaseEventType.InsertOrUpdate));\n        }\n\n        private async void SynchronizeThread()\n        {\n            while (true)\n            {\n                try\n                {\n                    var validEntries = this.database.Where(e => e.Value != null);\n                    await this.PullEntriesAsync(validEntries.Where(kvp => kvp.Value.SyncOptions == SyncOptions.Pull));\n                    await this.PushEntriesAsync(validEntries.Where(kvp => kvp.Value.SyncOptions == SyncOptions.Push));\n                }\n                catch (Exception ex)\n                {\n                    this.SyncExceptionThrown?.Invoke(this, new ExceptionEventArgs(ex));\n                }\n\n                await Task.Delay(1000);\n            }\n        }\n\n        private string GetLatestKey()\n        {\n            return this.database.OrderBy(o => o.Key, StringComparer.Ordinal).LastOrDefault().Key;\n        }\n\n        private async Task PushEntriesAsync(IEnumerable<KeyValuePair<string, OfflineEntry>> pushEntries)\n        {\n            var groups = pushEntries.GroupBy(pair => pair.Value.Priority).OrderByDescending(kvp => kvp.Key);\n\n            foreach (var group in groups)\n            {\n                var tasks = group.Select(kvp => this.childQuery.Child(kvp.Key).PutAsync(kvp.Value.Deserialize<T>())).ToList();\n\n                await Task.WhenAll(tasks);\n\n                this.ResetSyncOptions(group.Select(s => s.Key));\n            }\n        }\n\n        private async Task PullEntriesAsync(IEnumerable<KeyValuePair<string, OfflineEntry>> pullEntries)\n        {\n            var taskGroups = pullEntries.GroupBy(pair => pair.Value.Priority).OrderByDescending(kvp => kvp.Key);\n\n            foreach (var group in taskGroups)\n            {\n                var tasks = group.Select(pair => new { Key = pair.Key, Task = this.childQuery.Child(pair.Key).OnceSingleAsync<T>(), Priority = pair.Value.Priority }).ToList();\n\n                await Task.WhenAll(tasks.Select(t => t.Task));\n\n                foreach (var task in tasks)\n                {\n                    this.SetAndRaise(task.Key, new OfflineEntry(task.Key, task.Task.Result, task.Priority, SyncOptions.None));\n                }\n            }\n        }\n\n        private void ResetSyncOptions(IEnumerable<string> entries)\n        {\n            foreach (var key in entries)\n            {\n                var item = this.database[key];\n                item.SyncOptions = SyncOptions.None;\n                this.database[key] = item;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Database/Offline/SyncOptions.cs",
    "content": "﻿namespace Firebase.Xamarin.Database.Offline\n{\n    /// <summary>\n    /// Specifies type of sync requested for given data.\n    /// </summary>\n    public enum SyncOptions\n    {\n        /// <summary>\n        /// No sync needed for given data. \n        /// </summary>\n        None,\n\n        /// <summary>\n        /// Data should be pulled from firebase.\n        /// </summary>\n        Pull,\n\n        /// <summary>\n        /// Data should be pushed to firebase.\n        /// </summary>\n        Push\n    }\n}\n"
  },
  {
    "path": "Database/Properties/AssemblyInfo.cs",
    "content": "﻿using System.Resources;\nusing 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(\"Firebase.Database\")]\n[assembly: AssemblyDescription(\"\")]\n[assembly: AssemblyConfiguration(\"\")]\n[assembly: AssemblyCompany(\"Step Up Labs, Inc.\")]\n[assembly: AssemblyProduct(\"Firebase.Database\")]\n[assembly: AssemblyCopyright(\"Copyright © Step Up Labs, Inc. 2016\")]\n[assembly: AssemblyTrademark(\"\")]\n[assembly: AssemblyCulture(\"\")]\n[assembly: NeutralResourcesLanguage(\"en\")]\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[assembly: InternalsVisibleTo(\"Firebase.Database.Tests\")]\n"
  },
  {
    "path": "Database/Query/AuthQuery.cs",
    "content": "namespace Firebase.Xamarin.Database.Query\n{\n    using System;\n\n    /// <summary>\n    /// Represents an auth parameter in firebase query, e.g. \"?auth=xyz\".\n    /// </summary>\n    public class AuthQuery : ParameterQuery\n    {\n        private readonly Func<string> tokenFactory;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"AuthQuery\"/> class.\n        /// </summary>\n        /// <param name=\"parent\"> The parent.  </param>  \n        /// <param name=\"tokenFactory\"> The authentication token factory. </param>\n        /// <param name=\"client\"> The owner. </param>\n        public AuthQuery(FirebaseQuery parent, Func<string> tokenFactory, FirebaseClient client) : base(parent, () => \"auth\", client)\n        {\n            this.tokenFactory = tokenFactory;\n        }\n\n        /// <summary>\n        /// Build the url parameter value of this child. \n        /// </summary>\n        /// <param name=\"child\"> The child of this child. </param>\n        /// <returns> The <see cref=\"string\"/>. </returns>\n        protected override string BuildUrlParameter(FirebaseQuery child)\n        {\n            return this.tokenFactory();\n        }\n    }\n}\n"
  },
  {
    "path": "Database/Query/ChildQuery.cs",
    "content": "namespace Firebase.Xamarin.Database.Query\n{\n    using System;\n\tusing Firebase.Xamarin.Database;\n    using Firebase.Xamarin.Database.Offline;\n\n    /// <summary>\n    /// Firebase query which references the child of current node.\n    /// </summary>\n    public class ChildQuery : FirebaseQuery\n    {\n        private readonly Func<string> pathFactory;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ChildQuery\"/> class.\n        /// </summary>\n        /// <param name=\"parent\"> The parent.  </param>\n        /// <param name=\"pathFactory\"> The path to the child node.  </param>\n        /// <param name=\"client\"> The owner. </param>\n        public ChildQuery(FirebaseQuery parent, Func<string> pathFactory, FirebaseClient client)\n            : base(parent, client)\n        {\n            this.pathFactory = pathFactory;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ChildQuery\"/> class.\n        /// </summary>\n        /// <param name=\"client\"> The client. </param>\n        /// <param name=\"pathFactory\"> The path to the child node.  </param>\n        public ChildQuery(FirebaseClient client, Func<string> pathFactory)\n            : this(null, pathFactory, client)\n        {\n        }\n\n        /// <summary>\n        /// The as offline database.\n        /// </summary>\n        /// <typeparam name=\"T\"> Type of elements. </typeparam>\n        /// <param name=\"filenameModifier\"> Custom string which will get appended to the file name. </param>\n        /// <param name=\"elementRoot\"> Optional custom root element of received json items. </param>\n        /// <param name=\"streamChanges\"> Specifies whether changes should be streamed from the server. </param> \n        /// <returns> The <see cref=\"RealtimeDatabase{T}\"/>. </returns>\n        public RealtimeDatabase<T> AsRealtimeDatabase<T>(string filenameModifier, string elementRoot = \"\", bool streamChanges = true) where T : class\n        {\n            return new RealtimeDatabase<T>(this, elementRoot, this.Client.OfflineDatabaseFactory, filenameModifier, streamChanges);\n        }\n\n        /// <summary>\n        /// Build the url segment of this child.\n        /// </summary>\n        /// <param name=\"child\"> The child of this child. </param>\n        /// <returns> The <see cref=\"string\"/>. </returns>\n        protected override string BuildUrlSegment(FirebaseQuery child)\n        {\n            var s = this.pathFactory();\n\n            if (s != string.Empty && !s.EndsWith(\"/\"))\n            {\n                s += '/';\n            }\n\n            if (!(child is ChildQuery))\n            {\n                return s + \".json\";\n            }\n\n            return s;\n        }\n    }\n}\n"
  },
  {
    "path": "Database/Query/FilterQuery.cs",
    "content": "namespace Firebase.Xamarin.Database.Query \n{\n    using System;\n    using System.Globalization;\n\n    /// <summary>\n    /// Represents a firebase filtering query, e.g. \"?LimitToLast=10\".\n    /// </summary>\n    public class FilterQuery : ParameterQuery \n    {\n        private readonly Func<string> valueFactory;\n        private readonly Func<double> doubleValueFactory;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FilterQuery\"/> class.\n        /// </summary>\n        /// <param name=\"parent\"> The parent. </param>\n        /// <param name=\"filterFactory\"> The filter. </param>\n        /// <param name=\"valueFactory\"> The value for filter. </param>\n        /// <param name=\"client\"> The owning client. </param>  \n        public FilterQuery(FirebaseQuery parent, Func<string> filterFactory, Func<string> valueFactory, FirebaseClient client)\n            : base(parent, filterFactory, client)\n        {\n            this.valueFactory = valueFactory;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FilterQuery\"/> class.\n        /// </summary>\n        /// <param name=\"parent\"> The parent. </param>\n        /// <param name=\"filterFactory\"> The filter. </param>\n        /// <param name=\"valueFactory\"> The value for filter. </param>\n        /// <param name=\"client\"> The owning client. </param>\n        public FilterQuery(FirebaseQuery parent, Func<string> filterFactory, Func<double> valueFactory, FirebaseClient client)\n            : base(parent, filterFactory, client)\n        {\n            this.doubleValueFactory = valueFactory;\n        }\n\n        /// <summary>\n        /// The build url parameter.\n        /// </summary>\n        /// <param name=\"child\"> The child. </param> \n        /// <returns> Url parameter part of the resulting path. </returns> \n        protected override string BuildUrlParameter(FirebaseQuery child)\n        {\n            if (this.valueFactory != null)\n            {\n                return $\"\\\"{this.valueFactory()}\\\"\";\n            }\n            else if (this.doubleValueFactory != null)\n            {\n                return this.doubleValueFactory().ToString(CultureInfo.InvariantCulture);\n            }\n\n            return string.Empty;\n        }\n    }\n}\n"
  },
  {
    "path": "Database/Query/FirebaseQuery.cs",
    "content": "namespace Firebase.Xamarin.Database.Query\n{\n    using System;\n    using System.Collections.Generic;\n    using System.Net.Http;\n    using System.Reactive.Linq;\n    using System.Threading.Tasks;\n\n    using Firebase.Xamarin.Database.Http;\n    using Firebase.Xamarin.Database.Offline;\n    using Firebase.Xamarin.Database.Streaming;\n\n    using Newtonsoft.Json;\n\n    /// <summary>\n    /// Represents a firebase query. \n    /// </summary>\n    public abstract class FirebaseQuery : IFirebaseQuery, IDisposable\n    {\n        protected readonly FirebaseQuery Parent;\n         \n        private HttpClient client;\n\n        /// <summary> \n        /// Initializes a new instance of the <see cref=\"FirebaseQuery\"/> class.\n        /// </summary>\n        /// <param name=\"parent\"> The parent of this query. </param>\n        /// <param name=\"client\"> The owning client. </param>\n        protected FirebaseQuery(FirebaseQuery parent, FirebaseClient client)\n        {\n            this.Client = client;\n            this.Parent = parent;\n        }\n\n        /// <summary>\n        /// Gets the client.\n        /// </summary>\n        public FirebaseClient Client\n        {\n            get;\n        }\n\n        /// <summary>\n        /// Queries the firebase server once returning collection of items.\n        /// </summary>\n        /// <typeparam name=\"T\"> Type of elements. </typeparam>\n        /// <returns> Collection of <see cref=\"FirebaseObject{T}\"/> holding the entities returned by server. </returns>\n        public async Task<IReadOnlyCollection<FirebaseObject<T>>> OnceAsync<T>()\n        {\n            var path = await this.BuildUrlAsync().ConfigureAwait(false);\n\n            using (var client = new HttpClient())\n            {\n                return await client.GetObjectCollectionAsync<T>(path).ConfigureAwait(false);\n            }\n        }\n\n\n        /// <summary>\n        /// Assumes given query is pointing to a single object of type <typeparamref name=\"T\"/> and retrieves it.\n        /// </summary>\n        /// <typeparam name=\"T\"> Type of elements. </typeparam>\n        /// <returns> Single object of type <typeparamref name=\"T\"/>. </returns>\n        public async Task<T> OnceSingleAsync<T>()\n        {\n            var path = await this.BuildUrlAsync().ConfigureAwait(false);\n\n            using (var client = new HttpClient())\n            {\n                var data = await client.GetStringAsync(path).ConfigureAwait(false);\n                return JsonConvert.DeserializeObject<T>(data);\n            }\n        }\n\n        /// <summary>\n        /// Starts observing this query watching for changes real time sent by the server.\n        /// </summary>\n        /// <typeparam name=\"T\"> Type of elements. </typeparam>\n        /// <param name=\"elementRoot\"> Optional custom root element of received json items. </param>\n        /// <returns> Observable stream of <see cref=\"FirebaseEvent{T}\"/>. </returns>\n        public IObservable<FirebaseEvent<T>> AsObservable<T>(string elementRoot = \"\")\n        {\n            return Observable.Create<FirebaseEvent<T>>(observer => new FirebaseSubscription<T>(observer, this, elementRoot, new FirebaseCache<T>()).Run());\n        }\n\n        /// <summary>\n        /// Builds the actual URL of this query.\n        /// </summary>\n        /// <returns> The <see cref=\"string\"/>. </returns>\n        public async Task<string> BuildUrlAsync()\n        {\n            // if token factory is present on the parent then use it to generate auth token\n            if (this.Client.AuthTokenAsyncFactory != null)\n            {\n                var token = await this.Client.AuthTokenAsyncFactory().ConfigureAwait(false);\n                return this.WithAuth(token).BuildUrl(null);\n            }\n\n            return this.BuildUrl(null);\n        }\n\n        /// <summary>\n        /// Posts given object to repository.\n        /// </summary>\n        /// <param name=\"obj\"> The object. </param> \n        /// <param name=\"generateKeyOffline\"> Specifies whether the key should be generated offline instead of online. </param> \n        /// <typeparam name=\"T\"> Type of <see cref=\"obj\"/> </typeparam>\n        /// <returns> Resulting firebase object with populated key. </returns>\n        public async Task<FirebaseObject<T>> PostAsync<T>(T obj, bool generateKeyOffline = true)\n        {\n            // post generates a new key server-side, while put can be used with an already generated local key\n            if (generateKeyOffline)\n            {\n                var key = FirebaseKeyGenerator.Next();\n                await new ChildQuery(this, () => key, this.Client).PutAsync(obj).ConfigureAwait(false);\n\n                return new FirebaseObject<T>(key, obj);\n            }\n            else\n            {\n                var c = this.GetClient();\n                var data = await this.SendAsync(c, obj, HttpMethod.Post).ConfigureAwait(false);\n                var result = JsonConvert.DeserializeObject<PostResult>(data);\n\n                return new FirebaseObject<T>(result.Name, obj);\n            }\n        }\n\n        /// <summary>\n        /// Patches data at given location instead of overwriting them. \n        /// </summary> \n        /// <param name=\"obj\"> The object. </param>  \n        /// <typeparam name=\"T\"> Type of <see cref=\"obj\"/> </typeparam>\n        /// <returns> The <see cref=\"Task\"/>. </returns>\n        public async Task PatchAsync<T>(T obj)\n        {\n            var c = this.GetClient();\n\n            await this.SendAsync(c, obj, new HttpMethod(\"PATCH\")).ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Sets or overwrites data at given location. \n        /// </summary> \n        /// <param name=\"obj\"> The object. </param>  \n        /// <typeparam name=\"T\"> Type of <see cref=\"obj\"/> </typeparam>\n        /// <returns> The <see cref=\"Task\"/>. </returns>\n        public async Task PutAsync<T>(T obj)\n        {\n            var c = this.GetClient();\n\n            await this.SendAsync(c, obj, HttpMethod.Put).ConfigureAwait(false);\n        }\n\n        /// <summary>\n        /// Deletes data from given location.\n        /// </summary>\n        /// <returns> The <see cref=\"Task\"/>. </returns>\n        public async Task DeleteAsync()\n        {\n            var c = this.GetClient();\n            var url = await this.BuildUrlAsync().ConfigureAwait(false);\n            var result = await c.DeleteAsync(url).ConfigureAwait(false);\n\n            result.EnsureSuccessStatusCode();\n        }\n\n        /// <summary>\n        /// Disposes this instance.  \n        /// </summary>\n        public void Dispose()\n        {\n            this.client?.Dispose();\n        }\n\n        /// <summary>\n        /// Build the url segment of this child.\n        /// </summary>\n        /// <param name=\"child\"> The child of this query. </param>\n        /// <returns> The <see cref=\"string\"/>. </returns>\n        protected abstract string BuildUrlSegment(FirebaseQuery child);\n\n        private string BuildUrl(FirebaseQuery child)\n        {\n            var url = this.BuildUrlSegment(child);\n\n            if (this.Parent != null)\n            {\n                url = this.Parent.BuildUrl(this) + url;\n            }\n\n            return url;\n        }\n\n        private HttpClient GetClient()\n        {\n            if (this.client == null)\n            {\n                this.client = new HttpClient();\n            }\n\n            return this.client;\n        }\n\n        private async Task<string> SendAsync<T>(HttpClient client, T obj, HttpMethod method)\n        {\n            var url = await this.BuildUrlAsync().ConfigureAwait(false);\n            var message = new HttpRequestMessage(method, url)\n            {\n                Content = new StringContent(JsonConvert.SerializeObject(obj))\n            };\n\n            var result = await client.SendAsync(message).ConfigureAwait(false);\n\n            result.EnsureSuccessStatusCode();\n\n            return await result.Content.ReadAsStringAsync().ConfigureAwait(false);\n        }\n    }\n}\n"
  },
  {
    "path": "Database/Query/IFirebaseQuery.cs",
    "content": "﻿namespace Firebase.Xamarin.Database.Query\n{\n    using System;\n    using System.Collections.Generic;\n    using System.Threading.Tasks;\n\n    using Firebase.Xamarin.Database.Streaming;\n\n    /// <summary>\n    /// The FirebaseQuery interface.\n    /// </summary>\n    public interface IFirebaseQuery\n    {\n        /// <summary>\n        /// Retrieves items which exist on the location specified by this query instance.\n        /// </summary>\n        /// <typeparam name=\"T\"> Type of the items. </typeparam>\n        /// <returns> Collection of <see cref=\"FirebaseObject{T}\"/>. </returns> \n        Task<IReadOnlyCollection<FirebaseObject<T>>> OnceAsync<T>();\n\n        /// <summary>\n        /// Returns current location as an observable which allows to real-time listening to events from the firebase server. \n        /// </summary>\n        /// <typeparam name=\"T\"> Type of the items. </typeparam>\n        /// <returns> Cold observable of <see cref=\"FirebaseEvent{T}\"/>. </returns>\n        IObservable<FirebaseEvent<T>> AsObservable<T>(string elementRoot = \"\");\n\n        /// <summary>\n        /// Builds the actual url of this query.\n        /// </summary>\n        /// <returns> The <see cref=\"string\"/>. </returns>\n        Task<string> BuildUrlAsync();\n    }\n}\n"
  },
  {
    "path": "Database/Query/OrderQuery.cs",
    "content": "namespace Firebase.Xamarin.Database.Query\n{\n    using System;\n\n    /// <summary>\n    /// Represents a firebase ordering query, e.g. \"?OrderBy=Foo\".\n    /// </summary>\n    public class OrderQuery : ParameterQuery\n    {\n        private readonly Func<string> propertyNameFactory;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"OrderQuery\"/> class.\n        /// </summary>\n        /// <param name=\"parent\"> The query parent. </param>\n        /// <param name=\"propertyNameFactory\"> The property name. </param>\n        /// <param name=\"client\"> The owning client. </param>\n        public OrderQuery(ChildQuery parent, Func<string> propertyNameFactory, FirebaseClient client)\n            : base(parent, () => \"orderBy\", client)\n        {\n            this.propertyNameFactory = propertyNameFactory;\n        }\n\n        /// <summary>\n        /// The build url parameter.\n        /// </summary>\n        /// <param name=\"child\"> The child. </param>\n        /// <returns> The <see cref=\"string\"/>. </returns>\n        protected override string BuildUrlParameter(FirebaseQuery child)\n        {\n            return $\"\\\"{this.propertyNameFactory()}\\\"\";\n        }\n    }\n}\n"
  },
  {
    "path": "Database/Query/ParameterQuery.cs",
    "content": "namespace Firebase.Xamarin.Database.Query\n{\n    using System;\n\n    /// <summary>\n    /// Represents a parameter in firebase query, e.g. \"?data=foo\".\n    /// </summary>\n    public abstract class ParameterQuery : FirebaseQuery\n    {\n        private readonly Func<string> parameterFactory;\n        private readonly string separator;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ParameterQuery\"/> class.\n        /// </summary>\n        /// <param name=\"parent\"> The parent of this query. </param>\n        /// <param name=\"parameterFactory\"> The parameter. </param>\n        /// <param name=\"client\"> The owning client. </param>\n        protected ParameterQuery(FirebaseQuery parent, Func<string> parameterFactory, FirebaseClient client)\n            : base(parent, client)\n        {\n            this.parameterFactory = parameterFactory;\n            this.separator = (this.Parent is ChildQuery) ? \"?\" : \"&\";\n        }\n\n        /// <summary>\n        /// Build the url segment represented by this query. \n        /// </summary> \n        /// <param name=\"child\"> The child. </param>\n        /// <returns> The <see cref=\"string\"/>. </returns>\n        protected override string BuildUrlSegment(FirebaseQuery child)\n        {\n            return $\"{this.separator}{this.parameterFactory()}={this.BuildUrlParameter(child)}\";\n        }\n\n        /// <summary>\n        /// The build url parameter.\n        /// </summary>\n        /// <param name=\"child\"> The child. </param>\n        /// <returns> The <see cref=\"string\"/>. </returns>\n        protected abstract string BuildUrlParameter(FirebaseQuery child);\n    }\n}\n"
  },
  {
    "path": "Database/Query/QueryExtensions.cs",
    "content": "namespace Firebase.Xamarin.Database.Query\n{\n    /// <summary>\n    /// Query extensions providing linq like syntax for firebase server methods.\n    /// </summary>\n    public static class QueryExtensions\n    {\n        /// <summary>\n        /// Adds an auth parameter to the query.\n        /// </summary>\n        /// <param name=\"node\"> The child. </param>\n        /// <param name=\"token\"> The auth token. </param>\n        /// <returns> The <see cref=\"AuthQuery\"/>. </returns>\n        public static AuthQuery WithAuth(this FirebaseQuery node, string token)\n        {\n            return node.WithAuth(() => token);\n        }\n\n        /// <summary>\n        /// References a sub child of the existing node.\n        /// </summary>\n        /// <param name=\"node\"> The child. </param>\n        /// <param name=\"path\"> The path of sub child. </param>\n        /// <returns> The <see cref=\"ChildQuery\"/>. </returns>\n        public static ChildQuery Child(this ChildQuery node, string path)\n        {\n            return node.Child(() => path);\n        }\n\n        /// <summary>\n        /// Order data by given <see cref=\"propertyName\"/>. Note that this is used mainly for following filtering queries and due to firebase implementation\n        /// the data may actually not be ordered.\n        /// </summary>\n        /// <param name=\"child\"> The child. </param>\n        /// <param name=\"propertyName\"> The property name. </param>\n        /// <returns> The <see cref=\"OrderQuery\"/>. </returns>\n        public static OrderQuery OrderBy(this ChildQuery child, string propertyName)\n        {\n            return child.OrderBy(() => propertyName);\n        }\n\n        /// <summary>\n        /// Instructs firebase to send data greater or equal to the <see cref=\"value\"/>. This must be preceded by an OrderBy query.\n        /// </summary>\n        /// <param name=\"child\"> Current node. </param>\n        /// <param name=\"value\"> Value to start at. </param>\n        /// <returns> The <see cref=\"FilterQuery\"/>. </returns>\n        public static FilterQuery StartAt(this ParameterQuery child, string value)\n        {\n            return child.StartAt(() => value);\n        }\n\n        /// <summary>\n        /// Instructs firebase to send data lower or equal to the <see cref=\"value\"/>. This must be preceded by an OrderBy query.\n        /// </summary>\n        /// <param name=\"child\"> Current node. </param>\n        /// <param name=\"value\"> Value to start at. </param>\n        /// <returns> The <see cref=\"FilterQuery\"/>. </returns>\n        public static FilterQuery EndAt(this ParameterQuery child, string value)\n        {\n            return child.EndAt(() => value);\n        }\n\n        /// <summary>\n        /// Instructs firebase to send data equal to the <see cref=\"value\"/>. This must be preceded by an OrderBy query.\n        /// </summary>\n        /// <param name=\"child\"> Current node. </param>\n        /// <param name=\"value\"> Value to start at. </param>\n        /// <returns> The <see cref=\"FilterQuery\"/>. </returns>\n        public static FilterQuery EqualTo(this ParameterQuery child, string value)\n        {\n            return child.EqualTo(() => value);\n        }\n\n        /// <summary>\n        /// Instructs firebase to send data greater or equal to the <see cref=\"value\"/>. This must be preceded by an OrderBy query.\n        /// </summary>\n        /// <param name=\"child\"> Current node. </param>\n        /// <param name=\"value\"> Value to start at. </param>\n        /// <returns> The <see cref=\"FilterQuery\"/>. </returns>\n        public static FilterQuery StartAt(this ParameterQuery child, double value)\n        {\n            return child.StartAt(() => value);\n        }\n\n        /// <summary>\n        /// Instructs firebase to send data lower or equal to the <see cref=\"value\"/>. This must be preceded by an OrderBy query.\n        /// </summary>\n        /// <param name=\"child\"> Current node. </param>\n        /// <param name=\"value\"> Value to start at. </param>\n        /// <returns> The <see cref=\"FilterQuery\"/>. </returns>\n        public static FilterQuery EndAt(this ParameterQuery child, double value)\n        {\n            return child.EndAt(() => value);\n        }\n\n        /// <summary>\n        /// Instructs firebase to send data equal to the <see cref=\"value\"/>. This must be preceded by an OrderBy query.\n        /// </summary>\n        /// <param name=\"child\"> Current node. </param>\n        /// <param name=\"value\"> Value to start at. </param>\n        /// <returns> The <see cref=\"FilterQuery\"/>. </returns>\n        public static FilterQuery EqualTo(this ParameterQuery child, double value)\n        {\n            return child.EqualTo(() => value);\n        }\n\n        /// <summary>\n        /// Limits the result to first <see cref=\"count\"/> items.\n        /// </summary>\n        /// <param name=\"child\"> Current node. </param>\n        /// <param name=\"count\"> Number of elements. </param>\n        /// <returns> The <see cref=\"FilterQuery\"/>. </returns>\n        public static FilterQuery LimitToFirst(this ParameterQuery child, int count)\n        {\n            return child.LimitToFirst(() => count);\n        }\n\n        /// <summary>\n        /// Limits the result to last <see cref=\"count\"/> items.\n        /// </summary>\n        /// <param name=\"child\"> Current node. </param>\n        /// <param name=\"count\"> Number of elements. </param>\n        /// <returns> The <see cref=\"FilterQuery\"/>. </returns>\n        public static FilterQuery LimitToLast(this ParameterQuery child, int count)\n        {\n            return child.LimitToLast(() => count);\n        }\n    }\n}\n"
  },
  {
    "path": "Database/Query/QueryFactoryExtensions.cs",
    "content": "namespace Firebase.Xamarin.Database.Query\n{\n    using System;\n\n    /// <summary>\n    /// Query extensions providing linq like syntax for firebase server methods.\n    /// </summary>\n    public static class QueryFactoryExtensions\n    {\n        /// <summary>\n        /// Adds an auth parameter to the query.\n        /// </summary>\n        /// <param name=\"node\"> The child. </param>\n        /// <param name=\"tokenFactory\"> The auth token. </param>\n        /// <returns> The <see cref=\"AuthQuery\"/>. </returns>\n        public static AuthQuery WithAuth(this FirebaseQuery node, Func<string> tokenFactory)\n        {\n            return new AuthQuery(node, tokenFactory, node.Client);\n        }\n\n        /// <summary>\n        /// References a sub child of the existing node.\n        /// </summary>\n        /// <param name=\"node\"> The child. </param>\n        /// <param name=\"pathFactory\"> The path of sub child. </param>\n        /// <returns> The <see cref=\"ChildQuery\"/>. </returns>\n        public static ChildQuery Child(this ChildQuery node, Func<string> pathFactory)\n        {\n            return new ChildQuery(node, pathFactory, node.Client);\n        }\n\n        /// <summary>\n        /// Order data by given <see cref=\"propertyNameFactory\"/>. Note that this is used mainly for following filtering queries and due to firebase implementation\n        /// the data may actually not be ordered.\n        /// </summary>\n        /// <param name=\"child\"> The child. </param>\n        /// <param name=\"propertyNameFactory\"> The property name. </param>\n        /// <returns> The <see cref=\"OrderQuery\"/>. </returns>\n        public static OrderQuery OrderBy(this ChildQuery child, Func<string> propertyNameFactory)\n        {\n            return new OrderQuery(child, propertyNameFactory, child.Client);\n        }\n\n        /// <summary>\n        /// Order data by $key. Note that this is used mainly for following filtering queries and due to firebase implementation\n        /// the data may actually not be ordered.\n        /// </summary>\n        /// <param name=\"child\"> The child. </param>\n        /// <returns> The <see cref=\"OrderQuery\"/>. </returns>\n        public static OrderQuery OrderByKey(this ChildQuery child)\n        {\n            return child.OrderBy(\"$key\");\n        }\n\n        /// <summary>\n        /// Order data by $value. Note that this is used mainly for following filtering queries and due to firebase implementation\n        /// the data may actually not be ordered.\n        /// </summary>\n        /// <param name=\"child\"> The child. </param>\n        /// <returns> The <see cref=\"OrderQuery\"/>. </returns>\n        public static OrderQuery OrderByValue(this ChildQuery child)\n        {\n            return child.OrderBy(\"$value\");\n        }\n\n        /// <summary>\n        /// Order data by $priority. Note that this is used mainly for following filtering queries and due to firebase implementation\n        /// the data may actually not be ordered.\n        /// </summary>\n        /// <param name=\"child\"> The child. </param>\n        /// <returns> The <see cref=\"OrderQuery\"/>. </returns>\n        public static OrderQuery OrderByPriority(this ChildQuery child)\n        {\n            return child.OrderBy(\"$priority\");\n        }\n\n        /// <summary>\n        /// Instructs firebase to send data greater or equal to the <see cref=\"valueFactory\"/>. This must be preceded by an OrderBy query.\n        /// </summary>\n        /// <param name=\"child\"> Current node. </param>\n        /// <param name=\"valueFactory\"> Value to start at. </param>\n        /// <returns> The <see cref=\"FilterQuery\"/>. </returns>\n        public static FilterQuery StartAt(this ParameterQuery child, Func<string> valueFactory)\n        {\n            return new FilterQuery(child, () => \"startAt\", valueFactory, child.Client);\n        }\n\n        /// <summary>\n        /// Instructs firebase to send data lower or equal to the <see cref=\"valueFactory\"/>. This must be preceded by an OrderBy query.\n        /// </summary>\n        /// <param name=\"child\"> Current node. </param>\n        /// <param name=\"valueFactory\"> Value to start at. </param>\n        /// <returns> The <see cref=\"FilterQuery\"/>. </returns>\n        public static FilterQuery EndAt(this ParameterQuery child, Func<string> valueFactory)\n        {\n            return new FilterQuery(child, () => \"endAt\", valueFactory, child.Client);\n        }\n\n        /// <summary>\n        /// Instructs firebase to send data equal to the <see cref=\"valueFactory\"/>. This must be preceded by an OrderBy query.\n        /// </summary>\n        /// <param name=\"child\"> Current node. </param>\n        /// <param name=\"valueFactory\"> Value to start at. </param>\n        /// <returns> The <see cref=\"FilterQuery\"/>. </returns>\n        public static FilterQuery EqualTo(this ParameterQuery child, Func<string> valueFactory)\n        {\n            return new FilterQuery(child, () => \"equalTo\", valueFactory, child.Client);\n        }\n\n        /// <summary>\n        /// Instructs firebase to send data greater or equal to the <see cref=\"valueFactory\"/>. This must be preceded by an OrderBy query.\n        /// </summary>\n        /// <param name=\"child\"> Current node. </param>\n        /// <param name=\"valueFactory\"> Value to start at. </param>\n        /// <returns> The <see cref=\"FilterQuery\"/>. </returns>\n        public static FilterQuery StartAt(this ParameterQuery child, Func<double> valueFactory)\n        {\n            return new FilterQuery(child, () => \"startAt\", valueFactory, child.Client);\n        }\n\n        /// <summary>\n        /// Instructs firebase to send data lower or equal to the <see cref=\"valueFactory\"/>. This must be preceded by an OrderBy query.\n        /// </summary>\n        /// <param name=\"child\"> Current node. </param>\n        /// <param name=\"valueFactory\"> Value to start at. </param>\n        /// <returns> The <see cref=\"FilterQuery\"/>. </returns>\n        public static FilterQuery EndAt(this ParameterQuery child, Func<double> valueFactory)\n        {\n            return new FilterQuery(child, () => \"endAt\", valueFactory, child.Client);\n        }\n\n        /// <summary>\n        /// Instructs firebase to send data equal to the <see cref=\"valueFactory\"/>. This must be preceded by an OrderBy query.\n        /// </summary>\n        /// <param name=\"child\"> Current node. </param>\n        /// <param name=\"valueFactory\"> Value to start at. </param>\n        /// <returns> The <see cref=\"FilterQuery\"/>. </returns>\n        public static FilterQuery EqualTo(this ParameterQuery child, Func<double> valueFactory)\n        {\n            return new FilterQuery(child, () => \"equalTo\", valueFactory, child.Client);\n        }\n\n        /// <summary>\n        /// Limits the result to first <see cref=\"countFactory\"/> items.\n        /// </summary>\n        /// <param name=\"child\"> Current node. </param>\n        /// <param name=\"countFactory\"> Number of elements. </param>\n        /// <returns> The <see cref=\"FilterQuery\"/>. </returns>\n        public static FilterQuery LimitToFirst(this ParameterQuery child, Func<int> countFactory)\n        {\n            return new FilterQuery(child, () => \"limitToFirst\", () => countFactory(), child.Client);\n        }\n\n        /// <summary>\n        /// Limits the result to last <see cref=\"countFactory\"/> items.\n        /// </summary>\n        /// <param name=\"child\"> Current node. </param>\n        /// <param name=\"countFactory\"> Number of elements. </param>\n        /// <returns> The <see cref=\"FilterQuery\"/>. </returns>\n        public static FilterQuery LimitToLast(this ParameterQuery child, Func<int> countFactory)\n        {\n            return new FilterQuery(child, () => \"limitToLast\", () => countFactory(), child.Client);\n        }\n    }\n}\n"
  },
  {
    "path": "Database/Streaming/FirebaseCache.cs",
    "content": "namespace Firebase.Xamarin.Database.Streaming\n{\n    using System;\n    using System.Collections;\n    using System.Collections.Generic;\n    using System.Linq;\n    using System.Reflection;\n\n    using Firebase.Xamarin.Database.Http;\n\n    using Newtonsoft.Json;\n\n    /// <summary>\n    /// The firebase cache.\n    /// </summary>\n    /// <typeparam name=\"T\"> Type of top-level entities in the cache. </typeparam>\n    public class FirebaseCache<T> : IEnumerable<FirebaseObject<T>>\n    {\n        private readonly IDictionary<string, T> dictionary;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FirebaseCache{T}\"/> class.\n        /// </summary>\n        public FirebaseCache() \n            : this(new Dictionary<string, T>())\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FirebaseCache{T}\"/> class and populates it with existing data.\n        /// </summary>\n        /// <param name=\"existingItems\"> The existing items. </param>\n        public FirebaseCache(IDictionary<string, T> existingItems)\n        {\n            this.dictionary = existingItems;\n        }\n\n        /// <summary>\n        /// The push data.\n        /// </summary>\n        /// <param name=\"path\"> The path of incoming data, separated by slash. </param>  \n        /// <param name=\"data\"> The data in json format as returned by firebase. </param>  \n        /// <returns> Collection of top-level entities which were affected by the push. </returns>\n        public IEnumerable<FirebaseObject<T>> PushData(string path, string data) \n        {\n            object obj = this.dictionary;\n            Action<object> primitiveObjSetter = null;\n            Action objDeleter = null;\n\n            var pathElements = path.Split(new[] { \"/\" }, StringSplitOptions.RemoveEmptyEntries);\n\n            // first find where we should insert the data to\n            foreach (var element in pathElements)\n            {\n                if (obj is IDictionary)\n                {\n                    // if it's a dictionary, then it's just a matter of inserting into it / accessing existing object by key\n                    var dictionary = obj as IDictionary;\n                    var valueType = obj.GetType().GenericTypeArguments[1];\n\n                    primitiveObjSetter = (d) => dictionary[element] = d;\n                    objDeleter = () => dictionary.Remove(element);\n\n                    if (dictionary.Contains(element))\n                    {\n                        obj = dictionary[element];\n                    }\n                    else\n                    {\n                        if (valueType == typeof(string))\n                        {\n                            dictionary[element] = string.Empty;\n                            obj = dictionary[element];\n                        }\n                        else\n                        {\n                            dictionary[element] = Activator.CreateInstance(valueType);\n                            obj = dictionary[element];\n                        }\n                    }\n                }\n                else\n                {\n                    // if it's not a dictionary, try to find the property of current object with the matching name\n                    var objParent = obj;\n                    var property = objParent\n                        .GetType()\n                        .GetRuntimeProperties()\n                        .First(p => p.Name.Equals(element, StringComparison.OrdinalIgnoreCase) || element == p.GetCustomAttribute<JsonPropertyAttribute>()?.PropertyName);\n\n                    objDeleter = () => property.SetValue(objParent, null);\n                    primitiveObjSetter = (d) => property.SetValue(objParent, d);\n                    obj = property.GetValue(obj);\n                }\n            }\n\n            // if data is null (=empty string) delete it\n            if (string.IsNullOrWhiteSpace(data))\n            {\n                var key = pathElements[0];\n                var target = this.dictionary[key];\n\n                objDeleter();\n\n                yield return new FirebaseObject<T>(key, target);\n                yield break;\n            }\n\n            // now insert the data\n            if (obj is IDictionary)\n            {\n                // insert data into dictionary and return it as a collection of FirebaseObject\n                var dictionary = obj as IDictionary;\n                var valueType = obj.GetType().GenericTypeArguments[1];\n                var objectCollection = data.GetObjectCollection(valueType);\n\n                foreach (var item in objectCollection)\n                {\n                    dictionary[item.Key] = item.Object;\n                    yield return new FirebaseObject<T>(item.Key, (T)item.Object);\n                }\n            }\n            else\n            {\n                // set the data on a property of the given object\n                var valueType = obj.GetType();\n                var targetObject = JsonConvert.DeserializeObject(data, valueType);\n\n                if ((valueType.GetTypeInfo().IsPrimitive || valueType == typeof(string)) && primitiveObjSetter != null)\n                {\n                    // handle primitive (value) types separately\n                    primitiveObjSetter(targetObject);\n                }\n                else\n                {\n                    JsonConvert.PopulateObject(data, obj);\n                }\n\n                this.dictionary[pathElements[0]] = this.dictionary[pathElements[0]];\n                yield return new FirebaseObject<T>(pathElements[0], this.dictionary[pathElements[0]]);\n            }\n        }\n\n        #region IEnumerable\n\n        IEnumerator IEnumerable.GetEnumerator()\n        {\n            return this.GetEnumerator();\n        }\n\n        public IEnumerator<FirebaseObject<T>> GetEnumerator()\n        {\n            return this.dictionary.Select(p => new FirebaseObject<T>(p.Key, p.Value)).GetEnumerator();\n        }\n\n        #endregion\n    }\n}\n"
  },
  {
    "path": "Database/Streaming/FirebaseEvent.cs",
    "content": "namespace Firebase.Xamarin.Database.Streaming\n{\n    /// <summary>\n    /// Firebase event which hold <see cref=\"EventType\"/> and the object affected by the event.\n    /// </summary>\n    /// <typeparam name=\"T\"> Type of object affected by the event. </typeparam>\n    public class FirebaseEvent<T> : FirebaseObject<T>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FirebaseEvent{T}\"/> class.\n        /// </summary>\n        /// <param name=\"key\"> The key of the object. </param>\n        /// <param name=\"obj\"> The object. </param>\n        /// <param name=\"eventType\"> The event type. </param>\n        public FirebaseEvent(string key, T obj, FirebaseEventType eventType)\n            : base(key, obj)\n        {\n            this.EventType = eventType;\n        }\n\n        /// <summary>\n        /// Gets the event type.\n        /// </summary>\n        public FirebaseEventType EventType\n        {\n            get;\n        }\n    }\n}\n"
  },
  {
    "path": "Database/Streaming/FirebaseEventType.cs",
    "content": "namespace Firebase.Xamarin.Database.Streaming\n{\n    /// <summary>\n    /// The type of event. \n    /// </summary>\n    public enum FirebaseEventType\n    {\n        /// <summary>\n        /// Item was inserted or updated.\n        /// </summary>\n        InsertOrUpdate,\n\n        /// <summary>\n        /// Item was deleted.\n        /// </summary>\n        Delete\n    }\n}\n"
  },
  {
    "path": "Database/Streaming/FirebaseServerEventType.cs",
    "content": "namespace Firebase.Xamarin.Database.Streaming\n{\n    internal enum FirebaseServerEventType\n    {\n        Put,\n\n        Patch,\n\n        KeepAlive,\n\n        Cancel,\n\n        AuthRevoked\n    }\n}\n"
  },
  {
    "path": "Database/Streaming/FirebaseSubscription.cs",
    "content": "namespace Firebase.Xamarin.Database.Streaming\n{\n    using System;\n    using System.Diagnostics;\n    using System.IO;\n    using System.Linq;\n    using System.Net.Http;\n    using System.Net.Http.Headers;\n    using System.Threading;\n    using System.Threading.Tasks;\n\n    using Firebase.Xamarin.Database.Query;\n\n    using Newtonsoft.Json.Linq;\n\n    /// <summary>\n    /// The firebase subscription.\n    /// </summary>\n    /// <typeparam name=\"T\"> Type of object to be streaming back to the called. </typeparam>\n    internal class FirebaseSubscription<T> : IDisposable\n    {\n        private readonly CancellationTokenSource cancel;\n        private readonly HttpClient httpClient;\n        private readonly IObserver<FirebaseEvent<T>> observer;\n        private readonly IFirebaseQuery query;\n        private readonly FirebaseCache<T> cache;\n        private readonly string elementRoot;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"FirebaseSubscription{T}\"/> class.\n        /// </summary>\n        /// <param name=\"observer\"> The observer.  </param>\n        /// <param name=\"query\"> The query.  </param>\n        /// <param name=\"cache\"> The cache. </param>\n        public FirebaseSubscription(IObserver<FirebaseEvent<T>> observer, IFirebaseQuery query, string elementRoot, FirebaseCache<T> cache)\n        {\n            this.observer = observer;\n            this.query = query;\n            this.elementRoot = elementRoot;\n            this.cancel = new CancellationTokenSource();\n            this.httpClient = new HttpClient();\n            this.cache = cache;\n\n            var handler = new HttpClientHandler\n            {\n                AllowAutoRedirect = true,\n                MaxAutomaticRedirections = 10,\n            };\n\n            this.httpClient = new HttpClient(handler, true)\n            {\n                Timeout = TimeSpan.FromMilliseconds(Timeout.Infinite),\n            };\n\n            this.httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(\"text/event-stream\"));\n        }\n\n        public void Dispose()\n        {\n            this.httpClient.Dispose();\n            this.cancel.Cancel();\n        }\n\n        public IDisposable Run()\n        {\n            Task.Factory.StartNew(this.ReceiveThread);\n\n            return this;\n        }\n\n        private async void ReceiveThread()\n        {\n            while (true)\n            {\n                try\n                {\n                    this.cancel.Token.ThrowIfCancellationRequested();\n\n                    // initialize network connection\n                    var serverEvent = FirebaseServerEventType.KeepAlive;\n                    var request = new HttpRequestMessage(HttpMethod.Get, await this.query.BuildUrlAsync().ConfigureAwait(false));\n                    var response = await this.httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, this.cancel.Token).ConfigureAwait(false);\n\n                    response.EnsureSuccessStatusCode();\n\n                    using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))\n                    using (var reader = new StreamReader(stream))\n                    {\n                        while (true)\n                        {\n                            var line = reader.ReadLine();\n\n                            this.cancel.Token.ThrowIfCancellationRequested();\n\n                            if (string.IsNullOrWhiteSpace(line))\n                            {\n                                await Task.Delay(2000).ConfigureAwait(false);\n                                continue;\n                            }\n\n                            var tuple = line.Split(new[] { ':' }, 2, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).ToArray();\n\n                            switch (tuple[0].ToLower())\n                            {\n                                case \"event\":\n                                    serverEvent = this.ParseServerEvent(serverEvent, tuple[1]);\n                                    break;\n                                case \"data\":\n                                    this.ProcessServerData(serverEvent, tuple[1]);\n                                    break;\n                            }\n\n                            if (serverEvent == FirebaseServerEventType.AuthRevoked)\n                            {\n                                // auth token no longer valid, reconnect\n                                break;\n                            }\n                        }\n                    }\n                }\n                catch (OperationCanceledException)\n                {\n                    break;\n                }\n                catch (Exception ex)\n                {\n                    Debug.WriteLine(\"************************************************************\");\n                    Debug.WriteLine(ex.ToString());\n                    Debug.WriteLine(\"************************************************************\");\n                    await Task.Delay(2000).ConfigureAwait(false);\n                }\n            }\n        }\n\n        private FirebaseServerEventType ParseServerEvent(FirebaseServerEventType serverEvent, string eventName)\n        {\n            switch (eventName)\n            {\n                case \"put\":\n                    serverEvent = FirebaseServerEventType.Put;\n                    break;\n                case \"patch\":\n                    serverEvent = FirebaseServerEventType.Patch;\n                    break;\n                case \"keep-alive\":\n                    serverEvent = FirebaseServerEventType.KeepAlive;\n                    break;\n                case \"cancel\":\n                    serverEvent = FirebaseServerEventType.Cancel;\n                    break;\n                case \"auth_revoked\":\n                    serverEvent = FirebaseServerEventType.AuthRevoked;\n                    break;\n            }\n\n            return serverEvent;\n        }\n\n        private void ProcessServerData(FirebaseServerEventType serverEvent, string serverData)\n        {\n            switch (serverEvent)\n            {\n                case FirebaseServerEventType.Put:\n                case FirebaseServerEventType.Patch:\n                    var result = JObject.Parse(serverData);\n                    var path = result[\"path\"].ToString();\n                    var data = result[\"data\"].ToString();\n                    var eventType = string.IsNullOrWhiteSpace(data) ? FirebaseEventType.Delete : FirebaseEventType.InsertOrUpdate;\n\n                    var items = this.cache.PushData(this.elementRoot + path, data);\n\n                    foreach (var i in items.ToList())\n                    {\n                        this.observer.OnNext(new FirebaseEvent<T>(i.Key, i.Object, eventType));\n                    }\n\n                    break;\n                case FirebaseServerEventType.KeepAlive:\n                    break;\n                case FirebaseServerEventType.Cancel:\n                    this.observer.OnError(new Exception(\"cancel\"));\n                    this.Dispose();\n                    throw new OperationCanceledException();\n                case FirebaseServerEventType.AuthRevoked:\n                    this.observer.OnError(new Exception(\"auth\"));\n                    this.Dispose();\n                    throw new OperationCanceledException();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Firebase.Xamarin.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"14.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\r\n  <PropertyGroup>\r\n    <MinimumVisualStudioVersion>10.0</MinimumVisualStudioVersion>\r\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\r\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\r\n    <ProjectGuid>{4ED07DF1-95A7-4780-BC6A-BEF0BD4FF4C3}</ProjectGuid>\r\n    <OutputType>Library</OutputType>\r\n    <AppDesignerFolder>Properties</AppDesignerFolder>\r\n    <RootNamespace>Firebase.Xamarin</RootNamespace>\r\n    <AssemblyName>Firebase.Xamarin</AssemblyName>\r\n    <DefaultLanguage>en-US</DefaultLanguage>\r\n    <FileAlignment>512</FileAlignment>\r\n    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>\r\n    <TargetFrameworkProfile>Profile111</TargetFrameworkProfile>\r\n    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>\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  </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  </PropertyGroup>\r\n  <ItemGroup>\r\n    <Compile Include=\"Auth\\FirebaseAuth.cs\" />\r\n    <Compile Include=\"Auth\\FirebaseAuthLink.cs\" />\r\n    <Compile Include=\"Auth\\FirebaseAuthProvider.cs\" />\r\n    <Compile Include=\"Auth\\FirebaseAuthType.cs\" />\r\n    <Compile Include=\"Auth\\FirebaseConfig.cs\" />\r\n    <Compile Include=\"Auth\\IFirebaseAuthProvider.cs\" />\r\n    <Compile Include=\"Auth\\User.cs\" />\r\n    <Compile Include=\"Database\\FirebaseClient.cs\" />\r\n    <Compile Include=\"Database\\FirebaseKeyGenerator.cs\" />\r\n    <Compile Include=\"Database\\FirebaseObject.cs\" />\r\n    <Compile Include=\"Database\\GlobalSuppressions.cs\" />\r\n    <Compile Include=\"Database\\ObservableExtensions.cs\" />\r\n    <Compile Include=\"Database\\Http\\HttpClientExtensions.cs\" />\r\n    <Compile Include=\"Database\\Http\\PostResult.cs\" />\r\n    <Compile Include=\"Database\\Offline\\ExceptionEventArgs.cs\" />\r\n    <Compile Include=\"Database\\Offline\\OfflineCacheAdapter.cs\" />\r\n    <Compile Include=\"Database\\Offline\\OfflineEntry.cs\" />\r\n    <Compile Include=\"Database\\Offline\\RealtimeDatabase.cs\" />\r\n    <Compile Include=\"Database\\Offline\\SyncOptions.cs\" />\r\n    <Compile Include=\"Database\\Properties\\AssemblyInfo.cs\" />\r\n    <Compile Include=\"Database\\Query\\AuthQuery.cs\" />\r\n    <Compile Include=\"Database\\Query\\ChildQuery.cs\" />\r\n    <Compile Include=\"Database\\Query\\FilterQuery.cs\" />\r\n    <Compile Include=\"Database\\Query\\FirebaseQuery.cs\" />\r\n    <Compile Include=\"Database\\Query\\IFirebaseQuery.cs\" />\r\n    <Compile Include=\"Database\\Query\\OrderQuery.cs\" />\r\n    <Compile Include=\"Database\\Query\\ParameterQuery.cs\" />\r\n    <Compile Include=\"Database\\Query\\QueryExtensions.cs\" />\r\n    <Compile Include=\"Database\\Query\\QueryFactoryExtensions.cs\" />\r\n    <Compile Include=\"Database\\Streaming\\FirebaseCache.cs\" />\r\n    <Compile Include=\"Database\\Streaming\\FirebaseEvent.cs\" />\r\n    <Compile Include=\"Database\\Streaming\\FirebaseEventType.cs\" />\r\n    <Compile Include=\"Database\\Streaming\\FirebaseServerEventType.cs\" />\r\n    <Compile Include=\"Database\\Streaming\\FirebaseSubscription.cs\" />\r\n    <Compile Include=\"Token\\StreamToken.cs\" />\r\n    <Compile Include=\"Token\\TokenGenerator.cs\" />\r\n    <Compile Include=\"Token\\TokenOptions.cs\" />\r\n    <Compile Include=\"Auth\\FirebaseAuthException.cs\" />\r\n    <Compile Include=\"Notification\\PushNotification.cs\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Reference Include=\"System.Reactive.Core, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\r\n      <HintPath>packages\\Rx-Core.2.2.5\\lib\\portable-net45+winrt45+wp8+wpa81\\System.Reactive.Core.dll</HintPath>\r\n      <Private>True</Private>\r\n    </Reference>\r\n    <Reference Include=\"System.Reactive.Interfaces, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\r\n      <HintPath>packages\\Rx-Interfaces.2.2.5\\lib\\portable-net45+winrt45+wp8+wpa81\\System.Reactive.Interfaces.dll</HintPath>\r\n      <Private>True</Private>\r\n    </Reference>\r\n    <Reference Include=\"System.Reactive.Linq, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\r\n      <HintPath>packages\\Rx-Linq.2.2.5\\lib\\portable-net45+winrt45+wp8+wpa81\\System.Reactive.Linq.dll</HintPath>\r\n      <Private>True</Private>\r\n    </Reference>\r\n    <Reference Include=\"System.Reactive.PlatformServices, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\r\n      <HintPath>packages\\Rx-PlatformServices.2.2.5\\lib\\portable-net45+winrt45+wp8+wpa81\\System.Reactive.PlatformServices.dll</HintPath>\r\n      <Private>True</Private>\r\n    </Reference>\r\n    <Reference Include=\"crypto\">\r\n      <HintPath>packages\\Portable.BouncyCastle.1.8.0\\lib\\portable-net45+win8+wpa81+MonoTouch10+MonoAndroid10+xamarinmac20+xamarinios10\\crypto.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"JWT\">\r\n      <HintPath>packages\\Portable.JWT.1.0.5\\lib\\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\\JWT.dll</HintPath>\r\n    </Reference>\r\n    <Reference Include=\"Newtonsoft.Json\">\r\n      <HintPath>packages\\Newtonsoft.Json.9.0.1\\lib\\portable-net45+wp80+win8+wpa81\\Newtonsoft.Json.dll</HintPath>\r\n    </Reference>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"packages.config\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Folder Include=\"Token\\\" />\r\n    <Folder Include=\"Notification\\\" />\r\n  </ItemGroup>\r\n  <Import Project=\"$(MSBuildExtensionsPath32)\\Microsoft\\Portable\\$(TargetFrameworkVersion)\\Microsoft.Portable.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>\r\n"
  },
  {
    "path": "Firebase.Xamarin.sln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio 14\r\nVisualStudioVersion = 14.0.25123.0\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Firebase.Xamarin\", \"Firebase.Xamarin.csproj\", \"{4ED07DF1-95A7-4780-BC6A-BEF0BD4FF4C3}\"\r\nEndProject\r\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"NuGet.Packager\", \"..\\NuGet.Packager\\NuGet.Packager.csproj\", \"{0451BAEF-DF2E-4B98-8644-94EE9415E389}\"\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|Any CPU = Debug|Any CPU\r\n\t\tRelease|Any CPU = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{4ED07DF1-95A7-4780-BC6A-BEF0BD4FF4C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{4ED07DF1-95A7-4780-BC6A-BEF0BD4FF4C3}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{4ED07DF1-95A7-4780-BC6A-BEF0BD4FF4C3}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{4ED07DF1-95A7-4780-BC6A-BEF0BD4FF4C3}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\t\t{0451BAEF-DF2E-4B98-8644-94EE9415E389}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r\n\t\t{0451BAEF-DF2E-4B98-8644-94EE9415E389}.Debug|Any CPU.Build.0 = Debug|Any CPU\r\n\t\t{0451BAEF-DF2E-4B98-8644-94EE9415E389}.Release|Any CPU.ActiveCfg = Release|Any CPU\r\n\t\t{0451BAEF-DF2E-4B98-8644-94EE9415E389}.Release|Any CPU.Build.0 = Release|Any CPU\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\r\n\r\nCopyright (c) 2016 ricardo\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\nSOFTWARE.\r\n"
  },
  {
    "path": "Notification/PushNotification.cs",
    "content": "using System;\nusing System.Net.Http;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Firebase.Xamarin.Auth;\n\nnamespace Firebase.Xamarin.Notification\n{\n  public class PushNotification\n  {\n    private const string NotificationUrl = \"https://fcm.googleapis.com/fcm/send\";\n\n    private readonly FirebaseConfig authConfig;\n\n    public PushNotification(FirebaseConfig authConfig)\n    {\n      this.authConfig = authConfig;\n    }\n\n    public async Task Send(string to, string title, string message)\n    {\n      using (HttpClient client = new HttpClient())\n      {\n        var postContent = $\"{{\\\"to\\\":\\\"{to}\\\",\\\"notification\\\":{{ \\\"title\\\":\\\"{title}\\\",\\\"text\\\":\\\"{message}\\\" }}}}\";\n\n        client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(\"key\", $\"={this.authConfig.ApiKeyForPushNotification}\");\n        var response = await client.PostAsync(NotificationUrl, new StringContent(postContent, Encoding.UTF8, \"application/json\")).ConfigureAwait(false);\n\n        response.EnsureSuccessStatusCode();\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "Properties/AssemblyInfo.cs",
    "content": "﻿using System.Resources;\r\nusing System.Reflection;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\n\r\n// General Information about an assembly is controlled through the following \r\n// set of attributes. Change these attribute values to modify the information\r\n// associated with an assembly.\r\n[assembly: AssemblyTitle(\"Firebase.Xamarin\")]\r\n[assembly: AssemblyDescription(\"\")]\r\n[assembly: AssemblyConfiguration(\"\")]\r\n[assembly: AssemblyCompany(\"\")]\r\n[assembly: AssemblyProduct(\"Firebase.Xamarin\")]\r\n[assembly: AssemblyCopyright(\"Copyright ©  2016\")]\r\n[assembly: AssemblyTrademark(\"\")]\r\n[assembly: AssemblyCulture(\"\")]\r\n[assembly: NeutralResourcesLanguage(\"en\")]\r\n\r\n// Version information for an assembly consists of the following four values:\r\n//\r\n//      Major Version\r\n//      Minor Version \r\n//      Build Number\r\n//      Revision\r\n//\r\n// You can specify all the values or you can default the Build and Revision Numbers \r\n// by using the '*' as shown below:\r\n// [assembly: AssemblyVersion(\"1.0.*\")]\r\n[assembly: AssemblyVersion(\"1.0.0.0\")]\r\n[assembly: AssemblyFileVersion(\"1.0.0.0\")]\r\n"
  },
  {
    "path": "README.md",
    "content": "# Firebase.Xamarin\nLight weight wrapper for Firebase Realtime Database REST API.\n## Installation\n```csharp\n// Install release version\nInstall-Package Firebase.Xamarin\n\n```\n\n## Supported frameworks\n* .NET 4.5+\n* ASP.Net Core 1.0\n* Xamarin Android\n* Xamarin iOS \n* Xamarin iOS Classic\n* Windows 8\n\n## Usage\n\nDepending on your [database rules](https://firebase.google.com/docs/database/security/) you may need to first Authenticate with your Auth Provider. Instructions for Authentication are towards the bottom.\n\n### Querying\n\n```csharp\nvar firebase = new FirebaseClient(\"https://yourdatabase.firebaseio.com/\");\nvar items = await firebase\n  .Child(\"yourentity\")\n  //.WithAuth(\"<Authentication Token>\") // <-- Add Auth token if required. Auth instructions further down in readme.\n  .OrderByKey()\n  .LimitToFirst(2)\n  .OnceAsync<YourObject>();\n  \nforeach (var item in items)\n{\n  Console.WriteLine($\"{item.Key} name is {item.Object.Name}\");\n}\n```\n\n### Saving data\n\n```csharp\nvar firebase = new FirebaseClient(\"https://yourdatabase.firebaseio.com/\");\n\n// add new item to list of data \nvar item = await firebase\n  .Child(\"yourentity\")\n  //.WithAuth(\"<Authentication Token>\") // <-- Add Auth token if required. Auth instructions further down in readme.\n  .PostAsync(new YourObject());\n  \n// note that there is another overload for the PostAsync method which delegates the new key generation to the client\n  \nConsole.WriteLine($\"Key for the new item: {item.Key}\");  \n\n// add new item directly to the specified location (this will overwrite whatever data already exists at that location)\nvar item = await firebase\n  .Child(\"yourentity\")\n  .Child(\"Ricardo\")\n  //.WithAuth(\"<Authentication Token>\") // <-- Add Auth token if required. Auth instructions further down in readme.\n  .PutAsync(new YourObject());\n\n```\n\n### Realtime streaming\n\n```csharp\nvar firebase = new FirebaseClient(\"https://dinosaur-facts.firebaseio.com/\");\nvar observable = firebase\n  .Child(\"dinosaurs\")\n  .AsObservable<Dinosaur>()\n  .Subscribe(d => Console.WriteLine(d.Key));\n  \n```\n\n```AsObservable<T>``` methods returns an ```IObservable<T>``` which you can take advantage of using [Reactive Extensions](https://github.com/Reactive-Extensions/Rx.NET)\n\n\n## Authentication\n\n### firebase.google.com Auth\n\nYou will need a firebase.google.com API Key for Authentication. The easiset way to find this is to click on 'Add Firebase to your web app' in the Overview section of your firebase.google.com console. The site will generate a JavaScript snippet that contains the ```apiKey``` variable.\n```csharp\n// Email/Password Auth\nvar authProvider = new FirebaseAuthProvider(new FirebaseConfig(\"<google.firebase.com API Key>\"));\n\nvar auth = await authProvider.CreateUserWithEmailAndPasswordAsync(\"email@email.com\", \"password\");\n\n// The auth Object will contain auth.User and the Authentication Token from the request\nSystem.Diagnostics.Debug.WriteLine(auth.FirebaseToken);\n\n\n// Facebook Auth\nvar authProvider = new FirebaseAuthProvider(new FirebaseConfig(\"<google.firebase.com API Key>\"));\nvar facebookAccessToken = \"<login with facebook and get oauth access token>\";\n\nvar auth = await authProvider.SignInWithOAuthAsync(FirebaseAuthType.Facebook, facebookAccessToken);\n\n// Using the Auth token to make requests.. (see more on requests below)\nvar firebase = new FirebaseClient(\"https://dinosaur-facts.firebaseio.com/\");\nvar dinos = await firebase\n  .Child(\"dinosaurs\")\n  .WithAuth(auth.FirebaseToken) // <-- Note the use of the Firebase Auth Token\n  .OnceAsync<Dinosaur>();\n\nforeach (var dino in dinos)\n{\n  System.Diagnostics.Debug.WriteLine($\"{dino.Key} is {dino.Object.Height}m high.\");\n}\n```\n\n\n### Custom Auth\n\n#### Generating Tokens\n\nTo generate tokens, you'll need your Firebase Secret which you can find by entering your Firebase\nURL into a browser and clicking the \"Secrets\" tab on the left-hand navigation menu.\n\nOnce you've downloaded the library and grabbed your Firebase Secret, you can generate a token with\nthis snippet of .Net code:\n\n```\nvar tokenGenerator = new Firebase.TokenGenerator(\"<YOUR_FIREBASE_SECRET>\");\nvar authPayload = new Dictionary<string, object>()\n{\n  { \"uid\", \"1\" },\n  { \"some\", \"arbitrary\" },\n  { \"data\", \"here\" }\n};\nstring token = tokenGenerator.CreateToken(authPayload);\n```\n\nThe payload object passed into `CreateToken()` is then available for use within your\nsecurity rules via the [`auth` variable](https://www.firebase.com/docs/security/api/rule/auth.html).\nThis is how you pass trusted authentication details (e.g. the client's user ID) to your\nFirebase rules. The payload can contain any data of your choosing, however it\nmust contain a \"uid\" key, which must be a string of less than 256 characters. The\ngenerated token must be less than 1024 characters in total.\n\n\n#### Token Options\n\nA second `options` argument can be passed to `CreateToken()` to modify how Firebase treats the\ntoken. Available options are:\n\n* **expires** (DateTime) - A timestamp denoting the time after which this token should no longer\nbe valid.\n\n* **notBefore** (DateTime) - A timestamp denoting the time before which this token should be\nrejected by the server.\n\n* **admin** (bool) - Set to `true` if you want to disable all security rules for this client. This\nwill provide the client with read and write access to your entire Firebase.\n\n* **debug** (bool) - Set to `true` to enable debug output from your security rules. You should\ngenerally *not* leave this set to `true` in production (as it slows down the rules implementation\nand gives your users visibility into your rules), but it can be helpful for debugging.\n\nHere is an example of how to use the second `options` argument:\n\n```\nvar tokenGenerator = new Firebase.TokenGenerator(\"<YOUR_FIREBASE_SECRET>\");\nvar authPayload = new Dictionary<string, object>()\n{\n  { \"uid\", \"1\" },\n  { \"some\", \"arbitrary\" },\n  { \"data\", \"here\" }\n};\nstring token = tokenGenerator.CreateToken(authPayload, new Firebase.TokenOptions(admin: true));\n  \n```\n## Thanks\nSpecial thanks to [bezysoftware](https://github.com/bezysoftware) for the original [firebase-database-dotnet] (https://github.com/step-up-labs/firebase-database-dotnet) and [firebase-authentication-dotnet] (https://github.com/step-up-labs/firebase-authentication-dotnet) code that is the core for this Xamarin adaptation. Also thanks to [mikelehen](https://github.com/mikelehen) for the original [Firebase Token Generator - .NET] (https://github.com/firebase/firebase-token-generator-dotNet)\n"
  },
  {
    "path": "Token/StreamToken.cs",
    "content": "﻿namespace Firebase.Xamarin.Token\n{\n\tusing System;\n\tusing System.Reactive.Linq;\n\tusing Firebase.Xamarin.Database.Streaming;\n\n\tpublic class StreamToken<T> : IDisposable\n\t{\n\t\tprivate IDisposable _observableDisposable;\n\t\tprivate IObservable<FirebaseEvent<T>> _observable;\n\n\t\tpublic StreamToken(IObservable<FirebaseEvent<T>> observable)\n\t\t{\n\t\t\t_observable = observable;\n\t\t}\n\n\t\tpublic StreamToken<T> Where(Func<FirebaseEvent<T>, bool> predicate)\n\t\t{\n\t\t\t_observable = _observable.Where(predicate);\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic StreamToken<T> Throttle(TimeSpan timeSpan)\n\t\t{\n\t\t\t_observable = _observable.Throttle(timeSpan);\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic void Subscribe(Action<FirebaseEvent<T>> onDataAdded)\n\t\t\t=> _observableDisposable = _observable.Subscribe(d => onDataAdded(d));\n\n\t\tpublic void Dispose()\n\t\t{\n\t\t\t_observableDisposable?.Dispose();\n\t\t}\n\t}\n}"
  },
  {
    "path": "Token/TokenGenerator.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Text;\n\n\nnamespace Firebase.Xamarin.Token\n{\n\tpublic class TokenGenerator\n\t{\n\t\tprivate static int TOKEN_VERSION = 0;\n\t\tprivate string _firebaseSecret;\n\n\t\t/// <summary>\n\t\t/// Constructor.\n\t\t/// </summary>\n\t\t/// <param name=\"firebaseSecret\">The Firebase Secret for your firebase (can be found by entering your Firebase URL into a web browser, and clicking the \"Auth\" pane).</param>\n\t\tpublic TokenGenerator(string firebaseSecret)\n\t\t{\n\t\t\t_firebaseSecret = firebaseSecret;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Creates an authentication token containing arbitrary auth data.\n\t\t/// </summary>\n\t\t/// <param name=\"data\">Arbitrary data that will be passed to the Firebase Rules API, once a client authenticates.  Must be able to be serialized to JSON with <see cref=\"System.Web.Script.Serialization.JavaScriptSerializer\"/>.</param>\n\t\t/// <returns>The auth token.</returns>\n\t\tpublic string CreateToken(Dictionary<string, object> data)\n\t\t{\n\t\t\treturn CreateToken(data, new TokenOptions());\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Creates an authentication token containing arbitrary auth data and the specified options.\n\t\t/// </summary>\n\t\t/// <param name=\"data\">Arbitrary data that will be passed to the Firebase Rules API, once a client authenticates.  Must be able to be serialized to JSON with <see cref=\"System.Web.Script.Serialization.JavaScriptSerializer\"/>.</param>\n\t\t/// <param name=\"options\">A set of custom options for the token.</param>\n\t\t/// <returns>The auth token.</returns>\n\t\tpublic string CreateToken(Dictionary<string, object> data, TokenOptions options)\n\t\t{\n\t\t\tvar dataEmpty = (data == null || data.Count == 0);\n\t\t\tif (dataEmpty && (options == null || (!options.admin && !options.debug)))\n\t\t\t{\n\t\t\t\tthrow new Exception(\"data is empty and no options are set.  This token will have no effect on Firebase.\");\n\t\t\t}\n\n\t\t\tvar claims = new Dictionary<string, object>();\n\t\t\tclaims[\"v\"] = TOKEN_VERSION;\n\t\t\tclaims[\"iat\"] = secondsSinceEpoch(DateTime.Now);\n\n\t\t\tvar isAdminToken = (options != null && options.admin);\n\t\t\tvalidateToken(data, isAdminToken);\n\n\t\t\tif (!dataEmpty)\n\t\t\t{\n\t\t\t\tclaims[\"d\"] = data;\n\t\t\t}\n\n\t\t\t// Handle options.\n\t\t\tif (options != null)\n\t\t\t{\n\t\t\t\tif (options.expires.HasValue)\n\t\t\t\t\tclaims[\"exp\"] = secondsSinceEpoch(options.expires.Value);\n\t\t\t\tif (options.notBefore.HasValue)\n\t\t\t\t\tclaims[\"nbf\"] = secondsSinceEpoch(options.notBefore.Value);\n\t\t\t\tif (options.admin)\n\t\t\t\t\tclaims[\"admin\"] = true;\n\t\t\t\tif (options.debug)\n\t\t\t\t\tclaims[\"debug\"] = true;\n\t\t\t}\n\n\t\t\tvar token = computeToken(claims);\n\t\t\tif (token.Length > 1024)\n\t\t\t{\n\t\t\t\tthrow new Exception(\"Generated token is too long. The token cannot be longer than 1024 bytes.\");\n\t\t\t}\n\t\t\treturn token;\n\t\t}\n\n\t\tprivate string computeToken(Dictionary<string, object> claims)\n\t\t{\n\t\t\treturn JWT.JsonWebToken.Encode(claims, this._firebaseSecret, JWT.JwtHashAlgorithm.HS256);\n\t\t}\n\n\t\tprivate static long secondsSinceEpoch(DateTime dt)\n\t\t{\n\t\t\tTimeSpan t = dt.ToUniversalTime() - new DateTime(1970, 1, 1);\n\t\t\treturn (long)t.TotalSeconds;\n\t\t}\n\n\t\tprivate static void validateToken(Dictionary<string, object> data, Boolean isAdminToken)\n\t\t{\n\t\t\tvar containsUid = (data != null && data.ContainsKey(\"uid\"));\n\t\t\tif ((!containsUid && !isAdminToken) || (containsUid && !(data[\"uid\"] is string)))\n\t\t\t{\n\t\t\t\tthrow new Exception(\"Data payload must contain a \\\"uid\\\" key that must not be a string.\");\n\t\t\t}\n\t\t\telse if (containsUid && data[\"uid\"].ToString().Length > 256)\n\t\t\t{\n\t\t\t\tthrow new Exception(\"Data payload must contain a \\\"uid\\\" key that must not be longer than 256 characters.\");\n\t\t\t}\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "Token/TokenOptions.cs",
    "content": "﻿using System;\n\nnamespace Firebase.Xamarin.Token\n{\n\tpublic class TokenOptions\n\t{\n\t\tpublic DateTime? expires { get; private set; }\n\t\tpublic DateTime? notBefore { get; private set; }\n\t\tpublic bool admin { get; private set; }\n\t\tpublic bool debug { get; private set; }\n\n\t\t/// <summary>\n\t\t/// Constructor.  All options are optional.\n\t\t/// </summary>\n\t\t/// <param name=\"notBefore\">The date/time before which the token should not be considered valid. (default is now)</param>\n\t\t/// <param name=\"expires\">The date/time at which the token should no longer be considered valid. (default is 24 hours from now)</param>\n\t\t/// <param name=\"admin\">Set to true to bypass all security rules. (you can use this for trusted server code)</param>\n\t\t/// <param name=\"debug\">Set to true to enable debug mode. (so you can see the results of Rules API operations)</param>\n\t\tpublic TokenOptions(DateTime? notBefore = null, DateTime? expires = null, bool admin = false, bool debug = false)\n\t\t{\n\t\t\tthis.notBefore = notBefore;\n\t\t\tthis.expires = expires;\n\t\t\tthis.admin = admin;\n\t\t\tthis.debug = debug;\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "TokenGenerator.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n</configuration>\n"
  },
  {
    "path": "packages.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n  <package id=\"Newtonsoft.Json\" version=\"9.0.1\" targetFramework=\"portable-net45+win+wpa81+MonoTouch10+MonoAndroid10+xamarinmac20+xamarintvos10+xamarinwatchos10+xamarinios10\" />\n  <package id=\"Portable.BouncyCastle\" version=\"1.8.0\" targetFramework=\"portable-net45+win+wpa81+MonoTouch10+MonoAndroid10+xamarinmac20+xamarintvos10+xamarinwatchos10+xamarinios10\" />\n  <package id=\"Portable.JWT\" version=\"1.0.5\" targetFramework=\"portable-net45+win+wpa81+MonoTouch10+MonoAndroid10+xamarinmac20+xamarintvos10+xamarinwatchos10+xamarinios10\" />\n  <package id=\"Rx-Core\" version=\"2.2.5\" targetFramework=\"portable45-net45+win8+wpa81\" />\n  <package id=\"Rx-Interfaces\" version=\"2.2.5\" targetFramework=\"portable45-net45+win8+wpa81\" />\n  <package id=\"Rx-Linq\" version=\"2.2.5\" targetFramework=\"portable45-net45+win8+wpa81\" />\n  <package id=\"Rx-Main\" version=\"2.2.5\" targetFramework=\"portable45-net45+win8+wpa81\" />\n  <package id=\"Rx-PlatformServices\" version=\"2.2.5\" targetFramework=\"portable45-net45+win8+wpa81\" />\n</packages>"
  }
]