Skip to end of metadata
Go to start of metadata

Nazwa wtyczki Data utworzenia Data ostatniej aktualizacji Link do instalki Krótki opis Dział utrzymujący Dokumentacja dla klienta Typ licencji Typ wtyczki Id wtyczki
Barcode Reader 2015-01-14 2024-11-08 Link Program służący do dzielenia plików na części na podstawie rozpoznanych kodów kreskowych. Dev Core Płatna Wtyczka com.suncode.plugin-barcode-reader



Wstęp

Dokumentacja starszego PlusBarcodeReader: [STARSZA WERSJA] PlusBarcodeReader

Podstawowe pojęcia

  • dokument - dokument wejściowy w formacie PDF
  • zbiór stron - zbiór stron dokumentu (zawiera wydzielone strony z dokumentu wejściowego)
  • klasyfikacja dokumentu - proces przydzielania poszczególnych stron dokumentu do pasujących klas dokumentów
  • klasa dokumentów - klasa opisująca zasady przypisywania do niej poszczególnych stron dokumentu
  • zestaw klas dokumentów - zestaw klas dokumentów, określający kontekst (podzbiór dokumentu wraz z indeksami) w jakim strony przydzielane są do klas dokumentów w tym zestawie

Instalacja

Aby dodać Barcode Reader do systemu należy zainstalować wtyczkę, którą można pobrać z lokalizacji BarcodeReader. Od wersji 2.3.0 wtyczka wymaga zainstalowanej bazowej wtyczki Plus Barcode Reader Core.

Jeżeli Barcode Reader był już dodany w systemie za pomocą zależności, wtedy należy usunąć zależność z pom'a. Następnie usunąć barcode-reader.jar z bibliotek systemu i zainstalować wtyczkę.

Zadania zaplanowane utworzone dla wcześniejszej wersji Barcode Readera będą nadal działać.


Instalacja na Windows Server

Przetestowane na Windows Server 2012 R2

1) Zaktualizować system

2) Zainstalować Windows Server Essentials Media Pack  https://www.microsoft.com/en-us/download/details.aspx?id=40837

Żeby zainstalować Media Pack wymagana jest instalacja Windows Server Essentials Experience

3) Restart serwera

Uruchomienie przez zadanie zaplanowane

Głównym sposobem uruchomienia Barcode Readera jest uruchomienie go poprzez zadanie zaplanowane.

KlasaMetodaParametr
com.suncode.barcodereader.integration.BarcodeReaderTaskreadBarcodesconfigPath - ścieżka do pliku konfiguracyjnego

Dokładny opis zadania zaplanowanego dla wtyczki znajduje się tutaj.

Uruchomienie przez zadanie automatyczne

Dokładny opis zadania automatycznego dla wtyczki znajduje się tutaj.

Uruchomienie ręczne

// Plik z konfiguracja Barcode Readera
File configurationFile = new File( "sample/conf.xml" );
// Sparsowany plik konfiguracyjny
Configuration configuration = new ConfigurationParser( configurationFile ).parse();
// Utworzenie instancji Barcode Readera
BarcodeReader barcodeReader = new BarcodeReader( configuration );
// Wystartowanie Barcode Readera
barcodeReader.start();

Zatrzymanie

Zatrzymanie Barcode Readera nie oznacza natychmiastowego zatrzymania. Podejmowana jest próba jego zatrzymania. Wszystkie oczekujące zadania są o anulowane, natomiast zadania wykonywane są przerywane, jeżeli jest to możliwe.

// Zatrzymanie Barcode Readera
barcodeReader.stop();

Rozpoznawanie kodów kreskowych

Rozpoznawanie kodów kreskowych jest podstawową funkcjonalnością BarcodeReader'a. Wspierane są następujące kody kreskowe:

Wspierane kody kreskowe
Kody 1DKody 2D

CODE_39

CODE_93

CODE_128

CODABAR

ITF

RSS_14

RSS_EXPANDED

UPC_A

UPC_E

EAN_8

EAN_13

QR_CODE

DATA_MATRIX

AZTEC

PDF_417

W wersji 2.0.0 kody kreskowe rozpoznawane są przy użyciu biblioteki ZXing (Zebra Crossing) w wersji 2.2.

Zalecany format plików pdf to PDF/A.

 Poprawa rozpoznawania kodów o niskiej jakości (od wersji 2.0.7)

W przypadku, gdy skany z kodami kreskowymi są niskiej jakości i standardowy mechanizm ma problemy z ich rozpoznawaniem można w pliku konfiguracyjnym zdefiniować filtry jakie mają być użyte do poprawy jakości kodów zanim zostaną one rozpoznane. Rozpoznawanie przy pomocy filtrów może być stopniowe, czyli program nakłada pierwszy zestaw filtrów, próbuje rozpoznać kod i jeżeli nie rozpozna to w kolejnym kroku stosuje kolejny zestaw zdefiniowanych filtrów i znowu próbuje odczytać kod.

Dostępne są następujące filtry:

  • MEDIAN - filtr medianowy, przetwarza piksel na podstawie jego sąsiadów. Ma zastosowanie np.: dla kodów, które są "podziurawione", czyli czarne paski posiadają w środku białe piksele. Jest on nakładany tylko na obrazy czarno-białe i w odcieniach szarości. Dla obrazów kolorowych nie zostanie on nałożony, nawet mimo tego, że zostanie zdefiniowany w konfiguracji.
  • AUTOTHRESHOLD - filtr, który automatycznie wyznacza granicę dla danego obrazu, na podstawie której określa jaki odcień danego piksela ma zostać zamieniony na kolor czarny, a jaki na kolor biały. Filtr ten nie jest wykorzystywany dla stron, które już został zeskanowane w czarno-bieli.
    • W filtrze możemy podać przesunięcie w atrybucie value. Przesunięcie to działa na takiej zasadzie, że jest ono dodawane do automatycznej wartości thresholdu, która została określona dla danej strony.
  • THRESHOLD - filtr, który zamienia dany piksel na kolor czarny lub biały w zależności od podanej wartości.
    • W filtrze musimy podać wartość thresholdu w atrybucie value.

Konfiguracja filtrów odbywa się bezpośrednio w węźle configuration i może wyglądać następująco:

<!-- Zostanie wykonana tylko jedna próba odczytania kodów z zastosowaniem filtru threshold o wartości 130. -->
<filters>
	<step>
		<filter type="threshold" value="130" />
	</step>
</filters>
<!-- Zostanie wykonana tylko jedna próba odczytania kodów z zastosowaniem jednocześnie filtru medianowego i autothersholdu. -->
<filters>
	<step>
		<filter type="median" />
		<filter type="autothreshold" />
	</step>
</filters>
<!-- Zostaną wykonane 3 kroki odczytania kodu.
Krok 1: Bez zastosowania żadnych filtrów.
Krok 2: Z zastosowaniem tylko filtra medianowego. Ten krok wykona się tylko w przypadku, gdy w kroku 1 nie zostanie znaleziony żaden kod pasujący do wzorca.
Krok 3: Z zastosowaniem tylko filtra autothreshold. Ten krok wykona się tylko w przypadku, gdy w kroku 1 i kroku 2 nie zostanie znaleziony żaden kod pasujący do wzorca. -->
<filters>
	<step></step>
	<step>
		<filter type="median" />
	</step>
	<step>
		<filter type="autothreshold" />
	</step>
</filters>

 

Użycie filtrów z ustawioną wartością threshold:

    <filters>
        <step>
            <filter type="threshold" value="130" />
        </step>
        <step>
            <filter type="median" />
            <filter type="autothreshold" />
        </step>
    </filters>

 

 

Należy pamiętać, że korzystanie z filtrów wydłuża czas przetwarzania pliku. Szczególnie będzie to widoczne, jeżeli będzie zdefiniowanych kilka kroków, a dokument posiada wiele stron bez żadnych kodów kreskowych. Wtedy dla każdej takiej strony będą musiały być zastosowane wszystkie kroki.

W większości przypadków definiowanie filtrów nie będzie w ogóle konieczne. Szczególnie, gdy dokumenty są skanowane w czarno-bieli i mają dobrą jakość.



Jednostka przetwarzania

Jednostka przetwarzania jest podstawową jednostką pracy Barcode Readera. Definiuje ona wszystkie elementy potrzebne do klasyfikacji wraz z zachowaniem po klasyfikacji.

<unit name="DokumentyKosztowe">
...
</unit>

Atrybuty elementu unit:

NazwaWymaganyOpis
name(tick)Nazwa jednostki przetwarzania

Elementy wchodzące w skład jednostki przetwarzania:


Katalog plików wejściowych

Aby wskazać katalog z plikami wejściowymi do klasyfikacji należy zdefiniować następujący element:

<source>
	<directory path="D:/input" recursive="true" pattern="(^*.[pP][dD][fF]$)" />
</source>

Element source może zawierać wiele elementów directory

Atrybuty elementu directory

NazwaWymaganyWartość domyślnaOpis
path(tick) Ścieżka do katalogu z plikami
pattern  Wzorzec do jakiego pasować mają pliki
recursive trueOkreśla, czy przeszukiwać katalog rekursywnie



Wzorzec kodów kreskowych

Aby w procesie klasyfikacji móc wykorzystać kod kreskowy należy wcześniej zdefiniować odpowiedni wzorzec kodu kreskowego.

<barcodes multiple="true">
	<barcode name="umowy" type="CODE_128" pattern="(^000.+)" skipNextIdentical="false" />
</barcodes>

Atrybuty elementu barcodes

NazwaWymaganyWartość domyślnaOpis
multiple(error)falseOkreśla, czy na jednej stronie dokumentu może wystąpić wiele kodów tego samego typu.

Jeżeli wiadomo, że na pojedynczej stronie dokumentu występuje tylko jeden kod danego typu to zalecana wartością dla atrybutu multiple jest wartość false. Dzięki temu kody zostaną znalezione szybciej.


Atrybuty elementu barcode

NazwaWymaganyWartość domyślnaOpis
name(tick) Nazwa po jakiej będzie rozpoznawana definicja kodu kreskowego
type(tick) Typ kodu kreskowego. Jeżeli wzorzec dotyczy wielu typów należy rozdzielić je przecinkiem.
pattern(error) Wyrażenie regularne jakie musi spełnić wartość
skipNextIdentical(error)falseOkreśla, czy pomijać następny kod kreskowy jeżeli jest identyczny jak poprzedni rozpoznany.

Tak zdefiniowany kod kreskowy może być wykorzystywany w definicji klasy dokumentów.


Klasyfikacja dokumentów

Klasyfikacja dokumentów to proces przydzielania stron przetwarzanego dokumentu do zdefiniowanych klas dokumentów.

Metody klasyfikacji

Definicja klasyfikacji dokumentów zawiera się pomiędzy znacznikami:

<classify method="standard" pageInClass="many">
...
<classify>

Atrybuty elementu classify

NazwaWymaganyWartość domyślnaOpis

method

(od 2.0.9)

(error)STANDARD

Sposób klasyfikacji dokumentów. Dopuszczalne wartości:

  • STANDARD - strony dokumentu mogą zostać zaklasyfikowane do jakieś klasy lub nie
  • ALLPAGES - wszystkie strony dokumentu muszą zostać zaklasyfikowane do przynajmniej jednej klasy

pageInClass

(od 2.0.10)

(error)MANY

Określa do ilu klas może być zaklasyfikowana strona. Dopuszczalne wartości:

  • ONE - strona może być zaklasyfikowana tylko do jednej klasy
  • MANY - strona może być zaklasyfikowana do wielu klas

 

Klasy dokumentów

Klasa dokumentów definiuje zbiór dokumentów spełniający pewne warunki. Każda klasa dokumentów spełnia pewien zakres warunków, które strony musza spełnić,aby zostać zaklasyfikowane do danej klasy dokumentów. Zakres definiowany jest poprzez:

  • warunki początkowe
  • warunki końcowe

Warunki

WarunekWłączenie strony w warunku końcowym*Opis
<barcode>umowy</barcode>(error)Strona, która zawiera kod kreskowy pasujący do definicji o podanej nazwie. (W tym przykładzie umowy)
<classified/>(error)Strona, która została już zaklasyfikowana do jakieś klasy dokumentów
<unclassified/>(error)Strona, która nie została jeszcze zaklasyfikowana do żadnej klasy dokumentów.
<firstpage/>(tick)Pierwsza strona dokumentu
<lastpage/>(tick)Ostatnia strona dokumentu

*Włączenie strony w warunku końcowym oznacza, że jeżeli strona spełnia warunek końcowy to ta strona także zostanie zaklasyfikowana do danej klasy dokumentów.

Przykład definicji warunków początkowych i końcowych w klasie dokumentów Umowy

<class name="Umowy">
	<start>
		<barcode>umowy</barcode>
	</start>
	<end>
		<barcode>umowy</barcode>
		<lastpage/>
	</end>
	...
</class>

W elemencie start definiowane są warunki początkowe. W elemencie end definiowane są warunki końcowe.

Jak widać na przykładzie w sekcjach warunków początkowych i warunków końcowych można definiować więcej niż jeden warunek. Strona spełnia warunek (początkowy lub końcowy), jeżeli spełnia którykolwiek zdefiniowany warunek. Dlatego w powyższym przykładzie strona spełnia warunek końcowy, jeżeli na stronie jest kod kreskowy umowy lub jest to ostatnia strona. 

Modyfikatory

Warunki mogą posiadać modyfikatory. Modyfikator pozwala na "przesunięcie" dopasowanej strony. Np. mając zdefiniowany następujący warunek:

<start>
	<firstpage modifier="+2" />
</start>

stroną, która zostanie zaklasyfikowana do klasy będzie strona numer 3 (1 (pierwsza strona) + 2).

Możliwy jest rownież podanie modyfikatora o wartości ujemnej (np. "-3"), wówczas zaklasyfikowana strona jest odpowiednią stroną poprzednią.

Indeksy

Indeksy przechowują wartości znalezionych kodów kreskowych. Indeksy mogą być później wykorzystane np. w nazwach plików wyjściowych.

<class name="Umowy">
	...
	<indexes>
		<index name="Index1" type="barcode">umowy</index>
	</indexes>
	...
</class>

Atrybuty elementu index

NazwaWymaganyOpis
name(tick)Nazwa indeksu.
type(tick)Typ indeksu.

Mozliwe wartości atrybutu type

WartośćOpis
barcodeWartość odczytanego kodu kreskowego
import

Wykorzystywany tylko, gdy zdefiniowano zestaw klas dokumentów. Pozwala na importowanie

indeksów zdefiniowanych na poziomie zestawu.

Miejsce docelowy

Miejsce docelowy wskazuje miejsce w które mają trafić zaklasyfikowane dokumenty oraz pod jaką nazwą.

<destination split="true">
	<filename>${basename}_${Index1}.${extension}</filename>
	<directory path="D:/output" flat="false" />
</destination>

Atrybuty elementu destination

NazwaWymaganyWartość domyślnaOpis
split(error)false

Określa, czy zaklasyfikowany dokument ma zostać zapisany jako całość (wartość false),

czy każda strona ma zostać zapisana osobno (wartość true)


Element filename określa nazwę pod jaką zapisany ma zostać plik. W określeniu nazwy pliku można użyć predefiniowane wartości jak:

NazwaOpisOd wersji
${basename}Nazwa pliku wejściowego bez rozszerzenia2.0.0
${filename}Nazwa pliku wejściowego z rozszerzeniem2.0.0
${extension}Rozszerzenie pliku wejściowego2.0.0
${pageNumber}

Numer strony.

Uwaga! Może być użyty tylko gdy atrybut split ma wartość true.

2.0.0
${nazwa_indeksu}Wartość przechowywana w indeksie o nazwie nazwa_indeksu2.0.0
${lastModified}Data modyfikacji pliku jako timestamp2.0.5
${lastModifiedFormatted}Data modyfikacji pliku w formacie yyyy-MM-dd (np. 2016-09-01)2.0.5

Jeżeli plik posiada taką samą nawę jak plik znajdujący się już w katalogu to do nazwy pliku zostanie dodany numer sekwencyjny. Np. plik 001.pdf zostanie zapisany jako 001_1.pdf.


Atrybuty elementu filename

NazwaWymaganyOpis
pattern(error)Wyrażenie regularne dopasowywane do wartości indeksu
mask

(error)

(UWAGA! Wymagany, gdy ustawiono atrybut pattern)

Określa maskę w celu przekształcenia wartości indeksu dopasowanego do wyrażenia regularnego pattern.

(możemy też używać referencji do grup wyrażenia regularnego np. $0)

Uwaga! Maska nakładana jest po ewaluacji nazwy pliku czyli po zastąpieniu wszystkich wartości predefiniowanych rzeczywistymi wartościami.

Przykład:Dla elementu filename zdefiniowanego jak poniżej:

<filename pattern="([a-z]+)-([a-z]+)\.(pdf)" mask="$1+$2.$3">${Index1}.pdf</filename>

i wartości indexu Index1 asd-qwe wyjściową nazwą pliku będzie asd+qwe.pdf


Element directory określa katalog pod jakim zapisany ma zostać plik.

Atrybuty elementu directory

NazwaWymaganyWartość domyślnaOpis
path(tick) Ścieżka do katalogu
flat(error)false

Parametr określa, czy zachowana ma zostać struktura katalogów plików wejściowych (wartość false)

czy wszystkie pliki wyjściowe mają zostać zapisane w jednym katalogu (wartość true)

Resize

Element destination może posiadać dodatkowo element resize.Element resize odpowiada za zmianę rozmiaru pliku docelowego

<destination split="true">
	...
	<resize scale="2.0" /> 
	...
</destination>

Atrybuty elementu resize

NazwaWymaganyWartość domyślnaOpis
scale(tick) Parametr określa współczynnik zmiany rozmiaru pliku (jego wysokości i szerokości).
compression(error)0.75

Parametr określa poziom kompresji podczas generowania nowego pliku. Im wyższa wartość, tym lepsza jakość, ale też większy rozmiar pliku. Wartości mogą być z zakresu 0.1 - 1.0.

method(error)balancedParametr określa metodę skalowania obrazu. Metody dające lepsze wyniki są wolniejsze. Możliwe wartości to: auto, speed, balanced, quality, ultra.


Zestaw klas dokumentów

Zestaw klas dokumentów określa kontekst (zakres stron oraz indeksy) jaki w dalszej części ma zostać przetworzony przez zdefiniowane klasy dokumentów. Klasy dokumentów zdefiniowane w zestawie klas dokumentów współdzielą indeksy zdefiniowane na poziomie zestawu klas dokumentów.

<barcodes mutliple="false">
	<barcode name="kod" type="CODE_128" pattern="(^KOD.*)" />
</barcodes>
<classify>
	<class-set name="Zestaw klas">
		<start>
			<firstpage modifier="+1" />
		</start>
		<end>
			<lastpage modifier="-1" />
		</end>
		<indexes>
			<index name="kodIndex" type="barcode">kod</index>
		</indexes>
		<class name="Faktury">
			...
			<indexes>
				<index name="kodIndex" type="import">kodIndex</index>
			</indexes>
			<destination>
				<filename>${basename}_${kodIndex}.pdf</filename>
				<directory path="D:/Faktury" />
			</destination>
			...
		</class>
		<class name="Załączniki">
			...
		</class>
	</class-set>
</classify>

// TODO opis

Na początku zdefiniowano wzorzec kodu kreskowego kod. Zdefiniowany zestaw klas dokumentów (element class-set) odrzuca pierwszą (linia 7) i ostatnią strone (linia 10). Definiuje również wspólny indeks kodIndex dla wszystkich klas dokumentów wchodzących w ten zestaw klas dokumentów.

Powyższy zestaw klas dokumentów zawiera 2 klasy dokumentów: Faktury (linia 15) Załączniki (linia 26). Klasa Faktury importuje indeks kodIndex (linia 18) i wykorzystuje go w nazwie pliku wyjściowego (linia 21).

Zasady klasyfikacji dokumentów

Poniżej przedstawiono kilka przykładów klasyfikacji dokumentów.


Przykład 1

<barcodes>
	<barcode name="umowa" type="CODE_128" pattern="(.+)" />
</barcodes>
<classify>
	<class name="Umowy">
		<start>
			<barcode>umowy</barcode>
		</start>
		<end>
			<barcode>umowy</barcode>
			<lastpage/>
		</end>
		<indexes>
			<index name="Index1" type="barcode">umowy</index>
		</indexes>
		<destination>
			<filename>${Index1}.pdf</filename>
			<directory path="D:/Umowy" />
		</destination>
	</class>
</classify>

Na początku zdefiniowano wzorzec kodu kreskowego umowa (linia 2). Wzorzec dotyczy kodów kreskowych typu CODE 128 o dowolnej wartości.

Aby dokument został zaklasyfikowany do klasy Umowy musi zaczynać się od kodu kreskowego umowa (linia 7) i kończyć się na następnym kodzie umowa (linia 10) lub ostatniej stronie (linia 11).

Zdefiniowano również indeks Index1, który przechowuje wartość odczytanego kodu kreskowego (linia 14).

Miejscem docelowym zaklasyfikowanych plików jest katalog D:/Umowy (linia 18). Nazwa zaklasyfikowanych plików będzie składać się z nazwy rozpoznanego kodu kreskowego i rozszerzenia ".pdf" (linia 17)

Dokument wejściowy:

Numer stronyKod kreskowy
1CODE_128(001)
2-
3-
4CODE_128(002)
5-
6-

Wynik klasyfikacji:

Plik wyjściowyZakres stron
001.pdf1-3
002.pdf4-6

Przykład 2

<barcodes multiple="false">
	<barcode name="faktura" type="CODE_128" pattern="(.+)" />
</barcodes>
<classify>
	<class name="Faktury">
		<start>
			<barcode>Faktury</barcode>
		</start>
		<end>
			<barcode>Faktury</barcode>
			<lastpage/>
		</end>
		<indexes>
			<index name="Index1" type="barcode">Faktury</index>
		</indexes>
		<destination>
			<filename>${Index1}.pdf</filename>
			<directory path="D:/Faktury" />
		</destination>
	</class>
	<class name="Niesklasyfikowane">
		<start>
			<unclassified />	
		</start>
		<end>
			<classified />
			<lastpage/>
		</end>
		<indexes>
		</indexes>
		<destination>
			<filename>BRAK_KODU.pdf</filename>
			<directory path="D:/Niesklasyfikowane" />
		</destination>
	</class>
</classify>

Na początku zdefiniowano wzorzec kodu kreskowego faktura typu CODE 128 o dowolnej wartości.

Następnie zdefiniowano 2 klasy dokumentów:

  • Faktury
  • Niesklasyfikowane

Klasa Faktury jest analogiczna do klasy dokumentów zdefiniowanej w przykładzie 1

Natomiast, aby dokument został zaklasyfikowany do klasy Niesklasyfikowane (linia 21) musi zaczynać się od strony, która nie została jeszcze sklasyfikowana (linia 23) i kończyć się na sklasyfikowanej stronie (linia 26) lub ostatniej stronie dokumentu (linia 27).

Sklasyfikowane pliki zostaną zapisane w katalogu D:/Niesklasyfikowane pod nazwą BRAK_KODU (kolejne pliki otrzymają na końcu numer sekwencyjny. Patrz info).

Dokument wejściowy

Numer stronyKod kreskowy
1-
2CODE_128(001)
3-
4CODE_128(002)
5-
6-

Wynik klasyfikacji

Jeżeli zdefiniowanych jest więcej niż jedna klasa dokumentów to dokument wejściowy jest przetwarzany po kolei przez te klasy dokumentów. W powyższym przypadku najpierw zostanie przetworzony przez klasę Faktury, a następnie przez klasę Niesklasyfikowane.

Faktury

Plik wyjściowyZakres stron
001.pdf2-3
002.pdf4-6

Niesklasyfikowane

Plik wyjściowyZakres stron
BRAK_KODU.pdf1


Akcje klas dokumentów

Akcje klas dokumentów są to akcje jakie wykonują się po klasyfikacji i określają co ma się stać z plikami wejściowymi. Osobno definiowane są akcje dla dokumentów, które zostały przetworzone prawidłowo (success) i osobno dla dokumentów, których przetwarzanie zakończyło się błędem (error).

Dostępne akcje:

NazwaOpis
copyKopiuje plik źródłowy do miejsca docelowego
movePrzenosi plik źródłowy do miejsca docelowego
removeUsuwa plik źródłowy

Aby wskazać miejsce docelowe należy zdefiniować w akcji element destination

Przykład:

<actions>
	<success>
		<move>
	        <destination>
    			<filename>${filename}</filename>
        		<directory path="D:/success"/>
        	</destination>
    	</move>
	</success>
	<error>
    	<copy>
        	<destination>
				<filename>${filename}</filename>
				<directory path="D:/error"/>
			</destination>
		</copy>
	</error>
</actions>

Wymagane minimalne wersje systemu

System 4.1System 4.2
Wersja wtyczkiWersja systemuWersja wtyczkiWersja systemu
4.0.194.1.114.0.194.1.11
Write a comment…