Vibe Card Library Update
@@ -0,0 +1,10 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,205 @@
|
|||||||
|
using System.Text;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
var repoRoot = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", ".."));
|
||||||
|
var docsDir = Path.Combine(repoRoot, "chrono.docs");
|
||||||
|
var webWwwRoot = Path.Combine(repoRoot, "Chrono", "Web", "wwwroot");
|
||||||
|
|
||||||
|
Console.WriteLine($"Repo root: {repoRoot}");
|
||||||
|
Console.WriteLine($"Docs dir: {docsDir}");
|
||||||
|
Console.WriteLine($"Web wwwroot: {webWwwRoot}");
|
||||||
|
|
||||||
|
if (!Directory.Exists(docsDir))
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"ERROR: docs dir not found: {docsDir}");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mdFiles = Directory.GetFiles(docsDir, "*.md");
|
||||||
|
var cards = new List<CardData>();
|
||||||
|
|
||||||
|
foreach (var file in mdFiles)
|
||||||
|
{
|
||||||
|
var content = Encoding.UTF8.GetString(File.ReadAllBytes(file));
|
||||||
|
if (!content.StartsWith("---"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var endIndex = content.IndexOf("---", 3, StringComparison.Ordinal);
|
||||||
|
if (endIndex < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var frontmatter = content[3..endIndex].Trim();
|
||||||
|
var yaml = ParseYaml(frontmatter);
|
||||||
|
|
||||||
|
var name = Path.GetFileNameWithoutExtension(file);
|
||||||
|
var category = yaml.GetValueOrDefault("category");
|
||||||
|
if (category == null) continue;
|
||||||
|
|
||||||
|
var card = new CardData
|
||||||
|
{
|
||||||
|
Name = name,
|
||||||
|
Category = category,
|
||||||
|
Cost = ParseInt(yaml, "cost"),
|
||||||
|
Attack = ParseInt(yaml, "attack"),
|
||||||
|
Health = ParseInt(yaml, "health"),
|
||||||
|
Description = StripWikiLinks(yaml.GetValueOrDefault("description")),
|
||||||
|
Faction = StripWikiLink(yaml.GetValueOrDefault("faction")),
|
||||||
|
Set = StripWikiLink(yaml.GetValueOrDefault("set")),
|
||||||
|
Speed = StripWikiLink(yaml.GetValueOrDefault("speed")),
|
||||||
|
Archetypes = ParseList(yaml, "archetypes").Select(s => StripWikiLink(s) ?? "").Where(s => s != "").ToList(),
|
||||||
|
ImmortalizeTo = yaml.ContainsKey("immortalizeTo") ? ParseListOrScalar(yaml, "immortalizeTo").Select(s => StripWikiLink(s) ?? "").Where(s => s != "").ToList() : null,
|
||||||
|
ImmortalizeFrom = StripWikiLink(yaml.GetValueOrDefault("immortalizeFrom")),
|
||||||
|
ImmortalizeWhen = NullIfNa(StripWikiLinks(yaml.GetValueOrDefault("immortalizeWhen"))),
|
||||||
|
ImageFile = StripWikiLink(yaml.GetValueOrDefault("imageLink")),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (card.ImageFile != null && !card.ImageFile.EndsWith(".png"))
|
||||||
|
card.ImageFile += ".png";
|
||||||
|
|
||||||
|
cards.Add(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy PNGs to wwwroot/cards
|
||||||
|
var cardsDir = Path.Combine(webWwwRoot, "cards");
|
||||||
|
Directory.CreateDirectory(cardsDir);
|
||||||
|
foreach (var card in cards)
|
||||||
|
{
|
||||||
|
if (card.ImageFile == null) continue;
|
||||||
|
var src = Path.Combine(docsDir, card.ImageFile);
|
||||||
|
var dst = Path.Combine(cardsDir, card.ImageFile);
|
||||||
|
if (File.Exists(src))
|
||||||
|
File.Copy(src, dst, overwrite: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write cards.json
|
||||||
|
var output = new { cards };
|
||||||
|
var json = JsonSerializer.Serialize(output, new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
WriteIndented = true,
|
||||||
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||||
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||||
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
||||||
|
});
|
||||||
|
var jsonPath = Path.Combine(webWwwRoot, "sample-data", "cards.json");
|
||||||
|
File.WriteAllText(jsonPath, json);
|
||||||
|
|
||||||
|
Console.WriteLine($"Processed {cards.Count} cards");
|
||||||
|
Console.WriteLine($"Written to {jsonPath}");
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// --- Helpers ---
|
||||||
|
|
||||||
|
static int? ParseInt(Dictionary<string, string> yaml, string key)
|
||||||
|
{
|
||||||
|
if (!yaml.TryGetValue(key, out var val)) return null;
|
||||||
|
if (int.TryParse(val, out var i)) return i;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static string? StripWikiLink(string? s)
|
||||||
|
{
|
||||||
|
if (s == null || s == "N/A") return null;
|
||||||
|
return Regex.Replace(s, @"\[\[([^\]]*)\]\]", "$1").Trim('"');
|
||||||
|
}
|
||||||
|
|
||||||
|
static string? NullIfNa(string? s) => s is "N/A" or null ? null : s.Trim('"');
|
||||||
|
|
||||||
|
static string? StripWikiLinks(string? s)
|
||||||
|
{
|
||||||
|
if (s == null || s == "N/A") return null;
|
||||||
|
return Regex.Replace(s.Trim('"'), @"\[\[([^\]]*)\]\]", "$1").Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<string> ParseList(Dictionary<string, string> yaml, string key)
|
||||||
|
{
|
||||||
|
if (!yaml.TryGetValue(key, out var raw)) return [];
|
||||||
|
var result = new List<string>();
|
||||||
|
foreach (var item in raw.Split('\n', StringSplitOptions.RemoveEmptyEntries))
|
||||||
|
{
|
||||||
|
var trimmed = item.TrimStart('-', ' ').Trim(' ', '"');
|
||||||
|
if (trimmed.Length > 0) result.Add(trimmed);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<string> ParseListOrScalar(Dictionary<string, string> yaml, string key)
|
||||||
|
{
|
||||||
|
if (!yaml.TryGetValue(key, out var raw)) return [];
|
||||||
|
raw = raw.Trim();
|
||||||
|
if (!raw.StartsWith('-'))
|
||||||
|
return [raw.Trim('"')];
|
||||||
|
|
||||||
|
var result = new List<string>();
|
||||||
|
foreach (var item in raw.Split('\n', StringSplitOptions.RemoveEmptyEntries))
|
||||||
|
{
|
||||||
|
var trimmed = item.TrimStart('-', ' ').Trim(' ', '"');
|
||||||
|
if (trimmed.Length > 0) result.Add(trimmed);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Dictionary<string, string> ParseYaml(string yaml)
|
||||||
|
{
|
||||||
|
var dict = new Dictionary<string, string>();
|
||||||
|
var lines = yaml.Split('\n');
|
||||||
|
string? currentKey = null;
|
||||||
|
var listBuffer = new List<string>();
|
||||||
|
|
||||||
|
foreach (var line in lines)
|
||||||
|
{
|
||||||
|
var trimmed = line.Trim();
|
||||||
|
if (trimmed.Length == 0) continue;
|
||||||
|
|
||||||
|
if (trimmed.StartsWith("- "))
|
||||||
|
{
|
||||||
|
listBuffer.Add(trimmed);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listBuffer.Count > 0 && currentKey != null)
|
||||||
|
{
|
||||||
|
dict[currentKey] = string.Join("\n", listBuffer);
|
||||||
|
listBuffer.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
var colonIndex = trimmed.IndexOf(':');
|
||||||
|
if (colonIndex < 0) continue;
|
||||||
|
|
||||||
|
currentKey = trimmed[..colonIndex].Trim();
|
||||||
|
var value = trimmed[(colonIndex + 1)..].Trim();
|
||||||
|
|
||||||
|
if (value.Length == 0)
|
||||||
|
{
|
||||||
|
// Could be a list or multi-line value starting on next line
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
dict[currentKey] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listBuffer.Count > 0 && currentKey != null)
|
||||||
|
dict[currentKey] = string.Join("\n", listBuffer);
|
||||||
|
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
record CardData
|
||||||
|
{
|
||||||
|
[JsonPropertyName("name")] public string Name { get; set; } = "";
|
||||||
|
[JsonPropertyName("category")] public string Category { get; set; } = "";
|
||||||
|
[JsonPropertyName("cost")] public int? Cost { get; set; }
|
||||||
|
[JsonPropertyName("attack")] public int? Attack { get; set; }
|
||||||
|
[JsonPropertyName("health")] public int? Health { get; set; }
|
||||||
|
[JsonPropertyName("description")] public string? Description { get; set; }
|
||||||
|
[JsonPropertyName("faction")] public string? Faction { get; set; }
|
||||||
|
[JsonPropertyName("set")] public string? Set { get; set; }
|
||||||
|
[JsonPropertyName("speed")] public string? Speed { get; set; }
|
||||||
|
[JsonPropertyName("archetypes")] public List<string>? Archetypes { get; set; }
|
||||||
|
[JsonPropertyName("immortalizeTo")] public List<string>? ImmortalizeTo { get; set; }
|
||||||
|
[JsonPropertyName("immortalizeFrom")] public string? ImmortalizeFrom { get; set; }
|
||||||
|
[JsonPropertyName("immortalizeWhen")] public string? ImmortalizeWhen { get; set; }
|
||||||
|
[JsonPropertyName("imageFile")] public string? ImageFile { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
"""
|
||||||
|
One-time script: Download card images from playchrono.com and add imageLink frontmatter.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python process_cards.py
|
||||||
|
|
||||||
|
Requires a saved HTML copy of https://www.playchrono.com/collections/cards
|
||||||
|
with the embedded JSON.parse('...') card data.
|
||||||
|
"""
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import urllib.request
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Adjust these paths for your environment
|
||||||
|
html_file = r"../playchrono_cards_page.html"
|
||||||
|
docs_dir = r"../../chrono.docs"
|
||||||
|
|
||||||
|
if not os.path.exists(html_file):
|
||||||
|
# Fallback: search for saved tool output
|
||||||
|
possible = [f for f in os.listdir(r"C:\Users\jonmc\.local\share\opencode\tool-output")
|
||||||
|
if f.startswith("tool_") and os.path.isfile(os.path.join(r"C:\Users\jonmc\.local\share\opencode\tool-output", f))]
|
||||||
|
if possible:
|
||||||
|
html_file = os.path.join(r"C:\Users\jonmc\.local\share\opencode\tool-output", possible[-1])
|
||||||
|
|
||||||
|
with open(html_file, 'r', encoding='utf-8') as f:
|
||||||
|
html = f.read()
|
||||||
|
|
||||||
|
start_marker = "JSON.parse('"
|
||||||
|
idx = html.find(start_marker)
|
||||||
|
if idx < 0:
|
||||||
|
print("ERROR: Could not find JSON.parse in HTML")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
start = idx + len(start_marker)
|
||||||
|
quote_end = html.find("')", start)
|
||||||
|
if quote_end < 0:
|
||||||
|
print("ERROR: Could not find closing '")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
raw_json_str = html[start:quote_end]
|
||||||
|
|
||||||
|
json_str = raw_json_str.encode('utf-8').decode('unicode_escape')
|
||||||
|
json_str = json_str.replace('\\/', '/')
|
||||||
|
|
||||||
|
try:
|
||||||
|
cards = json.loads(json_str)
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
print(f"ERROR parsing JSON: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f"Found {len(cards)} cards")
|
||||||
|
|
||||||
|
name_to_image = {}
|
||||||
|
for card in cards:
|
||||||
|
name = card.get('name', '')
|
||||||
|
image_url = card.get('image_url', '')
|
||||||
|
if name and image_url:
|
||||||
|
name_to_image[name.lower()] = image_url
|
||||||
|
counterpart = card.get('counterpart')
|
||||||
|
if counterpart and isinstance(counterpart, dict):
|
||||||
|
cname = counterpart.get('name', '')
|
||||||
|
cimage = counterpart.get('image_url', '')
|
||||||
|
if cname and cimage:
|
||||||
|
name_to_image[cname.lower()] = cimage
|
||||||
|
|
||||||
|
print(f"Built mapping for {len(name_to_image)} card names")
|
||||||
|
|
||||||
|
md_files = [f for f in os.listdir(docs_dir) if f.endswith('.md')]
|
||||||
|
print(f"Found {len(md_files)} markdown files")
|
||||||
|
|
||||||
|
processed = 0
|
||||||
|
downloaded = 0
|
||||||
|
matched = 0
|
||||||
|
for md_file in sorted(md_files):
|
||||||
|
filepath = os.path.join(docs_dir, md_file)
|
||||||
|
|
||||||
|
card_name = md_file[:-3]
|
||||||
|
card_name_lower = card_name.lower()
|
||||||
|
|
||||||
|
if card_name_lower not in name_to_image:
|
||||||
|
continue
|
||||||
|
|
||||||
|
matched += 1
|
||||||
|
image_url = name_to_image[card_name_lower]
|
||||||
|
|
||||||
|
png_filename = f"{card_name}.png"
|
||||||
|
png_filepath = os.path.join(docs_dir, png_filename)
|
||||||
|
|
||||||
|
if not os.path.exists(png_filepath):
|
||||||
|
try:
|
||||||
|
print(f" DL: {png_filename}")
|
||||||
|
req = urllib.request.Request(image_url, headers={
|
||||||
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36'
|
||||||
|
})
|
||||||
|
with urllib.request.urlopen(req) as response:
|
||||||
|
with open(png_filepath, 'wb') as out:
|
||||||
|
out.write(response.read())
|
||||||
|
downloaded += 1
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ERR: {png_filename} - {e}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
with open(filepath, 'r', encoding='utf-8') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
has_image_link = 'imageLink:' in content
|
||||||
|
img_ref = f"![[{png_filename}]]"
|
||||||
|
has_img_ref = img_ref in content
|
||||||
|
|
||||||
|
if has_image_link and has_img_ref:
|
||||||
|
continue
|
||||||
|
|
||||||
|
modified = content
|
||||||
|
|
||||||
|
if not has_image_link:
|
||||||
|
modified = modified.rstrip()
|
||||||
|
if modified.endswith('---'):
|
||||||
|
modified = modified[:-3] + f'imageLink: "[[{png_filename}]]"\n---'
|
||||||
|
else:
|
||||||
|
modified = modified + f'\nimageLink: "[[{png_filename}]]"\n'
|
||||||
|
|
||||||
|
if not has_img_ref:
|
||||||
|
modified = modified.rstrip() + f'\n\n\n{img_ref}\n'
|
||||||
|
|
||||||
|
with open(filepath, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(modified)
|
||||||
|
|
||||||
|
processed += 1
|
||||||
|
|
||||||
|
print(f"\nDone! Matched: {matched}, Downloaded: {downloaded}, Updated markdown: {processed}")
|
||||||
|
print(f"Skipped (no card match): {len(md_files) - matched}")
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web", "Web\Web.csproj", "{18981096-443A-44BF-AE56-6499C2B03AEF}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web", "Web\Web.csproj", "{18981096-443A-44BF-AE56-6499C2B03AEF}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Build", "Build\Build.csproj", "{36E3775C-0E28-4EAE-AE92-4FB493E3787F}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -12,5 +14,9 @@ Global
|
|||||||
{18981096-443A-44BF-AE56-6499C2B03AEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{18981096-443A-44BF-AE56-6499C2B03AEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{18981096-443A-44BF-AE56-6499C2B03AEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{18981096-443A-44BF-AE56-6499C2B03AEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{18981096-443A-44BF-AE56-6499C2B03AEF}.Release|Any CPU.Build.0 = Release|Any CPU
|
{18981096-443A-44BF-AE56-6499C2B03AEF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{36E3775C-0E28-4EAE-AE92-4FB493E3787F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{36E3775C-0E28-4EAE-AE92-4FB493E3787F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{36E3775C-0E28-4EAE-AE92-4FB493E3787F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{36E3775C-0E28-4EAE-AE92-4FB493E3787F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
|
After Width: | Height: | Size: 157 KiB |
|
After Width: | Height: | Size: 164 KiB |
|
After Width: | Height: | Size: 148 KiB |
|
After Width: | Height: | Size: 115 KiB |
|
After Width: | Height: | Size: 213 KiB |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 199 KiB |
|
After Width: | Height: | Size: 150 KiB |
|
After Width: | Height: | Size: 164 KiB |
|
After Width: | Height: | Size: 262 KiB |
|
After Width: | Height: | Size: 220 KiB |
|
After Width: | Height: | Size: 151 KiB |
|
After Width: | Height: | Size: 164 KiB |
|
After Width: | Height: | Size: 101 KiB |
|
After Width: | Height: | Size: 118 KiB |
|
After Width: | Height: | Size: 145 KiB |
|
After Width: | Height: | Size: 142 KiB |
|
After Width: | Height: | Size: 189 KiB |
|
After Width: | Height: | Size: 138 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
After Width: | Height: | Size: 158 KiB |
|
After Width: | Height: | Size: 126 KiB |
|
After Width: | Height: | Size: 127 KiB |
|
After Width: | Height: | Size: 156 KiB |
|
After Width: | Height: | Size: 144 KiB |
|
After Width: | Height: | Size: 170 KiB |
|
After Width: | Height: | Size: 146 KiB |
|
After Width: | Height: | Size: 162 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 137 KiB |
|
After Width: | Height: | Size: 126 KiB |
|
After Width: | Height: | Size: 123 KiB |
|
After Width: | Height: | Size: 142 KiB |
|
After Width: | Height: | Size: 131 KiB |
|
After Width: | Height: | Size: 160 KiB |
|
After Width: | Height: | Size: 131 KiB |
|
After Width: | Height: | Size: 152 KiB |
|
After Width: | Height: | Size: 156 KiB |
|
After Width: | Height: | Size: 167 KiB |
|
After Width: | Height: | Size: 164 KiB |
|
After Width: | Height: | Size: 118 KiB |
|
After Width: | Height: | Size: 126 KiB |
|
After Width: | Height: | Size: 166 KiB |
|
After Width: | Height: | Size: 145 KiB |
|
After Width: | Height: | Size: 147 KiB |
|
After Width: | Height: | Size: 114 KiB |
|
After Width: | Height: | Size: 191 KiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 247 KiB |
|
After Width: | Height: | Size: 169 KiB |
|
After Width: | Height: | Size: 138 KiB |
|
After Width: | Height: | Size: 133 KiB |
|
After Width: | Height: | Size: 177 KiB |
|
After Width: | Height: | Size: 154 KiB |
|
After Width: | Height: | Size: 184 KiB |
|
After Width: | Height: | Size: 170 KiB |
|
After Width: | Height: | Size: 148 KiB |
|
After Width: | Height: | Size: 151 KiB |
|
After Width: | Height: | Size: 158 KiB |
|
After Width: | Height: | Size: 160 KiB |
|
After Width: | Height: | Size: 175 KiB |
|
After Width: | Height: | Size: 150 KiB |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 213 KiB |
|
After Width: | Height: | Size: 164 KiB |
|
After Width: | Height: | Size: 177 KiB |
|
After Width: | Height: | Size: 199 KiB |
|
After Width: | Height: | Size: 147 KiB |
|
After Width: | Height: | Size: 131 KiB |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 163 KiB |
|
After Width: | Height: | Size: 172 KiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 245 KiB |
|
After Width: | Height: | Size: 163 KiB |
|
After Width: | Height: | Size: 149 KiB |
|
After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 136 KiB |
|
After Width: | Height: | Size: 154 KiB |
|
After Width: | Height: | Size: 175 KiB |
|
After Width: | Height: | Size: 143 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
After Width: | Height: | Size: 121 KiB |
|
After Width: | Height: | Size: 193 KiB |
|
After Width: | Height: | Size: 157 KiB |
|
After Width: | Height: | Size: 135 KiB |
|
After Width: | Height: | Size: 181 KiB |
|
After Width: | Height: | Size: 158 KiB |
|
After Width: | Height: | Size: 155 KiB |
|
After Width: | Height: | Size: 150 KiB |
|
After Width: | Height: | Size: 138 KiB |
|
After Width: | Height: | Size: 227 KiB |
|
After Width: | Height: | Size: 165 KiB |
|
After Width: | Height: | Size: 156 KiB |