string UploadToS3(UploadInfo info, Func<Stream> streamFunc, GithubUploadResponse uploadResponse)
 {
     return _s3Uploader.Upload(streamFunc,
                               "http://github.s3.amazonaws.com/",
                               info.Name,
                               uploadResponse.Policy,
                               uploadResponse.Path,
                               uploadResponse.AccessKeyId,
                               uploadResponse.ContentType,
                               uploadResponse.Signature,
                               uploadResponse.Acl);
 }
        public string Upload(UploadInfo info)
        {
            if (string.IsNullOrEmpty(info.Repository))
            {
                throw new ArgumentException("Repository name is required", "info");
            }

            info.Repository = QualifyRepositoryName(info.Repository);

            if (info.FileName != null)
            {
                if (!File.Exists(info.FileName))
                {
                    throw new ArgumentException(string.Format("No file with the name: {0} exists.", info.FileName), "info");
                }
            }

            info.Name = info.Name ?? Path.GetFileName(info.FileName);

            if (info.FileName == null && info.Data == null)
            {
                throw new ArgumentException("Either FileName or Data must be present in the UploadInfo", "info");
            }

            if (info.Data != null && string.IsNullOrEmpty(info.Name))
            {
                throw new ArgumentException("Name must be specified if Data supplied", "info");
            }

            if (info.Replace)
            {
                IEnumerable<FileInfo> filesToDelete = ListFiles(info.Repository).Where(f => f.Name.Equals(info.Name));

                foreach (FileInfo file in filesToDelete)
                {
                    Delete(info.Repository, file.Id);
                }
            }
            else
            {
                var files = ListFiles(info.Repository);

                if (files.Any(f => f.Name.EndsWith(info.Name)))
                {
                    throw new InvalidOperationException(string.Format("The file {0} is already uploaded. please try a different name", info.Name));
                }
            }

            string url = string.Format("https://github.com/{0}/downloads", info.Repository);

            long fileLength = info.Data != null ? info.Data.Length : new System.IO.FileInfo(info.FileName).Length;

            string response = HttpClient.Post(url, new Dictionary<string, object>
                                                   	{
                                                   		{"file_size", fileLength},
                                                   		{"content_type", info.ContentType},
                                                   		{"file_name", info.Name},
                                                   		{"description", info.Description},
                                                   		{"login", _login},
                                                   		{"token", _token}
                                                   	});

            var uploadResponse = (GithubUploadResponse) JsonConvert.DeserializeObject(response, typeof (GithubUploadResponse));

            Func<Stream> streamFunc = (info.Data != null) ? new Func<Stream>(() => new MemoryStream(info.Data)) : () => File.OpenRead(info.FileName);

            return UploadToS3(info, streamFunc, uploadResponse);
        }