Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

etcd support easycaching #463

Open
wants to merge 63 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
76ccc15
Merge pull request #317 from dotnetcore/dev
catcherwong Jul 23, 2021
426a2b6
Update distributed lock
pengweiqhca Jul 28, 2021
159a930
Merge pull request #318 from pengweiqhca/master
catcherwong Jul 29, 2021
c842bfe
Merge pull request #327 from dotnetcore/dev
catcherwong Oct 7, 2021
90d9768
Merge pull request #340 from dotnetcore/dev
catcherwong Jan 23, 2022
fd4ca61
Merge pull request #346 from dotnetcore/dev
catcherwong Mar 9, 2022
2251cb7
Merge pull request #368 from dotnetcore/dev
catcherwong May 2, 2022
ff26702
Updated hybrid provider documentation
JudeVajira Jun 12, 2022
6b3f478
Merge pull request #373 from JudeVajira/patch-1
catcherwong Jun 12, 2022
acec880
feat:add EasyCaching.Bus.ConfluentKafka module
bingtianyiyan Jul 13, 2022
4d05e50
feat:
bingtianyiyan Jul 14, 2022
2cbc781
feat:zookeeperBus
bingtianyiyan Jul 14, 2022
769ef24
Merge pull request #394 from dotnetcore/dev
catcherwong Aug 20, 2022
b640a9e
feat:
bingtianyiyan Aug 26, 2022
429413a
fix:
bingtianyiyan Oct 11, 2022
8409cc8
feat:
bingtianyiyan Oct 11, 2022
a2f5886
fix:
bingtianyiyan Oct 14, 2022
9c793de
Merge branch 'dev' of https://github.com/dotnetcore/EasyCaching into dev
bingtianyiyan Oct 18, 2022
174a00a
Merge pull request #411 from dotnetcore/dev
catcherwong Oct 25, 2022
ce90d95
Merge pull request #440 from dotnetcore/dev
catcherwong Jan 1, 2023
9776bf4
Merge pull request #462 from dotnetcore/dev
catcherwong Feb 26, 2023
bdf15fe
feat:
bingtianyiyan Mar 3, 2023
9fb81be
feat:
bingtianyiyan Mar 6, 2023
3e01fc3
feat:
bingtianyiyan Mar 6, 2023
4a6138f
feat:
bingtianyiyan Mar 7, 2023
48dc4cc
feat:
bingtianyiyan Mar 7, 2023
b23c3e1
feat;
bingtianyiyan Mar 7, 2023
a9b3907
feat:
bingtianyiyan Mar 7, 2023
dfbe7d5
feat:
bingtianyiyan Mar 7, 2023
b2bfd29
feat:
bingtianyiyan Mar 7, 2023
beebe2e
feat:
bingtianyiyan Mar 8, 2023
a44061d
feat:
bingtianyiyan Mar 8, 2023
8e5f6f6
feat:
bingtianyiyan Mar 8, 2023
7f09ded
feat:
bingtianyiyan Mar 8, 2023
fce5b02
feat:
bingtianyiyan Mar 8, 2023
ce81b3c
Merge branch 'dev' of https://github.com/bingtianyiyan/EasyCaching in…
bingtianyiyan Mar 8, 2023
539bb68
Merge branch 'dev' into mydev_etcd20230308
bingtianyiyan Mar 8, 2023
4c826bd
feat:
bingtianyiyan Mar 9, 2023
12590b4
Merge branch 'mydev_etcd20230308' of https://github.com/bingtianyiyan…
bingtianyiyan Mar 9, 2023
21d0f56
fix:
bingtianyiyan Mar 9, 2023
a04a195
feat:
bingtianyiyan Mar 9, 2023
ee80f57
Update distributed lock
pengweiqhca Jul 28, 2021
2685fa1
Updated hybrid provider documentation
JudeVajira Jun 12, 2022
7673110
feat:
bingtianyiyan Mar 3, 2023
aeb30d0
feat:
bingtianyiyan Mar 6, 2023
84da31c
feat:
bingtianyiyan Mar 6, 2023
f10741e
feat:
bingtianyiyan Mar 7, 2023
75b91d1
feat:
bingtianyiyan Mar 7, 2023
98eae8c
feat;
bingtianyiyan Mar 7, 2023
3d9b5d3
feat:
bingtianyiyan Mar 7, 2023
9d28611
feat:
bingtianyiyan Mar 7, 2023
a89f314
feat:
bingtianyiyan Mar 7, 2023
8b003ec
feat:
bingtianyiyan Mar 8, 2023
4c8725a
feat:
bingtianyiyan Mar 8, 2023
0774030
feat:
bingtianyiyan Mar 8, 2023
5e81e5a
feat:
bingtianyiyan Mar 8, 2023
ce43526
feat:
bingtianyiyan Mar 8, 2023
20949e1
feat:
bingtianyiyan Mar 9, 2023
027e376
fix:
bingtianyiyan Mar 9, 2023
44c2c52
feat:
bingtianyiyan Mar 9, 2023
001ad06
Merge branch 'mydev_etcd20230308' of https://github.com/bingtianyiyan…
bingtianyiyan Mar 11, 2023
e1b2337
feat:
bingtianyiyan Mar 12, 2023
48c1744
Merge branch 'mydev_etcd20230308' of https://github.com/bingtianyiyan…
bingtianyiyan Mar 12, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions EasyCaching.sln
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Microsoft Visual Studio Solution File, Format Version 12.00

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32616.157
MinimumVisualStudioVersion = 10.0.40219.1
Expand Down Expand Up @@ -72,11 +73,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyCaching.Serialization.S
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyCaching.Bus.ConfluentKafka", "bus\EasyCaching.Bus.ConfluentKafka\EasyCaching.Bus.ConfluentKafka.csproj", "{F7FBADEB-D766-4595-949A-07104B52692C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyCaching.Bus.Zookeeper", "bus\EasyCaching.Bus.Zookeeper\EasyCaching.Bus.Zookeeper.csproj", "{5E488583-391E-4E15-83C1-7301B4FE79AE}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyCaching.Bus.Zookeeper", "bus\EasyCaching.Bus.Zookeeper\EasyCaching.Bus.Zookeeper.csproj", "{5E488583-391E-4E15-83C1-7301B4FE79AE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyCaching.FasterKv", "src\EasyCaching.FasterKv\EasyCaching.FasterKv.csproj", "{7191E567-38DF-4879-82E1-73EC618AFCAC}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyCaching.FasterKv", "src\EasyCaching.FasterKv\EasyCaching.FasterKv.csproj", "{7191E567-38DF-4879-82E1-73EC618AFCAC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyCaching.Serialization.MemoryPack", "serialization\EasyCaching.Serialization.MemoryPack\EasyCaching.Serialization.MemoryPack.csproj", "{EEF22C21-F380-4980-B72C-F14488369333}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyCaching.Serialization.MemoryPack", "serialization\EasyCaching.Serialization.MemoryPack\EasyCaching.Serialization.MemoryPack.csproj", "{EEF22C21-F380-4980-B72C-F14488369333}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyCaching.Etcd", "src\EasyCaching.Etcd\EasyCaching.Etcd.csproj", "{984B7E9C-B8C3-4C01-BBC2-345AF28FCC11}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -208,6 +211,10 @@ Global
{EEF22C21-F380-4980-B72C-F14488369333}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EEF22C21-F380-4980-B72C-F14488369333}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EEF22C21-F380-4980-B72C-F14488369333}.Release|Any CPU.Build.0 = Release|Any CPU
{984B7E9C-B8C3-4C01-BBC2-345AF28FCC11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{984B7E9C-B8C3-4C01-BBC2-345AF28FCC11}.Debug|Any CPU.Build.0 = Debug|Any CPU
{984B7E9C-B8C3-4C01-BBC2-345AF28FCC11}.Release|Any CPU.ActiveCfg = Release|Any CPU
{984B7E9C-B8C3-4C01-BBC2-345AF28FCC11}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -244,6 +251,7 @@ Global
{5E488583-391E-4E15-83C1-7301B4FE79AE} = {B337509B-75F9-4851-821F-9BBE87C4E4BC}
{7191E567-38DF-4879-82E1-73EC618AFCAC} = {A0F5CC7E-155F-4726-8DEB-E966950B3FE9}
{EEF22C21-F380-4980-B72C-F14488369333} = {15070C49-A507-4844-BCFE-D319CFBC9A63}
{984B7E9C-B8C3-4C01-BBC2-345AF28FCC11} = {A0F5CC7E-155F-4726-8DEB-E966950B3FE9}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {63A57886-054B-476C-AAE1-8D7C8917682E}
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ public class Startup
config.DBConfig.Endpoints.Add(new ServerEndPoint("127.0.0.1", 6379));
}, "redis1")
.WithMessagePack()//with messagepack serialization
.UseRedisLock()//with distributed lock
;
});
}
Expand Down
3 changes: 3 additions & 0 deletions build/releasenotes.props
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,8 @@
<EasyCachingFaskKVPackageNotes>
1. Upgrading dependencies.
</EasyCachingFaskKVPackageNotes>
<EasyCachingEtcdPackageNotes>
1. Add etcd module.
</EasyCachingEtcdPackageNotes>
</PropertyGroup>
</Project>
1 change: 1 addition & 0 deletions build/version.props
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@
<EasyCachingSTJsonPackageVersion>1.9.0</EasyCachingSTJsonPackageVersion>
<EasyCachingMemoryPackageVersion>1.9.0</EasyCachingMemoryPackageVersion>
<EasyCachingFaskKVPackageVersion>1.9.0</EasyCachingFaskKVPackageVersion>
<EasyCachingEtcdPackageVersion>1.9.0</EasyCachingEtcdPackageVersion>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ public void AddServices(IServiceCollection services)
services.AddSingleton<IEasyCachingBus, DefaultZookeeperBus>();
}
}
}
}
86 changes: 86 additions & 0 deletions docs/Etcd.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# DefaultEtcdCachingProvider

Etcd is a hybrid memory and disk Kv Store, so it can support much larger data storage than memory.

EasyCaching.Etcd is a lib that is based on **EasyCaching.Core** and **dotnet-etcd-core**.


# How to use ?

## 1. Install the package via Nuget

```
Install-Package EasyCaching.Etcd
```

## 2. Config in Startup class

```csharp
public class Startup
{
//...

public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();

services.AddEasyCaching(option =>
{
//use Etcd cache
option.UseEtcd(config =>
{
config.Address = "http://127.0.0.1:2379";
config.Timeout = 30000;
// Etcd must be set SerializerName
config.SerializerName = "msg";
})
.WithMessagePack("msg");
});
}
}
```

### 3. Call the EasyCachingProvider

The following code show how to use EasyCachingProvider in ASP.NET Core Web API.

```csharp
[Route("api/[controller]")]
public class ValuesController : Controller
{
private readonly IEasyCachingProvider _provider;

public ValuesController(IEasyCachingProvider provider)
{
this._provider = provider;
}

[HttpGet]
public string Get()
{
//Remove
_provider.Remove("demo");

//Set
_provider.Set("demo", "123", TimeSpan.FromMinutes(1));

//Get
var res = _provider.Get("demo", () => "456", TimeSpan.FromMinutes(1));

//Get without data retriever
var res = _provider.Get<string>("demo");

//Remove Async
await _provider.RemoveAsync("demo");

//Set Async
await _provider.SetAsync("demo", "123", TimeSpan.FromMinutes(1));

//Get Async
var res = await _provider.GetAsync("demo",async () => await Task.FromResult("456"), TimeSpan.FromMinutes(1));

//Get without data retriever Async
var res = await _provider.GetAsync<string>("demo");
}
}
```
3 changes: 2 additions & 1 deletion docs/Hybrid.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Install-Package EasyCaching.HybridCache
Install-Package EasyCaching.InMemory
Install-Package EasyCaching.Redis
Install-Package EasyCaching.Bus.Redis
Install-Package EasyCaching.Serialization.Json
```

## 2. Config in Startup class
Expand All @@ -41,7 +42,7 @@ public class Startup
// distributed
option.UseRedis(config =>
{
config.DBConfig.Endpoints.Add(new Core.Configurations.ServerEndPoint("127.0.0.1", 6379));
config.DBConfig.Endpoints.Add(new ServerEndPoint("127.0.0.1", 6379));
config.DBConfig.Database = 5;
config.SerializerName = "myjson";
}, "myredis");
Expand Down
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pages:
- Disk : Disk.md
- LiteDB : LiteDB.md
- FasterKv: FasterKv.md
- Etcd: Etcd.md
# - ProviderFactory : ProviderFactory.md
- Provider Factory:
- Overview : FactoryOverview.md
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<ProjectReference Include="..\..\src\EasyCaching.Core\EasyCaching.Core.csproj" />
<ProjectReference Include="..\..\src\EasyCaching.CSRedis\EasyCaching.CSRedis.csproj" />
<ProjectReference Include="..\..\src\EasyCaching.Disk\EasyCaching.Disk.csproj" />
<ProjectReference Include="..\..\src\EasyCaching.Etcd\EasyCaching.Etcd.csproj" />
<ProjectReference Include="..\..\src\EasyCaching.HybridCache\EasyCaching.HybridCache.csproj" />
<ProjectReference Include="..\..\src\EasyCaching.InMemory\EasyCaching.InMemory.csproj" />
<ProjectReference Include="..\..\interceptor\EasyCaching.Interceptor.AspectCore\EasyCaching.Interceptor.AspectCore.csproj" />
Expand Down
60 changes: 46 additions & 14 deletions sample/EasyCaching.Demo.ConsoleApp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ namespace EasyCaching.Demo.ConsoleApp
using EasyCaching.Disk;
using EasyCaching.Serialization.SystemTextJson.Configurations;
using EasyCaching.SQLite;
using Google.Protobuf.WellKnownTypes;
using MemoryPack;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;

class Program
Expand All @@ -27,6 +30,17 @@ static void Main(string[] args)

option.UseInMemory("m1");

option.UseEtcd(options =>
{
options.Address = "http://127.0.0.1:2379";
options.Timeout = 30000;
options.SerializerName= "json";
}, "e1").WithJson(jsonSerializerSettingsConfigure: x =>
{
x.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.None;
x.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
}, "json");

option.UseRedis((options) =>
{
options.SerializerName = "mempack";
Expand All @@ -43,33 +57,38 @@ static void Main(string[] args)
};
}, "s1");

// option.WithJson(jsonSerializerSettingsConfigure: x =>
// {
// x.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.None;
// }, "json");
option.WithJson(jsonSerializerSettingsConfigure: x =>
{
x.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.None;
x.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
}, "json");

option.UseDisk(cfg =>
{
cfg.DBConfig = new DiskDbOptions { BasePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Cache") };
cfg.SerializerName = "msgpack";
}, "disk")
.WithJson("json")
.WithJson(jsonSerializerSettingsConfigure: x =>
{
x.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.None;
x.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
}, "json")
.WithSystemTextJson("sysjson")
.WithMessagePack("msgpack");
});

IServiceProvider serviceProvider = services.BuildServiceProvider();
var factory = serviceProvider.GetService<IEasyCachingProviderFactory>();

// var redisCache = factory.GetCachingProvider("r1");
//
// redisCache.Set<Product>("rkey", new Product() { Name = "test" }, TimeSpan.FromSeconds(20));
//
// var redisAllKey = redisCache.GetAllKeysByPrefix("rkey");
//
// var redisVal = redisCache.Get<Product>("rkey");
//
// Console.WriteLine($"redis cache get value, {redisVal.HasValue} {redisVal.IsNull} {redisVal.Value}");
var redisCache = factory.GetCachingProvider("r1");

redisCache.Set<Product>("rkey", new Product() { Name = "test" }, TimeSpan.FromSeconds(20));

var redisAllKey = redisCache.GetAllKeysByPrefix("rkey");

var redisVal = redisCache.Get<Product>("rkey");

Console.WriteLine($"redis cache get value, {redisVal.HasValue} {redisVal.IsNull} {redisVal.Value}");

var prod = new Product()
{
Expand Down Expand Up @@ -104,6 +123,19 @@ static void Main(string[] args)
var diskVal = diskCache.Get<string>("diskkey");
Console.WriteLine($"disk cache get value, {diskVal.HasValue} {diskVal.IsNull} {diskVal.Value} ");

//etcd cache
var etcdCache = factory.GetCachingProvider("e1");
var re11 = etcdCache.GetAllKeysByPrefix("emk");
var re12 = etcdCache.GetByPrefix<Product>("emk");
etcdCache.Set<Product>("emkey3", prod, TimeSpan.FromSeconds(2000));
var re13 = etcdCache.Get<Product>("emkey3");
var re14 = etcdCache.GetAll<Product>(new List<string>()
{
"emkey3"
});
etcdCache.Remove("emkey3");
Console.WriteLine($"etcd cache get value, {re13.HasValue} {re13.IsNull} {re13.Value} ");

Console.ReadKey();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
[Route("api/[controller]")]
public class ValuesController : Controller
{
//1. InMemory,Memcached,Redis,SQLite,FasterKv
//1. InMemory,Memcached,Redis,SQLite,FasterKv,Etcd
private readonly IEasyCachingProvider _provider;

public ValuesController(IEasyCachingProvider provider)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
<ItemGroup>
<ProjectReference Include="..\..\bus\EasyCaching.Bus.ConfluentKafka\EasyCaching.Bus.ConfluentKafka.csproj" />
<ProjectReference Include="..\..\bus\EasyCaching.Bus.Zookeeper\EasyCaching.Bus.Zookeeper.csproj" />
<ProjectReference Include="..\..\serialization\EasyCaching.Serialization.Json\EasyCaching.Serialization.Json.csproj" />
<ProjectReference Include="..\..\src\EasyCaching.Etcd\EasyCaching.Etcd.csproj" />
<ProjectReference Include="..\..\src\EasyCaching.FasterKv\EasyCaching.FasterKv.csproj" />
<ProjectReference Include="..\..\src\EasyCaching.Redis\EasyCaching.Redis.csproj" />
<ProjectReference Include="..\..\src\EasyCaching.Memcached\EasyCaching.Memcached.csproj" />
Expand Down
11 changes: 11 additions & 0 deletions sample/EasyCaching.Demo.Providers/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

public class Startup
{
Expand Down Expand Up @@ -69,6 +70,16 @@ public void ConfigureServices(IServiceCollection services)
config.SerializerName = "msg";
})
.WithMessagePack("msg");

//use Etcd
option.UseEtcd(config =>
{
config.Address = "http://127.0.0.1:2379";
config.Timeout = 30000;
// Etcd must be set SerializerName
config.SerializerName = "json";
})
.WithMessagePack("msg2").WithJson("json");
});
}

Expand Down
1 change: 1 addition & 0 deletions src/EasyCaching.Core/Internal/CachingProviderType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ public enum CachingProviderType
Ext2,
LiteDB,
FasterKv,
Etcd
}
}
19 changes: 15 additions & 4 deletions src/EasyCaching.Core/Internal/EasyCachingConstValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ public class EasyCachingConstValue
/// </summary>
public const string HybridSection = "easycaching:hybrid";

/// <summary>
/// The etcd section.
/// </summary>
public const string EtcdSection = "easycaching:etcd";

/// <summary>
/// The redis bus section.
/// </summary>
Expand All @@ -53,13 +58,13 @@ public class EasyCachingConstValue
/// <summary>
/// The rabbitMQ Bus section.
/// </summary>
public const string RabbitMQBusSection = "easycaching:rabbitmqbus";

public const string RabbitMQBusSection = "easycaching:rabbitmqbus";
/// <summary>
/// The kafka bus section.
/// </summary>
public const string KafkaBusSection = "easycaching:kafkabus";

public const string KafkaBusSection = "easycaching:kafkabus";
/// <summary>
/// The zookeeper bus section.
/// </summary>
Expand Down Expand Up @@ -110,6 +115,12 @@ public class EasyCachingConstValue
/// The default name of the LiteDB.
/// </summary>
public const string DefaultLiteDBName = "DefaultLiteDB";

/// <summary>
/// The default name of the etcd.
/// </summary>
public const string DefaultEtcdName = "DefaultEtcd";

/// <summary>
/// The LiteDB Bus section.
/// </summary>
Expand Down
Loading