From be30ef3c2511388a55e5e3c8ff6a160807caa9ed Mon Sep 17 00:00:00 2001
From: Paul Schneider
Date: Sat, 22 May 2021 22:49:57 +0100
Subject: [PATCH] gestion des versions : * dossier des versions = FullString *
Suppressioni de versions
---
.../Controllers/PackageVersionController.cs | 96 ++++++
.../Controllers/PackagesController.cs | 2 +-
src/nuget-host/Data/ApplicationDbContext.cs | 11 +-
src/nuget-host/Data/PackageVersion.cs | 4 +-
...210522194803_packageVersionKey.Designer.cs | 312 ++++++++++++++++++
.../20210522194803_packageVersionKey.cs | 56 ++++
.../ApplicationDbContextModelSnapshot.cs | 12 +-
src/nuget-host/Startup.cs | 1 -
.../PackageVersionIndexViewModel.cs | 11 +
.../Views/PackageVersion/Delete.cshtml | 52 +++
.../Views/PackageVersion/Details.cshtml | 48 +++
.../Views/PackageVersion/Index.cshtml | 66 ++++
src/nuget-host/Views/_ViewImports.cshtml | 1 +
.../nuget-cli/1.0.0/nuget-cli-1.0.0.nupkg | Bin 0 -> 12018 bytes
14 files changed, 659 insertions(+), 13 deletions(-)
create mode 100644 src/nuget-host/Controllers/PackageVersionController.cs
create mode 100644 src/nuget-host/Migrations/20210522194803_packageVersionKey.Designer.cs
create mode 100644 src/nuget-host/Migrations/20210522194803_packageVersionKey.cs
create mode 100644 src/nuget-host/ViewModels/PackageVersionIndexViewModel.cs
create mode 100644 src/nuget-host/Views/PackageVersion/Delete.cshtml
create mode 100644 src/nuget-host/Views/PackageVersion/Details.cshtml
create mode 100644 src/nuget-host/Views/PackageVersion/Index.cshtml
create mode 100644 src/nuget-host/packages/nuget-cli/1.0.0/nuget-cli-1.0.0.nupkg
diff --git a/src/nuget-host/Controllers/PackageVersionController.cs b/src/nuget-host/Controllers/PackageVersionController.cs
new file mode 100644
index 0000000..153e494
--- /dev/null
+++ b/src/nuget-host/Controllers/PackageVersionController.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Claims;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Rendering;
+using Microsoft.EntityFrameworkCore;
+using nuget_host.Data;
+using nuget_host.ViewModels;
+
+namespace nuget_host
+{
+ [AllowAnonymous]
+ public class PackageVersionController : Controller
+ {
+ private readonly ApplicationDbContext _context;
+
+ public PackageVersionController(ApplicationDbContext context)
+ {
+ _context = context;
+ }
+
+ // GET: PackageVersion
+ public async Task Index(PackageVersionIndexViewModel model)
+ {
+ var applicationDbContext = _context.PackageVersions.Include(p => p.Package).Where(p => p.PackageId == model.PackageId);
+
+ model.Versions = await applicationDbContext.ToListAsync();
+
+ return View(model);
+ }
+
+ // GET: PackageVersion/Details/5
+ public async Task Details(string pkgid, string version)
+ {
+ if (pkgid == null || version == null)
+ {
+ return NotFound();
+ }
+
+ var packageVersion = await _context.PackageVersions
+ .Include(p => p.Package)
+ .FirstOrDefaultAsync(m => m.PackageId == pkgid && m.FullString == version);
+ if (packageVersion == null)
+ {
+ return NotFound();
+ }
+
+ return View(packageVersion);
+ }
+
+ [Authorize]
+ public async Task Delete(string pkgid, string version)
+ {
+ if (pkgid == null || version == null)
+ {
+ return NotFound();
+ }
+
+ var packageVersion = await _context.PackageVersions
+ .Include(p => p.Package)
+ .FirstOrDefaultAsync(m => m.PackageId == pkgid && m.FullString == version);
+ if (packageVersion == null)
+ {
+ return NotFound();
+ }
+
+ if (!IsOwner(packageVersion)) return Unauthorized();
+
+ return View(packageVersion);
+ }
+
+ bool IsOwner(PackageVersion v)
+ {
+ var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
+ return v.Package.OwnerId == userId;
+ }
+
+ // POST: PackageVersion/Delete/5
+ [HttpPost, ActionName("Delete")]
+ [ValidateAntiForgeryToken]
+ public async Task DeleteConfirmed(string PackageId, string FullString)
+ {
+ var packageVersion = await _context.PackageVersions.Include(p => p.Package)
+ .FirstOrDefaultAsync(m => m.PackageId == PackageId && m.FullString == FullString);
+ if (packageVersion == null) return NotFound();
+ if (!IsOwner(packageVersion)) return Unauthorized();
+
+ _context.PackageVersions.Remove(packageVersion);
+ await _context.SaveChangesAsync();
+ return RedirectToAction(nameof(Index));
+ }
+ }
+}
diff --git a/src/nuget-host/Controllers/PackagesController.cs b/src/nuget-host/Controllers/PackagesController.cs
index d7937d8..6ba520c 100644
--- a/src/nuget-host/Controllers/PackagesController.cs
+++ b/src/nuget-host/Controllers/PackagesController.cs
@@ -84,7 +84,7 @@ namespace nuget_host.Controllers
var version = reader.GetVersion();
string pkgidpath = Path.Combine(nugetSettings.PackagesRootDir,
pkgid);
- string pkgpath = Path.Combine(pkgidpath, version.Version.ToString());
+ string pkgpath = Path.Combine(pkgidpath, version.ToFullString());
string name = $"{pkgid}-{version}.nupkg";
string fullpath = Path.Combine(pkgpath, name);
Package package;
diff --git a/src/nuget-host/Data/ApplicationDbContext.cs b/src/nuget-host/Data/ApplicationDbContext.cs
index 757479f..01671c0 100644
--- a/src/nuget-host/Data/ApplicationDbContext.cs
+++ b/src/nuget-host/Data/ApplicationDbContext.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Text;
+using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using nuget_host.Data;
@@ -14,7 +15,15 @@ namespace nuget_host.Data
: base(options)
{
}
-
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ base.OnModelCreating(modelBuilder);
+ modelBuilder.Entity().HasKey(v => new
+ {
+ v.PackageId,
+ v.FullString
+ });
+ }
public DbSet ApiKeys { get; set; }
public DbSet Packages { get; set; }
public DbSet PackageVersions { get; set; }
diff --git a/src/nuget-host/Data/PackageVersion.cs b/src/nuget-host/Data/PackageVersion.cs
index 018d34c..8b1b6ff 100644
--- a/src/nuget-host/Data/PackageVersion.cs
+++ b/src/nuget-host/Data/PackageVersion.cs
@@ -18,8 +18,8 @@ namespace nuget_host.Data
[Required]
public int Patch { get; set; }
- [StringLength(32)]
- [Required][Key]
+ [StringLength(256)]
+ [Required]
public string FullString { get; set; }
public bool IsPrerelease { get; set; }
diff --git a/src/nuget-host/Migrations/20210522194803_packageVersionKey.Designer.cs b/src/nuget-host/Migrations/20210522194803_packageVersionKey.Designer.cs
new file mode 100644
index 0000000..2c37c3a
--- /dev/null
+++ b/src/nuget-host/Migrations/20210522194803_packageVersionKey.Designer.cs
@@ -0,0 +1,312 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using nuget_host.Data;
+
+namespace nugethost.Migrations
+{
+ [DbContext(typeof(ApplicationDbContext))]
+ [Migration("20210522194803_packageVersionKey")]
+ partial class packageVersionKey
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
+ .HasAnnotation("ProductVersion", "2.2.6-servicing-10079")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken();
+
+ b.Property("Name")
+ .HasMaxLength(256);
+
+ b.Property("NormalizedName")
+ .HasMaxLength(256);
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedName")
+ .IsUnique()
+ .HasName("RoleNameIndex");
+
+ b.ToTable("AspNetRoles");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ClaimType");
+
+ b.Property("ClaimValue");
+
+ b.Property("RoleId")
+ .IsRequired();
+
+ b.HasKey("Id");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetRoleClaims");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ClaimType");
+
+ b.Property("ClaimValue");
+
+ b.Property("UserId")
+ .IsRequired();
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserClaims");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
+ {
+ b.Property("LoginProvider");
+
+ b.Property("ProviderKey");
+
+ b.Property("ProviderDisplayName");
+
+ b.Property("UserId")
+ .IsRequired();
+
+ b.HasKey("LoginProvider", "ProviderKey");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserLogins");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b =>
+ {
+ b.Property("UserId");
+
+ b.Property("RoleId");
+
+ b.HasKey("UserId", "RoleId");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetUserRoles");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
+ {
+ b.Property("UserId");
+
+ b.Property("LoginProvider");
+
+ b.Property("Name");
+
+ b.Property("Value");
+
+ b.HasKey("UserId", "LoginProvider", "Name");
+
+ b.ToTable("AspNetUserTokens");
+ });
+
+ modelBuilder.Entity("nuget_host.Data.ApiKeys.ApiKey", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("CreationDate");
+
+ b.Property("Name");
+
+ b.Property("UserId")
+ .IsRequired();
+
+ b.Property("ValidityPeriodInDays");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("ApiKeys");
+ });
+
+ modelBuilder.Entity("nuget_host.Data.ApplicationUser", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("AccessFailedCount");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken();
+
+ b.Property("Email")
+ .HasMaxLength(256);
+
+ b.Property("EmailConfirmed");
+
+ b.Property("FullName");
+
+ b.Property("LockoutEnabled");
+
+ b.Property("LockoutEnd");
+
+ b.Property("NormalizedEmail")
+ .HasMaxLength(256);
+
+ b.Property("NormalizedUserName")
+ .HasMaxLength(256);
+
+ b.Property("PasswordHash");
+
+ b.Property("PhoneNumber");
+
+ b.Property("PhoneNumberConfirmed");
+
+ b.Property("SecurityStamp");
+
+ b.Property("TwoFactorEnabled");
+
+ b.Property("UserName")
+ .HasMaxLength(256);
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedEmail")
+ .HasName("EmailIndex");
+
+ b.HasIndex("NormalizedUserName")
+ .IsUnique()
+ .HasName("UserNameIndex");
+
+ b.ToTable("AspNetUsers");
+ });
+
+ modelBuilder.Entity("nuget_host.Data.Package", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Description");
+
+ b.Property("OwnerId")
+ .IsRequired();
+
+ b.HasKey("Id");
+
+ b.HasIndex("OwnerId");
+
+ b.ToTable("Packages");
+ });
+
+ modelBuilder.Entity("nuget_host.Data.PackageVersion", b =>
+ {
+ b.Property("PackageId");
+
+ b.Property("FullString")
+ .HasMaxLength(256);
+
+ b.Property("IsPrerelease");
+
+ b.Property("Major");
+
+ b.Property("Minor");
+
+ b.Property("Patch");
+
+ b.HasKey("PackageId", "FullString");
+
+ b.ToTable("PackageVersions");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b =>
+ {
+ b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
+ .WithMany()
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
+ {
+ b.HasOne("nuget_host.Data.ApplicationUser")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
+ {
+ b.HasOne("nuget_host.Data.ApplicationUser")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b =>
+ {
+ b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
+ .WithMany()
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("nuget_host.Data.ApplicationUser")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
+ {
+ b.HasOne("nuget_host.Data.ApplicationUser")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("nuget_host.Data.ApiKeys.ApiKey", b =>
+ {
+ b.HasOne("nuget_host.Data.ApplicationUser", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("nuget_host.Data.Package", b =>
+ {
+ b.HasOne("nuget_host.Data.ApplicationUser", "Owner")
+ .WithMany()
+ .HasForeignKey("OwnerId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("nuget_host.Data.PackageVersion", b =>
+ {
+ b.HasOne("nuget_host.Data.Package", "Package")
+ .WithMany()
+ .HasForeignKey("PackageId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/nuget-host/Migrations/20210522194803_packageVersionKey.cs b/src/nuget-host/Migrations/20210522194803_packageVersionKey.cs
new file mode 100644
index 0000000..bed68db
--- /dev/null
+++ b/src/nuget-host/Migrations/20210522194803_packageVersionKey.cs
@@ -0,0 +1,56 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace nugethost.Migrations
+{
+ public partial class packageVersionKey : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropPrimaryKey(
+ name: "PK_PackageVersions",
+ table: "PackageVersions");
+
+ migrationBuilder.DropIndex(
+ name: "IX_PackageVersions_PackageId",
+ table: "PackageVersions");
+
+ migrationBuilder.AlterColumn(
+ name: "FullString",
+ table: "PackageVersions",
+ maxLength: 256,
+ nullable: false,
+ oldClrType: typeof(string),
+ oldMaxLength: 32);
+
+ migrationBuilder.AddPrimaryKey(
+ name: "PK_PackageVersions",
+ table: "PackageVersions",
+ columns: new[] { "PackageId", "FullString" });
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropPrimaryKey(
+ name: "PK_PackageVersions",
+ table: "PackageVersions");
+
+ migrationBuilder.AlterColumn(
+ name: "FullString",
+ table: "PackageVersions",
+ maxLength: 32,
+ nullable: false,
+ oldClrType: typeof(string),
+ oldMaxLength: 256);
+
+ migrationBuilder.AddPrimaryKey(
+ name: "PK_PackageVersions",
+ table: "PackageVersions",
+ column: "FullString");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_PackageVersions_PackageId",
+ table: "PackageVersions",
+ column: "PackageId");
+ }
+ }
+}
diff --git a/src/nuget-host/Migrations/ApplicationDbContextModelSnapshot.cs b/src/nuget-host/Migrations/ApplicationDbContextModelSnapshot.cs
index 0815c76..eba417d 100644
--- a/src/nuget-host/Migrations/ApplicationDbContextModelSnapshot.cs
+++ b/src/nuget-host/Migrations/ApplicationDbContextModelSnapshot.cs
@@ -218,9 +218,10 @@ namespace nugethost.Migrations
modelBuilder.Entity("nuget_host.Data.PackageVersion", b =>
{
+ b.Property("PackageId");
+
b.Property("FullString")
- .ValueGeneratedOnAdd()
- .HasMaxLength(32);
+ .HasMaxLength(256);
b.Property("IsPrerelease");
@@ -228,14 +229,9 @@ namespace nugethost.Migrations
b.Property("Minor");
- b.Property("PackageId")
- .IsRequired();
-
b.Property("Patch");
- b.HasKey("FullString");
-
- b.HasIndex("PackageId");
+ b.HasKey("PackageId", "FullString");
b.ToTable("PackageVersions");
});
diff --git a/src/nuget-host/Startup.cs b/src/nuget-host/Startup.cs
index c9dfbb7..cf585f9 100644
--- a/src/nuget-host/Startup.cs
+++ b/src/nuget-host/Startup.cs
@@ -30,7 +30,6 @@ namespace nuget_host
}
public IConfiguration Configuration { get; }
- public static string RootApiKeySecret { get; private set; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
diff --git a/src/nuget-host/ViewModels/PackageVersionIndexViewModel.cs b/src/nuget-host/ViewModels/PackageVersionIndexViewModel.cs
new file mode 100644
index 0000000..e3e66b9
--- /dev/null
+++ b/src/nuget-host/ViewModels/PackageVersionIndexViewModel.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+using nuget_host.Data;
+
+namespace nuget_host.ViewModels
+{
+ public class PackageVersionIndexViewModel
+ {
+ public List Versions {get; set;}
+ public string PackageId { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/nuget-host/Views/PackageVersion/Delete.cshtml b/src/nuget-host/Views/PackageVersion/Delete.cshtml
new file mode 100644
index 0000000..7f72598
--- /dev/null
+++ b/src/nuget-host/Views/PackageVersion/Delete.cshtml
@@ -0,0 +1,52 @@
+@model nuget_host.Data.PackageVersion
+
+@{
+ ViewData["Title"] = "Delete";
+}
+
+Delete
+
+Are you sure you want to delete this?
+
+
PackageVersion
+
+
+ -
+ @Html.DisplayNameFor(model => model.Major)
+
+ -
+ @Html.DisplayFor(model => model.Major)
+
+ -
+ @Html.DisplayNameFor(model => model.Minor)
+
+ -
+ @Html.DisplayFor(model => model.Minor)
+
+ -
+ @Html.DisplayNameFor(model => model.Patch)
+
+ -
+ @Html.DisplayFor(model => model.Patch)
+
+ -
+ @Html.DisplayNameFor(model => model.IsPrerelease)
+
+ -
+ @Html.DisplayFor(model => model.IsPrerelease)
+
+ -
+ @Html.DisplayNameFor(model => model.Package)
+
+ -
+ @Html.DisplayFor(model => model.Package.Id)
+
+
+
+
+
diff --git a/src/nuget-host/Views/PackageVersion/Details.cshtml b/src/nuget-host/Views/PackageVersion/Details.cshtml
new file mode 100644
index 0000000..7005d46
--- /dev/null
+++ b/src/nuget-host/Views/PackageVersion/Details.cshtml
@@ -0,0 +1,48 @@
+@model nuget_host.Data.PackageVersion
+
+@{
+ ViewData["Title"] = "Details";
+}
+
+Details
+
+
+
PackageVersion
+
+
+ -
+ @Html.DisplayNameFor(model => model.Major)
+
+ -
+ @Html.DisplayFor(model => model.Major)
+
+ -
+ @Html.DisplayNameFor(model => model.Minor)
+
+ -
+ @Html.DisplayFor(model => model.Minor)
+
+ -
+ @Html.DisplayNameFor(model => model.Patch)
+
+ -
+ @Html.DisplayFor(model => model.Patch)
+
+ -
+ @Html.DisplayNameFor(model => model.IsPrerelease)
+
+ -
+ @Html.DisplayFor(model => model.IsPrerelease)
+
+ -
+ @Html.DisplayNameFor(model => model.Package)
+
+ -
+ @Html.DisplayFor(model => model.Package.Id)
+
+
+
+
+ @Html.ActionLink("Edit", "Edit", new { /* id = Model.PrimaryKey */ }) |
+
Back to List
+
diff --git a/src/nuget-host/Views/PackageVersion/Index.cshtml b/src/nuget-host/Views/PackageVersion/Index.cshtml
new file mode 100644
index 0000000..1b112b6
--- /dev/null
+++ b/src/nuget-host/Views/PackageVersion/Index.cshtml
@@ -0,0 +1,66 @@
+@model PackageVersionIndexViewModel
+
+@{
+ ViewData["Title"] = "Index";
+}
+
+Index
+
+
+
+
+
+
+
+
+
+ @Html.DisplayNameFor(model => model.Versions[0].Major)
+ |
+
+ @Html.DisplayNameFor(model => model.Versions[0].Minor)
+ |
+
+ @Html.DisplayNameFor(model => model.Versions[0].Patch)
+ |
+
+ @Html.DisplayNameFor(model => model.Versions[0].IsPrerelease)
+ |
+
+ @Html.DisplayNameFor(model => model.Versions[0].Package)
+ |
+ |
+
+
+
+@foreach (var item in Model.Versions) {
+
+
+ @Html.DisplayFor(modelItem => item.Major)
+ |
+
+ @Html.DisplayFor(modelItem => item.Minor)
+ |
+
+ @Html.DisplayFor(modelItem => item.Patch)
+ |
+
+ @Html.DisplayFor(modelItem => item.IsPrerelease)
+ |
+
+ @Html.ActionLink("Details", "Details", new { pkgid = Model.PackageId, version = item.FullString }) |
+ @Html.ActionLink("Delete", "Delete", new { pkgid = Model.PackageId, version = item.FullString })
+ |
+
+}
+
+
diff --git a/src/nuget-host/Views/_ViewImports.cshtml b/src/nuget-host/Views/_ViewImports.cshtml
index 1056335..3fedf00 100644
--- a/src/nuget-host/Views/_ViewImports.cshtml
+++ b/src/nuget-host/Views/_ViewImports.cshtml
@@ -1,2 +1,3 @@
@using nuget_host.Data
+@using nuget_host.ViewModels
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
diff --git a/src/nuget-host/packages/nuget-cli/1.0.0/nuget-cli-1.0.0.nupkg b/src/nuget-host/packages/nuget-cli/1.0.0/nuget-cli-1.0.0.nupkg
new file mode 100644
index 0000000000000000000000000000000000000000..2b57d2ce3aa0f7f7470de08bb274c47e3cfa8803
GIT binary patch
literal 12018
zcmcJVWl$x}(x7oYID-z%;O_43?hHD}!QGvK!QI`R!QI^*20OUByTfvKBli97jk`a$
zJ36bot1>GpGpnPk;!%`=gu(;^1A_zWsIFB;I1lK<0S5!S`MeN6-|9O6tsEKX|0NS*
zbuIh8V+LKk(Dc8E$D4%W%Z)D6SFijP_<5T$d<<(bc7H*U|2v5ZRJm(6d2`v>yxyLU
z(JC0Syo8(#Jpfm3r@T_ycTkW7uzenQ2BXNjmda>|retAvag!erKtmq@1P%4NSG(uy
zF!Js($@V*54N`pnQiufKguKdt+B%!J6CC_aIbY0frc@Qqw6ZgU4qryvOa{=TB_xYO
z;GXi`IR)hCle}Gk=ov)_C0!_>V6jtm
zqPi;hxokUa)m!fa9t`Z`0}@Q}-yBG{PhQ~u={y8TFfi0l2iiEB0-flLtjy_coE`0e
zMiI(F@_me`?GIm)rsm|es8Jo1zkmzFA)tG8gVN_L3}IJt>GXHH;~ybx;-}$MOF5>_
zPfsT+y9ByGPP$l!1m!B?6rAK};yHn_(g*OB-t4?XvrgUA^hvz1n4o1cw=HjHp;8P)
z$`+DB^aaj%cVby7d>ho9d`iMuGhyd5YE@ALg}w*AjJoUW
zaW1WEc?jnWqcskp9bskIb95Sh@guOllo7t}5i<8gL2F%b&Aw4`%I
zG-k;&ndw-jb2D8KZY2&)wYc9DNAZ`bsItwe>S;%fv+iwxYUQ5_u*fQ_tX%R-<~-m+fn*kW=V4oOOQOp+nsTLHhP#5-M$ck@-h
za8yL{DMZ5!af3b!Re~}wPiW8Yq<$@m&LVhC$(fb-O;S=9@!`6x)0Z7z(xeSDyOTvW
zTn9D)dYxeU)!9W%(W1b4!0p=}axvPMkGo?Gvyy$9WPfJ=I;mn$YO$pLwZQg}1h%zF
z(FXDTTSG(vE_P?!RC(D2dP@b%n%7U&`Zl)^{Gvt3aZ3orUvG=1qg^YeOduk#jRuyL
zYw<5yes?g|0NID5SO;U-E#qbyIbJ>_OLp%Z(HF-}ngK{m?>OZ{(G?@l!Ee32!a@QR3uX(~xYEiFwyzWC4
z1A*5KQLoz>uXA3~3uI_?RA03Y0J_@%vBTQQ9JjzoEw6zE?B=dtyYhjEY;*BJf#rUj
z3im-nZip;|-)sAJ<<
z*#XpfVEEQ^BqAEKXsdNt`f3;PZ>4*Dr&wy+rzPW!j9ZKfhVc_R{UzA!UA*@An-#V7
z01NmfG_?T*{sZJilh{9`L-sUcCfD5e$grOklyGTKpdg*YyO|w$6$;XLb;RFV_Q)FU
z^yYQskKcrR_rwa@Sv9pZe8SW{_QV?6X*JakvZ4(=rlV2)$;t$`gt0Yb{#wvgq8DmK
z&c(3ncniMR!`i(8mdgfw+9U3FfQABo
z+OUBYG=UW&e;3qx)dg0#zgx9{7W^_Q=5s6(>Fc7-_5cUmi1=)h+xtV#sHzmDUeCAO
z4eAxTfIqqlQ2}OgYR+-g<+xFp=FZ%Q-&q#rlj6hu026j>I0ks$u=ew_5nnOFl5AgU);lE^)cM48vH
zNVKr-F}h!^=?PzRFWyhhGg@Y)S7-{k25Ej!?Y2`TKK;J)gTZWR4LBbRcUBT;#HZB
zG^ZyfBZ?qF#knHUx*lsFBwexOATg*
z7f$uQQ_$y`RAlYClBFwpA(d@jiLIVcFYi)fW8E-rcTF@)!8mngzHWB``x@xT!;q}K
z5wZI0(DH`2>u{3J*VJicGqPiUonnJ}M<~?Hei(g9w4=N9MNEEPxtKn=vBkuEeX<#q
z>OsZ29Ie4V(Tr369+~ZY525umvw%1D{8YEVTXJrkN07HwaiU)tX?~lDRKhmdDa=n=
z7#|`6XT3~M%k!dV%@f9#xMdl?VNtok(ht`a`igd|n432_o9y~H7SU&a+myOo!m@>M
zLR%*B*J%1-MWBkMpdN|77PK9WCR%k5*KAb6&{SfTprXC}^->
zr-3B-P^q%9{w~`*oKVd0L~OfcVYZ+&8c-6C?;uv0J#I_|dsrLlik$6Dc7@C|_55YN
zx$JrmIevJa)IpB_i7&7ZHiV<$$JZHJy8xYaVz@aF6LI~GKam;o^>Y!?t)g_9txD7g
z_--3NDe1DNf2C1TPr|U$f-t71X1|QqINH4_O*jVYRnE;1+Z=Vv(l8=IjOVWlCW(N*
z6X)nzT+$GWIlnSVooF|(lcdp>L^n~WV(T4ma_@3HidF7g^a
z&!4#5Gy;rm`FYV3e{Q)
zsbOGag~jjQxKz$raUG^D$6v7Ofr!OUZ)p&?a@4>O`OPYe%2LW|d&bx(Cl
zrny{=!vLu59N(IJigB>oS!>c;Vy
zORC>{U*3C(>>2fmkdc^bG{$*ZL#%WaEZr+bVkokBc`}%an;rCjAtEZWsq0Kan=+J0
zR31p{C`m@khVz`pP_j3#Y^pdpI&wKD9BTG&Zp3u%3rvY*Gq>smBcaK!03H6Aoi#PxOxz>{Du|sadLrOyX*Re=wq8XL}Q9bcb*>+
zz8@9f_IjPd5vICxwz?CWXO~-+(Y`eGG?^}zRZJUr5JI(po2Cvc5xVwN7Xq7yp8M+B
z6V-O8ndd|1b&j8>Q2O4}C5*ktF3lnD-P&|1`rDOjcJXiw%DZilhJzt)>&dyg9V+~oROtb~5xUN7^SO*(1{$UQYAUr{;GlbYGO^!@i4TwfwdxTYJ>@
zG#oq3m*Afw3C^}1#zzVFyG8k%sW&NO)G?+PIxUsfhdU|<(C|9Z(_+}(SHLwm<2ZxE
zYcz#Q0_w)-S}=X@FkO!I6-t+k=9+3lWK^tBJ(Y%>lxbKCeZb^#X0;mswN@IeD7UjGg!+oBT9g_+{1y&$IDW(TiQ8<3?t)7^oJ$v#I10OUR~?k~+ZD+G;~@%`sEDC9g<^zsKwR3Bl-TbD{IK{Ds2t
zs&`nT=q}4@^-Fgkf0uU3#5Y;uBK0?{7%PvWa7`mc%(4J)<&s}bz?9lDu8Ge;xG
zS&zJCBB=vLJ;x-2g|478@#6=Ra#0HqdFY20ay7I{M|l^vmPXh`W765_MSnQrsqia>
zncLC=sqS#yL92t^Nb#GP8>l-w(WC@3_<_j1(r6UimZv(Y0x|=#XDB{s0p)=Ti&x;V
z-JdJ2NG7Ap*Z<;4RFpg6ISSS(gsJ^-4UaO=6GF7B^6-J5z~zaaVPOkJ4C8%l6KZ7H|B-EYO3H*4i*&**up<){xi(wDB1@ZHt}DnM{eZFaSyKHIPhA$RP)
zEp&hVyT2e*OSkE+N>(tQx4i-I=D{xFfV7T>+#uip)Q4s(F{VFR)*2bOn>>Z}L(V&D
zIs7?2e2*g#%Jw#s4yi}4h&8_e86`Qkamb(aW6G!2EjgHyK=0b3F8T1mLG;2PyXp#6
z6_S*TqZ*r~I-1Jnp1tp~VcX~SU
zmJw{j#JBQc2IOnnrYF#Y?QIJMiMkWv{Ka>*LWJWl&DQf~bQpFw^3)c(7VZwceX^1r
z%vesXReTqG?Mt`5Y|5x6uIzDuyS+12$QmA|CXHBmVx7PAXEWwlsN?xb&jp}b}a
zQ@iVTc9bN)#(Dsu16m^(z0o>FiUwrajT>Ecko!k>d&Bf7h-mP>ch5bpqnb*g_FE(4
z!ZG3`OESXykv+9kj7^4c^N8yuU)ph9sDd?
z5JL;f_Uqf6CsHr0Ow{+=Wb#--C98nUW71xfKcp>+p5J;OSa|bR1L8Om*ZnT@;TC)G
z7A15NWBff)-?O&9VfrUYU%Ce&E#n3>F}<>gK=TJ*!gIzS^kJjDk4oq%(Q*ff75M$9
z1j~DcMcr#caQBR;d%#e8REb(8Y(Ut0n8(wZ_@Ge?zElh94c2$a_9B_WU;8l4QekJO
zq$}ANbD3hkHHVtjqWLS3Z!P=?aX{VAU*&rB+N<7V1f;khvm^Ulby4aUI+5u7Spgt;qXNn%u3aE8QxU>0c=yRa
zdmiGFY2+rSL-{dbH!=US$k^qp6!`7DM>OK8%ph`#Hp26}{d-1oJ8TSg0L3*iLeCTw
zN>cMwOU>XSXS*~=dFPUPODA%8N##9w6>;;%JuZBc1{!1(!B^FePD=e9ID@XVYV@1M0oDH?@Y*jbyT!5sF0knsg8^h&uEQt)@_sp+>+c
zuq=o@RJS@jo5wb69G`5
zPWsLA-lGK_`0bzbPG@wCC%6<+Rb%R@m*@i?+&@3WP%CKb7aNEVwX)E?_%$0B@88!u
z(;*(Z-{1t0)MUH9(PR3e9lf2~=E?TH=(?%6FT7y#!mAFgs}kPu23}(K=o53OJwr%$
zD!wv{i>D>m4eVLjb7{AWwM?C;*(ilLggbO~>HG*?PNH(A-GCT_@JxujY^&`XWq(u|
zsjh|ntK)~#LQ(TUP_URw;YuxbOw)rQtr+P}Re3Y;O(gYO@>*$o6xIhg(UJZi#iac*
zm}f41BqOo)p#=Fo1u_A(FwDR08En{88$IcJ>C#f0$vGum&V0pCiOaRg2{?y7Y3FLE^MYXEl3=7*7e$>~}&WYG_iGL_Wui_}imf}SafK^g_XZnTfBQ6(v
zKRAcp9HmD^I=y>m3o13fQEC_88^D~aPEv7r@XR}oX2-UvQawDBX~;Z(ToNc9l%eFk
zat(;47LFo6Fx~mw7pr(TvsRp|424JMSNJ?6cvR&juN4p~>%*;A`hWw^g`1h(V7B@S
zvz0I`x?W~cRaAPqG$>TBO+)HDsvLUmkl032r|kA^l_&*pCtm}u)86B_b9pPf!t9hT
zks4H-TQ*dyjGpj+yo)F4{CNj8h_*!@eFHvAq*j(h8|XAqCKPHXd^4K-rbKw@Vp%+Y
z@Yb;`y@&8H4~Mdo!C%_`rM{jb@%gXMoxIvZ_T0G|&sY)aeZpE!riwy~jo72=rhJhv
zfNk~QjkGuYN|m<)rX6UfhfDuLt4v7$x#a^f^1>@|
zOL|eNP(77xkgb2vaD{vS+U`+(Dt89Hj<%s8;ZL}D!n;@nDTdbF(b@B5VC@ax6?1fp
zEdY@yN8&0WExZ~F5HJxV1VuA>MG=|NPF;q$;Jp8e$>R)v8{;!==^Ai`RMH9FVxRhf
ztyJWkXLZGR%baWgg>1P0PQed8p<$88GP*&fuikD^(<+7kchb_vC$DYZ5j;Ec+^Or=
zB|UbJV9Zba*^fL7FSy*WMA1GpGB~vi6+GQA#Q}@6+&ZM(u%>e2(_|9W8i(f^0a&6A
zCWfAOod9b7yF^1@eqjcy0na$>#vb$p?l5nGh@V|hw5Q2}FfYJM{?p{1NDxXdZ1uMQ
z6vHk;`JRJKh3X$mxwkYD3H7zmuD8ka-%1op)AkqD&F+?`>h;aB*%s?xg-IXG_c8uH
z(b{__&GhPXM$I55;X3RM`0u}3*!4H0XXnUV@22SpPNQ4?r
z+tZ$*qnPyfEdlcSrFmytw}|@DnUPVbIJ#Lz!yf}ah!ZRsgzFmR-NjbQ
zX}_!BuPmSdSlLim*?I>nHHqihQ$!?aN!A)oe!W;XS}C>KfBvQ&72x78$4cV4WG`82
z4k4ATWl0X0^CH#{z``_=ojNhI&%{P7HGW4h3T!k%!J>~Y
zxRHwz%>}dKwa_vWsgaHNEyha3bCkknW%{ynKkP$dt(8h!Sdp0SDh(wSsZ!_4n;L;c
z9!VlM-NMJlZ=#8Q626oVsvly3X9>*IO_lXXM#E<=hpgFco-rVg7f%|pFc(aY#bpX^
zjG~C6q)4pK4k2TX03sR7_TH18j>lRds~J55{V9E%N5HcX{bMP0Z
z&633_l?9g}HvZWV;>vc4qcCtqylzm$NU)oPX=X9$KCQC}Zg@0fpd8piqyt}cijuZd
znw!E#G((sXlr{6YEayP%nCP`*d2)(7D2C=%No}Cxa-@Ua*AngSz#R*TjP;W7fg$aI
zuM*R=udkq*4g$fSbnFDN)zBp2Nh3f@*8lKcl?574#<2TicunK1+UB%plEq!KaqU?m
zCRCA0SgnUxn&X-nEA&&fn2hc}X;COrR674)AdORNr#G!==+>g4`o5%|JAxYlwGx-v
zcvpRuVqFBMn_XBn^<2L`6SC%HgzrxdQ3lUSa>yJ!7%z?wz)$tNUyquUKX<->(Pr(y
za2do2cX5HVZd+SpG#QekNyRCUj@{$-?29^QRSrrF>GR3x;&=442*HNC#amhzLUbL<
z5*KNAt@eyI@v4n^Uul_Fy_
zCB!lXaZbv&p>Fv64T;7uJRqqPT}o%)4%K9~r>o^~xv;?}zyaZfN0Te}@t}*Nn=kbw
zJ9w~!-2bR)W};zWiQ-3^=sjV!;$i1Sgsf}gU}s0n=L>cJns(STFH+`1F2Ete3!4(c
zw95RorNlx99GD!p!#OGZM0vnXLrOA?095*$6l|lgw39T$Ll|wO<9=(rL^q0wGd3EU8G+in;Gj8CIITMqxYO0ut@ykl}{XJQMAS`)2xqt)+
zqmJe5lt13#1drR@Kv`B?gO*>oK#xS_*9tToHAW{ns9RKPnp?ERkhckj4nUqX`STnU
zY9-BytusN|IXk@jOdy4k%V;2|FkTC^naJ&*5zXk!(+pI@rNF4vnQiWboI)ZBN(-T)
zgX+|N{~c9qTjh@CJQBvXyLTS{t2k+0=vug+9a0>|aX4IC<>XvwZWkI11*`jxlIXGEuu;4H5%S_
zpe2{0E%kPH{rg%BrNy>H@7^afh@Ol##$54g3KuugmuC;&(z9Z~K5iWfvKy^u32o+c
z%-@Tn*Xs&3UiwxRxX
z`yFl)$v5Wev@Wo_S{?LrmgL(h(~j3fURU5?c@qF&Tr%Xzi1uy5J%Eg0J~vxQx{_}!
z6RCAP0ryMz0+zPQ_Z0w-4H>Df4p269CX-_&yQU=1kO5w!*83n;>2_~nlwu?^i|lTB
zgpegQMB&nErCp(M(5kh0yJ2EKT!uVp6m;zqHWlNtE>`xlSQ;I<=e7@--_y)KEZpK@
zlW80Z-%Npg0^@84*HJ*-DZE79?mL5jbNU`~vEDuTocCuEfwAxjk`bXP81Guc(rmaf
zlURPg^Kj&oVV#UZT`aX98@)$l`15xF;%~J|@wFwEQ|`Vfw+WC^%ZWJ&7-F3@aJ>()
zgFlrPsj{tzIRvRj^%OJyU~m-#-XDKprSR>Iy^{UlX{O~DyecNG$3C`#>Q3HSPvaP`
z&1s>4=2WHb@y)~>FSrv2mmmL@SQTF;$XZsAb}_;*z6ns*7Ne&h+3m~-0YgfJR6RJ@
z2~Y7IfO|^TJ-CkJVDBvi2&%yzWQP_3;n|^+F@rgZD@g!`C~^qJWBI|;1ygyVi~@M=
zd*dKKw<=f6fM01tNUSj|hDY~jbG?L@$8**>JyO65DM$2j)f507IK6NPgP4VWPLW{a
z4SU1FQwc3p36yiK;B+*>&x%7(_fg%2=mw|r2iNrwSNUf1+oy^$ojX8b<)LX47<&vV
zB}M;7Kt`W+Jq)5}L9#(}z+!c91A&-U#zFT_9;$k3X8DbD3w$|yzTg^HiSlGYnb@E^of;UH>;SoD%k-85704G6c1{W^=
zf&hkZt9gaMF0Nc0f0K*g&>96tcgt}xyFt`GKoB&2>n*w_{D`HXse;wgvF;GPLgSx}
z!HOExn;Sq6XR|Oq(}kVys)At`nETaf6t)QQ2WN;KVfcAzr?^_-cp{y;7e8BBd~Foo
z@KL~GzJn$;S6$@$h#&m5nRa3^2>*}b@7W8K`M@GuA)!;4Vp|Gfh_#`G9Ske!&yK;#
z*C%5;MlWsT$8OgMyLZRo$?SUP#0aC4*HYd+O2|09^=>bU$baQRAi2e`b({_`yLg~E
z??Wjt6n178iQO}CXHSMyQOexcEa_wLb|~Zc{tZt>%B+Nkg7Ohi(DX)==VT8FFD=_*
zlH(seKf03y?M}G3tvA*6%?dmWS4s?SCQB8XfgTr^9&XAjizI2)q=hQKT@WixWg`n=&LX5RNz`gIL_3zXR1F%i=(I5UjpD
z);wir4q18e3s%QZP)+TNL>G#wPb^Q)@1Trd$tJ}FEJ7>Fz@eAYaC5a8!NXfNH6oqF
z(`e1mTeh%2
zBHvt~0Ggoz?&VQSq+Wrk?w#>NC1F~p%6yq(XV`NSYIAybhop3~lg)FjN-lC97XH#$&5S@)-F_i}nGsN9%B8AIG)=jTFDarW!<*rH38F$e42!
z-R5GZ>dx0N)M}N1%ICq)WZeAd{wK6Ka>gwZrggjE%t=GqE^x$B&S@J
zw1v1(d?8l~1=XA`?mJh*Yq_6b3}>&B4qFc`RMAU@nf97OZmIM9#RDBP7-e8FDIL}~
ze<^@-2v|d4=Jyntk-SkH%H_2w`|Y)G@F_hd6}TkX=5>p`Polc&IV?^-@?%sg9uC;6
zUuR~mS#IpLDI6;OY|1}g%f??<+k$~!7)QUg+L&Fy^1+5!f4!Kn^!1w87d$#1d5_$_
zh~Ana3|6SUeb~Gmi+H(wZmBBUJh}DvJqYK2@oc&~x9Hlz*MFw)UL5j1558ELSCQbx
z6CY>FCnCUCV4v1mInrD;L%rcOTuy~q3FFu;>gf5(yU<;?9>dH`ccRWyZsuWzI^BEB
zW+}AnZsJ$}yGF-Vvx7SRz5lnu>G8*L)l?L>4`13_(}c+rFJoHtmP$dxTR~6N!lNZ!
zUkEZ;{J3WsOs}?y#LhL}Gat(1g+MXl(>BMgwrTFHDGU>Zz%~0dpC%Q5M8?qd
z`&!+Q>NB<+vLFNC`zrEFjYL;+HTIQ!08f9{0*t#s?KJ*
z>cTFA9LrZ6{UjB))HRx_m)n-x?+~D2qgwXHt3b}l##!jj3HC;`@Iscx%cn5@?U1qe
zm
z?b=9o4eC>{6rq$rp}$BP5}#(kWnm$ab8j)*TWz>`frVs4$s_a-_kCe9T#dyC(;Lxt
ztMa}}$LGlYDiahv=2(oU5OiEk)TIGZUE65N?`+_ftr`z9lwtu|{mEiHJ)W>8>qOre
zOnJ2+ji6S(FFLlTY3PZH#xY`Q^Pxp+lJ(Hn{l+oG-hWzicvW=Fn1vOZuUUw)yCMSI
zvXlRDfJ%rNIxgy`aI5dk8F;W(bX*yF&)Pw=V~dtouTtj+JCz
zK)3NK`IRb(Q!XNxkjDONbeuuoJ52+-#zFn=37Y=T{2|YX9dYIi(&kcb6W5}s^!y+-
z0z!ol1_2JWZ;@oyA}|BecqUimCmtex7x?%NQi5JaBJ8Es$(UUq9Q+df8>eq4dmn32
zuOCysLkGT){|;291tQzeeiC|PpHSt$NIh*4TN@{!jg!8ryB*L`m)_0VDkGN9rjHR2
z_>dtytp#%6h7vR25&4UM3jrawB5WOodeq(GoseBBIGaau)$!2jcjuEy;n+(`q-@j#
z1R|mL(@#%>#9p>1&R68#+)Xg!>qsLB)SlM3{LoApfW`%~&nYHVPqM#_Q1pESAGFkX
zU}G_*5Ibx@E=IE6{p$?zY0+%)ZQNU=3t!Kd$|`HJ+z~d}99{Fy(@WeWM_1c{#sFFd
zuAh-FBfZS7-5)oCvYK|ItmfStvd!BVa!_L4e~ZL$wiF;6+W3k)K1cW;wBjd~%YWb_
ztp7QFT?jBRrOy_221b?!ra%Tqpo5FK5zvvr8t7zTY~WU0@|f%HJK_iPAmQrnli+zD>)!;
z?){)Ki_LPs{$r}9CRSFkw-zzP^rG3(9tw%+RS+Rz1LgEbZ%Z3A+p4BQ!gGQU)#*&x
z!gQHals~q7q9y}_zVAx>
z(1sRG%dQhM*~wc;roZJ2Vot70%dRu6Q$}sJB_zR?&JPOjtlD?b9NRlj?bC-adDu=%2Nu>*sMx
z#-l*yjzD9F?Ao$o7^;^SnQMms8%=NsOvwK?W&PRge;ogVxmJ||1
z@YVmr8vmR2e}P{A(LVf4tp9?*{+of%Jp9kO_>X}&>i;@3|I@&KCh|W9l4$-vq_v_9
UG|a!cfc`w)J{@FC_phh_1t#?2RR910
literal 0
HcmV?d00001