private ENSessionListNotebooksContext ListNotebooks_Complete(ENSessionListNotebooksContext context)
		{
			NotebooksCache = context.ResultNotebooks;
			NotebooksCacheDate = DateTime.Now;
			return context;
		}
		private ENSessionListNotebooksContext ListNotebooks_ProcessSharedNotebooks(ENSessionListNotebooksContext context)
		{
			// Process the results
			foreach (LinkedNotebook linkedNotebook in context.LinkedPersonalNotebooks)
			{
				object sharedNotebook = context.SharedNotebooks[linkedNotebook.Guid];
				ENNotebook result = null;
				if (sharedNotebook.GetType() == typeof(SharedNotebook))
				{
					// Shared notebook with individuals
					result = new ENNotebook((SharedNotebook)sharedNotebook, linkedNotebook);
				}
				else
				{
					// Public notebook
					result = new ENNotebook((Notebook)sharedNotebook, linkedNotebook);
				}
				context.ResultNotebooks.Add(result);
			}

			context = ListNotebooks_PrepareResults(context);
			return context;
		}
		private ENSessionListNotebooksContext ListNotebooks_PrepareResults(ENSessionListNotebooksContext context)
		{
			// If there's only one notebook, and it's not flagged as the default notebook for the account, then
			// we must be in a single-notebook auth scenario. In this case, simply override the flag so to a caller it
			// will appear to be the default anyway. Note that we only do this if it's not already the default. If a single
			// notebook result is already marked default, then it *could* be that there really is one notebook, and we don't
			// want to have the caller persist an override flag that might be inapplicable later.
			if (context.ResultNotebooks.Count == 1)
			{
				ENNotebook soleNotebook = context.ResultNotebooks[0];
				if (!soleNotebook.IsDefaultNotebook)
				{
					soleNotebook.IsDefaultNotebookOverride = true;
				}
			}

			// Sort them by name. This is just a convenience for the caller in case they don't bother to sort them themselves.
			context.ResultNotebooks.Sort((x, y) => x.Name.CompareTo(y.Name));
			context = ListNotebooks_Complete(context);
			return context;
		}
		private ENSessionListNotebooksContext ListNotebooks_FetchSharedNotebooks(ENSessionListNotebooksContext context)
		{
			// Fetch shared notebooks for any non-business linked notebooks remaining in the
			// array in the context. We will have already pulled out the linked notebooks that
			// were processed for business.
			context.PendingSharedNotebooks = context.LinkedPersonalNotebooks.Count;
			Dictionary<string, object> sharedNotebooks = new Dictionary<string, object>();
			context.SharedNotebooks = sharedNotebooks;

			foreach (var linkedNotebook in context.LinkedPersonalNotebooks)
			{
				ENNoteStoreClient noteStore = NoteStoreForLinkedNotebook(linkedNotebook);
				if (linkedNotebook.ShareKey == null)
				{
					// ShareKey is null means it's a public notebook.
					try
					{
						PublicUserInfo info = UserStore.GetPublicUserInfo(linkedNotebook.Username);
						try
						{
							Notebook sharedNotebook = noteStore.GetPublicNotebook(info.UserId, linkedNotebook.Uri);
							sharedNotebooks.Add(linkedNotebook.Guid, sharedNotebook);
							context = ListNotebooks_CompletePendingSharedNotebook(context);
						}
						catch (Exception ex)
						{
							ENSDKLogger.ENSDKLogError(string.Format("Error from getSharedNotebookByAuth against a personal linked notebook: {0}", ex.Message));
							throw new Exception(ex.Message, ex.InnerException);
						}
					}
					catch (Exception ex)
					{
						ENSDKLogger.ENSDKLogError(string.Format("Error from getSharedNotebookByAuth against a personal linked notebook: {0}", ex.Message));
						throw new Exception(ex.Message, ex.InnerException);
					}
				}
				else
				{
					try
					{
						SharedNotebook sharedNotebook = noteStore.GetSharedNotebookByAuth();
						// Add the shared notebook to the map.
						sharedNotebooks.Add(linkedNotebook.Guid, sharedNotebook);
						context = ListNotebooks_CompletePendingSharedNotebook(context);
					}
					catch (Exception ex)
					{
						ENSDKLogger.ENSDKLogError(string.Format("Error from getSharedNotebookByAuth against a personal linked notebook: {0}", ex.Message));
						throw new Exception(ex.Message, ex.InnerException);
					}
				}
			}

			return context;
		}
		private ENSessionListNotebooksContext ListNotebooks_CompletePendingSharedNotebook(ENSessionListNotebooksContext context)
		{
			context.PendingSharedNotebooks--;
			if (context.PendingSharedNotebooks == 0)
			{
				context = ListNotebooks_ProcessSharedNotebooks(context);
			}
			return context;
		}
		private ENSessionListNotebooksContext ListNotebooks_FetchBusinessNotebooks(ENSessionListNotebooksContext context)
		{
			try
			{
				List<Notebook> notebooks = BusinessNoteStore.ListNotebooks();
				// Run through the results, and set each notebook keyed by its guid, which
				// is how we'll find it from the shared notebook.
				context.BusinessNotebooks = new Dictionary<string, Notebook>();
				foreach (Notebook notebook in notebooks)
				{
					context.BusinessNotebooks.Add(notebook.Guid, notebook);
				}
				context = ListNotebooks_ProcessBusinessNotebooks(context);
			}
			catch (Exception ex)
			{
				ENSDKLogger.ENSDKLogError(string.Format("Error from listNotebooks in business store: {0}", ex.Message));
				throw new Exception(ex.Message, ex.InnerException);
			}
			return context;
		}
		private ENSessionListNotebooksContext ListNotebooks_ProcessBusinessNotebooks(ENSessionListNotebooksContext context)
		{
			// Postprocess our notebook sets for business notebooks. For every linked notebook in the personal
			// account, check for a corresponding business shared notebook (by shareKey). If we find it, also
			// grab its corresponding notebook object from the business notebook list.
			List<LinkedNotebook> linkedPersonalNotebooksCopy = new List<LinkedNotebook>(context.LinkedPersonalNotebooks);
			foreach (LinkedNotebook linkedNotebook in linkedPersonalNotebooksCopy)
			{
				SharedNotebook sharedNotebook = null;
				context.SharedBusinessNotebooks.TryGetValue(linkedNotebook.ShareKey, out sharedNotebook);
				if (sharedNotebook != null)
				{
					// This linked notebook corresponds to a business notebook.
					Notebook businessNotebook = context.BusinessNotebooks[sharedNotebook.NotebookGuid];
					ENNotebook result = new ENNotebook(businessNotebook, sharedNotebook, linkedNotebook);

					context.ResultNotebooks.Add(result);
					context.LinkedPersonalNotebooks.Remove(linkedNotebook);

				}
			}

			// Any remaining linked notebooks are personal shared notebooks. No shared notebooks?
			// Then go directly to results preparation.
			if (context.LinkedPersonalNotebooks.Count == 0)
			{
				context = ListNotebooks_PrepareResults(context);
			}
			else
			{
				context = ListNotebooks_FetchSharedNotebooks(context);
			}

			return context;
		}
		private ENSessionListNotebooksContext ListNotebooks_FetchSharedBusinessNotebooks(ENSessionListNotebooksContext context)
		{
			try
			{
				List<SharedNotebook> sharedNotebooks = BusinessNoteStore.ListSharedNotebooks();
				// Run through the results, and set each notebook keyed by its shareKey, which
				// is how we'll find corresponding linked notebooks.
				context.SharedBusinessNotebooks = new Dictionary<string, SharedNotebook>();
				context.SharedBusinessNotebookGuids = new List<string>();
				foreach (SharedNotebook notebook in sharedNotebooks)
				{
					context.SharedBusinessNotebooks.Add(notebook.ShareKey, notebook);
					context.SharedBusinessNotebookGuids.Add(notebook.NotebookGuid);
				}

				// Now continue on to grab all of the linked notebooks for the business.
				context = ListNotebooks_FetchBusinessNotebooks(context);
			}
			catch (Exception ex)
			{
				ENSDKLogger.ENSDKLogError(string.Format("Error from listSharedNotebooks in business store: {0}", ex.Message));
				throw new Exception(ex.Message, ex.InnerException);
			}
			return context;
		}
		private ENSessionListNotebooksContext ListNotebooks_ListLinkedNotebooks(ENSessionListNotebooksContext context)
		{
			try
			{
				List<LinkedNotebook> linkedNotebooks = PrimaryNoteStore.ListLinkedNotebooks();
				if (linkedNotebooks.Count == 0)
				{
					context = ListNotebooks_PrepareResults(context);
				}
				else
				{
					context.LinkedPersonalNotebooks = linkedNotebooks;
					if (BusinessNoteStore != null)
					{
						context = ListNotebooks_FetchSharedBusinessNotebooks(context);
					}
					else
					{
						context = ListNotebooks_FetchSharedNotebooks(context);
					}
				}
			}
			catch (Evernote.EDAM.Error.EDAMUserException ex)
			{
				if (ex.ErrorCode == Evernote.EDAM.Error.EDAMErrorCode.PERMISSION_DENIED)
				{
					// App has a single notebook auth token, so skip to the end.
					context = ListNotebooks_PrepareResults(context);
				}
				else
				{
					ENSDKLogger.ENSDKLogError(string.Format("Error from listLinkedNotebooks in user's store: {0}", ex.Message));
					throw new Exception(ex.Message, ex.InnerException);
				}
			}
			catch (Exception ex)
			{
				ENSDKLogger.ENSDKLogError(string.Format("Error from listLinkedNotebooks in user's store: {0}", ex.Message));
				throw new Exception(ex.Message, ex.InnerException);
			}
			return context;
		}
		private ENSessionListNotebooksContext ListNotebooks_ListSharedNotebooks(ENSessionListNotebooksContext context)
		{
			try
			{
				// The return value "notebooks" is no longer currently being used. But we might do something later in this block and this call is not expensive so we leave it there without intentionally doing anything.
				List<SharedNotebook> notebooks = PrimaryNoteStore.ListSharedNotebooks();
				context = ListNotebooks_ListLinkedNotebooks(context);
			}
			catch (Exception ex)
			{
				ENSDKLogger.ENSDKLogError(string.Format("Error from listSharedNotebooks in user's store: {0}", ex.Message));
				throw new Exception(ex.Message, ex.InnerException);
			}
			return context;
		}
		private ENSessionListNotebooksContext ListNotebooks_ListNotebooks(ENSessionListNotebooksContext context)
		{
			List<Notebook> notebooks = PrimaryNoteStore.ListNotebooks();
			if (notebooks.Count > 0)
			{
				// Populate the result list with personal notebooks.
				foreach (Notebook book in notebooks)
				{
					ENNotebook result = new ENNotebook(book);
					context.ResultNotebooks.Add(result);
				}
				// Now get any shared notebook records for the personal account.
				context = ListNotebooks_ListSharedNotebooks(context);
			}
			else
			{
				// This must be a single notebook auth token, so try getting linked notebooks.
				context = ListNotebooks_ListLinkedNotebooks(context);
			}

			return context;
		}
		public List<ENNotebook> ListNotebooks()
		{
			if (!IsAuthenticated)
			{
				throw new ENAuthExpiredException();
			}

			// Do we have a cached result that is unexpired?
			if (NotebooksCache != null && NotebooksCache.Count > 0 && DateTime.Now.Subtract(NotebooksCacheDate).TotalSeconds < ENSessionNotebooksCacheValidity)
			{
				return NotebooksCache;
			}

			NotebooksCache = null;
			NotebooksCacheDate = new DateTime();

			ENSessionListNotebooksContext context = new ENSessionListNotebooksContext();
			context.ResultNotebooks = new List<ENNotebook>();
			context = ListNotebooks_ListNotebooks(context);
			return context.ResultNotebooks;
		}