// Group list retrieved for a user
        private void OnGroupListReturned(object sender, GetGroupListEventArgs e)
        {
            // Find the user
            if (!UserCache.ContainsKey(e.UserId))
                return;

            User user = UserCache[e.UserId];

            JObject rawJson = JObject.Parse(e.Response);
            JObject rootJson = (JObject)rawJson["groups"];

            List<FlickrGroup> result = new List<FlickrGroup>();
            user.GroupIds = new List<string>();
            foreach (var entry in rootJson["group"])
            {
                JObject json = (JObject)entry;
                FlickrGroup group = FlickrGroupFactory.GroupWithJObject(json);
                user.GroupIds.Add(group.ResourceId);
                result.Add(group);
            }

            // Dispatch event
            GroupListUpdatedEventArgs evt = new GroupListUpdatedEventArgs();
            evt.UserId = e.UserId;
            evt.Groups = result;
            GroupListUpdated.DispatchEvent(this, evt);
        }
        public async void GetGroupListAsync(string userId, Dictionary<string, string> parameters = null)
        {
            if (groupListFetchingQueue.Contains(userId))
                return;

            groupListFetchingQueue.Add(userId);

            string timestamp = DateTimeUtils.GetTimestamp();
            string nonce = Guid.NewGuid().ToString().Replace("-", null);

            Dictionary<string, string> paramDict = new Dictionary<string, string>();
            paramDict["method"] = "flickr.people.getGroups";
            paramDict["format"] = "json";
            paramDict["nojsoncallback"] = "1";
            paramDict["oauth_consumer_key"] = consumerKey;
            paramDict["oauth_nonce"] = nonce;
            paramDict["oauth_signature_method"] = "HMAC-SHA1";
            paramDict["oauth_timestamp"] = timestamp;
            paramDict["oauth_token"] = AccessToken;
            paramDict["oauth_version"] = "1.0";

            if (parameters != null)
            {
                foreach (var entry in parameters)
                {
                    paramDict[entry.Key] = entry.Value;
                }
            }

            paramDict["user_id"] = UrlHelper.Encode(userId);
            paramDict["extras"] = UrlHelper.Encode("privacy,throttle,restrictions");

            string paramString = GenerateParamString(paramDict);
            string signature = GenerateSignature("GET", AccessTokenSecret, "https://api.flickr.com/services/rest", paramString);
            string requestUrl = "https://api.flickr.com/services/rest?" + paramString + "&oauth_signature=" + signature;
            HttpWebResponse response = await DispatchRequest("GET", requestUrl, null).ConfigureAwait(false);
            using (StreamReader reader = new StreamReader(response.GetResponseStream()))
            {
                if(groupListFetchingQueue.Contains(userId))
                    groupListFetchingQueue.Remove(userId);

                GetGroupListExceptionEventArgs exceptionEvt = null;

                if (response.StatusCode != HttpStatusCode.OK)
                {
                    HandleHTTPException(response);

                    exceptionEvt = new GetGroupListExceptionEventArgs();
                    exceptionEvt.Message = "Unknown network error";
                    exceptionEvt.UserId = userId;
                    GetGroupListException.DispatchEvent(this, exceptionEvt);
                    return;
                }

                string jsonString = await reader.ReadToEndAsync().ConfigureAwait(false);
                if (!TryHandleResponseException(jsonString, () => { GetGroupListAsync(userId, parameters); }))
                {
                    exceptionEvt = new GetGroupListExceptionEventArgs();
                    exceptionEvt.Message = "Unknown network error";
                    exceptionEvt.UserId = userId;
                    GetGroupListException.DispatchEvent(this, exceptionEvt);

                    return;
                }

                GetGroupListEventArgs args = new GetGroupListEventArgs();
                args.UserId = userId;
                args.Response = jsonString;
                GroupListReturned.DispatchEvent(this, args);
            }
        }