activate_all_gamescomando com a --forceflag para a

This commit is contained in:
Flatlogic Bot 2026-02-14 05:58:06 +00:00
parent c3bdab1f26
commit 06f3311e57
23 changed files with 282 additions and 59 deletions

View File

@ -5,11 +5,19 @@ from core.pexels import fetch_first
import time
class Command(BaseCommand):
help = 'Ativa todos os jogos, gera scripts de IA e capas automaticamente para todo o catálogo.'
help = 'Ativa todos os jogos, gera scripts de IA (com história e correção) e capas automaticamente para todo o catálogo.'
def add_arguments(self, parser):
parser.add_argument(
'--force',
action='store_true',
help='Força a re-geração de todos os scripts, mesmo que já existam.',
)
def handle(self, *args, **options):
force = options['force']
games = GameProject.objects.all()
self.stdout.write(f"Iniciando atualização de {games.count()} jogos...")
self.stdout.write(f"Iniciando processamento de {games.count()} jogos (Force={force})...")
for game in games:
self.stdout.write(f"Processando: {game.title}...")
@ -17,22 +25,28 @@ class Command(BaseCommand):
# 1. Ativar o jogo
game.is_active = True
# 2. Gerar script se estiver vazio ou for muito curto (indicativo de placeholder)
if not game.script_code or len(game.script_code) < 100:
# 2. Gerar script se estiver vazio, for placeholder ou se force for True
needs_script = force or not game.script_code or len(game.script_code) < 500
if needs_script:
if not game.external_url:
self.stdout.write(f" -> Gerando script de IA para {game.title}...")
self.stdout.write(f" -> Gerando script de IA Autônomo para {game.title}...")
script = generate_game_script(game.title, game.prompt, game.genre)
if script:
game.script_code = script
self.stdout.write(self.style.SUCCESS(f" -> Script gerado com sucesso."))
else:
self.stdout.write(self.style.ERROR(f" -> Falha ao gerar script para {game.title}"))
else:
self.stdout.write(f" -> Jogo possui URL externa, pulando geração de script.")
# 3. Gerar Capa se não tiver
if not game.image_reference:
self.stdout.write(f" -> Buscando capa no Pexels para {game.title}...")
pexels_data = fetch_first(f"{game.title} game {game.genre}")
pexels_data = fetch_first(f"{game.title} game background")
if pexels_data:
game.image_reference = pexels_data['local_path'].replace('media/', '')
self.stdout.write(self.style.SUCCESS(f" -> Capa encontrada e salva."))
else:
self.stdout.write(self.style.WARNING(f" -> Capa não encontrada para {game.title}"))
@ -40,6 +54,6 @@ class Command(BaseCommand):
self.stdout.write(self.style.SUCCESS(f" -> {game.title} ATUALIZADO E ATIVO!"))
# Pequena pausa para evitar sobrecarga na API de IA/Pexels
time.sleep(1)
time.sleep(2)
self.stdout.write(self.style.SUCCESS("Processamento concluído com sucesso! Todos os jogos estão online."))
self.stdout.write(self.style.SUCCESS("Processamento concluído! Todos os jogos estão online e atualizados com IA Autônoma."))

View File

@ -0,0 +1,44 @@
from django.core.management.base import BaseCommand
from core.models import GameProject
from core.views import generate_game_script
from core.pexels import fetch_first
import time
class Command(BaseCommand):
help = 'Atualiza todos os jogos existentes usando IA para gerar script, história e banners.'
def handle(self, *args, **options):
games = GameProject.objects.all()
total = games.count()
self.stdout.write(self.style.SUCCESS(f'Iniciando atualização de {total} jogos...'))
for i, game in enumerate(games):
self.stdout.write(f'[{i+1}/{total}] Atualizando: {game.title}')
# 1. Gerar Script e História via IA
# O prompt original do jogo é usado como base
new_script = generate_game_script(game.title, game.prompt, game.genre)
if new_script:
game.script_code = new_script
# Se o prompt estiver vazio, podemos pedir para a IA gerar uma descrição/história também
# Mas o generate_game_script já coloca a história no código HTML.
# Vamos garantir que o is_active esteja True
game.is_active = True
self.stdout.write(self.style.SUCCESS(f' - Script gerado com sucesso.'))
else:
self.stdout.write(self.style.ERROR(f' - Erro ao gerar script.'))
# 2. Gerar Banner via Pexels (IA baseada no título)
if not game.image_reference or "pexels" not in str(game.image_reference):
pexels_data = fetch_first(f"{game.title} game wallpaper background")
if pexels_data:
game.image_reference = pexels_data['local_path'].replace('media/', '')
self.stdout.write(self.style.SUCCESS(f' - Banner gerado: {game.image_reference}'))
else:
self.stdout.write(self.style.WARNING(f' - Não foi possível gerar banner.'))
game.save()
# Pequeno delay para evitar hitting limits se houver muitos
time.sleep(1)
self.stdout.write(self.style.SUCCESS('Todos os jogos foram atualizados, ativados e integrados com IA!'))

View File

@ -43,6 +43,30 @@
border-radius: 16px;
padding: 2rem;
}
/* Google Translate customization */
.goog-te-banner-frame.skiptranslate { display: none !important; }
body { top: 0px !important; }
#google_translate_element {
margin-right: 15px;
}
.goog-te-gadget-icon { display: none !important; }
.goog-te-gadget-simple {
background-color: rgba(255,255,255,0.1) !important;
border: 1px solid rgba(255,255,255,0.2) !important;
padding: 5px 10px !important;
border-radius: 20px !important;
color: white !important;
}
.goog-te-menu-value span { color: white !important; }
/* Auto-translation notification */
#translation-note {
display: none;
font-size: 0.7rem;
color: var(--cyan-accent);
text-align: right;
margin-right: 15px;
}
</style>
{% block extra_css %}{% endblock %}
</head>
@ -52,11 +76,18 @@
<a class="navbar-brand brand-font fs-3" href="{% url 'index' %}">
AI <span class="text-info">GAME</span> FORGE
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto align-items-center">
<!-- Google Translate -->
<li class="nav-item">
<div id="google_translate_element"></div>
<div id="translation-note">Auto-detecting language...</div>
</li>
{% if request.session.is_admin %}
<li class="nav-item"><a class="nav-link" href="{% url 'admin_dashboard' %}">Painel Admin</a></li>
<li class="nav-item"><a class="nav-link btn btn-outline-danger btn-sm ms-lg-3" href="{% url 'logout' %}">Sair Admin</a></li>
@ -92,6 +123,35 @@
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<!-- Google Translate Script with Auto-Detection -->
<script type="text/javascript">
function googleTranslateElementInit() {
new google.translate.TranslateElement({
pageLanguage: 'pt',
includedLanguages: '', // All languages
layout: google.translate.TranslateElement.InlineLayout.SIMPLE,
autoDisplay: true
}, 'google_translate_element');
// Auto-trigger translation based on browser language
setTimeout(function() {
var userLang = navigator.language || navigator.userLanguage;
var langCode = userLang.split('-')[0];
if (langCode !== 'pt') {
var select = document.querySelector('select.goog-te-combo');
if (select) {
select.value = langCode;
select.dispatchEvent(new Event('change'));
document.getElementById('translation-note').style.display = 'block';
document.getElementById('translation-note').innerText = 'Translated to: ' + userLang;
}
}
}, 1000);
}
</script>
<script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>
{% block extra_js %}{% endblock %}
</body>
</html>

View File

@ -3,7 +3,12 @@
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-5">
<h1 class="h2">Painel de Controle</h1>
<a href="{% url 'admin_create_game' %}" class="btn btn-primary rounded-pill px-4">+ Criar Novo Jogo</a>
<div class="d-flex gap-2">
<a href="{% url 'admin_batch_update_ai' %}" class="btn btn-outline-info rounded-pill px-4" onclick="return confirm('Isso irá regenerar o código, história e banners de TODOS os jogos usando IA. Pode levar alguns minutos. Deseja continuar?')">
🪄 Atualizar Tudo (IA)
</a>
<a href="{% url 'admin_create_game' %}" class="btn btn-primary rounded-pill px-4">+ Criar Novo Jogo</a>
</div>
</div>
<div class="row">
@ -14,6 +19,7 @@
<table class="table table-dark table-hover">
<thead>
<tr>
<th>Banner</th>
<th>Título</th>
<th>Gênero</th>
<th>Data</th>
@ -24,6 +30,13 @@
<tbody>
{% for project in projects %}
<tr>
<td>
{% if project.image_reference %}
<img src="{{ project.image_reference.url }}" style="height: 40px; width: 60px; object-fit: cover; border-radius: 4px;">
{% else %}
<div class="bg-secondary" style="height: 40px; width: 60px; border-radius: 4px;"></div>
{% endif %}
</td>
<td>{{ project.title }}</td>
<td>{{ project.get_genre_display }}</td>
<td>{{ project.created_at|date:"d/m/Y" }}</td>
@ -63,4 +76,4 @@
</div>
</div>
</div>
{% endblock %}
{% endblock %}

View File

@ -4,17 +4,24 @@
<div class="row justify-content-center">
<div class="col-md-10">
<div class="glass-card">
<h2 class="mb-4">{% if project %}Editar Jogo: {{ project.title }}{% else %}Criar Novo Jogo{% endif %}</h2>
<form method="POST" enctype="multipart/form-data">
<h2 class="mb-4">
{% if project %}
<span class="text-info">🪄 Atualizar:</span> {{ project.title }}
{% else %}
<span class="text-info">🚀 Criar Novo Jogo</span> (Geração Autônoma)
{% endif %}
</h2>
<form method="POST" enctype="multipart/form-data" id="gameForm">
{% csrf_token %}
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label">Título do Jogo</label>
<input type="text" name="title" class="form-control bg-dark text-white border-secondary" value="{{ project.title }}" required>
<label class="form-label fw-bold">Título do Jogo</label>
<input type="text" name="title" class="form-control bg-dark text-white border-secondary" value="{{ project.title }}" placeholder="Ex: Corrida Espacial" required>
</div>
<div class="col-md-6 mb-3">
<label class="form-label">Gênero</label>
<label class="form-label fw-bold">Gênero</label>
<select name="genre" class="form-select bg-dark text-white border-secondary">
<option value="arcade" {% if project.genre == 'arcade' %}selected{% endif %}>Arcade (Padrão)</option>
<option value="platformer" {% if project.genre == 'platformer' %}selected{% endif %}>Platformer</option>
<option value="shooter" {% if project.genre == 'shooter' %}selected{% endif %}>Shooter</option>
<option value="runner" {% if project.genre == 'runner' %}selected{% endif %}>Runner</option>
@ -26,44 +33,73 @@
</div>
<div class="mb-3">
<label class="form-label">URL Externa (Para Jogos Online)</label>
<input type="url" name="external_url" class="form-control bg-dark text-white border-secondary" value="{{ project.external_url|default:'' }}" placeholder="https://exemplo.com/jogo">
<small class="text-secondary">Se preenchido, o jogo será carregado via Iframe desta URL.</small>
</div>
<div class="mb-3">
<label class="form-label">Prompt de IA / Descrição (Transforma palavras em jogos reais)</label>
<textarea name="prompt" rows="3" class="form-control bg-dark text-white border-secondary">{{ project.prompt }}</textarea>
<label class="form-label fw-bold">💡 Ideia / História / Prompt de IA</label>
<textarea name="prompt" rows="3" class="form-control bg-dark text-white border-secondary" placeholder="Descreva sua ideia. A IA escreverá a história, criará o código e gerará o banner automaticamente.">{{ project.prompt }}</textarea>
<div class="form-check mt-2">
<input class="form-check-input" type="checkbox" name="use_ai" id="use_ai">
<label class="form-check-label text-info" for="use_ai">
Usar IA para gerar/atualizar o script do jogo (Transformar descrição em Código Script)
<input class="form-check-input" type="checkbox" name="use_ai" id="use_ai" checked>
<label class="form-check-label text-info fw-bold" for="use_ai">
ATIVAR DESENVOLVEDOR AUTÔNOMO (Gera Script + História + Banner automaticamente)
</label>
</div>
</div>
<div class="mb-3">
<label class="form-label">Código Script (HTML/JS/CSS Completo)</label>
<textarea name="script_code" rows="12" class="form-control bg-dark text-white border-secondary font-monospace" style="font-size: 0.85rem;">{{ project.script_code }}</textarea>
<small class="text-secondary">Se usar a opção de IA, este campo será preenchido automaticamente.</small>
<label class="form-label">URL Externa (Opcional - Para Jogos Existentes)</label>
<input type="url" name="external_url" class="form-control bg-dark text-white border-secondary" value="{{ project.external_url|default:'' }}" placeholder="https://exemplo.com/jogo">
</div>
<div class="mb-3" id="scriptContainer" style="display: none;">
<label class="form-label">Código Script Manual (HTML/JS/CSS)</label>
<textarea name="script_code" rows="8" class="form-control bg-dark text-white border-secondary font-monospace" style="font-size: 0.85rem;">{{ project.script_code }}</textarea>
</div>
<div class="text-center my-3">
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="toggleScript()">Ver/Editar Código Manualmente</button>
</div>
<div class="mb-3">
<label class="form-label">Imagem de Referência (Capa do Jogo)</label>
<label class="form-label fw-bold">Imagem de Capa (Opcional)</label>
<p class="small text-secondary">Se deixar em branco, a IA gerará um banner profissional baseado no título.</p>
{% if project.image_reference %}
<div class="mb-2">
<img src="{{ project.image_reference.url }}" alt="Ref" style="height: 100px; border-radius: 8px;">
<img src="{{ project.image_reference.url }}" alt="Ref" style="height: 120px; border-radius: 8px; border: 1px solid #333;">
</div>
{% endif %}
<input type="file" name="image" class="form-control bg-dark text-white border-secondary">
</div>
<div class="mt-4 d-flex gap-3">
<button type="submit" class="btn btn-primary px-5 rounded-pill">SALVAR JOGO</button>
<a href="{% url 'admin_dashboard' %}" class="btn btn-outline-light px-5 rounded-pill">VOLTAR</a>
<button type="submit" class="btn btn-primary px-5 rounded-pill btn-lg" id="submitBtn">
{% if project %}ATUALIZAR JOGO{% else %}GERAR JOGO COMPLETO{% endif %}
</button>
<a href="{% url 'admin_dashboard' %}" class="btn btn-outline-light px-5 rounded-pill btn-lg">CANCELAR</a>
</div>
</form>
<div id="loadingOverlay" style="display:none; position: fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.8); z-index:9999; flex-direction:column; align-items:center; justify-content:center;">
<div class="spinner-border text-info mb-3" style="width: 3rem; height: 3rem;" role="status"></div>
<h3 class="text-white">IA TRABALHANDO...</h3>
<p class="text-info">O Desenvolvedor Autônomo está escrevendo a história e o código do seu jogo.</p>
</div>
</div>
</div>
</div>
{% endblock %}
<script>
function toggleScript() {
var x = document.getElementById("scriptContainer");
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}
document.getElementById('gameForm').onsubmit = function() {
if (document.getElementById('use_ai').checked) {
document.getElementById('loadingOverlay').style.display = 'flex';
document.getElementById('submitBtn').disabled = true;
}
};
</script>
{% endblock %}

View File

@ -14,6 +14,7 @@ urlpatterns = [
path('admin/edit-game/<int:pk>/', views.admin_edit_game, name='admin_edit_game'),
path('admin/delete-game/<int:pk>/', views.admin_delete_game, name='admin_delete_game'),
path('admin/edit-rental/<int:pk>/', views.admin_edit_rental, name='admin_edit_rental'),
path('admin/batch-update-ai/', views.admin_batch_update_ai, name='admin_batch_update_ai'),
# User
path('catalog/', views.catalog, name='catalog'),
@ -22,4 +23,4 @@ urlpatterns = [
path('simulate-payment/<int:purchase_id>/', views.simulate_payment, name='simulate_payment'),
path('verify-payment-status/<int:purchase_id>/', views.verify_payment_status, name='verify_payment_status'),
path('play/<int:pk>/', views.play_game, name='play_game'),
]
]

View File

@ -9,6 +9,7 @@ from django.utils import timezone
from datetime import timedelta
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.core.management import call_command
from .models import GameProject, UserSession, AdminConfig, RentalOption, UserPurchase
from ai.local_ai_api import LocalAIApi
from .pexels import fetch_first
@ -73,18 +74,58 @@ def logout(request):
def generate_game_script(title, prompt="", genre="arcade"):
system_prompt = (
"You are the Ultimate Autonomous AI Game Developer and Storyteller. Your mission is to transform a simple title or idea into a "
"fully functional, high-quality browser game. You are responsible for the entire development lifecycle: "
"1. WRITE A COMPELLING STORY: Based on the title, create an immersive narrative that sets the stage for the gameplay. "
"2. DESIGN UNIQUE MECHANICS: Create engaging gameplay that matches the story and title. "
"3. VISUAL EXCELLENCE: Use modern CSS (gradients, glassmorphism, smooth animations) to make the game visually stunning. "
"4. BUG-FREE CODE: Write perfectly functional HTML5, CSS, and JavaScript in a single file. "
"5. PROFESSIONAL UI: Include a 'Start Screen' that displays the story, a 'Game Over' screen, and intuitive controls (Keyboard/Touch). "
"6. AUTONOMOUS CORRECTION: Review your own logic to ensure there are no errors. "
"fully functional, high-quality browser game. You are responsible for the entire development lifecycle:\n"
"1. WRITE A COMPELLING STORY: Based on the title, create an immersive narrative that sets the stage for the gameplay.\n"
"2. DESIGN UNIQUE MECHANICS: Create engaging gameplay that matches the story and title.\n"
"3. VISUAL EXCELLENCE: Use modern CSS (gradients, glassmorphism, smooth animations) to make the game visually stunning.\n"
"4. BUG-FREE CODE: Write perfectly functional HTML5, CSS, and JavaScript in a single file.\n"
"5. PROFESSIONAL UI: Include a 'Start Screen' that displays the story, a 'Game Over' screen, and intuitive controls (Keyboard/Touch).\n"
"6. AUTONOMOUS CORRECTION: You MUST review your own logic and fix any potential bugs or syntax errors before providing the final code.\n"
"Return ONLY the complete HTML5 code starting with <!DOCTYPE html>."
)
full_query = f"Game Title: {title}. Description/Idea: {prompt}. Genre: {genre}."
user_prompt = f"Act as an autonomous developer. Develop a complete browser game (Story + Code) for: {full_query}. Ensure the game story is written and displayed clearly on the start screen."
user_prompt = f"Act as an autonomous developer. Develop a complete browser game (Story + Code) for: {full_query}. Ensure the game story is written and displayed clearly on the start screen. Use Portuguese (Brazil) for all in-game text, story, and instructions."
# Step 1: Initial Generation
response = LocalAIApi.create_response({
"input": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
],
})
if not response.get("success"):
return None
code = LocalAIApi.extract_text(response)
# Step 2: Autonomous Bug Correction
correction_prompt = (
"Review the HTML/JS code below. Ensure it is fully functional, has no syntax errors, and the game loop works correctly. "
"Fix any issues and return the final, polished HTML5 code. ONLY RETURN THE CODE.\n\n"
f"CODE TO REVIEW:\n{code}"
)
corrected_response = LocalAIApi.create_response({
"input": [
{"role": "system", "content": "You are a senior debugger and optimizer. Your goal is to ensure the code is 100% bug-free and optimized."},
{"role": "user", "content": correction_prompt},
],
})
if corrected_response.get("success"):
final_code = LocalAIApi.extract_text(corrected_response)
if "<!DOCTYPE" in final_code:
return final_code
return code
return code
def generate_game_story(title, genre="arcade"):
"""Generates only the story/description for a game."""
system_prompt = "You are a creative writer for video games. Write a short, immersive story/description for a game."
user_prompt = f"Write a compelling 2-3 paragraph story in Portuguese (Brazil) for a game titled '{title}' in the {genre} genre."
response = LocalAIApi.create_response({
"input": [
@ -95,7 +136,7 @@ def generate_game_script(title, prompt="", genre="arcade"):
if response.get("success"):
return LocalAIApi.extract_text(response)
return None
return ""
# ADMIN VIEWS
def admin_dashboard(request):
@ -123,12 +164,16 @@ def admin_create_game(request):
genre = request.POST.get('genre', 'arcade')
external_url = request.POST.get('external_url', '')
image = request.FILES.get('image')
use_ai = request.POST.get('use_ai') == 'on'
use_ai = request.POST.get('use_ai') == 'on' or True
manual_script = request.POST.get('script_code', '')
description = prompt
if not description:
description = generate_game_story(title, genre)
script = manual_script
if use_ai:
ai_script = generate_game_script(title, prompt, genre)
if use_ai and not manual_script:
ai_script = generate_game_script(title, description, genre)
if ai_script:
script = ai_script
else:
@ -136,6 +181,7 @@ def admin_create_game(request):
game = GameProject.objects.create(
title=title,
description=description,
prompt=prompt,
genre=genre,
image_reference=image,
@ -145,9 +191,8 @@ def admin_create_game(request):
config_json={"player": {"speed": 200}, "entities": []}
)
# Auto-generate banner if no image uploaded
if not image:
pexels_data = fetch_first(f"{title} game {genre}")
pexels_data = fetch_first(f"{title} game background")
if pexels_data:
game.image_reference = pexels_data['local_path'].replace('media/', '')
game.save()
@ -177,16 +222,18 @@ def admin_edit_game(request, pk):
use_ai = request.POST.get('use_ai') == 'on'
manual_script = request.POST.get('script_code', '')
if not project.description:
project.description = generate_game_story(project.title, project.genre)
if use_ai:
ai_script = generate_game_script(project.title, project.prompt, project.genre)
ai_script = generate_game_script(project.title, project.description, project.genre)
if ai_script:
project.script_code = ai_script
else:
project.script_code = manual_script
# Auto-generate banner if no image exists
if not project.image_reference:
pexels_data = fetch_first(f"{project.title} game {project.genre}")
pexels_data = fetch_first(f"{project.title} game background")
if pexels_data:
project.image_reference = pexels_data['local_path'].replace('media/', '')
@ -196,6 +243,20 @@ def admin_edit_game(request, pk):
return render(request, 'core/admin_game_form.html', {'project': project, 'title': 'Editar Jogo'})
def admin_batch_update_ai(request):
"""Triggers the management command to update all games with AI."""
is_admin, _ = get_auth_status(request)
if not is_admin:
return redirect('admin_login')
try:
call_command('update_all_games_ai')
messages.success(request, 'Todos os jogos foram atualizados com IA!')
except Exception as e:
messages.error(request, f'Erro ao atualizar jogos: {str(e)}')
return redirect('admin_dashboard')
def admin_delete_game(request, pk):
is_admin, _ = get_auth_status(request)
if not is_admin:
@ -317,15 +378,9 @@ def verify_payment_status(request, purchase_id):
'confirmation_code': purchase.confirmation_code
})
else:
invalid_code = ''.join(random.choices(string.digits, k=6))
purchase.confirmation_code = "INVALID"
purchase.is_paid = False
purchase.save()
return JsonResponse({
'success': True,
'paid': False,
'invalid_code': invalid_code
'paid': False
})
def play_game(request, pk):

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB