This commit is contained in:
2026-05-22 06:08:51 +00:00
parent c078a257e9
commit bafec754d1
131 changed files with 2346 additions and 893 deletions

2
.gitignore vendored
View File

@@ -19,7 +19,7 @@ dist/
downloads/ downloads/
eggs/ eggs/
.eggs/ .eggs/
lib/ #lib/
lib64/ lib64/
parts/ parts/
sdist/ sdist/

View File

@@ -6,7 +6,7 @@ from fleet.models import Stroj
from kupci.models import Kupac from kupci.models import Kupac
class Command(BaseCommand): class Command(BaseCommand):
help = 'Popunjava bazu podataka isključivo Liebherr strojevima koristeći Faker' help = 'Popunjava bazu podataka isključivo Liebherr strojevima sinkronizirano s logistikom flote'
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument( parser.add_argument(
@@ -18,69 +18,86 @@ class Command(BaseCommand):
def handle(self, *args, **kwargs): def handle(self, *args, **kwargs):
total = kwargs['total'] total = kwargs['total']
fake = Faker(['hr_HR']) # Koristimo hrvatski lokalitet fake = Faker(['hr_HR'])
kupci = list(Kupac.objects.all()) kupci = list(Kupac.objects.all())
if not kupci: if not kupci:
self.stdout.write(self.style.ERROR("Greška: Nema kupaca u bazi. Prvo pokreni populate_kupci!")) self.stdout.write(self.style.ERROR("Greška: Nema kupaca u bazi. Prvo pokreni populate_kupci!"))
return return
# Katalog usklađen s tvojim TIP_STROJA choices # Bogatiji katalog usklađen s tvorničkim Liebherr oznakama i tvojim TIP_STROJA choices
liebherr_katalog = { liebherr_katalog = {
'dizalica_toranj': [ 'dizalica_toranj': [
'132 EC-H 8 Litronic', '132 EC-H 8 Litronic',
'280 EC-H 12', '280 EC-H 12',
'81 K.1', '81 K.1',
'172 EC-B 8' '172 EC-B 8',
'125 K'
], ],
'dizalica_auto': [ 'dizalica_auto': [
'LTM 1030-2.1', 'LTM 1030-2.1',
'LTM 1050-3.1', 'LTM 1050-3.1',
'LTM 1060-3.1', 'LTM 1060-3.1',
'LTM 1120-4.1', 'LTM 1120-4.1',
'LTM 1350-6.1', # Dodan LTM 1350 (sukladno planiranim modifikacijama ventila)
'LTC 1050-3.1' 'LTC 1050-3.1'
] ]
} }
self.stdout.write(self.style.MIGRATE_HEADING(f'🚀 Generiram {total} Liebherr strojeva...')) self.stdout.write(self.style.MIGRATE_HEADING(f'🚀 Generiram {total} Liebherr strojeva u bazu...'))
created_count = 0 created_count = 0
for _ in range(total): for _ in range(total):
# Odabir tipa (usklađeno s tvojim modelom)
tip = random.choice(['dizalica_toranj', 'dizalica_auto']) tip = random.choice(['dizalica_toranj', 'dizalica_auto'])
model_naziv = random.choice(liebherr_katalog[tip]) model_naziv = random.choice(liebherr_katalog[tip])
# Faker za generiranje serijskog broja i registracije # Odabiremo nasumičnog vlasnika za ovaj stroj
serijski = f"LE-{fake.bothify(text='######')}" # npr. LE-482931 vlasnik_stroja = random.choice(kupci)
# Registracija samo za autodizalice (Faker format) # Realistični Liebherr tvornički serijski brojevi (npr. LE-054321)
serijski = f"LE-{fake.numerify(text='0######')}"
# USKLAĐENO: Registracija za autodizalice sada ima ispravne razmake i crticu
# Koristimo reg. oznaku koja odgovara sjedištu vlasnika ili nasumični HR grad
reg = None reg = None
if tip == 'dizalica_auto': if tip == 'dizalica_auto':
# Generira format sličan ZG-1234-LH gradovi = ['ZG', 'KA', 'RI', 'ST', 'OS', 'KR']
reg = f"ZG-{fake.numerify('####')}-LH" grad = random.choice(gradovi)
reg_broj = fake.numerify(text='####')
reg_slova = fake.bothify(text='??', letters='ABCDEFGHIJKLMNOPQRSTUVWXYZ')
reg = f"{grad} {reg_broj}-{reg_slova}"
# Radni sati # Radni sati dizalice
sati = random.uniform(500.0, 12000.0) if tip == 'dizalica_toranj' else random.uniform(100.0, 5000.0) sati = random.uniform(800.0, 15000.0) if tip == 'dizalica_toranj' else random.uniform(200.0, 6000.0)
# Faker za datume (unutar zadnjih godinu dana) # Atesti unutar zadnjih godinu dana
datum_atesta = fake.date_between(start_date='-1y', end_date='today') datum_atesta = fake.date_between(start_date='-1y', end_date='today')
# USKLAĐENO: Generiramo lokaciju. Ako klijent/vlasnik ima definiran grad,
# stroj se primarno nalazi na gradilištu u tom gradu (ili okolici), inače koristimo fake.city()
lokacija_stroja = vlasnik_stroja.grad if (vlasnik_stroja and hasattr(vlasnik_stroja, 'grad')) else fake.city()
# Nasumična simulacija aktivnih gradilišta u regiji
if random.random() > 0.6:
lokacija_stroja = f"Gradilište {lokacija_stroja}"
try: try:
Stroj.objects.create( Stroj.objects.create(
vlasnik=random.choice(kupci), vlasnik=vlasnik_stroja,
naziv=f"Liebherr {model_naziv}", naziv=f"Liebherr {model_naziv}",
serijski_broj=serijski, serijski_broj=serijski,
marka='Liebherr', marka='Liebherr',
model_stroja=model_naziv, model_stroja=model_naziv,
godina_proizvodnje=random.randint(2015, 2024), godina_proizvodnje=random.randint(2012, 2025),
tip=tip, tip=tip,
radni_sati=round(sati, 2), radni_sati=round(sati, 1), # Zaokružujemo na 1 decimalu sukladno formama
registracija=reg, registracija=reg,
datum_zadnjeg_atesta=datum_atesta datum_zadnjeg_atesta=datum_atesta
) )
created_count += 1 created_count += 1
self.stdout.write(f" ✅ Kreiran: Liebherr {model_naziv} (Vlasnik: {vlasnik_stroja.naziv})")
except Exception as e: except Exception as e:
self.stderr.write(f"Greška kod S/N {serijski}: {e}") self.stderr.write(f"Greška kod S/N {serijski}: {e}")
continue continue
self.stdout.write(self.style.SUCCESS(f' Uspješno dodano {created_count} Liebherr strojeva!')) self.stdout.write(self.style.SUCCESS(f'\nGotovo! Uspješno dodano {created_count} Liebherr strojeva u bazu.'))

View File

@@ -1,11 +1,12 @@
import random import random
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import IntegrityError
from faker import Faker from faker import Faker
from fleet.models import Vozilo from fleet.models import Vozilo
class Command(BaseCommand): class Command(BaseCommand):
help = 'Popunjava bazu podataka s gospodarskim vozilima koristeći Faker' help = 'Popunjava bazu podataka s gospodarskim vozilima sinkronizirano s Astro logistikom'
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument( parser.add_argument(
@@ -19,7 +20,7 @@ class Command(BaseCommand):
total = kwargs['total'] total = kwargs['total']
fake = Faker(['hr_HR']) fake = Faker(['hr_HR'])
# Modeli koji se pojavljuju u tvom radnom nalogu (CSV) # Modeli koji odgovaraju tvom voznom parku za mobilne servisne timove
modeli_podaci = [ modeli_podaci = [
'VW Transporter T6', 'VW Transporter T6',
'Mercedes-Benz Vito', 'Mercedes-Benz Vito',
@@ -30,42 +31,56 @@ class Command(BaseCommand):
'Opel Vivaro', 'Opel Vivaro',
] ]
self.stdout.write(self.style.MIGRATE_HEADING(f'🚀 Kreiram {total} vozila u flotu...')) self.stdout.write(self.style.MIGRATE_HEADING(f'🚀 Kreiram {total} servisnih vozila u flotu...'))
brojac = 0 brojac = 0
while brojac < total: maksimalni_pokusaji = total * 5
pokusaji = 0
while brojac < total and pokusaji < maksimalni_pokusaji:
pokusaji += 1
model_naziv = random.choice(modeli_podaci) model_naziv = random.choice(modeli_podaci)
# Generiranje registracije koristeći Faker numerify/bothify # Generiranje realistične registracije u formatu: ZG 1234-AB
# Format: ZG 1234 AB gradovi = ['ZG', 'KR', 'KA', 'ST', 'RI', 'OS', 'VZ', 'PU']
gradovi = ['ZG', 'ST', 'RI', 'OS', 'VZ', 'PU', 'KA', 'KC']
grad = random.choice(gradovi) grad = random.choice(gradovi)
reg_oznaka = fake.numerify(text='####') # npr. 6732
reg_slova = fake.bothify(text='??', letters='ABCDEFGHIJKLMNOPQRSTUVWXYZ') # npr. II
registracija = f"{grad}{reg_oznaka}{reg_slova}"
# Kilometri: Koristimo tvoju logiku da trenutni budu veći od početnih reg_broj = fake.numerify(text=random.choice(['###', '####']))
pocetni = random.randint(0, 150000) reg_slova = fake.bothify(text=random.choice(['?', '??']), letters='ABCDEFGHIJKLMNOPQRSTUVWXYZ')
dodatni = random.randint(500, 20000) registracija = f"{grad} {reg_broj}-{reg_slova}"
# Kilometraža: Trenutni kilometri moraju pratiti povijest korištenja vozila
pocetni = random.randint(10000, 220000)
dodatni = random.randint(1500, 45000)
trenutni = pocetni + dodatni trenutni = pocetni + dodatni
# POPRAVLJENO: Koristimo mala slova sukladno tvojim Choice ograničenjima u modelu
status_izbor = random.choice(['aktivan', 'aktivan', 'servis', 'neaktivan'])
try: try:
# Koristimo registraciju u nazivu radi lakšeg prepoznavanja u Astro frontendu # Provjeravamo postoji li već ova registracija u bazi unaprijed
if Vozilo.objects.filter(registracija=registracija).exists():
continue
vozilo = Vozilo.objects.create( vozilo = Vozilo.objects.create(
naziv=f"{model_naziv} ({grad})", naziv=model_naziv,
registracija=registracija, registracija=registracija,
pocetni_kilometri=pocetni, pocetni_kilometri=pocetni,
trenutni_kilometri=trenutni, trenutni_kilometri=trenutni,
status=random.choice(['aktivan', 'aktivan', 'servis', 'neaktivan']) status=status_izbor
) )
brojac += 1 brojac += 1
self.stdout.write(f" ✅ Kreirano: {vozilo.naziv} [{vozilo.registracija}]") self.stdout.write(f" ✅ Kreirano: {vozilo.naziv} [{vozilo.registracija}] | Status: {status_izbor} ({brojac}/{total})")
except ValidationError: except IntegrityError:
# Ako Faker pogodi postojeću registraciju, samo nastavi dalje # Ako baza ipak prijavi duplikat registracije unutar transakcije, samo idemo dalje
continue
except ValidationError as ve:
# Ako se pojavi neka druga validacijska greška, ispiši je da znamo o čemu se radi
self.stderr.write(f" ⚠️ Validacijska greška za {model_naziv}: {ve}")
continue continue
except Exception as e: except Exception as e:
self.stderr.write(f"Greška: {e}") self.stderr.write(f"Kritična greška pri upisu vozila: {e}")
break break
self.stdout.write(self.style.SUCCESS(f'\nGotovo! Uspješno dodano {brojac} vozila u flotu.')) self.stdout.write(self.style.SUCCESS(f'\nGotovo! Uspješno dodano {brojac} servisnih vozila u bazu flote.'))

View File

@@ -1,4 +1,4 @@
# Generated by Django 6.0.5 on 2026-05-20 20:03 # Generated by Django 6.0.5 on 2026-05-22 03:53
import django.db.models.deletion import django.db.models.deletion
from django.db import migrations, models from django.db import migrations, models

View File

@@ -1,4 +1,4 @@
# Generated by Django 6.0.5 on 2026-05-20 20:04 # Generated by Django 6.0.5 on 2026-05-22 03:53
import django.db.models.deletion import django.db.models.deletion
from django.conf import settings from django.conf import settings

View File

@@ -1,9 +1,9 @@
from rest_framework import serializers from rest_framework import serializers
from .models import Dogadaj from .models import Dogadaj
from operations.serializers import RadniNalogListaSerializer import re
class DogadajSerializer(serializers.ModelSerializer): class DogadajSerializer(serializers.ModelSerializer):
# 1. Mapiranje za standardne kalendarske knjižnice (FullCalendar traži title, start, end) # 1. Mapiranje za standardne kalendarske knjižnice
title = serializers.CharField(source='naslov') title = serializers.CharField(source='naslov')
start = serializers.DateTimeField(source='pocetak') start = serializers.DateTimeField(source='pocetak')
end = serializers.DateTimeField(source='kraj') end = serializers.DateTimeField(source='kraj')
@@ -16,23 +16,27 @@ class DogadajSerializer(serializers.ModelSerializer):
boja = serializers.SerializerMethodField() boja = serializers.SerializerMethodField()
je_radni_nalog = serializers.SerializerMethodField() je_radni_nalog = serializers.SerializerMethodField()
# 4. NOVA RAZDVOJENA POLJA ZA VOCILO I ČISTI OPIS KWARTA
vozilo_naziv = serializers.SerializerMethodField()
opis_cisti = serializers.SerializerMethodField()
class Meta: class Meta:
model = Dogadaj model = Dogadaj
fields = [ fields = [
'id', 'title', 'start', 'end', 'tip', 'tip_display', 'id', 'title', 'start', 'end', 'tip', 'tip_display',
'opis', 'izvrsitelj_ime', 'boja', 'je_radni_nalog', 'opis', 'opis_cisti', 'vozilo_naziv', 'izvrsitelj_ime',
'klijent', 'vozilo', 'radni_nalog' 'boja', 'je_radni_nalog', 'klijent', 'vozilo', 'radni_nalog'
] ]
def get_izvrsitelj_ime(self, obj): def get_izvrsitelj_ime(self, obj):
"""Dohvaća ime preko tvog @property izvrsitelj u modelu""" """Dohvaća ime preko tvog @property izvrsitelj u modelu"""
korisnik = obj.izvrsitelj # Poziva @property iz models.py korisnik = obj.izvrsitelj
if korisnik: if korisnik:
return korisnik.get_full_name() or korisnik.username return korisnik.get_full_name() or korisnik.username
return "Nije dodijeljeno" return "Nije dodijeljeno"
def get_boja(self, obj): def get_boja(self, obj):
"""Dodjeljuje boju ovisno o tipu događaja za vizualni kalendar""" """Dodjeljuje boju ovisno o tipu događaja"""
boje = { boje = {
'servis': '#3498db', # Plava 'servis': '#3498db', # Plava
'isporuka': '#2ecc71', # Zelena 'isporuka': '#2ecc71', # Zelena
@@ -44,3 +48,30 @@ class DogadajSerializer(serializers.ModelSerializer):
def get_je_radni_nalog(self, obj): def get_je_radni_nalog(self, obj):
"""Pomaže frontendu da zna treba li prikazati link na radni nalog""" """Pomaže frontendu da zna treba li prikazati link na radni nalog"""
return obj.radni_nalog is not None return obj.radni_nalog is not None
def _parsiraj_spojeni_opis(self, obj):
"""Pomoćna metoda koja analizira tekst i vraća (vozilo, opis)"""
sirovi_tekst = obj.opis or ""
# Ako tekst sadrži ključne riječi, razdvajamo ga pomoću Regexa na backendu
if "Vozilo:" in sirovi_tekst or "Opis kvara:" in sirovi_tekst:
vozilo_match = re.search(r"Vozilo:\s*(.*?)(?=\s*Opis kvara:|$)", sirovi_tekst, re.IGNORECASE)
opis_match = re.search(r"Opis kvara:\s*(.*)", sirovi_tekst, re.IGNORECASE)
vozilo = vozilo_match.group(1).strip() if vozilo_match else None
opis = opis_match.group(1).strip() if opis_match else sirovi_tekst
return vozilo, opis
# Ako je polje vozilo na modelu već popunjeno kao relacija/tekst, iskoristi ga
model_vozilo = str(obj.vozilo) if obj.vozilo else None
return model_vozilo, sirovi_tekst
def get_vozilo_naziv(self, obj):
"""Vraća samo čisti naziv vozila"""
vozilo, _ = self._parsiraj_spojeni_opis(obj)
return vozilo
def get_opis_cisti(self, obj):
"""Vraća samo čisti tekst opisa kvara"""
_, opis = self._parsiraj_spojeni_opis(obj)
return opis if opis else "Nema dodatnog opisa."

View File

@@ -4,7 +4,7 @@ from faker import Faker
from kupci.models import Kupac from kupci.models import Kupac
class Command(BaseCommand): class Command(BaseCommand):
help = 'Popunjava bazu podataka s testnim kupcima' help = 'Popunjava bazu podataka s testnim kupcima spremnim za logistički modul'
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument( parser.add_argument(
@@ -18,7 +18,21 @@ class Command(BaseCommand):
total = kwargs['total'] total = kwargs['total']
fake = Faker(['hr_HR']) fake = Faker(['hr_HR'])
self.stdout.write(self.style.MIGRATE_HEADING(f'🚀 Kreiram {total} kupaca...')) self.stdout.write(self.style.MIGRATE_HEADING(f'🚀 Kreiram {total} testnih kupaca...'))
# Kontrolirani skup gradova u nominativu za savršen ispis relacija i odredišta u logistici
hr_gradovi = [
{'grad': 'Zagreb', 'pbr': '10000'},
{'grad': 'Karlovac', 'pbr': '47000'},
{'grad': 'Ozalj', 'pbr': '47280'},
{'grad': 'Split', 'pbr': '21000'},
{'grad': 'Rijeka', 'pbr': '51000'},
{'grad': 'Osijek', 'pbr': '31000'},
{'grad': 'Varaždin', 'pbr': '42000'},
{'grad': 'Zadar', 'pbr': '23000'},
{'grad': 'Velika Gorica', 'pbr': '10410'},
{'grad': 'Sisak', 'pbr': '44000'}
]
created_count = 0 created_count = 0
for _ in range(total): for _ in range(total):
@@ -29,27 +43,33 @@ class Command(BaseCommand):
else: else:
naziv = fake.name() naziv = fake.name()
# Generiramo OIB (nasumičnih 11 znamenki) # Generiramo OIB (točno 11 znamenki u string formatu)
oib = "".join([str(random.randint(0, 9)) for _ in range(11)]) oib = "".join([str(random.randint(0, 9)) for _ in range(11)])
# Odabiremo grad i poštanski broj u paru kako bi podaci imali smisla
lokacija = random.choice(hr_gradovi)
# Generiramo telefonski broj koji je čist i siguran za tel: linkove u Astru
pozivni = random.randint(1, 9)
telefon = f"+385 {pozivni} {random.randint(100, 999)}-{random.randint(1000, 9999)}"
try: try:
# Koristimo get_or_create ili create da izbjegnemo duplikate OIB-a # Upotrebljavamo create, a jedinstvenost OIB-a hvatamo u iznimci
# ako je polje unique=True u modelu
Kupac.objects.create( Kupac.objects.create(
naziv=naziv, naziv=naziv,
oib=oib, oib=oib,
email=fake.email(), email=fake.email(),
telefon=fake.phone_number(), telefon=telefon,
adresa=fake.street_address(), adresa=fake.street_address(),
grad=fake.city(), grad=lokacija['grad'], # Usklađeno: čisti nominativ (npr. 'Karlovac')
postanski_broj=fake.postcode(), postanski_broj=lokacija['pbr'], # Usklađeno: odgovarajući poštanski broj
tip=tip, tip=tip,
napomena="Automatski generiran testni kupac.", napomena="Automatski generiran testni kupac usklađen s modulom operativne logistike.",
aktivno=True aktivno=True
) )
created_count += 1 created_count += 1
except Exception as e: except Exception as e:
# Ako OIB slučajno bude isti, samo nastavi dalje # Ako OIB slučajno kolidira (unutar unique=True), preskoči i nastavi generirati sljedećeg
continue continue
self.stdout.write(self.style.SUCCESS(f'✅ Uspješno dodano {created_count} novih kupaca!')) self.stdout.write(self.style.SUCCESS(f'✅ Uspješno dodano {created_count} novih kupaca u bazu!'))

View File

@@ -1,4 +1,4 @@
# Generated by Django 6.0.5 on 2026-05-20 20:03 # Generated by Django 6.0.5 on 2026-05-22 03:52
from django.db import migrations, models from django.db import migrations, models

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

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