.NET рдХреЛрд░ рдореЗрдВ рд▓реЛрдб рд╣реЛ рд░рд╣рд╛ рд╣реИ рдФрд░ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдЗрдореЗрдЬреЗрд╕

рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдореИрдВ .NET рдХреЛрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдЫрд╡рд┐рдпреЛрдВ рдХреЛ рд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рддрдВрддреНрд░ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рдЕрдкрдиреЗ рдЕрдиреБрднрд╡ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ, рдЗрд╕рдХреЗ рдмрд╛рдж рдЙрдирдХреЗ рдЖрдХрд╛рд░ рдФрд░ рдлрд╝рд╛рдЗрд▓ рд╕рд┐рд╕реНрдЯрдо рдореЗрдВ рд╕рд╣реЗрдЬреЗрдВред рдЗрдореЗрдЬ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рд╕рд┐рдХреНрд╕ рд▓реЗрдмрд░реНрд╕ рд╕реЗ рдХреНрд░реЙрд╕-рдкреНрд▓реЗрдЯрдлреЙрд░реНрдо ImageSharp рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ ред рдЫрд╡рд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрдИ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╣реИрдВ, рд▓реЗрдХрд┐рди рдХреНрдпреЛрдВрдХрд┐ рдореИрдВ рдПрдХ рдХреНрд░реЙрд╕-рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╡рд┐рдХрд╕рд┐рдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рдореИрдВ рдПрдХ рдХреНрд░реЙрд╕-рдкреНрд▓реЗрдЯрдлреЙрд░реНрдо рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдвреВрдВрдврдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛ред рд▓реЗрдЦрди рдХреЗ рд╕рдордп, рд╡реЗ рдЕрднреА рднреА рд░рд┐рд▓реАрдЬ рдХреЗ рдЙрдореНрдореАрджрд╡рд╛рд░ рдХреЗ рдЪрд░рдг рдореЗрдВ рд╣реИрдВ, рд▓реЗрдХрд┐рди рд╕рдореБрджрд╛рдп рдХрд╛ рдХрд╣рдирд╛ рд╣реИ рдХрд┐ рд╕рдм рдХреБрдЫ рдареАрдХ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдФрд░ рд╕реБрд░рдХреНрд╖рд┐рдд рд░реВрдк рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рдХрд╛рд░реНрдп рд╕рд╛рдордиреЗ рд╕реЗ рдЫрд╡рд┐ рдХреЛ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рдирд╛ рдерд╛, рдЗрд╕реЗ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдкрд╣рд▓реВ рдЕрдиреБрдкрд╛рдд рдореЗрдВ рдХреНрд░реЙрдк рдХрд░рдирд╛ рдФрд░ рдЖрдХрд╛рд░ рдмрджрд▓рдирд╛ рддрд╛рдХрд┐ рд╕рд╣реЗрдЬреЗ рдЧрдП рдЪрд┐рддреНрд░ рдмрд╣реБрдд рд╕рд╛рд░реЗ рдбрд┐рд╕реНрдХ рд╕реНрдерд╛рди рдирд╣реАрдВ рдЦрд╛рдПрдВ, рдХреНрдпреЛрдВрдХрд┐ рдХреНрд▓рд╛рдЙрдб рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдореЗрдЧрд╛рдмрд╛рдЗрдЯ рдкреИрд╕рд╛ рд╣реИред

рдореЛрд░реНрдЪреЗ рдкрд░, рдПрдХ рдХреЛрдгреАрдп рдШрдЯрдХ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рдЬреЛ рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХреЗ рддреБрд░рдВрдд рдмрд╛рдж рдЗрд╕реЗ рд╕рд╣реЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдкреАрдЖрдИ рд╡рд┐рдзрд┐ рдХреЛ рднреЗрдЬрддрд╛ рд╣реИред рдПрдкреАрдЖрдИ, рдмрджрд▓реЗ рдореЗрдВ, рдкрд╣рд▓реЗ рд╕реЗ рд╕рд╣реЗрдЬреА рдЧрдИ рдЫрд╡рд┐ рдХреЗ рд▓рд┐рдП рдкрде рджреЗрддрд╛ рд╣реИ, рдЬреЛ рддрдм рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рд╕рд╣реЗрдЬрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЪреВрдВрдХрд┐ рдЪреВрдВрдХрд┐ рдпрд╣ рд▓реЗрдЦ рдПрдВрдЧреБрд▓рд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдирд╣реАрдВ рд╣реИ, рд╣рдо рдШрдЯрдХ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ рдЫреЛрдбрд╝ рджреЗрддреЗ рд╣реИрдВ рдФрд░ рд╕реАрдзреЗ рдПрдкреАрдЖрдИ рд╡рд┐рдзрд┐ рдкрд░ рдЬрд╛рддреЗ рд╣реИрдВред

[HttpPost]
[Route("upload/box")]
public IActionResult UploadBoxImage(IFormFile file)
{
    return UploadImage(file, ImageType.Box);
}

[HttpPost]
[Route("upload/logo")]
public IActionResult UploadLogoImage(IFormFile file)
{
    return UploadImage(file, ImageType.Logo);
}

private IActionResult UploadImage(IFormFile file, ImageType type)
{
    if (file.Length == 0)
        return BadRequest(new ApiResponse(ErrorCodes.EmptyFile, Strings.EmptyFile));

    try
    {
        var filePath = _imageService.SaveImage(file, type);
        return Ok(new ApiResponse<string>(filePath));
    }
    catch (ImageProcessingException ex)
    {
        var response = new ApiResponse(ErrorCodes.ImageProcessing, ex.Message);
        return BadRequest(response);
    }
    catch (Exception ex)
    {
        var response = new ApiResponse(ErrorCodes.Unknown, ex.Message);
        return BadRequest(response);
    }
}

рдФрд░ рдЕрдзрд┐рдХ рд╕рдЯреАрдХ рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП, рдлрд┐рд░ рджреЛ рддрд░реАрдХреЛрдВ рд╕реЗред рдореЗрд░рд╛ рдХрд╛рдо рджреЛ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдЙрджреНрджреЗрд╢реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рдЫрд╡рд┐рдпрд╛рдВ рдЕрдкрд▓реЛрдб рдХрд░рдирд╛ рдерд╛, рдЬреЛ рд╡рд┐рднрд┐рдиреНрди рдЖрдХрд╛рд░реЛрдВ рдХрд╛ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рд╡рд┐рднрд┐рдиреНрди рд╕реНрдерд╛рдиреЛрдВ рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдЫрд╡рд┐ рдкреНрд░рдХрд╛рд░ Enum рдореЗрдВ рд╕реВрдЪреАрдмрджреНрдз рд╣реИрдВ ImageTypeред рдФрд░ рдЫрд╡рд┐ рдХреЗ рдкреНрд░рдХрд╛рд░ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ IImageProfileрдкреНрд░рддреНрдпреЗрдХ рдкреНрд░рдХрд╛рд░ рдХреА рдЫрд╡рд┐ рдХреЗ рд▓рд┐рдП рдПрдХ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдФрд░ рджреЛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдмрдирд╛рдП , рдЬрд┐рд╕рдореЗрдВ рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рд╢рд╛рдорд┐рд▓ рд╣реИ рдХрд┐ рдЫрд╡рд┐ рдХреЛ рдХреИрд╕реЗ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред

public interface IImageProfile
{
    ImageType ImageType { get; }

    string Folder { get; }

    int Width { get; }

    int Height { get; }

    int MaxSizeBytes { get; }

    IEnumerable<string> AllowedExtensions { get; }
}

public class BoxImageProfile : IImageProfile
{
    private const int mb = 1048576;

    public BoxImageProfile()
    {
        AllowedExtensions = new List<string> { ".jpg", ".jpeg", ".png", ".gif" };
    }

    public ImageType ImageType => ImageType.Box;

    public string Folder => "boxes";

    public int Width => 500;

    public int Height => 500;

    public int MaxSizeBytes => 10 * mb;

    public IEnumerable<string> AllowedExtensions { get; }
}

public class LogoImageProfile : IImageProfile
{
    private const int mb = 1048576;

    public LogoImageProfile()
    {
        AllowedExtensions = new List<string> { ".jpg", ".jpeg", ".png", ".gif" };
    }

    public ImageType ImageType => ImageType.Logo;

    public string Folder => "logos";

    public int Width => 300;

    public int Height => 300;

    public int MaxSizeBytes => 5 * mb;

    public IEnumerable<string> AllowedExtensions { get; }
}

рдЕрдЧрд▓рд╛, рдореИрдВ рдЗрди рдЫрд╡рд┐ рдкреНрд░реЛрдлрд╛рдЗрд▓ рдХреЛ рд╕реЗрд╡рд╛ рдкрджреНрдзрддрд┐ рдореЗрдВ рдЗрдВрдЬреЗрдХреНрдЯ рдХрд░реВрдВрдЧрд╛, рдЗрд╕рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдЙрдиреНрд╣реЗрдВ рдбреАрдЖрдИ рдХрдВрдЯреЗрдирд░ рдореЗрдВ рдкрдВрдЬреАрдХреГрдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред

...
services.AddTransient<IImageProfile, BoxImageProfile>();
services.AddTransient<IImageProfile, LogoImageProfile>();
...

рдЙрд╕рдХреЗ рдмрд╛рдж, рдЖрдк рдПрдХ рд╕рдВрдЧреНрд░рд╣ рдХреЛ рдирд┐рдпрдВрддреНрд░рдХ рдпрд╛ рд╕реЗрд╡рд╛ рдореЗрдВ рдЗрдВрдЬреЗрдХреНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ IImageProfile

...
private readonly IEnumerable<IImageProfile> _imageProfiles;

public ImageService(IEnumerable<IImageProfile> imageProfiles)
{
    ...
    _imageProfiles = imageProfiles;
}

рдЕрдм рд╣рдо рд╕реЗрд╡рд╛ рдкрджреНрдзрддрд┐ рдХреЛ рджреЗрдЦрддреЗ рд╣реИрдВ, рдЬрд╣рд╛рдВ рд╣рдо рдпрд╣ рд╕рдм рдкреНрд░рдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рдЖрдкрдХреЛ рдпрд╛рдж рджрд┐рд▓рд╛ рджреВрдВ рдХрд┐ рдЗрдореЗрдЬ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ ImageSharp, рдЬреЛ рдиреБрдЧреЗрдЯ рдореЗрдВ рдорд┐рд▓ рд╕рдХрддреА рд╣реИред рдЕрдЧрд▓реА рд╡рд┐рдзрд┐ рдореЗрдВ, рдореИрдВ ImageрдЫрд╡рд┐ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░рдХрд╛рд░ рдФрд░ рдЙрд╕рдХреЗ рддрд░реАрдХреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реВрдБрдЧрд╛ ред рд╡рд┐рд╕реНрддреГрдд рдкреНрд░рд▓реЗрдЦрди рдпрд╣рд╛рдБ рдкрдврд╝рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

public string SaveImage(IFormFile file, ImageType imageType)
{
    var imageProfile = _imageProfiles.FirstOrDefault(profile => 
                       profile.ImageType == imageType);

    if (imageProfile == null)
        throw new ImageProcessingException("Image profile has not found");

    ValidateExtension(file, imageProfile);
    ValidateFileSize(file, imageProfile);

    var image = Image.Load(file.OpenReadStream());

    ValidateImageSize(image, imageProfile);

    var folderPath = Path.Combine(_hostingEnvironment.WebRootPath, imageProfile.Folder);

    if (!Directory.Exists(folderPath))
        Directory.CreateDirectory(folderPath);

    string filePath;
    string fileName;

    do
    {
        fileName = GenerateFileName(file);
        filePath = Path.Combine(folderPath, fileName);
    } while (File.Exists(filePath));

    Resize(image, imageProfile);
    Crop(image, imageProfile);
    image.Save(filePath, new JpegEncoder { Quality = 75 });

    return Path.Combine(imageProfile.Folder, fileName);
}

рдФрд░ рдХреБрдЫ рдирд┐рдЬреА рддрд░реАрдХреЗ рдЬреЛ рдЗрд╕реЗ рдкрд░реЛрд╕рддреЗ рд╣реИрдВ

private void ValidateExtension(IFormFile file, IImageProfile imageProfile)
{
    var fileExtension = Path.GetExtension(file.FileName);

    if (imageProfile.AllowedExtensions.Any(ext => ext == fileExtension.ToLower()))
        return;

    throw new ImageProcessingException(Strings.WrongImageFormat);
}

private void ValidateFileSize(IFormFile file, IImageProfile imageProfile)
{
    if (file.Length > imageProfile.MaxSizeBytes)
        throw new ImageProcessingException(Strings.ImageTooLarge);
}

private void ValidateImageSize(Image image, IImageProfile imageProfile)
{
    if (image.Width < imageProfile.Width || image.Height < imageProfile.Height)
        throw new ImageProcessingException(Strings.ImageTooSmall);
}

private string GenerateFileName(IFormFile file)
{
    var fileExtension = Path.GetExtension(file.FileName);
    var fileName = Path.GetFileNameWithoutExtension(Path.GetRandomFileName());

    return $"{fileName}{fileExtension}";
}

private void Resize(Image image, IImageProfile imageProfile)
{
    var resizeOptions = new ResizeOptions
    {
        Mode = ResizeMode.Min,
        Size = new Size(imageProfile.Width)
    };

    image.Mutate(action => action.Resize(resizeOptions));
}

private void Crop(Image image, IImageProfile imageProfile)
{
    var rectangle = GetCropRectangle(image, imageProfile);
    image.Mutate(action => action.Crop(rectangle));
}

private Rectangle GetCropRectangle(IImageInfo image, IImageProfile imageProfile)
{
    var widthDifference = image.Width - imageProfile.Width;
    var heightDifference = image.Height - imageProfile.Height;
    var x = widthDifference / 2;
    var y = heightDifference / 2;

    return new Rectangle(x, y, imageProfile.Width, imageProfile.Height);
}

рд╡рд┐рдзрд┐ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рд╢рдмреНрдж Resizeред рдореЗрдВ ResizeOptionsрдореИрдВ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ ResizeMode.Min, рдЗрд╕ рдореЛрдб рдЬрдм рдЫрд╡рд┐ рдЫрд╡рд┐ рдХреЗ рдЫреЛрдЯреЗ рдкрдХреНрд╖ рдХреА рдЗрдЪреНрдЫрд┐рдд рд▓рдВрдмрд╛рдИ рддрдХ рдХрд╛ рдЖрдХрд╛рд░ рдмрджрд▓рдиреЗ рдкрд░ рдкрд╣реБрдБрдЪ рдЬрд╛рддрд╛ рд╣реИ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдореВрд▓ рдЫрд╡рд┐ 1000x2000 рд╣реИ, рдФрд░ рдореЗрд░рд╛ рд▓рдХреНрд╖реНрдп 500x500 рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рд╣реИ, рддреЛ рдЖрдХрд╛рд░ рдмрджрд▓рдиреЗ рдХреЗ рдмрд╛рдж рдпрд╣ 500x1000 рд╣реЛ рдЬрд╛рдПрдЧрд╛, рдлрд┐рд░ рдЗрд╕реЗ 500x500 рдкрд░ рдХреНрд░реЙрдк рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдмрдЪрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рдпрд╣ рдПрдХ рдХреНрд╖рдг рдХреЛ рдЫреЛрдбрд╝рдХрд░ рд▓рдЧрднрдЧ рд╕рдм рдХреБрдЫ рд╣реИред рд╕реЗрд╡рд╛ рдкрджреНрдзрддрд┐ рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдкрде рд╡рд╛рдкрд╕ рдХрд░ рджреЗрдЧреА, рд▓реЗрдХрд┐рди рдпрд╣ URL рдирд╣реАрдВ рд╣реЛрдЧрд╛, рдмрд▓реНрдХрд┐ рдПрдХ PATH рд╣реЛрдЧрд╛ рдФрд░ рдпрд╣ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦреЗрдЧрд╛:logos\\yourFile.jpgред рдпрджрд┐ рдЖрдк рдЗрд╕ PATH рдХреЛ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдХреЛ рдЦрд┐рд▓рд╛рддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рдЗрд╕рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдПрдЧрд╛ рдФрд░ рдЖрдкрдХреЛ рдЫрд╡рд┐ рджрд┐рдЦрд╛рдПрдЧрд╛, рд▓реЗрдХрд┐рди рдпрджрд┐ рдЖрдк рдЗрд╕реЗ рджреВрд░ рдХрд░рддреЗ рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдореЛрдмрд╛рдЗрд▓ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдкрд░, рддреЛ рдЖрдкрдХреЛ рдЫрд╡рд┐ рджрд┐рдЦрд╛рдИ рдирд╣реАрдВ рджреЗрдЧреАред рдЗрд╕рдХреЗ рдмрд╛рд╡рдЬреВрдж, рдореИрдВрдиреЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ PATH рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛, рддрд╛рдХрд┐ рдпрджрд┐ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ рддреЛ рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛ, рдФрд░ рдбреАрдЯреАрдУ рдореЗрдВ, рдЬреЛ рд╕рд╛рдордиреЗ рдХреА рдУрд░ рдЙрдбрд╝рддрд╛ рд╣реИ, рдореИрдВ рдЗрд╕реЗ URL рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рдХреЗ рдЗрд╕ рдлрд╝реАрд▓реНрдб рдХреЛ рдореИрдк рдХрд░рддрд╛ рд╣реВрдВред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореБрдЭреЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдПрдХреНрд╕рдЯреЗрдВрд╢рди рд╡рд┐рдзрд┐ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ

public static string PathToUrl(this string path)
{
    return path?.Replace("\\", "/");
}

рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рд╕реНрд╡рдЪреНрдЫ рдХреЛрдб рд▓рд┐рдЦреЗрдВ рдФрд░ рдмреАрдорд╛рд░ рди рд╣реЛрдВ!

All Articles