private void OnGroupSearchReturned(object sender, GroupSearchEventArgs e)
        {
            JObject json = JObject.Parse(e.Response);
            JObject groupJson = (JObject)json["groups"];

            int page = int.Parse(groupJson["page"].ToString());
            int perPage = int.Parse(groupJson["perpage"].ToString());
            int numTotal = int.Parse(groupJson["total"].ToString());

            List<FlickrGroup> groups = new List<FlickrGroup>();
            foreach (var js in groupJson["group"])
            {
                FlickrGroup group = FlickrGroupFactory.GroupWithJObject((JObject)js);
                groups.Add(group);
            }

            GroupSearchResultEventArgs evt = new GroupSearchResultEventArgs();
            evt.SearchSessionId = e.SearchSessionId;
            evt.Page = page;
            evt.PerPage = perPage;
            evt.TotalCount = numTotal;
            evt.Groups = groups;
            GroupSearchCompleted.DispatchEvent(this, evt);
        }
        public async void SearchGroupsAsync(string searchSessionId, string query = null, Dictionary<string, string> parameters = null)
        {
            string timestamp = DateTimeUtils.GetTimestamp();
            string nonce = Guid.NewGuid().ToString().Replace("-", null);

            Dictionary<string, string> paramDict = new Dictionary<string, string>();
            paramDict["method"] = "flickr.groups.search";
            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";
            paramDict["text"] = UrlHelper.Encode(query);

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

            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 (response.StatusCode != HttpStatusCode.OK)
                {
                    HandleHTTPException(response);
                    return;
                }

                string jsonString = await reader.ReadToEndAsync().ConfigureAwait(false);
                if (!TryHandleResponseException(jsonString, () => { SearchGroupsAsync(searchSessionId, query, parameters); }))
                    return;

                GroupSearchEventArgs evt = new GroupSearchEventArgs();
                evt.SearchSessionId = searchSessionId;
                evt.Response = jsonString;
                GroupSearchReturned.DispatchEvent(this, evt);

            }
        }