fix: ajustes de nome no template
78
BaseDomain/Base/AEntity.cs
Normal file
@ -0,0 +1,78 @@
|
||||
using BaseDomain.SimpleValidator;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BaseDomain.Base
|
||||
{
|
||||
public abstract class AEntity<T, TKey> where TKey : class
|
||||
where T : class
|
||||
{
|
||||
ObjectValidatorBuilder<T> objectValidatorBuilder;
|
||||
bool rulesAdded;
|
||||
|
||||
public ObjectValidatorBuilder<T> ValidatorBuilder { get { return objectValidatorBuilder; } }
|
||||
|
||||
public AEntity()
|
||||
{
|
||||
T entity;
|
||||
try
|
||||
{
|
||||
entity = (T)Convert.ChangeType(this, typeof(T));
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
entity = default;
|
||||
}
|
||||
|
||||
objectValidatorBuilder = new ObjectValidatorBuilder<T>(entity);
|
||||
AddRules();
|
||||
}
|
||||
|
||||
public ObjectValidatorBuilder<T> InitValidator()
|
||||
{
|
||||
T entity;
|
||||
try
|
||||
{
|
||||
entity = (T)Convert.ChangeType(this, typeof(T));
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
entity = default;
|
||||
}
|
||||
|
||||
objectValidatorBuilder = new ObjectValidatorBuilder<T>(entity);
|
||||
return objectValidatorBuilder;
|
||||
}
|
||||
|
||||
public abstract TKey Id { get; set; }
|
||||
|
||||
public void ValidateAndThrow()
|
||||
{
|
||||
SetClearAndRules();
|
||||
objectValidatorBuilder.ThrowErrorMessages();
|
||||
}
|
||||
|
||||
public string GetErrorMessages()
|
||||
{
|
||||
SetClearAndRules();
|
||||
return objectValidatorBuilder.ErrorMessagesAsString();
|
||||
}
|
||||
|
||||
public bool IsValid()
|
||||
{
|
||||
SetClearAndRules();
|
||||
return objectValidatorBuilder.IsValid();
|
||||
}
|
||||
|
||||
private void SetClearAndRules()
|
||||
{
|
||||
objectValidatorBuilder.ClearRules();
|
||||
AddRules();
|
||||
objectValidatorBuilder.Build();
|
||||
}
|
||||
public abstract void AddRules();
|
||||
}
|
||||
}
|
||||
63
BaseDomain/Base/AValueObject.cs
Normal file
@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BaseDomain
|
||||
{
|
||||
public abstract class AValueObject
|
||||
{
|
||||
protected static bool EqualOperator(AValueObject left, AValueObject right)
|
||||
{
|
||||
if (ReferenceEquals(left, null) ^ ReferenceEquals(right, null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return ReferenceEquals(left, right) || left.Equals(right);
|
||||
}
|
||||
|
||||
protected static bool NotEqualOperator(AValueObject left, AValueObject right)
|
||||
{
|
||||
return !EqualOperator(left, right);
|
||||
}
|
||||
protected abstract IEnumerable<object> GetEqualityComponents();
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != GetType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var other = (AValueObject)obj;
|
||||
|
||||
return GetEqualityComponents().SequenceEqual(other.GetEqualityComponents());
|
||||
}
|
||||
|
||||
public static bool operator ==(AValueObject one, AValueObject two)
|
||||
{
|
||||
return EqualOperator(one, two);
|
||||
}
|
||||
|
||||
public static bool operator !=(AValueObject one, AValueObject two)
|
||||
{
|
||||
return NotEqualOperator(one, two);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return GetEqualityComponents()
|
||||
.Select(x => x != null ? x.GetHashCode() : 0)
|
||||
.Aggregate((x, y) => x ^ y);
|
||||
}
|
||||
|
||||
public Func<bool> GetValidationFunc() => GetValidationExpression;
|
||||
public abstract bool GetValidationExpression();
|
||||
|
||||
public const string ErrorMessage = "";
|
||||
|
||||
public bool IsValid { get; protected set; }
|
||||
}
|
||||
}
|
||||
21
BaseDomain/BaseDomain.csproj
Normal file
@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Repositories\Contracts\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Serilog" Version="4.0.2" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
|
||||
<PackageReference Include="Serilog.Enrichers.Context" Version="4.6.5" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Grafana.Loki" Version="8.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
10
BaseDomain/Repositories/Contracts/IRepoCommand.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace DIC.Test.Data.Contracts
|
||||
{
|
||||
public interface IRepoCommand<T, TId> where T : class
|
||||
where TId : struct
|
||||
{
|
||||
void Add(T entity);
|
||||
void Update(T entity);
|
||||
void Delete(T entity);
|
||||
}
|
||||
}
|
||||
14
BaseDomain/Repositories/Contracts/IRepoQuery.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace DIC.Test.Data.Contracts
|
||||
{
|
||||
public interface IRepoQuery<T, TId> where T : class
|
||||
where TId : struct
|
||||
{
|
||||
public T GetById(TId id);
|
||||
|
||||
public IEnumerable<T> GetAll();
|
||||
|
||||
public IEnumerable<T> FindAll(Expression<T> expression);
|
||||
}
|
||||
}
|
||||
8
BaseDomain/Repositories/Contracts/IRepoReadOnly.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace DIC.Test.Data.Contracts
|
||||
{
|
||||
public interface IRepoReadOnly<T, TId> : IRepoQuery<T, TId>
|
||||
where T : class
|
||||
where TId : struct
|
||||
{
|
||||
}
|
||||
}
|
||||
10
BaseDomain/Repositories/Contracts/IRepository.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DIC.Test.Data.Contracts
|
||||
{
|
||||
public interface IRepository<T, TId> : IRepoCommand<T, TId>, IRepoQuery<T, TId>
|
||||
where T : class
|
||||
where TId : struct
|
||||
{
|
||||
}
|
||||
}
|
||||
36
BaseDomain/Results/Error.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BaseDomain.Results
|
||||
{
|
||||
public class Error
|
||||
{
|
||||
public enum ErrorTypeEnum
|
||||
{
|
||||
None = 0, //Erro vazio (para result)
|
||||
Failure = 1, //Quando for uma falha que eu queira retornar no lugar de uma Exception
|
||||
Validation = 2, //Quando for um problema de validação
|
||||
Others = 3 //Inesperado ou sem categoria
|
||||
}
|
||||
|
||||
public Error(ErrorTypeEnum error, string message, string description="")
|
||||
{
|
||||
ErrorType = error;
|
||||
Message = message;
|
||||
}
|
||||
|
||||
public static Error None => new Error(ErrorTypeEnum.None, string.Empty, string.Empty);
|
||||
|
||||
public ErrorTypeEnum ErrorType { get; }
|
||||
public string Message { get; }
|
||||
public string Description { get; }
|
||||
|
||||
public static implicit operator string(Error error) => error.Message;
|
||||
|
||||
//Permitir atribuir um error diretamente ao resultado.
|
||||
public static implicit operator Result(Error error) => Result.Failure(error);
|
||||
}
|
||||
}
|
||||
33
BaseDomain/Results/Result.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BaseDomain.Results
|
||||
{
|
||||
public class Result
|
||||
{
|
||||
protected Result(bool isSuccess, Error error)
|
||||
{
|
||||
if (isSuccess && error != Error.None)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
if (!isSuccess && error == Error.None)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
this.IsSuccess = isSuccess;
|
||||
this.Error = error;
|
||||
}
|
||||
|
||||
public bool IsSuccess { get; }
|
||||
public bool IsFalilure => !IsSuccess;
|
||||
public Error Error { get; }
|
||||
|
||||
public static Result Success() => new(true, Error.None);
|
||||
public static Result Failure(Error error) => new(false, Error.None);
|
||||
}
|
||||
}
|
||||
34
BaseDomain/Results/ResultT.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BaseDomain.Results
|
||||
{
|
||||
public class Result<TValue> : Result
|
||||
{
|
||||
private readonly TValue _value;
|
||||
|
||||
protected Result(TValue value, bool isSuccess, Error error) : base(isSuccess, error)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
protected Result(TValue value) : base(true, Error.None)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public TValue Value => IsSuccess ? _value : throw new InvalidOperationException("O valor náo pode ser processado!");
|
||||
|
||||
public static implicit operator Result<TValue>(TValue? value) => Create(value);
|
||||
public static Result<TValue> Success<TValue>(TValue value) => new(value);
|
||||
|
||||
public static Result<TValue> Create(TValue value)
|
||||
{
|
||||
return new Result<TValue>(value, true, Error.None);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
102
BaseDomain/SimpleValidator/ObjectValidatorBuilder.cs
Normal file
@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BaseDomain.SimpleValidator
|
||||
{
|
||||
public class ObjectValidatorBuilder<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// model that is validated
|
||||
/// </summary>
|
||||
private T model;
|
||||
private bool isValid;
|
||||
|
||||
public ObjectValidatorBuilder(T objectOrEntity)
|
||||
{
|
||||
model = objectOrEntity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if model meetf all rules
|
||||
/// </summary>
|
||||
public ObjectValidatorBuilder<T> Build()
|
||||
{
|
||||
//select all ruiles without OnlyIf expression or with satisfied OnlyIf expression
|
||||
var invalidResults = _rules.Where(m => m.OnlyIf == null || (m.OnlyIf != null && m.OnlyIf(model)));
|
||||
|
||||
//select all rules that arent satisfied
|
||||
invalidResults = invalidResults.Where(m => !m.ValidationExpression(model));
|
||||
|
||||
//set error messages of unsatisfied rules
|
||||
ErrorMessages = invalidResults.Select(m => m.ErrorMessage).ToList();
|
||||
|
||||
isValid =!invalidResults.Any();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public bool IsValid()
|
||||
{
|
||||
return isValid;
|
||||
}
|
||||
|
||||
public void ThrowErrorMessages()
|
||||
{
|
||||
if (!isValid) throw new ArgumentException(this.ErrorMessagesAsString());
|
||||
}
|
||||
|
||||
public string ErrorMessagesAsString()
|
||||
{
|
||||
return String.Join("\n", this.ErrorMessages);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get error messages for rules that are not satisfied
|
||||
/// </summary>
|
||||
public List<string> ErrorMessages { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of rules that are specified for model
|
||||
/// </summary>
|
||||
private readonly List<ValidationRule<T>> _rules = new List<ValidationRule<T>>();
|
||||
|
||||
public ObjectValidatorBuilder<T> AddRule(Func<T, bool> validationExpression, Func<T, bool> onlyIf, String errorMessage)
|
||||
{
|
||||
_rules.Add(new ValidationRule<T>()
|
||||
{
|
||||
ValidationExpression = validationExpression,
|
||||
OnlyIf = onlyIf,
|
||||
ErrorMessage = errorMessage
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ObjectValidatorBuilder<T> AddRule(Func<T, bool> validationExpression, String errorMessage)
|
||||
{
|
||||
AddRule(validationExpression, null, errorMessage);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ObjectValidatorBuilder<T> AddRule(AValueObject valueObject)
|
||||
{
|
||||
|
||||
AddRule((valueObject) => (valueObject as AValueObject).GetValidationExpression(), null, AValueObject.ErrorMessage);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ObjectValidatorBuilder<T> AddRule(ValidationRule<T> rule)
|
||||
{
|
||||
AddRule(rule);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void ClearRules()
|
||||
{
|
||||
_rules.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
41
BaseDomain/SimpleValidator/ValidationRule.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BaseDomain.SimpleValidator
|
||||
{
|
||||
public class ValidationRule<T>
|
||||
{
|
||||
public ValidationRule()
|
||||
{
|
||||
}
|
||||
|
||||
public ValidationRule(Func<T, bool> validationExpression, Func<T, bool> onlyIf, String errorMessage)
|
||||
{
|
||||
ValidationExpression = validationExpression;
|
||||
OnlyIf = onlyIf;
|
||||
ErrorMessage = errorMessage;
|
||||
}
|
||||
public ValidationRule(Func<T, bool> validationExpression, String errorMessage)
|
||||
{
|
||||
ValidationExpression = validationExpression;
|
||||
ErrorMessage = errorMessage;
|
||||
}
|
||||
/// <summary>
|
||||
/// Validation rule expression, examp. check is string null or empty !string.IsNullOrEmpty(o.Name)
|
||||
/// </summary>
|
||||
public Func<T, bool> ValidationExpression { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// You can specify OnlyIf expression, if this expresion is specified than ValidationExpression is going to be evaluated only if OnlyIf rule is satisfied
|
||||
/// </summary>
|
||||
public Func<T, bool> OnlyIf { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specify error message that will be returned if rule is not satisifed
|
||||
/// </summary>
|
||||
public string ErrorMessage { get; set; }
|
||||
}
|
||||
}
|
||||
@ -15,7 +15,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\vcart.me\vcart.back\Struct.ValueObjects\BaseDomain.csproj" />
|
||||
<ProjectReference Include="..\BaseDomain\BaseDomain.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
43
SumaTube.sln
Normal file
@ -0,0 +1,43 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.7.34031.279
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SumaTube.Domain", "SumaTube.Domain\SumaTube.Domain.csproj", "{9EE2B90B-6670-A0CB-C994-528BD66E1792}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SumaTube.Infra", "SumaTuba.Infra\SumaTube.Infra.csproj", "{AD1CCD27-71DF-8E98-B2F8-7169ABF34BF3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SumaTube", "SumaTube\SumaTube.csproj", "{48F33338-AF1C-3D68-A116-2799CC9E98F4}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseDomain", "BaseDomain\BaseDomain.csproj", "{8DEA200D-FF43-0D75-15A2-7DA8831449C9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{9EE2B90B-6670-A0CB-C994-528BD66E1792}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9EE2B90B-6670-A0CB-C994-528BD66E1792}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9EE2B90B-6670-A0CB-C994-528BD66E1792}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9EE2B90B-6670-A0CB-C994-528BD66E1792}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AD1CCD27-71DF-8E98-B2F8-7169ABF34BF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AD1CCD27-71DF-8E98-B2F8-7169ABF34BF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AD1CCD27-71DF-8E98-B2F8-7169ABF34BF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AD1CCD27-71DF-8E98-B2F8-7169ABF34BF3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{48F33338-AF1C-3D68-A116-2799CC9E98F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{48F33338-AF1C-3D68-A116-2799CC9E98F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{48F33338-AF1C-3D68-A116-2799CC9E98F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{48F33338-AF1C-3D68-A116-2799CC9E98F4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8DEA200D-FF43-0D75-15A2-7DA8831449C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8DEA200D-FF43-0D75-15A2-7DA8831449C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8DEA200D-FF43-0D75-15A2-7DA8831449C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8DEA200D-FF43-0D75-15A2-7DA8831449C9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {EC4AB36F-49CB-4819-ACA4-3A14CB1D9B50}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
|
||||
<link rel="stylesheet" href="~/Blinks.styles.css" asp-append-version="true" />
|
||||
<link rel="stylesheet" href="~/SumaTube.styles.css" asp-append-version="true" />
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||
@await RenderSectionAsync("Styles", required: false)
|
||||
</head>
|
||||
@ -17,7 +17,7 @@
|
||||
<partial name="_Busy" />
|
||||
<div id="wrapper">
|
||||
<nav id="nav-bar" class="navbar navbar-expand-lg navbar-dark">
|
||||
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">Blinks</a>
|
||||
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">SumaTube</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
Before Width: | Height: | Size: 476 B After Width: | Height: | Size: 476 B |
|
Before Width: | Height: | Size: 507 B After Width: | Height: | Size: 507 B |
|
Before Width: | Height: | Size: 514 B After Width: | Height: | Size: 514 B |
|
Before Width: | Height: | Size: 579 B After Width: | Height: | Size: 579 B |
|
Before Width: | Height: | Size: 250 B After Width: | Height: | Size: 250 B |
|
Before Width: | Height: | Size: 279 B After Width: | Height: | Size: 279 B |
|
Before Width: | Height: | Size: 286 B After Width: | Height: | Size: 286 B |
|
Before Width: | Height: | Size: 366 B After Width: | Height: | Size: 366 B |
|
Before Width: | Height: | Size: 854 B After Width: | Height: | Size: 854 B |
|
Before Width: | Height: | Size: 457 B After Width: | Height: | Size: 457 B |
|
Before Width: | Height: | Size: 477 B After Width: | Height: | Size: 477 B |
|
Before Width: | Height: | Size: 484 B After Width: | Height: | Size: 484 B |
|
Before Width: | Height: | Size: 564 B After Width: | Height: | Size: 564 B |
|
Before Width: | Height: | Size: 607 B After Width: | Height: | Size: 607 B |
|
Before Width: | Height: | Size: 642 B After Width: | Height: | Size: 642 B |
|
Before Width: | Height: | Size: 634 B After Width: | Height: | Size: 634 B |
|
Before Width: | Height: | Size: 714 B After Width: | Height: | Size: 714 B |
|
Before Width: | Height: | Size: 359 B After Width: | Height: | Size: 359 B |
|
Before Width: | Height: | Size: 421 B After Width: | Height: | Size: 421 B |