Decode entri direktori Microsoft MS-DOS 5.0 FAT


27

Sistem file Microsoft FAT memiliki tabel direktori untuk mewakili "file" mana di mana "folder" pada disk. Untuk saat ini, entri-entri ini menjejalkan banyak informasi menjadi sejumlah kecil bit. Ada banyak spesifikasi teknis di Wiki untuk yang penasaran, tetapi tantangan di sini adalah fokus pada decoding entri yang "sederhana".

Setiap entri terdiri dari kata biner 32 byte, dipecah menjadi beberapa bagian. Untuk konsistensi dalam tantangan ini, kita akan menggunakan versi MS-DOS 5.0, byte dipesan sebagai big endian , dan kami menyebut byte 0x00sebagai yang paling kiri, dan byte 0x1Fsebagai yang paling kanan.

Di bawah ini adalah skema singkat dari bagian yang relevan, dan apa yang harus menjadi output untuk setiap bagian ( dicetak tebal ).

  • 11 byte pertama adalah nama file dalam format ASCII (ini adalah asal nama file 8.3 yang terkenal - 8 byte untuk nama file, 3 byte untuk ekstensi). Ini adalah pengkodean ASCII lurus, dan harus menjadi keluaran ASCII dengan titik (.) Di antaranya .
    • Catatan: bagian 8 dan 3 diisi dengan spasi untuk membuat entri panjang penuh. Outputnya harus mengabaikan spasi (yaitu, jangan outputnya).
    • Ekstensi file mungkin kosong (yaitu, semua spasi), dalam hal ini output tidak boleh menampilkan titik .
    • Karena ASCII hanya menggunakan 7 bit yang lebih rendah, byte akan memiliki yang terdepan 0.
  • Byte berikutnya (0x0b) adalah bitmask dari berikut ini:
    • 0x01 Hanya Baca - RO output
    • 0x02 Tersembunyi - keluaran H
    • 0x04 Sistem - output S
    • 0x08 Volume Label - output VL . Ukuran file (di bawah) harus berupa 0 , terlepas dari entri yang sebenarnya.
    • Subdirektori 0x10 - output SD . Ukuran file (di bawah) harus berupa 0 , terlepas dari entri yang sebenarnya.
    • 0x20 Archive - output A
    • 0x40 Device - diabaikan untuk tantangan ini.
    • 0x80 Dicadangkan - diabaikan untuk tantangan ini.
    • Karena ini adalah bitmask, beberapa flag dimungkinkan - semua output yang berlaku harus disatukan bersama dalam urutan apa pun. Misalnya, 0xffbisa jadi ROHSVLSDA(atau kombinasi lainnya).
  • Dua byte berikutnya (0x0c dan 0x0d) tidak digunakan di bawah MS-DOS 5.0.
  • Dua byte berikutnya (0x0e dan 0x0f) adalah waktu pembuatan sebagai berikut:
    • Bit 15 hingga 11 adalah jam dalam format 24 jam - output 00 hingga 23
    • Bit 10 hingga 5 adalah menit - output 00 hingga 59
    • Bit 4 hingga 0 adalah detik / 2 - output 00 hingga 58 (perhatikan bahwa detik hanya dalam resolusi dua detik)
    • Untuk klarifikasi: hhhhhmmmmmmsssssketika ditulis big-endian.
  • Dua byte berikutnya (0x10 dan 0x11) adalah tanggal pembuatan sebagai berikut:
    • Bit 15-9 adalah tahun - output 1980 untuk 0hingga 2107 untuk127
    • Bit 8 hingga 5 adalah bulan - output 1 hingga 12 (dengan atau tanpa nol)
    • Bit 4 hingga 0 adalah hari - output 0 hingga 31 (dengan atau tanpa nol di depan)
    • Untuk klarifikasi: yyyyyyymmmmdddddketika ditulis big-endian.
  • Dua byte berikutnya (0x12 dan 0x13) adalah tanggal akses terakhir. Saat digunakan dalam MS-DOS 5.0, kami mengabaikan bagian ini untuk tantangan ini.
  • Dua byte berikutnya (0x14 dan 0x15) tidak digunakan oleh MS-DOS 5.0.
  • Dua byte berikutnya (0x16 dan 0x17) adalah waktu yang dimodifikasi terakhir, mengikuti format yang sama dengan waktu pembuatan, di atas.
  • Dua byte berikutnya (0x18 dan 0x19) adalah tanggal terakhir yang dimodifikasi, mengikuti format yang sama dengan tanggal pembuatan, di atas.
  • Dua byte berikutnya (0x1a dan 0x1b) adalah lokasi cluster dari file pada disk. Kami mengabaikan bagian ini untuk tantangan ini.
  • Empat byte terakhir (0x1c, 0x1d, 0x1e, dan 0x1f) adalah ukuran file - output sebagai integer yang tidak ditandai , kecuali jika flag VL atau SD diatur (di atas), dalam hal ini output 0.

Representasi visual

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

Memasukkan

  • Satu kata 32-byte (yaitu, 256 bit), dalam format apa pun yang nyaman.
    • Ini bisa berupa string 1dan 0, seperti beberapa unsigned int, array nilai Boolean, dll.
    • Silakan tentukan dalam jawaban Anda format apa yang Anda gunakan untuk input.
    • Anda tidak dapat mengambil beberapa input (yaitu, array yang dipecah sebelumnya ke ukuran byte yang relevan) kecuali jika itu satu - satunya cara bahasa Anda untuk mengambil input. Mengurai input adalah bagian dari tantangan.
  • Anda dapat menganggap input valid (misalnya, Anda tidak perlu melakukan pengecekan tanggal untuk memverifikasi bahwa tanggal tersebut valid).
  • Bytes yang tidak digunakan bisa semuanya 0, semua 1, dll., Asalkan ada. Dalam contoh di bawah ini, saya menggunakan semua 0byte yang tidak digunakan.

Keluaran

Baik dicetak ke layar atau dikembalikan, berikut ini:

  • Nama file sebagai string ASCII
  • Atribut file sebagai string ASCII
  • Waktu pembuatan dan tanggal pembuatan, dengan pemisah yang sesuai (titik dua, garis miring, sesuatu untuk membedakan komponen)
  • Waktu yang dimodifikasi dan tanggal yang dimodifikasi, sekali lagi dengan pemisah yang sesuai
  • Ukuran file

Outputnya dapat berupa string tunggal yang dipisahkan oleh spasi atau dipisahkan oleh baris baru, elemen yang terpisah dalam array, dll. Silakan tentukan dalam jawaban Anda bagaimana output Anda diformat.

Aturan

  • Format I / O standar dapat diterima.
  • Program lengkap atau fungsi dapat diterima.
  • Celah standar dilarang.
  • Ini adalah , jadi semua aturan golf biasa berlaku, dan kode terpendek menang.
  • Built-in yang melakukan fungsi ini persis dilarang.

Contohnya

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

Apakah saya tetap bisa jika ada spasi kosong di sekitar bendera? Misalnya, apakah SD Sset bendera yang valid?
Morgan Thrapp

@MorganThrapp Tentu, itu tidak masalah.
AdmBorkBork

Karena penasaran, apakah Anda mendapatkan banyak pengalaman berinteraksi dengan MS-DOS 5.0 pada hari itu, atau apakah Anda benar-benar bosan di Wikipedia suatu hari?
kucing

3
@cat Beberapa dari keduanya. Saya sudah sangat tertarik pada komputer sejak saya berusia sekitar 5 tahun dan menerima Commodore VIC-20. Salah satu proyek ilmu komputer tingkat pascasarjana saya sekitar 10 tahun yang lalu adalah membangun sistem file kami sendiri, jadi saya banyak meneliti untuk itu. Untuk ini, saya menarik banyak dari Wiki dan mengupasnya menjadi sesuatu yang bisa menjadi tantangan.
AdmBorkBork

Jawaban:


6

Verilog, 513 670 617 byte

Berjalan menggunakan IVerilog. Tidak diperlukan flag kompilasi khusus.

Ini adalah monster definisi bertingkat, bit-twiddling, dan gangguan karena harus membalik urutan bit karena endianness (jika string tidak dicetak, atau urutan bit nomor salah). Input diambil melalui iport, yang merupakan cara biasa mengambil input ke modul Verilog. $displaydigunakan untuk mencetak ke standar keluar. 6 byte dapat disimpan jika nol di depan tidak diperlukan untuk cap waktu.

`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

Demo

Testbench (Tidak diberi skor):

`timescale 1ns / 1ps

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

endmodule

Contoh dijalankan:

$ 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 byte.

Disimpan 19 byte, terima kasih kepada Cᴏɴᴏʀ O'Bʀɪᴇɴ yang mengingatkan saya bahwa saya dapat menetapkan fungsi ke sebuah surat.

Disimpan 6 byte berkat saran FryAmTheEggman untuk membersihkan filter bitmask.

Disimpan 21 byte berkat jawaban Ruby yang luar biasa dari W0lf yang memaksa saya untuk memainkan golf ini lagi. ;)

Ini adalah monster absolut. Cukup yakin saya bisa mengurangi sedikit lebih banyak, tetapi sudah hampir menjadi golf.

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)))

mungkin Anda bisa menugaskan intke char? atau mungkin membuat fungsi yang berkinerja str int.
Conor O'Brien

@ CᴏɴᴏʀO'Bʀɪᴇɴ Ide bagus!
Morgan Thrapp

Ruang antara or 'SD'bisa dihilangkan, saya pikir
Conor O'Brien

@ CᴏɴᴏʀO'Bʀɪᴇɴ Yup, baru saja melakukannya.
Morgan Thrapp

Wow. Cukup sedikit lebih pendek dari yang saya harapkan.
AdmBorkBork

4

Haskell, 781 710 byte

Berkat BlackCap untuk penyederhanaan

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

Ini juga memungkinkan sampah (seperti karakter baris baru) muncul setelah input.



3

Java, 1721 1587 1573 1560 1511 byte:

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()));}}

Mengambil input dalam format string biner 32 byte. Output dalam format string yang dipisahkan spasi. Ini mungkin jawaban yang sangat panjang, tapi saya masih belum kecewa. Saya senang saya bisa menerapkan ini di Jawa. Saya masih akan mencoba bermain golf sebanyak yang saya bisa.

Cobalah secara Online! (Ideone)


1
+1 karena menggunakan Java untuk masalah tingkat rendah sangat ironis (seperti Haskell saya)
Fox

2

Ruby, 344 byte

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))]*' '

Versi yang sedikit lebih mudah dibaca tersedia di sini .

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


1
Yang bagus! Sepertinya saya perlu bermain golf dengan 27 byte lainnya. ;)
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]

Kurang golf

(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
  ]

Uji

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, jadi saya menjalankan ini di Safari dan mendapatkannya Script error.. Tetapi untuk beberapa alasan di Firefox tampaknya berfungsi dengan baik. Saya heran mengapa ...
R. Kap

@ R.Kap mungkin Safari kurang kompatibel dengan ES6 dari Firefox. kangax.github.io/compat-table/es6
edc65

2

PHP ,301 288 byte

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];

Cobalah online!

Input adalah string kata 32 byte via STDIN, output ke STDOUT.

-13 byte sebagai program mandiri.


2

Stax , 111 byte

¼ΘUßU'ïMo^ø¬├▓> I¬i⌠·╥.↕¥½ßqS,=frT`d_`&&↓⌠ÉûÆiü=┌-< │∟Φ☼⌐¢3²Bu╜lJ╛§≥╪║ε┐╓ù♫╨Z░╖!¥É:╬Çß═╤às8Q←φ,ºï◘≥Ä£}èΦ╡FÉçø¶É

Jalankan dan debug itu


Ups, kesalahan saya. Saya akan memperbaikinya.
Rekursif

1
Ini berfungsi dengan benar sekarang dengan biaya 3 byte.
Rekursif

1

Perl, 249 byte

Mengambil 32 byte sebagai input, output dipisahkan oleh baris baru. unpacksangat cocok untuk parsing struktur biner jenis ini.

($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

Beberapa hal penting:

  • Yang disebutkan di atas unpack.
  • Operator kura-kura @{[]}memungkinkan untuk menginterpolasi kode dalam sebuah string. Ini sebenarnya membuat referensi array yang kemudian direferensikan.
  • "$str1"x!!$str2adalah cara yang bagus untuk mengembalikan $str1hanya jika $str2string tidak kosong.

Di bawah ini adalah versi yang berfungsi pada entri direktori nyata, dengan bidang little-endian, dan hanya mengabaikan bantalan kanan pada nama file dan ekstensi (jadi, mis. " ppcg"Spasi putih awalnya tidak dihapus) (254 byte)

($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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.