Dekoduj pozycję katalogu FAT Microsoft MS-DOS 5.0


27

System plików Microsoft FAT ma tabelę katalogów, która reprezentuje „pliki”, w których „folderach” na dysku. Na razie wpisy te wypełniały wiele informacji niewielką ilością bitów. Dla ciekawskich istnieje wiele specyfikacji technicznych na Wiki , ale wyzwanie polega na „prostym” dekodowaniu wpisu.

Każdy wpis składa się z 32-bajtowego słowa binarnego, podzielonego na kilka sekcji. Aby zachować spójność w tym wyzwaniu, będziemy używać wersji MS-DOS 5.0, bajty są uporządkowane jako duże endiany , a bajty nazywamy 0x00skrajnie lewe, a bajty 0x1Fskrajnie prawe.

Poniżej znajduje się krótki schemat odpowiednich sekcji i jaki powinien być wynik dla każdej sekcji ( pogrubioną czcionką ).

  • Pierwsze 11 bajtów to nazwa pliku w formacie ASCII (stąd pochodzi słynna nazwa pliku 8.3 - 8 bajtów dla nazwy pliku, 3 bajty dla rozszerzenia). Są to proste kodowania ASCII i powinny być wyprowadzane jako ASCII z kropką (.) Pomiędzy .
    • Uwaga: zarówno 8, jak i 3 części są wypełnione spacjami, aby umożliwić wejście na całej długości. Dane wyjściowe powinny ignorować spacje (tzn. Nie wypisywać ich).
    • Rozszerzenie pliku może być puste (tzn. Wszystkie spacje), w którym to przypadku wynik nie powinien wypisywać kropki .
    • Ponieważ ASCII używa tylko 7 niższych bitów, wszystkie bajty będą miały wiodące 0.
  • Następny bajt (0x0b) jest maską bitową następujących elementów:
    • 0x01 Tylko do odczytu - wyjście RO
    • 0x02 Ukryty - wyjście H
    • 0x04 System - wyjście S
    • 0x08 Etykieta woluminu - wyjście VL . Rozmiar pliku (poniżej) powinien być wyprowadzany jako 0 , niezależnie od jego rzeczywistego wpisu.
    • 0x10 Podkatalog - wyjście SD . Rozmiar pliku (poniżej) powinien być wyprowadzany jako 0 , niezależnie od jego rzeczywistego wpisu.
    • 0x20 Archiwum - wyjście A
    • 0x40 Urządzenie - zignorowane dla tego wyzwania.
    • 0x80 Zarezerwowane - zignorowane dla tego wyzwania.
    • Ponieważ jest to maska ​​bitowa, możliwych jest wiele flag - wszystkie odpowiednie dane wyjściowe powinny być łączone w dowolnej kolejności. Na przykład 0xffmoże być ROHSVLSDA(lub dowolną inną kombinacją).
  • Następne dwa bajty (0x0c i 0x0d) nie są używane w MS-DOS 5.0.
  • Następne dwa bajty (0x0e i 0x0f) to następujący czas utworzenia:
    • Bity od 15 do 11 to godziny w formacie 24-godzinnym - dane wyjściowe od 00 do 23
    • Bity od 10 do 5 są minutami - wyjście od 00 do 59
    • Bity od 4 do 0 to sekundy / 2 - wyjście od 00 do 58 (zauważ, że sekundy są w rozdzielczości dwóch sekund)
    • Dla wyjaśnienia: hhhhhmmmmmmsssssprzy pisaniu big-endian.
  • Następne dwa bajty (0x10 i 0x11) to data utworzenia w następujący sposób:
    • Bity od 15 do 9 to rok produkcji 1980 dla 0maksymalnie 2107 dla127
    • Bity od 8 do 5 to miesiące - dane wyjściowe od 1 do 12 (z wiodącym zerem lub bez zera)
    • Bity od 4 do 0 to dzień - wyjście od 0 do 31 (z wiodącym zerem lub bez zera)
    • Dla wyjaśnienia: yyyyyyymmmmdddddprzy pisaniu big-endian.
  • Następne dwa bajty (0x12 i 0x13) to data ostatniego dostępu. W wersji MS-DOS 5.0 ignorujemy tę część tego wyzwania.
  • Następne dwa bajty (0x14 i 0x15) nie są używane przez MS-DOS 5.0.
  • Następne dwa bajty (0x16 i 0x17) to czas ostatniej modyfikacji, zgodny z tym samym formatem, co czas utworzenia powyżej.
  • Następne dwa bajty (0x18 i 0x19) to data ostatniej modyfikacji, zgodna z tym samym formatem, co data utworzenia powyżej.
  • Następne dwa bajty (0x1a i 0x1b) to lokalizacja klastra pliku na dysku. W przypadku tego wyzwania ignorujemy tę część.
  • Ostatnie cztery bajty (0x1c, 0x1d, 0x1e i 0x1f) to rozmiar pliku - wyjście jako liczba całkowita bez znaku , chyba że ustawione są flagi VL lub SD (powyżej), w takim przypadku wyjście 0.

Reprezentacja wizualna

0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
\______________________________FILENAME________________________________________________/\_ATTR_/\___NOTUSED____/\_CREATIONTIME_/\_CREATIONDATE_/\__LASTACCESS__/\___NOTUSED____/\_MODIFIEDTIME_/\_MODIFIEDDATE_/\___NOTUSED____/\___________FILESIZE___________/

Wkład

  • Jedno 32-bajtowe słowo (tj. 256 bitów) w dowolnym dogodnym formacie.
    • Może to być ciąg znaków 1i 0, jako kilka znaków bez znaku int, tablica wartości boolowskich itp.
    • Podaj w odpowiedzi, jakiego formatu używasz do wprowadzania danych.
    • Nie można pobierać wielu danych wejściowych (tj. Tablicy wstępnie podzielonej na odpowiednie rozmiary bajtów), chyba że jest to jedyny sposób, w jaki Twój język może wprowadzić dane. Analiza danych wejściowych jest częścią wyzwania.
  • Możesz założyć, że dane wejściowe są prawidłowe (na przykład nie musisz sprawdzać daty, aby sprawdzić, czy data jest poprawna).
  • Nieużywane bajty mogą być wszystkie 0, wszystkie 1itd., O ile są obecne. W poniższych przykładach użyłem wszystkich 0dla nieużywanych bajtów.

Wydajność

Wydrukowano na ekranie lub zwrócono następujące informacje:

  • Nazwa pliku jako ciąg ASCII
  • Atrybuty pliku jako ciąg ASCII
  • Czas utworzenia i data utworzenia, z odpowiednimi separatorami (dwukropki, ukośniki, coś, co odróżnia składniki)
  • Zmodyfikowana godzina i data modyfikacji, ponownie z odpowiednimi separatorami
  • Rozmiar pliku

Dane wyjściowe mogą być pojedynczym ciągiem oddzielonym spacją lub znakiem nowej linii, oddzielnymi elementami w tablicy itp. W odpowiedzi należy określić sposób formatowania danych wyjściowych.

Zasady

  • Standardowe formaty We / Wy są dopuszczalne.
  • Dopuszczalny jest pełny program lub funkcja.
  • Standardowe luki są zabronione.
  • To jest , więc obowiązują wszystkie zwykłe zasady gry w golfa i wygrywa najkrótszy kod.
  • Wbudowane, które wykonują dokładnie tę funkcję, są zabronione.

Przykłady

0111000001110010011011110110011101110010011000010110110101101101011010010110111001100111000001100000000000000000101000100100010001001000110101000000000000000000000000000000000010100010010001000100100011010100000000000000000000000000000000001101000000000000

programm.ing HS 20:18:08 2016/06/20 20:18:08 2016/06/20 53248

0010000000100000001000000010000001110000011100000110001101100111001000000010000000100000000101000000000000000000010111010110110000111101100111110000000000000000000000000000000010100010010001000100100011010100000000000000000011110000000100111111001011100001

ppcg SDS 11:43:24 2010/12/31 20:18:08 2016/06/20 0

Czy jest w porządku, jeśli wokół flag występuje nadmiar białych znaków? Np. Czy SD Sbyłby prawidłowy zestaw flag?
Morgan Thrapp,

@MorganThrapp Pewnie, że powinno być w porządku.
AdmBorkBork

Z ciekawości, czy miałeś dużo doświadczenia w interakcji z MS-DOS 5.0 w ciągu dnia, czy też naprawdę znudziło Ci się kiedyś Wikipedia?
kot

3
@cat Niektóre z obu. Interesowałem się komputerami od kiedy miałem około 5 lat i otrzymałem Commodore VIC-20. Jednym z moich projektów informatycznych na studiach około 10 lat temu było zbudowanie własnego systemu plików, więc dużo tego szukałem. W tym celu ściągnąłem kilka z Wiki i sprowadziłem do czegoś, co może być wyzwaniem.
AdmBorkBork

Odpowiedzi:


6

Verilog, 513 670 617 bajtów

Działa przy użyciu IVerilog. Nie są potrzebne specjalne flagi kompilacji.

Jest to potwór z zagnieżdżonych definicji, skręcania bitów i irytacji z powodu konieczności zmiany kolejności bitów z powodu endianizmu (w przeciwnym razie albo łańcuch nie zostanie wydrukowany, albo kolejność bitów liczbowych będzie niepoprawna). Dane wejściowe są pobierane przez iport, co jest zwykłym sposobem wprowadzania danych do modułu Verilog. $displaysłuży do drukowania w standardowym formacie. Można zapisać 6 bajtów, jeśli początkowe zera nie byłyby wymagane dla znacznika czasu.

`define r(o,b)wire[3:0]o;assign o={i[b],i[b+1],i[b+2],i[b+3]}; 
`define R(t,a,b,c,d,s)`r(a,s)`r(b,s+4)`r(c,s+8)`r(d,s+12)wire[15:0]t;assign t={a,b,c,d};
`define p(m,k)i[90+m]?"k":"",
`define F(a,b)"a a a b\t b%d"
module f(input[0:255]i);`R(d,q,w,e,r,112)`R(D,Q,W,E,R,128)`R(s,z,x,c,v,224)`R(S,Z,X,C,V,240)`R(p,t,y,u,o,176)`R (A,b,n,m,l,192)always@(i)$display(`F(%s%s%s,%02d:%02d:%02d%d/%d/%d),i[0:63],i[64:87]=="   "?" ":".",i[64:87],`p(5,RO)`p(4,H)`p(3,S)`p(2,VL)`p(1,SD)`p(0,A)d[15:11],d[10:5],d[4:0]*2,D[15:9]+1980,D[8:5],D[4:0],p[15:11],p[10:5],p[4:0]*2,A[15:9]+1980,A[8:5],A[4:0],|i[91:92]?0:{s,S});endmodule

Próbny

Testbench (nie oceniono):

`timescale 1ns / 1ps

module ftest;
reg [0:255] i;
f uut (
.i(i)
);
initial begin
    i=256'b0111000001110010011011110110011101110010011000010110110101101101011010010110111001100111000001100000000000000000101000100100010001001000110101000000000000000000000000000000000010100010010001000100100011010100000000000000000000000000000000001101000000000000;
    #100;
i=256'b0010000000100000001000000010000001110000011100000110001101100111001000000010000000100000000101000000000000000000010111010110110000111101100111110000000000000000000000000000000010100010010001000100100011010100000000000000000011110000000100111111001011100001;     
end

endmodule

Przykładowy przebieg:

$ iverilog design.sv testbench.sv  && vvp a.out  
programm.ing   HS      20:18:08       2016/ 6/20      53248
    ppcg        S  SD  11:43:24       2010/12/31          0

5

Python, 485, 479, 442, 438, 431, 429, 418, 402, 395, 391 , 370 bajtów.

Zapisałem 19 bajtów dzięki Cᴏɴᴏʀ O'Bʀɪᴇɴ przypominając mi, że mogę przypisać funkcje do litery.

Zaoszczędzono 6 bajtów dzięki sugestii FryAmTheEggman, aby wyczyścić filtr maski bitowej.

Zaoszczędź 21 bajtów dzięki niesamowitej odpowiedzi Ruby W0lf, zmuszając mnie do gry w golfa. ;)

To absolutny potwór. Jestem pewien, że uda mi się to trochę zmniejszyć, ale zbliża się do gry w golfa.

a=input()
j=''.join
n=lambda v:int(v,2)
f=j('RO H S VL SD A'.split()[i]for i in range(6)if n(a[88:96])&2**i)
print(j(chr(n(a[x:x+8])).strip()+'.'*(x==56)for x in range(0,88,8)).strip('.'),f,j('%02d:%02d:%02d'%(n(a[b-11:b-6]),n(a[b-6:b]),n(a[b:b+6]))+' %d/%d/%d '%(n(a[b+6:b+12])+1980,n(a[b+12:b+16]),n(a[b+16:b+21]))for b in[123,187]),n(a[208:])*(1-('V'in f or'D'in f)))

może mógłbyś przypisać intchara? lub może wykonać funkcję, która wykonuje str int.
Conor O'Brien,

@ CᴏɴᴏʀO'Bʀɪᴇɴ Dobry pomysł!
Morgan Thrapp,

Wydaje mi się, że odstęp między or 'SD'nimi można usunąć
Conor O'Brien,

@ CᴏɴᴏʀO'Bʀɪᴇɴ Tak, właśnie to zrobiłem.
Morgan Thrapp,

Łał. Nieco krótsze niż się spodziewałem odpowiedzi.
AdmBorkBork,

4

Haskell, 781 710 bajtów

Dzięki BlackCap za pewne uproszczenia

w n=('0'<$[1..2-length a])++a where a=show n
x s=tail.foldr(\a b->s:a++b)""
t=snd.span(==' ')
y a|all(==' ')a=""|0<1='.':t a
nm=(\(a,b)->t a++y b).splitAt 8
ms n(r,s)|n`mod`2^(r+1)`div`2^r>0=s|0<1=""
tm n=x ':'[w$n`div`2^11,w$n`mod`2^11`div`32,w$2*n`mod`64]
dt n=x '/'[w$1980+n`div`2^9,w$n`mod`2^9`div`32,w$n`mod`32]
pa s=x ' '[nm.map(toEnum.v.take 8).takeWhile(not.null)$iterate(drop 8)a,t,dt$v i,tm$v g,dt$v o,tm$v m,show u,"\n"]where{z n=splitAt(8*n);(a,b)=z 11 s;(c,d)=z 1 b;(e,f)=z 2 d;(g,h)=z 2 f;(i,j)=z 2 h;(k,l)=z 4 j;(m,n)=z 2 l;(o,p)=z 2 n;(q,r)=z 2 p;t=(zip [0..](words"RO H S VL SD A")>>=).ms$v c;u|any(`elem`t)"LD"=0|0<1=v r;v=foldl((+).(2*))0.map(read.pure).filter(`elem`"01")}
main=interact pa

Pozwala to dodatkowo wyświetlać śmieci (jak znak nowej linii) po wprowadzeniu.


Mam trochę nisko wiszących owoców: pastebin.com/X69jH75f
BlackCap

3

Java, 1721 1587 1573 1560 1511 bajtów:

import java.util.*;class A{int Q(String a,int b){return Integer.parseInt(a,b);}String P(int a){return Integer.toString(a);}ArrayList<String>B=new ArrayList<String>();void J(String O){B.add(O);}String TD(String l,String p,int a,int c,int d){String X,Y,Z;X=Y=Z=new String();int i=0;for(char F:l.toCharArray()){if(i<a){X+=F;}if(a<=i&i<c){Y+=F;}if(c<=i){Z+=F;}i++;}String[]H=new String[3];H[0]=P(d+Q(X,2));H[1]=P(Q(Y,2));H[2]=(p==":")?P(Q(Z,2)*2):P(Q(Z,2));int T=0;for(String A:H){H[T]=(A.length()<2)?"0"+A:A;T++;}return H[0]+p+H[1]+p+H[2];}String D(String i){String K=new String();int L=0;for(char Y:i.toCharArray()){if(L%8<1){K+=" ";}K+=Y;L++;}String[]C=K.split(" ");String[]z={"RO","H","S","VL","SD","A"};int[]l={1,2,4,8,16,32};Map<Integer,String>U=new HashMap<Integer,String>();for (int e=0;e<l.length;e++){U.put(l[e],z[e]);}String[]N={":","/",":","/"};int[]M={15,17,23,25};int[]O={5,7,5,7};int[]P={0,1980,0,1980};for(int y=1;y<9;y++){if((char)Q(C[y],2)!=' '){J(Character.toString((char)Q(C[y],2)));}}for(int v=9;v<12;v++){if((char)Q(C[v],2)!=' '){if(!B.contains(".")){J(".");}J(Character.toString((char)Q(C[v],2)));}}J(" ");int T=(char)Q(C[12],2);while(T>0){int H=l[0];for(int V:l){if(V<=T){H=V;}}J(U.get(H));T-=H;}for(int w=0;w<4;w++){J(" ");J(TD(C[M[w]]+C[M[w]+1],N[w],O[w],11,P[w]));}J(" ");if(B.contains("SD")||B.contains("VL")){J("0");}else{J(P(Q(C[29]+C[30]+C[31]+C[32],2)));}return String.join("",B);}public static void main(String[]a){A H=new A();System.out.print(H.D(new Scanner(System.in).next()));}}

Pobiera dane wejściowe w formacie 32-bajtowego ciągu binarnego. Dane wyjściowe w formacie ciągu rozdzielanego spacjami. To może być bardzo długa odpowiedź, ale nadal nie jestem rozczarowany. Cieszę się, że udało mi się to zaimplementować w Javie. Mimo to będę się starał grać w golfa jak najwięcej.

Wypróbuj online! (Ideone)


1
+1, ponieważ używanie Javy do problemów niskiego poziomu jest przyjemnie ironiczne (podobnie jak mój Haskell)
Fox

2

Rubinowy, 344 bajty

m=gets
s=->b,l{b.slice!(0,l).to_i 2}
t=->b{'%02d:%02d:%02d %d/%d/%d'%[s[b,5],s[b,6],2*s[b,5],s[b,7]+1980,s[b,4],s[b,5],]}
i=(0..q=32).map{|i|m[i*8,8].to_i 2}
c=i.map(&:chr).join
n=c[0,8].strip
e=c[8,3].strip
e>?!&&n<<?.+e
f=''
6.times{|j|i[11][j]>0&&f<<%w(RO H S VL SD A)[j]}
$><<[n,f,t[m[112,q]],t[m[176,q]],(f[/VL|SD/]?0:m[-q,q].to_i(2))]*' '

Nieco bardziej czytelna wersja jest dostępna tutaj .

Test online: http://ideone.com/Fww1Rw


1
Niezłe! Wygląda na to, że muszę zagrać w golfa na kolejne 27 bajtów. ;)
Morgan Thrapp

2

JavaScript (ES6), 369

(b,Z=n=>n>9?n:'0'+n,W=n=>s[n]<<8|s[n+1],U=n=>[Z((t=W(n))>>11)+`:${Z(t>>5&63)}:`+Z(t%32*2),((t=W(n+2))>>9)+1980+`/${t>>5&15}/`+t%32],X=l=>String.fromCharCode(...s.slice(p,p+=l)).trim(),s=b.match(/.{8}/g).map(x=>+('0b'+x)),p=0)=>[X(8)+((x=X(3))?'.'+x:x),[...b].map((b,i)=>'A,SD,VL,S,H,RO'.split`,`[z=(2*z|b)%4294967296,i*b-90]||'',z=0).join``,U(14),U(22),b[92]|b[91]?0:z]

Mniej golfa

(b,
  Z=n=>n>9?n:'0'+n, // zero pad
  W=n=>s[n]<<8|s[n+1], // get word
  U=n=>[
   Z((t=W(n))>>11)+`:${Z((t>>5&63)}:`+Z(t%32*2),  // decode time
   ((t=W(n+2))>>9)+1980+`/${t>>5&15}/`+t%32 // decode date
  ],
  X=l=>String.fromCharCode(...s.slice(p,p+=l)).trim(), // extract space padded string
  s=b.match(/.{8}/g).map(x=>+('0b'+x)), // convert bits to bytes
  p=0
)=>
  [ X(8)+((x=X(3))?'.'+x:x),
    [...b].map((b,i)=>'A,SD,VL,S,H,RO'.split`,`[i*b-90]||'').join``,
    [...b].slice(-32).map((b,i)=>z=2*z|b,z=0), // this line merged with the preceding one in the golfed code
    U(14),U(22),
    b[92]|b[91]?0:z
  ]

Test

f=(b,Z=n=>n>9?n:'0'+n,W=n=>s[n]<<8|s[n+1],U=n=>[Z((t=W(n))>>11)+`:${Z(t>>5&63)}:`+Z(t%32*2),((t=W(n+2))>>9)+1980+`/${t>>5&15}/`+t%32],X=l=>String.fromCharCode(...s.slice(p,p+=l)).trim(),s=b.match(/.{8}/g).map(x=>+('0b'+x)),p=0)=>[X(8)+((x=X(3))?'.'+x:x),[...b].map((b,i)=>'A,SD,VL,S,H,RO'.split`,`[z=(2*z|b)%4294967296,i*b-90]||'',z=0).join``,U(14),U(22),b[92]|b[91]?0:z]

O.textContent+='\n'+f('0111000001110010011011110110011101110010011000010110110101101101011010010110111001100111000001100000000000000000101000100100010001001000110101000000000000000000000000000000000010100010010001000100100011010100000000000000000000000000000000001101000000000000')
O.textContent+='\n'+f('0010000000100000001000000010000001110000011100000110001101100111001000000010000000100000000101000000000000000000010111010110110000111101100111110000000000000000000000000000000010100010010001000100100011010100000000000000000011110000000100111111001011100001')
<pre id=O></pre>


Ok, więc uruchomiłem to w Safari i dostałem Script error.. Ale z jakiegoś powodu w Firefoksie wydaje się działać idealnie. Zastanawiam się, dlaczego ...
R. Kap

@ R.Kap prawdopodobnie Safari jest mniej kompatybilna z ES6 niż Firefox. kangax.github.io/compat-table/es6
edc65

2

PHP ,301 288 bajtów

for($b=unpack('A8f/A3e/Cl/n/Nc/N/Nm/n/Ns',$argn);$i<8;$f.=1<<$i++&$b[l]?[RO,H,S,VL,SD,A][$i-1]:'');echo trim($b[f].'.'.$b[e],' .')," $f ",($e=function($a){echo date('H:i:s Y/m/d ',mktime($a>>27&31,$a>>21&63,$a>>15&62,$a>>5&15,$a&31,1980+($a>>9&127)));})($b[c]),$e($b[m]),$b[l]&24?0:$b[s];

Wypróbuj online!

Dane wejściowe są 32-bajtowym ciągiem znaków przez STDIN, dane wyjściowe do STDOUT.

-13 bajtów jako samodzielny program.



1

Perl, 249 bajtów

Pobiera 32 bajty jako dane wejściowe, dane wyjściowe są oddzielone znakami nowej linii. unpackjest idealny do tego rodzaju analizy struktury binarnej.

($f,$e,$a,$C,$M,$s)=unpack"A8A3CxxNx4Nx2N",<>;$f=~s/ //g;$e=~s/ //g;printf"%s
@{[map+(RO,H,S,VL,SD,A)[$a&1<<$_?$_:9],0..5]}
"."%02d:%02d:%02d %d/%d/%d
"x2 .$s*!($a&24),$f.".$e"x!!$e,map{$_>>27,$_>>21&63,$_>>15&62,$_/512%128+1980,$_>>5&15,$_&31}$C,$M

Niektóre najważniejsze:

  • Wyżej wymienione unpack.
  • Operator żółwia @{[]}pozwala interpolować kod w ciągu. W rzeczywistości tworzy odwołanie do tablicy, które jest następnie usuwane z dereferencji.
  • "$str1"x!!$str2to dobry sposób na zwrócenie $str1tylko wtedy, gdy $str2jest niepusty ciąg.

Poniżej znajduje się wersja, która działa na prawdziwych pozycjach katalogu, z polami little-endian, i ignoruje tylko prawidłowe dopełnianie nazwy pliku i rozszerzenia (więc np. " ppcg"Nie ma usuniętej początkowej białej spacji) (254 bajty)

($f,$e,$a,$C,$M,$s)=unpack"A8A3CxxVx4Vx2V",<>;$f=~s/ +$//;$e=~s/ +$//;printf"%s
@{[map+(RO,H,S,VL,SD,A)[$a&1<<$_?$_:9],0..5]}
"."%02d:%02d:%02d %d/%d/%d
"x2 .$s*!($a&24),$f.".$e"x!!$e,map{$_>>11&31,$_>>5&63,2*$_&63,($_>>25)+1980,$_>>21&15,$_>>16&31}$C,$M
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.