first commit

This commit is contained in:
2026-02-15 09:23:44 +01:00
commit 5a22d3abae
276 changed files with 231906 additions and 0 deletions
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+70
View File
@@ -0,0 +1,70 @@
from django.contrib import admin
from .models import Category, Image, Product, Cart, CartItem, Order, OrderItem, OrderMessage
# Register your models here.
admin.site.register(Category)
admin.site.register(Image)
admin.site.register(Product)
class CartItemInline(admin.TabularInline):
model = CartItem
extra = 0
@admin.register(Cart)
class CartAdmin(admin.ModelAdmin):
list_display = ('id', 'user', 'session_key', 'get_items_count', 'get_total', 'created_at', 'updated_at')
list_filter = ('created_at', 'updated_at')
search_fields = ('user__username', 'user__email', 'session_key')
inlines = [CartItemInline]
def get_items_count(self, obj):
return obj.get_items_count()
get_items_count.short_description = 'Productos'
def get_total(self, obj):
return f"{obj.get_total()}"
get_total.short_description = 'Total'
@admin.register(CartItem)
class CartItemAdmin(admin.ModelAdmin):
list_display = ('id', 'cart', 'product', 'quantity', 'get_subtotal', 'added_at')
list_filter = ('added_at',)
search_fields = ('product__name', 'cart__user__username')
def get_subtotal(self, obj):
return f"{obj.get_subtotal()}"
get_subtotal.short_description = 'Subtotal'
class OrderItemInline(admin.TabularInline):
model = OrderItem
extra = 0
@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
list_display = ('id', 'buyer', 'total', 'status', 'payment_method', 'payment_reference', 'created_at')
list_filter = ('status', 'payment_method', 'created_at')
search_fields = ('buyer__username', 'buyer__email', 'payment_reference')
inlines = [OrderItemInline]
@admin.register(OrderItem)
class OrderItemAdmin(admin.ModelAdmin):
list_display = ('id', 'order', 'product_name', 'seller', 'quantity', 'total_price', 'status', 'created_at')
list_filter = ('status', 'created_at')
search_fields = ('product_name', 'seller__username', 'order__buyer__username')
@admin.register(OrderMessage)
class OrderMessageAdmin(admin.ModelAdmin):
list_display = ('id', 'order_item', 'sender', 'message_preview', 'created_at')
list_filter = ('created_at',)
search_fields = ('sender__username', 'message', 'order_item__product_name')
def message_preview(self, obj):
return obj.message[:50] + "..." if len(obj.message) > 50 else obj.message
message_preview.short_description = 'Mensaje'
+5
View File
@@ -0,0 +1,5 @@
from django.apps import AppConfig
class TiendaConfig(AppConfig):
name = 'tienda'
+22
View File
@@ -0,0 +1,22 @@
from .models import Cart
def cart_context(request):
"""Context processor para hacer el carrito disponible en todas las plantillas"""
cart_count = 0
if request.user.is_authenticated:
try:
cart = Cart.objects.get(user=request.user)
cart_count = cart.get_items_count()
except Cart.DoesNotExist:
cart_count = 0
elif request.session.session_key:
try:
cart = Cart.objects.get(session_key=request.session.session_key)
cart_count = cart.get_items_count()
except Cart.DoesNotExist:
cart_count = 0
return {
'cart_count': cart_count
}
+26
View File
@@ -0,0 +1,26 @@
# Generated by Django 6.0.1 on 2026-01-23 09:33
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Category',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200)),
('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='subcategories', to='tienda.category')),
],
options={
'verbose_name_plural': 'Categories',
},
),
]
@@ -0,0 +1,21 @@
# Generated by Django 6.0.1 on 2026-01-23 09:38
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('tienda', '0001_initial'),
]
operations = [
migrations.AlterModelOptions(
name='category',
options={},
),
migrations.RemoveField(
model_name='category',
name='parent',
),
]
+21
View File
@@ -0,0 +1,21 @@
# Generated by Django 6.0.1 on 2026-01-23 09:40
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tienda', '0002_alter_category_options_remove_category_parent'),
]
operations = [
migrations.CreateModel(
name='Image',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(default='', max_length=200)),
('image', models.ImageField(upload_to='')),
],
),
]
@@ -0,0 +1,18 @@
# Generated by Django 6.0.1 on 2026-01-23 09:42
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tienda', '0003_image'),
]
operations = [
migrations.AlterField(
model_name='image',
name='image',
field=models.ImageField(upload_to='images/'),
),
]
+25
View File
@@ -0,0 +1,25 @@
# Generated by Django 6.0.1 on 2026-01-23 09:48
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tienda', '0004_alter_image_image'),
]
operations = [
migrations.CreateModel(
name='Product',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(default='', max_length=200)),
('description', models.TextField(default='')),
('price', models.FloatField(default=0)),
('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tienda.category')),
('primary_image', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='tienda.image')),
],
),
]
@@ -0,0 +1,18 @@
# Generated by Django 6.0.1 on 2026-01-23 09:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tienda', '0005_product'),
]
operations = [
migrations.AddField(
model_name='product',
name='secondary_images',
field=models.ManyToManyField(blank=True, related_name='products_secondary', to='tienda.image'),
),
]
@@ -0,0 +1,18 @@
# Generated by Django 6.0.1 on 2026-02-06 07:52
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tienda', '0006_product_secondary_images'),
]
operations = [
migrations.AddField(
model_name='product',
name='briefdesc',
field=models.TextField(default=''),
),
]
+39
View File
@@ -0,0 +1,39 @@
# Generated by Django 6.0.1 on 2026-02-06 10:41
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tienda', '0007_product_briefdesc'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Cart',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('session_key', models.CharField(blank=True, max_length=40, null=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='CartItem',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('quantity', models.PositiveIntegerField(default=1)),
('added_at', models.DateTimeField(auto_now_add=True)),
('cart', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='tienda.cart')),
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tienda.product')),
],
options={
'unique_together': {('cart', 'product')},
},
),
]
+21
View File
@@ -0,0 +1,21 @@
# Generated by Django 6.0.1 on 2026-02-06 10:48
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tienda', '0008_cart_cartitem'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name='product',
name='creator',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='created_products', to=settings.AUTH_USER_MODEL),
),
]
+45
View File
@@ -0,0 +1,45 @@
# Generated by Django 6.0.1 on 2026-02-09 09:06
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tienda', '0009_product_creator'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Order',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('session_key', models.CharField(blank=True, max_length=40, null=True)),
('total', models.FloatField(default=0)),
('status', models.CharField(choices=[('paid', 'Pagado'), ('cancelled', 'Cancelado')], default='paid', max_length=20)),
('payment_method', models.CharField(choices=[('stripe', 'Stripe'), ('paypal', 'PayPal'), ('manual', 'Manual')], default='manual', max_length=20)),
('payment_reference', models.CharField(blank=True, default='', max_length=200)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('buyer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='orders', to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='OrderItem',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('product_name', models.CharField(default='', max_length=200)),
('quantity', models.PositiveIntegerField(default=1)),
('unit_price', models.FloatField(default=0)),
('total_price', models.FloatField(default=0)),
('status', models.CharField(choices=[('pending', 'Pendiente'), ('processing', 'En preparación'), ('shipped', 'Enviado')], default='pending', max_length=20)),
('created_at', models.DateTimeField(auto_now_add=True)),
('order', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='tienda.order')),
('product', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='tienda.product')),
('seller', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='order_items_to_fulfill', to=settings.AUTH_USER_MODEL)),
],
),
]
+29
View File
@@ -0,0 +1,29 @@
# Generated by Django 6.0.1 on 2026-02-09 09:12
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tienda', '0010_order_orderitem'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='OrderMessage',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('message', models.TextField()),
('created_at', models.DateTimeField(auto_now_add=True)),
('order_item', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='messages', to='tienda.orderitem')),
('sender', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sent_messages', to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['created_at'],
},
),
]
View File
+185
View File
@@ -0,0 +1,185 @@
from django.db import models
from django.contrib.auth.models import User
from .vars import VAT_RATE
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=200)
def __str__(self):
return self.name
class Image(models.Model):
name = models.CharField(max_length=200, default="")
image = models.ImageField(upload_to='images/')
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=200, default="")
description = models.TextField(default = "")
briefdesc = models.TextField(default = "")
price = models.FloatField(default = 0)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
primary_image = models.ForeignKey(Image, on_delete=models.SET_NULL, null=True)
secondary_images = models.ManyToManyField(Image, related_name='products_secondary', blank=True)
creator = models.ForeignKey(User, on_delete=models.CASCADE, related_name='created_products', null=True, blank=True)
def __str__(self):
return self.name + " " + str(self.price)
def get_price_with_vat(self):
"""Retorna el precio con IVA incluido"""
return round(self.price * (1 + VAT_RATE), 2)
def get_vat_amount(self):
"""Retorna la cantidad de IVA"""
return round(self.price * VAT_RATE, 2)
class Cart(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
session_key = models.CharField(max_length=40, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f"Cart {self.id} - {self.user or self.session_key}"
def get_total(self):
return sum(item.get_subtotal() for item in self.items.all())
def get_total_with_vat(self):
"""Retorna el total del carrito con IVA incluido"""
return round(self.get_total() * (1 + VAT_RATE), 2)
def get_vat_amount(self):
"""Retorna la cantidad total de IVA"""
return round(self.get_total() * VAT_RATE, 2)
def get_items_count(self):
return sum(item.quantity for item in self.items.all())
class CartItem(models.Model):
cart = models.ForeignKey(Cart, on_delete=models.CASCADE, related_name='items')
product = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(default=1)
added_at = models.DateTimeField(auto_now_add=True)
class Meta:
unique_together = ('cart', 'product')
def __str__(self):
return f"{self.quantity}x {self.product.name}"
def get_subtotal(self):
return self.product.price * self.quantity
def get_subtotal_with_vat(self):
"""Retorna el subtotal del item con IVA incluido"""
return round(self.get_subtotal() * (1 + VAT_RATE), 2)
def get_vat_amount(self):
"""Retorna la cantidad de IVA de este item"""
return round(self.get_subtotal() * VAT_RATE, 2)
class Order(models.Model):
STATUS_PAID = "paid"
STATUS_CANCELLED = "cancelled"
STATUS_CHOICES = [
(STATUS_PAID, "Pagado"),
(STATUS_CANCELLED, "Cancelado"),
]
PAYMENT_STRIPE = "stripe"
PAYMENT_PAYPAL = "paypal"
PAYMENT_MANUAL = "manual"
PAYMENT_CHOICES = [
(PAYMENT_STRIPE, "Stripe"),
(PAYMENT_PAYPAL, "PayPal"),
(PAYMENT_MANUAL, "Manual"),
]
buyer = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='orders')
session_key = models.CharField(max_length=40, null=True, blank=True)
total = models.FloatField(default=0)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default=STATUS_PAID)
payment_method = models.CharField(max_length=20, choices=PAYMENT_CHOICES, default=PAYMENT_MANUAL)
payment_reference = models.CharField(max_length=200, blank=True, default="")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f"Pedido {self.id} - {self.buyer or self.session_key}"
def get_items_count(self):
return sum(item.quantity for item in self.items.all())
class OrderItem(models.Model):
STATUS_PENDING = "pending"
STATUS_PROCESSING = "processing"
STATUS_SHIPPED = "shipped"
STATUS_CHOICES = [
(STATUS_PENDING, "Pendiente"),
(STATUS_PROCESSING, "En preparación"),
(STATUS_SHIPPED, "Enviado"),
]
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='items')
product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True, blank=True)
product_name = models.CharField(max_length=200, default="")
seller = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='order_items_to_fulfill')
quantity = models.PositiveIntegerField(default=1)
unit_price = models.FloatField(default=0)
total_price = models.FloatField(default=0)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default=STATUS_PENDING)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.quantity}x {self.product_name} (Pedido {self.order_id})"
class OrderMessage(models.Model):
order_item = models.ForeignKey(OrderItem, on_delete=models.CASCADE, related_name='messages')
sender = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='sent_messages')
message = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['created_at']
def __str__(self):
return f"Mensaje de {self.sender} - {self.created_at}"
class ShippingAddress(models.Model):
"""Direcciones de entrega de los usuarios"""
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='shipping_addresses')
full_name = models.CharField(max_length=200, verbose_name="Nombre completo")
address_line_1 = models.CharField(max_length=250, verbose_name="Dirección")
address_line_2 = models.CharField(max_length=250, blank=True, verbose_name="Dirección (línea 2)")
city = models.CharField(max_length=100, verbose_name="Ciudad")
postal_code = models.CharField(max_length=20, verbose_name="Código postal")
country = models.CharField(max_length=100, default="España", verbose_name="País")
phone = models.CharField(max_length=20, verbose_name="Teléfono")
is_default = models.BooleanField(default=False, verbose_name="Dirección predeterminada")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = "Dirección de envío"
verbose_name_plural = "Direcciones de envío"
ordering = ['-is_default', '-created_at']
def __str__(self):
return f"{self.full_name} - {self.city}"
def save(self, *args, **kwargs):
# Si se marca como predeterminada, desmarcar las demás del usuario
if self.is_default:
ShippingAddress.objects.filter(user=self.user, is_default=True).update(is_default=False)
super().save(*args, **kwargs)
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 858 KiB

+92
View File
@@ -0,0 +1,92 @@
const getCookie = (name) => {
let cookieValue = null;
if (document.cookie && document.cookie !== "") {
const cookies = document.cookie.split(";");
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
if (cookie.substring(0, name.length + 1) === (name + "=")) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
};
document.addEventListener("DOMContentLoaded", () => {
const button = document.getElementById("checkout-button");
console.log("Button found:", button);
if (!button) {
console.error("Checkout button not found");
return;
}
const configUrl = button.dataset.configUrl;
const sessionUrl = button.dataset.sessionUrl;
console.log("Config URL:", configUrl);
console.log("Session URL:", sessionUrl);
fetch(configUrl)
.then((result) => {
console.log("Config response status:", result.status);
return result.json();
})
.then((data) => {
console.log("Config data:", data);
if (!data.publicKey) {
console.error("No publicKey in response");
return;
}
const stripe = Stripe(data.publicKey);
console.log("Stripe initialized");
button.addEventListener("click", () => {
console.log("Checkout button clicked");
button.disabled = true;
button.innerHTML = "Procesando...";
fetch(sessionUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": getCookie("csrftoken")
},
body: JSON.stringify({})
})
.then((res) => {
console.log("Session response status:", res.status);
return res.json();
})
.then((data) => {
console.log("Session data:", data);
if (data.sessionId) {
console.log("Redirecting to Stripe Checkout with session:", data.sessionId);
return stripe.redirectToCheckout({ sessionId: data.sessionId });
} else if (data.error) {
alert("Error: " + data.error);
button.disabled = false;
button.innerHTML = "Pagar con Stripe";
} else {
alert("Error desconocido al procesar el pago");
button.disabled = false;
button.innerHTML = "Pagar con Stripe";
}
})
.catch((error) => {
console.error("Fetch error:", error);
alert("Error de conexión: " + error.message);
button.disabled = false;
button.innerHTML = "Pagar con Stripe";
});
});
})
.catch((error) => {
console.error("Config fetch error:", error);
alert("Error al cargar la configuración de pago: " + error.message);
});
});
Binary file not shown.

After

Width:  |  Height:  |  Size: 985 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 985 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 985 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 985 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 535 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 535 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 535 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 KiB

Some files were not shown because too many files have changed in this diff Show More