Compare commits
9916 Commits
2012.01.08
...
2015.12.09
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86e8c89488 | ||
|
|
47f48f5d85 | ||
|
|
e15e2ef7a0 | ||
|
|
d0c8b279da | ||
|
|
612d83b51d | ||
|
|
9c30efeb7e | ||
|
|
39fa4cc107 | ||
|
|
b09c122373 | ||
|
|
3348243b7b | ||
|
|
b46b65ed37 | ||
|
|
18e4088fad | ||
|
|
5fd6cd64f9 | ||
|
|
3d24bbfbe4 | ||
|
|
1775612512 | ||
|
|
0d2d967cc7 | ||
|
|
a5e52a1fd4 | ||
|
|
291a93bafa | ||
|
|
c4737bea17 | ||
|
|
45dad7ba1b | ||
|
|
db7c9da871 | ||
|
|
bc92621ade | ||
|
|
fd8e559c3a | ||
|
|
222e11d4ae | ||
|
|
7d682f0acb | ||
|
|
8364b6b0b1 | ||
|
|
7ac40e5521 | ||
|
|
36066dd3ee | ||
|
|
636aa83ed3 | ||
|
|
33d152b6cc | ||
|
|
51c4fec0d5 | ||
|
|
0017486dca | ||
|
|
edc70f4aaf | ||
|
|
756926ff00 | ||
|
|
cb160dd531 | ||
|
|
77334ccb44 | ||
|
|
796db21295 | ||
|
|
535d7b681b | ||
|
|
960e038886 | ||
|
|
ea14422ff1 | ||
|
|
38d05d17e5 | ||
|
|
db9bd5267f | ||
|
|
ab3b773bbe | ||
|
|
0bc4ee60e0 | ||
|
|
a3ef0e1cdd | ||
|
|
679bacf0b5 | ||
|
|
02e3952f3b | ||
|
|
64b7e89c0c | ||
|
|
bee4c5571a | ||
|
|
96929dd1e8 | ||
|
|
53e06b2507 | ||
|
|
b80d4bebf3 | ||
|
|
55bec9b658 | ||
|
|
2a63b0f110 | ||
|
|
07b88cffce | ||
|
|
58c8451f36 | ||
|
|
3047121c63 | ||
|
|
7079f8ff1f | ||
|
|
2c3b9f3570 | ||
|
|
fad2428f47 | ||
|
|
c3d3110f6a | ||
|
|
79ec00276c | ||
|
|
9c117d345f | ||
|
|
46cc1c65a4 | ||
|
|
71d9fe7818 | ||
|
|
4ccabf93db | ||
|
|
6612a34939 | ||
|
|
e5b4225f7c | ||
|
|
b2ca35ddbc | ||
|
|
76ab842d9b | ||
|
|
24dc1ed715 | ||
|
|
682d8dcd21 | ||
|
|
640bb54e73 | ||
|
|
e0977d7686 | ||
|
|
112ab398db | ||
|
|
af93fcfa05 | ||
|
|
62d231c004 | ||
|
|
49358274d7 | ||
|
|
7b1e379ca9 | ||
|
|
22d7368dfb | ||
|
|
24121bc703 | ||
|
|
9fc87fa767 | ||
|
|
328f82d59a | ||
|
|
78717fc328 | ||
|
|
3b35c3425e | ||
|
|
874ae0354e | ||
|
|
4c6b4764f0 | ||
|
|
59ee8a8647 | ||
|
|
af284305d5 | ||
|
|
d53a4af1a4 | ||
|
|
2e1b928540 | ||
|
|
040ac68679 | ||
|
|
049d71d874 | ||
|
|
bf2c8c8f82 | ||
|
|
ef428960c9 | ||
|
|
992fc9d6e1 | ||
|
|
8639f89f51 | ||
|
|
0424ec307b | ||
|
|
ac5a69af45 | ||
|
|
94e8c80473 | ||
|
|
87f0e62d94 | ||
|
|
46b4070f3f | ||
|
|
2a776f9788 | ||
|
|
f4c7ef9862 | ||
|
|
50e12e9df1 | ||
|
|
b7faebbac8 | ||
|
|
4191fdf147 | ||
|
|
9a4f12be98 | ||
|
|
7ad4258add | ||
|
|
9945c4994c | ||
|
|
5faf9fed7e | ||
|
|
13a9b69b09 | ||
|
|
4975650e00 | ||
|
|
0cc7178546 | ||
|
|
41f24c321d | ||
|
|
4b3fbafdd2 | ||
|
|
7ac40086f5 | ||
|
|
313dfc45f5 | ||
|
|
78a55d7a28 | ||
|
|
bb6ac83698 | ||
|
|
9d0e366880 | ||
|
|
9bff48a0e7 | ||
|
|
60121eb514 | ||
|
|
527ca1da4f | ||
|
|
7689413e42 | ||
|
|
ba7a92b0ce | ||
|
|
4c7d816dd7 | ||
|
|
032f2f260f | ||
|
|
20e98bf6c0 | ||
|
|
5c2266df4b | ||
|
|
67dda51722 | ||
|
|
e4c4bcf36f | ||
|
|
82d8a8b6e2 | ||
|
|
13a10d5aa3 | ||
|
|
9022726446 | ||
|
|
94bfcd23b7 | ||
|
|
526b3b0716 | ||
|
|
61f92af1cf | ||
|
|
a72778d364 | ||
|
|
5ae17037a3 | ||
|
|
02f0da20b0 | ||
|
|
b41631c4e6 | ||
|
|
0e49d9a6b0 | ||
|
|
4a7d108ab3 | ||
|
|
3cfd000849 | ||
|
|
1b38185361 | ||
|
|
9cb9a5df77 | ||
|
|
5035536e3f | ||
|
|
3e12bc583a | ||
|
|
e568c2233e | ||
|
|
061a75edd6 | ||
|
|
82c4d7b0ce | ||
|
|
136dadde95 | ||
|
|
0c14841585 | ||
|
|
0eebf34d9d | ||
|
|
cf186b77a7 | ||
|
|
a3372437bf | ||
|
|
4c57b4853d | ||
|
|
38eb2968ab | ||
|
|
bea56c9569 | ||
|
|
7e508ff2cf | ||
|
|
563772eda4 | ||
|
|
0533915aad | ||
|
|
c3a227d1c4 | ||
|
|
f6c903e708 | ||
|
|
7dc011c063 | ||
|
|
4e3b303016 | ||
|
|
7e1f5447e7 | ||
|
|
7e3472758b | ||
|
|
328a22e175 | ||
|
|
417b453699 | ||
|
|
6ea7190a3e | ||
|
|
b54b08c91b | ||
|
|
c30943b1c0 | ||
|
|
2abf7cab80 | ||
|
|
4137196899 | ||
|
|
019839faaa | ||
|
|
f52183a878 | ||
|
|
750b9ff032 | ||
|
|
28602e747c | ||
|
|
6cc37c69e2 | ||
|
|
a5cd0eb8a4 | ||
|
|
c23e266427 | ||
|
|
651acffbe5 | ||
|
|
71bd93b89c | ||
|
|
6da620de58 | ||
|
|
bdceea7afd | ||
|
|
d80a39cec8 | ||
|
|
5b5fae5f20 | ||
|
|
01b06aedcf | ||
|
|
c711383811 | ||
|
|
17cc153435 | ||
|
|
67446fd49b | ||
|
|
325bb615a7 | ||
|
|
ee5cd8418e | ||
|
|
342609a1b4 | ||
|
|
f270cf1a26 | ||
|
|
371c3b796c | ||
|
|
6b7ceee1b9 | ||
|
|
fdb20a27a3 | ||
|
|
2c94198eb6 | ||
|
|
e8110b8125 | ||
|
|
c39fd7b1ca | ||
|
|
a9c09a7c62 | ||
|
|
82beaabb41 | ||
|
|
63b4295d20 | ||
|
|
312a3f389b | ||
|
|
609af1ae1c | ||
|
|
4cd759f73d | ||
|
|
e156e70281 | ||
|
|
9b464929fe | ||
|
|
0c176d7bde | ||
|
|
7a3f0c00ad | ||
|
|
7aefc49c40 | ||
|
|
741dd8ea65 | ||
|
|
76adc82068 | ||
|
|
bd1512d196 | ||
|
|
9a4acbfaf5 | ||
|
|
ad1f4e7902 | ||
|
|
b328295910 | ||
|
|
828b2a5cd9 | ||
|
|
2ff7cbeaaa | ||
|
|
b2f7738830 | ||
|
|
dc0279532a | ||
|
|
0c59d02bdc | ||
|
|
0f72beb515 | ||
|
|
d781e29316 | ||
|
|
3b3e8ed332 | ||
|
|
dcdfeb33d2 | ||
|
|
0d85c3a732 | ||
|
|
903d136942 | ||
|
|
9d584da7d0 | ||
|
|
31752f76f7 | ||
|
|
5f1b2aea80 | ||
|
|
4479600d57 | ||
|
|
a90189c3ad | ||
|
|
d8a1caf04f | ||
|
|
cb33d389ed | ||
|
|
967e0955f0 | ||
|
|
e01b432ad3 | ||
|
|
fd91257c40 | ||
|
|
c7b959ce38 | ||
|
|
75eac8961e | ||
|
|
3b7d9aa487 | ||
|
|
1f4b722b00 | ||
|
|
f6519f89b0 | ||
|
|
24af85298e | ||
|
|
e721d857c2 | ||
|
|
5c17f0a67a | ||
|
|
4fcaa4f4a5 | ||
|
|
536f819eda | ||
|
|
a662489877 | ||
|
|
a2973eb597 | ||
|
|
4e21b3a94f | ||
|
|
b703ebeeaf | ||
|
|
b84a5f0337 | ||
|
|
a1ec9a7553 | ||
|
|
91d644b5ba | ||
|
|
5d6c3d6a66 | ||
|
|
1ebb4717df | ||
|
|
cf5881fc4d | ||
|
|
fcd817a326 | ||
|
|
031ec536f0 | ||
|
|
668db403f9 | ||
|
|
b9ad101926 | ||
|
|
435911029f | ||
|
|
699ed30cee | ||
|
|
9eab37dca0 | ||
|
|
9a8a12b7d8 | ||
|
|
a4c2ab35c1 | ||
|
|
3d9c4bf09a | ||
|
|
8b8a39e279 | ||
|
|
82393e2bb2 | ||
|
|
2eb99a4b98 | ||
|
|
6abce58a12 | ||
|
|
990e6e8fa3 | ||
|
|
bfd88516eb | ||
|
|
d8b7e80d29 | ||
|
|
37120974dc | ||
|
|
42fc93c709 | ||
|
|
a625e56543 | ||
|
|
9b738b2caa | ||
|
|
90bb5667bf | ||
|
|
d3d3e2e3aa | ||
|
|
37ca7b22b5 | ||
|
|
50f84a9ae1 | ||
|
|
ff29bf81f8 | ||
|
|
b25f753397 | ||
|
|
6a5d6de1e3 | ||
|
|
1c31a5b0e0 | ||
|
|
4f5cdf7c9b | ||
|
|
f09a767d31 | ||
|
|
cc8034cc4c | ||
|
|
50506cb607 | ||
|
|
aa8d2d5be6 | ||
|
|
114e6025b0 | ||
|
|
fda2717ef9 | ||
|
|
937511dfc0 | ||
|
|
d5c181a14e | ||
|
|
e8ce2375e0 | ||
|
|
6fdb39ded1 | ||
|
|
8e3a2bd620 | ||
|
|
a06bf87a2c | ||
|
|
ee4337d100 | ||
|
|
cff551c0b0 | ||
|
|
6d02b9a392 | ||
|
|
2c740cf28d | ||
|
|
5214f1e31d | ||
|
|
5d0f84d32c | ||
|
|
ee223abb88 | ||
|
|
21d0c33ecd | ||
|
|
8b6d9406db | ||
|
|
686f98816e | ||
|
|
0fa6b17dcc | ||
|
|
472404953a | ||
|
|
ae4ddf9efa | ||
|
|
ea8ed40b2f | ||
|
|
71bb016160 | ||
|
|
179ffab69c | ||
|
|
deb85c32bb | ||
|
|
92366d189e | ||
|
|
81413c0165 | ||
|
|
1e2eb4b40d | ||
|
|
01003d072c | ||
|
|
5003e4283b | ||
|
|
123c781044 | ||
|
|
e68dd1921a | ||
|
|
6953d8e95a | ||
|
|
b3613d36da | ||
|
|
53472df857 | ||
|
|
2549e113b8 | ||
|
|
b15c44cd36 | ||
|
|
f93ded9852 | ||
|
|
89ea063eeb | ||
|
|
44b2264fea | ||
|
|
cb5a470635 | ||
|
|
17d1900581 | ||
|
|
5d501a0901 | ||
|
|
c13722480b | ||
|
|
e7d34c03f2 | ||
|
|
264cd00fff | ||
|
|
a4a6b7b80f | ||
|
|
aebb42d32b | ||
|
|
b4ef6a0038 | ||
|
|
5d235ca7f6 | ||
|
|
c3459d24f1 | ||
|
|
e3778cce0e | ||
|
|
ad607563a2 | ||
|
|
236cb2131b | ||
|
|
66d041f250 | ||
|
|
f3cb54e6d9 | ||
|
|
0aeb9a106e | ||
|
|
fd8102820c | ||
|
|
bfdf891fd3 | ||
|
|
3fa3ff1bc3 | ||
|
|
0a0110fc6b | ||
|
|
852fad922f | ||
|
|
fc68d52bb9 | ||
|
|
dde9fe9788 | ||
|
|
a230068ff7 | ||
|
|
6a75040278 | ||
|
|
c514b0ec65 | ||
|
|
eb97f46e8b | ||
|
|
c90d16cf36 | ||
|
|
ab6ca04802 | ||
|
|
999079b454 | ||
|
|
8a06999ba0 | ||
|
|
80dcee5cd5 | ||
|
|
9550ca506f | ||
|
|
30eecc6a04 | ||
|
|
dbd82a1d4f | ||
|
|
76f0c50d3d | ||
|
|
dc519b5421 | ||
|
|
ae12bc3ebb | ||
|
|
e327b736ca | ||
|
|
82b69a5cbb | ||
|
|
11465da702 | ||
|
|
578c074575 | ||
|
|
8cdb5c8453 | ||
|
|
2b1b2d83ca | ||
|
|
c3040bd00a | ||
|
|
8c1aa28c27 | ||
|
|
78d7ee19dc | ||
|
|
892015b088 | ||
|
|
47f2d01a5a | ||
|
|
33a513faf7 | ||
|
|
240384afe6 | ||
|
|
6722ebd437 | ||
|
|
9a605c8859 | ||
|
|
402ca40c9d | ||
|
|
30bd1c16c8 | ||
|
|
721f5a277c | ||
|
|
6fb8ace671 | ||
|
|
ae37338e68 | ||
|
|
03c2c162f9 | ||
|
|
52c3a6e49d | ||
|
|
4e16c1f80b | ||
|
|
7ccb2b84dd | ||
|
|
0a192fbea7 | ||
|
|
a526167d40 | ||
|
|
f78546272c | ||
|
|
c137cc0d33 | ||
|
|
6e4b8b2891 | ||
|
|
5dadae079b | ||
|
|
cd08d806b1 | ||
|
|
5f9f87c06f | ||
|
|
387db16a78 | ||
|
|
36e6f62cd0 | ||
|
|
755ff8d22c | ||
|
|
7b3a19e533 | ||
|
|
4f13f8f798 | ||
|
|
feb7711cf5 | ||
|
|
589c33dade | ||
|
|
e572a1010b | ||
|
|
7e0dc61334 | ||
|
|
8e82ecfe8f | ||
|
|
ec29539e06 | ||
|
|
8cd9614abf | ||
|
|
324ac0a243 | ||
|
|
3711304510 | ||
|
|
50b936936d | ||
|
|
d97da29da2 | ||
|
|
7687b354c5 | ||
|
|
36d7281037 | ||
|
|
865d1fbafc | ||
|
|
ac21e71968 | ||
|
|
943a1e24b8 | ||
|
|
50f01302d3 | ||
|
|
0198807ef9 | ||
|
|
6856139705 | ||
|
|
c93153852f | ||
|
|
ab9c7214ee | ||
|
|
dae69640d0 | ||
|
|
edeb3e7cb1 | ||
|
|
5c43afd40f | ||
|
|
9170ca5b16 | ||
|
|
65d49afa48 | ||
|
|
ab03c0b47c | ||
|
|
7690787553 | ||
|
|
a65402ef42 | ||
|
|
7033bc1a51 | ||
|
|
89d5fbf354 | ||
|
|
8c3533ba97 | ||
|
|
44d6dd08b2 | ||
|
|
cc449417c4 | ||
|
|
497f5fd93f | ||
|
|
7308b8cb3d | ||
|
|
4211c83aa4 | ||
|
|
d01949dc89 | ||
|
|
63a6494834 | ||
|
|
8bea039b83 | ||
|
|
d65889bbc0 | ||
|
|
4a8963770e | ||
|
|
5b0aa2c7b1 | ||
|
|
b6aa99aff8 | ||
|
|
4bf5614195 | ||
|
|
0be30bafa4 | ||
|
|
7b091c370c | ||
|
|
334b5c3b72 | ||
|
|
b7cedb1604 | ||
|
|
2038ad6ee7 | ||
|
|
b243340f0c | ||
|
|
8cc83d301d | ||
|
|
d762f86e94 | ||
|
|
264b23e1a4 | ||
|
|
a6e0afa2bb | ||
|
|
4285a47f40 | ||
|
|
e36963e0eb | ||
|
|
dedd35c6bc | ||
|
|
608945d44a | ||
|
|
b1bf063503 | ||
|
|
14bddf35fb | ||
|
|
ef6c868f23 | ||
|
|
6682049dee | ||
|
|
b0f001a6cb | ||
|
|
dd67702a3e | ||
|
|
05a3879f1c | ||
|
|
4a7b790384 | ||
|
|
09ff81316e | ||
|
|
c88aec845a | ||
|
|
77a54b6a65 | ||
|
|
575036b405 | ||
|
|
f6dfd6603a | ||
|
|
e04edad621 | ||
|
|
f322bfb063 | ||
|
|
014e880372 | ||
|
|
01d22d4703 | ||
|
|
48aae2d2cf | ||
|
|
c571dea953 | ||
|
|
8b172c2e10 | ||
|
|
0a67a3632b | ||
|
|
985e4fdc07 | ||
|
|
1e399778ee | ||
|
|
2e022397c4 | ||
|
|
02835c6bf4 | ||
|
|
91816e8f16 | ||
|
|
10c38c7ca2 | ||
|
|
94a773feb9 | ||
|
|
448ef1f31c | ||
|
|
49941c4e4f | ||
|
|
80f48920c8 | ||
|
|
520e753390 | ||
|
|
355c7ad361 | ||
|
|
5a11b793fe | ||
|
|
7593fbaa12 | ||
|
|
2eb0f72a0e | ||
|
|
8e5b121948 | ||
|
|
648e6a1ffe | ||
|
|
55af2b26e0 | ||
|
|
583882fdce | ||
|
|
9eb31b265f | ||
|
|
ddeb1b3de2 | ||
|
|
59fe4824f8 | ||
|
|
dd8417526b | ||
|
|
09670d5ba4 | ||
|
|
41a7b00f18 | ||
|
|
d90e40305b | ||
|
|
350c948133 | ||
|
|
e5e9966199 | ||
|
|
fbd9f6ea80 | ||
|
|
6df7179e6c | ||
|
|
36eb802baf | ||
|
|
2ccb37beb9 | ||
|
|
246ce10858 | ||
|
|
ba717dca97 | ||
|
|
1e52776ac3 | ||
|
|
8daeeedc06 | ||
|
|
cce9d15d01 | ||
|
|
dd414c970b | ||
|
|
6744f36db7 | ||
|
|
497ca088a6 | ||
|
|
90bddb6cdd | ||
|
|
fafc7950e2 | ||
|
|
a13d06de42 | ||
|
|
1db82381e3 | ||
|
|
cb8961eeed | ||
|
|
af98f8ff37 | ||
|
|
caf80631f0 | ||
|
|
1812afb7b3 | ||
|
|
9fb66c780c | ||
|
|
ab953c64a0 | ||
|
|
db0a8ad979 | ||
|
|
1c29e81e62 | ||
|
|
7a6d76a64d | ||
|
|
4aa353673b | ||
|
|
f49b3d6efc | ||
|
|
36bb63fad1 | ||
|
|
1f36085df9 | ||
|
|
26669ea3cf | ||
|
|
3dc582e5ea | ||
|
|
506e261d20 | ||
|
|
b30c4992a9 | ||
|
|
3eeff489e8 | ||
|
|
5946cda7c6 | ||
|
|
ee2edd838a | ||
|
|
73e732eb6b | ||
|
|
cd7364a89c | ||
|
|
57d1db8dd0 | ||
|
|
964e7b2dd0 | ||
|
|
f101079ae0 | ||
|
|
0f61db4469 | ||
|
|
1bd3903582 | ||
|
|
da4daed5ef | ||
|
|
7d49502ab0 | ||
|
|
03e3b4e119 | ||
|
|
d8348c351d | ||
|
|
70cb4d51c9 | ||
|
|
7c84562945 | ||
|
|
68f3b61f0e | ||
|
|
08fd433f3e | ||
|
|
35a3ff1d33 | ||
|
|
fff496c689 | ||
|
|
e5c209a1bc | ||
|
|
75f105d455 | ||
|
|
00cde0b8dc | ||
|
|
58cd7e173e | ||
|
|
f4076bb736 | ||
|
|
6f7893653c | ||
|
|
55ebae26f9 | ||
|
|
ae8bdfd1a1 | ||
|
|
6a74719060 | ||
|
|
f6295bcb04 | ||
|
|
78f9d84318 | ||
|
|
b1ec70e4a9 | ||
|
|
c936d8cc7b | ||
|
|
e6174ee975 | ||
|
|
f790c43f6e | ||
|
|
8119597d6f | ||
|
|
43abd79950 | ||
|
|
97ae4d166c | ||
|
|
87cc0fbd18 | ||
|
|
baf39a1aa8 | ||
|
|
975977860d | ||
|
|
b5d48cb1ef | ||
|
|
de66571371 | ||
|
|
dab062fb6e | ||
|
|
6a959f2e52 | ||
|
|
47c165c3a9 | ||
|
|
4180a3d8b7 | ||
|
|
ef47b2c15f | ||
|
|
57935b2564 | ||
|
|
54a5428518 | ||
|
|
9d5fb3b58d | ||
|
|
cbb7287204 | ||
|
|
0553d0ee40 | ||
|
|
7faf7e7523 | ||
|
|
4356d907c1 | ||
|
|
c677e49bd1 | ||
|
|
96c4855331 | ||
|
|
b90b0c4ffa | ||
|
|
c725e2c8b0 | ||
|
|
db7a28eccb | ||
|
|
6a11bb77ba | ||
|
|
181f814e57 | ||
|
|
bd5376c182 | ||
|
|
ecf6de5b02 | ||
|
|
139f27827e | ||
|
|
945e5c56e3 | ||
|
|
fc10824cb6 | ||
|
|
83a5668694 | ||
|
|
f648e682a7 | ||
|
|
f2dbc54066 | ||
|
|
86be82610c | ||
|
|
4810c48d6d | ||
|
|
c4af7684d8 | ||
|
|
fcc2546269 | ||
|
|
40fbb05e1c | ||
|
|
dc5756fd77 | ||
|
|
41db733308 | ||
|
|
0bf219889e | ||
|
|
f2a7ed77ef | ||
|
|
4853eb63fe | ||
|
|
5820c4a29e | ||
|
|
7fd4ed9939 | ||
|
|
88c86d211b | ||
|
|
5d84b79a30 | ||
|
|
140ac73965 | ||
|
|
2a27e66234 | ||
|
|
e759a00119 | ||
|
|
9d5332518c | ||
|
|
90ab741e90 | ||
|
|
96229998c2 | ||
|
|
0659dfccfe | ||
|
|
9c544e2537 | ||
|
|
d7fc56318b | ||
|
|
4bba371644 | ||
|
|
ef5acfe32d | ||
|
|
30787f7259 | ||
|
|
85557f635a | ||
|
|
60d23e5e59 | ||
|
|
97d5bfcba6 | ||
|
|
c233e6bcc3 | ||
|
|
28809ab07a | ||
|
|
bad84757eb | ||
|
|
13118a50b8 | ||
|
|
5495937f46 | ||
|
|
b203095d4c | ||
|
|
f3b098fb90 | ||
|
|
af17794c65 | ||
|
|
8fc226ef99 | ||
|
|
3bb3f04108 | ||
|
|
59a9efe85b | ||
|
|
0facd2af3e | ||
|
|
7d0ada5ff9 | ||
|
|
44451f22d5 | ||
|
|
06c6efa970 | ||
|
|
e5851b963a | ||
|
|
4de6131090 | ||
|
|
3a1341a7bc | ||
|
|
c78e48177c | ||
|
|
6edaa0e25b | ||
|
|
fb97809e64 | ||
|
|
0c996b9f48 | ||
|
|
acfb717a18 | ||
|
|
647eab4541 | ||
|
|
1e5bcdec02 | ||
|
|
e7d8e98a9f | ||
|
|
2b3f951a2e | ||
|
|
6751a1284d | ||
|
|
b83831df1f | ||
|
|
f540b93706 | ||
|
|
8466336104 | ||
|
|
f88f1b40ce | ||
|
|
386a7b52d5 | ||
|
|
2e885de796 | ||
|
|
687c04cbb8 | ||
|
|
40c931de4b | ||
|
|
93bc7ef165 | ||
|
|
ee2d190253 | ||
|
|
aedb930cfc | ||
|
|
c596ce91cd | ||
|
|
c01e1a96aa | ||
|
|
8a64969404 | ||
|
|
c254f75bbb | ||
|
|
86692c019c | ||
|
|
1ab1c4ef57 | ||
|
|
926fb62eec | ||
|
|
817690ff73 | ||
|
|
98e1c935a1 | ||
|
|
f30e9976d6 | ||
|
|
80e98aed69 | ||
|
|
6a24cb3d22 | ||
|
|
e13b9e7885 | ||
|
|
dd467d33d0 | ||
|
|
c6b8f4d0c9 | ||
|
|
95240b8093 | ||
|
|
2f962d0a91 | ||
|
|
3c63e1bb57 | ||
|
|
c471b34575 | ||
|
|
d045f0bdb7 | ||
|
|
22becac4bd | ||
|
|
9d632b1b27 | ||
|
|
95c5e10103 | ||
|
|
a5d09d684e | ||
|
|
8aab976bbd | ||
|
|
26c6d1922e | ||
|
|
cd1bb54990 | ||
|
|
d4cd06138c | ||
|
|
961c5cbf17 | ||
|
|
b65e5bb72f | ||
|
|
54914380c0 | ||
|
|
26ccc68bed | ||
|
|
ee3d5a6d47 | ||
|
|
46fde8a1a2 | ||
|
|
fe1d858e35 | ||
|
|
fc42bc6ec9 | ||
|
|
fe6ad195ae | ||
|
|
7193650641 | ||
|
|
5db34f680f | ||
|
|
a82ba8d0ce | ||
|
|
3706fb5dc8 | ||
|
|
08bea4adde | ||
|
|
4c917d0314 | ||
|
|
4866b72eb2 | ||
|
|
2d00be0477 | ||
|
|
3d09aa4c82 | ||
|
|
c44c7895b8 | ||
|
|
8de28761c4 | ||
|
|
711762f0b7 | ||
|
|
5773803961 | ||
|
|
140359fc2c | ||
|
|
8ddf48d59f | ||
|
|
2e40a12225 | ||
|
|
dade7245af | ||
|
|
1f9fb20fcd | ||
|
|
0940c5b4c6 | ||
|
|
42ca72dff3 | ||
|
|
2949a6cda9 | ||
|
|
882fc9052e | ||
|
|
9b166fc1f8 | ||
|
|
d4364f30bd | ||
|
|
857421024d | ||
|
|
80faa7a152 | ||
|
|
545a23f11b | ||
|
|
caedb0721e | ||
|
|
47024eb564 | ||
|
|
9c58885c70 | ||
|
|
9fbd4b35a2 | ||
|
|
05b476a270 | ||
|
|
4395ca2e04 | ||
|
|
19f93d906e | ||
|
|
57565375c8 | ||
|
|
eb11cbe867 | ||
|
|
53407e3f38 | ||
|
|
f102819463 | ||
|
|
b942db3dc3 | ||
|
|
78f9fb902b | ||
|
|
d8fef8faac | ||
|
|
8ea6bd2802 | ||
|
|
c659022b5c | ||
|
|
8ca2e93e1a | ||
|
|
5600e214c3 | ||
|
|
6400f8ec0f | ||
|
|
c3a4e2ec40 | ||
|
|
e28c794699 | ||
|
|
da9f180835 | ||
|
|
6b8ce312e3 | ||
|
|
de3fc356e1 | ||
|
|
d0fed4ac02 | ||
|
|
7ce50a355c | ||
|
|
9612f23399 | ||
|
|
cccedc1aa4 | ||
|
|
c430802e32 | ||
|
|
cb4e421901 | ||
|
|
8e97596b7b | ||
|
|
92085e7099 | ||
|
|
c6aa838b51 | ||
|
|
9f5e8d16b3 | ||
|
|
82c06a40ac | ||
|
|
4423eba49b | ||
|
|
5b4c54631a | ||
|
|
5a1a2e9454 | ||
|
|
f005f96ea5 | ||
|
|
5e39123b3b | ||
|
|
393ca8c94d | ||
|
|
f817adc468 | ||
|
|
6c91a5a7f5 | ||
|
|
749b09616d | ||
|
|
5de5ab89b4 | ||
|
|
1d67c96640 | ||
|
|
d1c694ea4a | ||
|
|
06368a232a | ||
|
|
8a7bbd1606 | ||
|
|
131d05033b | ||
|
|
1806a75415 | ||
|
|
659ffe204c | ||
|
|
4647fd8910 | ||
|
|
d492dad8f4 | ||
|
|
3368d70dce | ||
|
|
0e1b2566ff | ||
|
|
369e60162e | ||
|
|
d5e7657fe2 | ||
|
|
f84ce1ebaf | ||
|
|
12bc242944 | ||
|
|
88060cce10 | ||
|
|
272e4db5c7 | ||
|
|
6e21cc3b67 | ||
|
|
0391bc8176 | ||
|
|
3b9264a049 | ||
|
|
2b3c254678 | ||
|
|
287be8c615 | ||
|
|
953fed280f | ||
|
|
e2ff3df314 | ||
|
|
31208a07c2 | ||
|
|
ac7a1b0dfb | ||
|
|
c246773599 | ||
|
|
25cd56a715 | ||
|
|
82c18e2a53 | ||
|
|
d5d38d16ae | ||
|
|
e1cbf33573 | ||
|
|
2ffe3bc14b | ||
|
|
d5867276a9 | ||
|
|
f665ef8fc5 | ||
|
|
b264c21302 | ||
|
|
349b3a2ea0 | ||
|
|
87813a8570 | ||
|
|
aab135516b | ||
|
|
141ba36996 | ||
|
|
d434ca5448 | ||
|
|
94e507aea7 | ||
|
|
3ebc121293 | ||
|
|
41ebd6530b | ||
|
|
2ec7b7b79b | ||
|
|
60ed60353b | ||
|
|
586f1cc532 | ||
|
|
73eb13dfc7 | ||
|
|
ed1269000f | ||
|
|
689fb748ee | ||
|
|
1721fef28b | ||
|
|
364ca0582e | ||
|
|
133a2b4ac2 | ||
|
|
d85187eb74 | ||
|
|
cc1ac11017 | ||
|
|
73f536439e | ||
|
|
b17e7d9a9b | ||
|
|
2f29b758e0 | ||
|
|
482aa3fecc | ||
|
|
d9c19db340 | ||
|
|
6c4d243de5 | ||
|
|
d1561ef777 | ||
|
|
7b4137c351 | ||
|
|
1072336249 | ||
|
|
75bb5c7028 | ||
|
|
376e1ad081 | ||
|
|
b58a22b963 | ||
|
|
47004d9579 | ||
|
|
12810c9cd3 | ||
|
|
7a459170fa | ||
|
|
3cf0df568a | ||
|
|
b88ebd472e | ||
|
|
64997815c4 | ||
|
|
3ecc527209 | ||
|
|
b1b7d1ffba | ||
|
|
4003bd82b0 | ||
|
|
8801255d7d | ||
|
|
3b18f539a7 | ||
|
|
c67a055d16 | ||
|
|
bc973e06d0 | ||
|
|
aeb3c8a0e8 | ||
|
|
cf33a47df0 | ||
|
|
daeb0f04cd | ||
|
|
97243fe395 | ||
|
|
9dbdb65abe | ||
|
|
9af461de35 | ||
|
|
4d71e200c6 | ||
|
|
8e0bdabed2 | ||
|
|
bca553caac | ||
|
|
a2f42a3baf | ||
|
|
7465222a9c | ||
|
|
e28034c5ac | ||
|
|
12bbd32ad0 | ||
|
|
266e466ee4 | ||
|
|
cf83f532ae | ||
|
|
cd019668dc | ||
|
|
515fc8776f | ||
|
|
c7c0996d8c | ||
|
|
b3e64671cc | ||
|
|
4abe214499 | ||
|
|
e94cb5ae7e | ||
|
|
e213c98df1 | ||
|
|
1639282434 | ||
|
|
be0e5dbd83 | ||
|
|
ad72917274 | ||
|
|
6a3f4c3f82 | ||
|
|
a6420bf50c | ||
|
|
eb387896e9 | ||
|
|
f43c163158 | ||
|
|
673bf566fc | ||
|
|
f95c5e1218 | ||
|
|
f33f32f159 | ||
|
|
8df5ae15d1 | ||
|
|
75b399f455 | ||
|
|
12439dd5ec | ||
|
|
3513d41436 | ||
|
|
cab792abe5 | ||
|
|
8870358b1b | ||
|
|
ee087c79ad | ||
|
|
51f579b635 | ||
|
|
c23c3d7d7d | ||
|
|
4abf617b9c | ||
|
|
3026164b16 | ||
|
|
9dd73ef4a4 | ||
|
|
75c72a1e67 | ||
|
|
08354db47b | ||
|
|
027eb5a6b0 | ||
|
|
f71264490c | ||
|
|
6270239a6d | ||
|
|
1195a38f46 | ||
|
|
66e289bab4 | ||
|
|
52c6f26cab | ||
|
|
dc534b674f | ||
|
|
f30c2e8e98 | ||
|
|
c482b3c69a | ||
|
|
266b0ad676 | ||
|
|
87f70ab39d | ||
|
|
8e636da499 | ||
|
|
22889ab175 | ||
|
|
5d2354f177 | ||
|
|
a41fb80ce1 | ||
|
|
2e2575e213 | ||
|
|
26c61e0809 | ||
|
|
e7a8c3032d | ||
|
|
725d1c58aa | ||
|
|
bd6742137f | ||
|
|
e8dcfa3d69 | ||
|
|
88720ed09b | ||
|
|
1e804244d0 | ||
|
|
198492bbf0 | ||
|
|
8f9d522f62 | ||
|
|
cbae233aba | ||
|
|
b17ca9c945 | ||
|
|
ebf4ca39ba | ||
|
|
e5e78797e6 | ||
|
|
080997b808 | ||
|
|
77306e8b97 | ||
|
|
6917d2a2f0 | ||
|
|
36c15522c1 | ||
|
|
804c343a4f | ||
|
|
cd5d75427e | ||
|
|
5ddc127da6 | ||
|
|
f859695b49 | ||
|
|
cb3d2eb9e9 | ||
|
|
33eae08f04 | ||
|
|
aa3f98677d | ||
|
|
fffccaaf41 | ||
|
|
cdc8d0c373 | ||
|
|
d14f0c45fc | ||
|
|
39955b0451 | ||
|
|
52dfb7ffe2 | ||
|
|
93462856e1 | ||
|
|
615f155a3a | ||
|
|
fcd9e423ec | ||
|
|
db8f2bfd99 | ||
|
|
55801fc76e | ||
|
|
d3d89c3256 | ||
|
|
8875b3d572 | ||
|
|
aabc2be693 | ||
|
|
c9afb51cea | ||
|
|
c0a656876c | ||
|
|
17a647630b | ||
|
|
c88e118b3c | ||
|
|
ae6a802106 | ||
|
|
b184f94413 | ||
|
|
ee3ec091f4 | ||
|
|
ef49b59053 | ||
|
|
1f8125805e | ||
|
|
efd712c69b | ||
|
|
109a4156e1 | ||
|
|
678d33295b | ||
|
|
5e58956d0a | ||
|
|
e276fd2cb3 | ||
|
|
9b22cb10c4 | ||
|
|
8ca31a0e05 | ||
|
|
20149a5da1 | ||
|
|
054d43bb11 | ||
|
|
65488b820c | ||
|
|
c3c9f87954 | ||
|
|
56f447be9f | ||
|
|
79fa9db0da | ||
|
|
071c10137b | ||
|
|
a4962b80d6 | ||
|
|
5307c33232 | ||
|
|
1b660cce12 | ||
|
|
8df8c278b6 | ||
|
|
d7e8264517 | ||
|
|
f11c316347 | ||
|
|
f62e02c24f | ||
|
|
70113c38c9 | ||
|
|
3d8132f5e2 | ||
|
|
39affb5aa4 | ||
|
|
a882c5f474 | ||
|
|
61a7ff1622 | ||
|
|
42e7373bd3 | ||
|
|
e269d3ae7d | ||
|
|
e7ddaef5bd | ||
|
|
62984e4584 | ||
|
|
3c53455d15 | ||
|
|
bbb43a39fd | ||
|
|
43e7d3c945 | ||
|
|
2f72e83bbd | ||
|
|
57179b4ca1 | ||
|
|
4bc8eec4eb | ||
|
|
baf510bf8c | ||
|
|
6d53cdd6ce | ||
|
|
ebbf078c7d | ||
|
|
95e431e9ec | ||
|
|
eba470f2f2 | ||
|
|
11addc50ff | ||
|
|
e4df2f98cc | ||
|
|
e7c14660d3 | ||
|
|
90076b6172 | ||
|
|
28b83495d8 | ||
|
|
551c7837ac | ||
|
|
59e6acc757 | ||
|
|
9990c960f2 | ||
|
|
2006a06eff | ||
|
|
2b6bda1ed8 | ||
|
|
468083d2f5 | ||
|
|
483fc223bb | ||
|
|
66ce97024d | ||
|
|
8c97f81943 | ||
|
|
d7c1630570 | ||
|
|
5e1a5ac8de | ||
|
|
9eb4ab6ad9 | ||
|
|
4932a817a0 | ||
|
|
5d003e29b1 | ||
|
|
dc95bd503e | ||
|
|
f738dd7b7c | ||
|
|
f908b74fa3 | ||
|
|
c687ac745b | ||
|
|
912e0b7e46 | ||
|
|
03bc7237ad | ||
|
|
061f62da54 | ||
|
|
dd565ac1ad | ||
|
|
5cdefc4625 | ||
|
|
ce00af8767 | ||
|
|
51047444aa | ||
|
|
aa6cd05ed8 | ||
|
|
dac14bf311 | ||
|
|
05fe2594e4 | ||
|
|
26e1c3514f | ||
|
|
22c83245c5 | ||
|
|
7900aede14 | ||
|
|
f877c6ae5a | ||
|
|
ca681f7041 | ||
|
|
a01da8bbf8 | ||
|
|
f3a65d9636 | ||
|
|
559f4c550f | ||
|
|
03c635a4b5 | ||
|
|
34a4cd0a34 | ||
|
|
3b9b32f404 | ||
|
|
9c724a9802 | ||
|
|
7a6e8a1b17 | ||
|
|
369c12e038 | ||
|
|
0fa5795b85 | ||
|
|
c00c7c0af0 | ||
|
|
cbaed4bb5e | ||
|
|
f74a7348f6 | ||
|
|
8626b23e4e | ||
|
|
0086874277 | ||
|
|
7fc18d9309 | ||
|
|
974f1a385a | ||
|
|
6900b4f6f5 | ||
|
|
d90e4bdb74 | ||
|
|
276c989772 | ||
|
|
ea99110d24 | ||
|
|
221a59fe6f | ||
|
|
eaa5646483 | ||
|
|
041bc3adc5 | ||
|
|
e64b756943 | ||
|
|
201ea3ee8e | ||
|
|
9303ce3e69 | ||
|
|
06c085ab6e | ||
|
|
c576ef1e7c | ||
|
|
11bed5827d | ||
|
|
fab83e2456 | ||
|
|
1d25e9d173 | ||
|
|
9c21f22923 | ||
|
|
3aa697f993 | ||
|
|
8b9848ac56 | ||
|
|
8b8c1093b6 | ||
|
|
d0d6c097fc | ||
|
|
6be5e46994 | ||
|
|
45694b504a | ||
|
|
41dbc50f9c | ||
|
|
4d2ad866f3 | ||
|
|
3cafca04aa | ||
|
|
594f51b859 | ||
|
|
fb56131dd9 | ||
|
|
a34e19629c | ||
|
|
3c12a027d4 | ||
|
|
cb28e03386 | ||
|
|
7393746da2 | ||
|
|
6828c809e4 | ||
|
|
28479149cc | ||
|
|
237c03c8ea | ||
|
|
e73c85cb23 | ||
|
|
b6b2711298 | ||
|
|
3b7130439a | ||
|
|
2c919adb74 | ||
|
|
60231c65b9 | ||
|
|
f196047832 | ||
|
|
240ca32e57 | ||
|
|
fa37c26c4d | ||
|
|
d7dbfc7cc1 | ||
|
|
d9ab5262b1 | ||
|
|
fb124e3741 | ||
|
|
479bf783d2 | ||
|
|
f0f3a6c99d | ||
|
|
f57b7835e2 | ||
|
|
1df3186e0e | ||
|
|
0b7c27828d | ||
|
|
0a19d4ccd6 | ||
|
|
9f3da13860 | ||
|
|
bf812ef714 | ||
|
|
b1ac38fadc | ||
|
|
fb0d12c6cb | ||
|
|
34952f09e1 | ||
|
|
34a7de2970 | ||
|
|
0ff827419e | ||
|
|
b29440aee6 | ||
|
|
11b5605815 | ||
|
|
844587669e | ||
|
|
f6c3664d71 | ||
|
|
c5864a8ce6 | ||
|
|
27c7114af6 | ||
|
|
0791ac1b44 | ||
|
|
1de5cd3ba5 | ||
|
|
729accb482 | ||
|
|
942acef594 | ||
|
|
fb2f339fec | ||
|
|
98044462b1 | ||
|
|
0dcb318f62 | ||
|
|
f32143469f | ||
|
|
3a30508b94 | ||
|
|
e0b9d78fab | ||
|
|
8d6765cf48 | ||
|
|
12bb392a0f | ||
|
|
08df685fe7 | ||
|
|
c8d1be772d | ||
|
|
887e9bc7b5 | ||
|
|
9f2e7c2f34 | ||
|
|
d7bb8884af | ||
|
|
464e792496 | ||
|
|
18c3281f9e | ||
|
|
8e2b1be127 | ||
|
|
b61b7787cb | ||
|
|
b465083f45 | ||
|
|
154655a85a | ||
|
|
59e89e62d7 | ||
|
|
d5d7bdaeb5 | ||
|
|
b2f82948ee | ||
|
|
428e4e4a85 | ||
|
|
1e83741c9a | ||
|
|
621d6a9516 | ||
|
|
3550821fb4 | ||
|
|
5b0c40da24 | ||
|
|
e0ac521438 | ||
|
|
c29458f3ec | ||
|
|
bf94d763ba | ||
|
|
8a37aa1517 | ||
|
|
f3d24df6f2 | ||
|
|
fd5d8270dc | ||
|
|
be612d9e0c | ||
|
|
4a7434d0b0 | ||
|
|
ad2141be2d | ||
|
|
f94639fadf | ||
|
|
89faae660f | ||
|
|
0f422256d6 | ||
|
|
acc1adbe7a | ||
|
|
8002ac9e0a | ||
|
|
6d30cf04db | ||
|
|
430b092a5f | ||
|
|
3eb5fdb581 | ||
|
|
9663bd3abb | ||
|
|
5a4d9ddb21 | ||
|
|
3be3c622dc | ||
|
|
cd6b555e19 | ||
|
|
671302b5c0 | ||
|
|
4f34cdb0a8 | ||
|
|
bd690a9f93 | ||
|
|
51f267d9d4 | ||
|
|
47f53ad958 | ||
|
|
c73cdd800f | ||
|
|
f535ec8278 | ||
|
|
238755752f | ||
|
|
c71a3195af | ||
|
|
54a9328b20 | ||
|
|
3e48522477 | ||
|
|
251a44b776 | ||
|
|
be7a8379b4 | ||
|
|
defce60385 | ||
|
|
354b4b8604 | ||
|
|
5b7dab2dd6 | ||
|
|
8a5601e42f | ||
|
|
232541df44 | ||
|
|
a346b1ff57 | ||
|
|
d96d604e53 | ||
|
|
e704f87f86 | ||
|
|
8f5639afcb | ||
|
|
03950c90f7 | ||
|
|
47a8b7c14a | ||
|
|
2a04d2c799 | ||
|
|
8de922724b | ||
|
|
67b8a28a2f | ||
|
|
51a575159a | ||
|
|
524229a297 | ||
|
|
754e70cf3e | ||
|
|
84bc4dcb0f | ||
|
|
10eaa8ef1d | ||
|
|
c3124c3085 | ||
|
|
8d5b8b477e | ||
|
|
d7d2a9a3db | ||
|
|
25a4c5a9ed | ||
|
|
5c45bbe57b | ||
|
|
d41d04c0f5 | ||
|
|
e422d7f4f7 | ||
|
|
cdc682d5a4 | ||
|
|
9cc93c64aa | ||
|
|
fa7a1cc5ef | ||
|
|
17712eeb19 | ||
|
|
41c3a5a7be | ||
|
|
8765222d22 | ||
|
|
645f814544 | ||
|
|
308cfe0ab3 | ||
|
|
e5e8d20a3a | ||
|
|
a107193e4b | ||
|
|
55eae65b39 | ||
|
|
3f125c8c70 | ||
|
|
75e8b2ac87 | ||
|
|
ee114368ad | ||
|
|
525a87f58e | ||
|
|
44cae2fb2e | ||
|
|
30a453884e | ||
|
|
3b58d94f71 | ||
|
|
8abb86fec4 | ||
|
|
16a089780e | ||
|
|
09b6468d30 | ||
|
|
80fb6d4aa4 | ||
|
|
1f04873517 | ||
|
|
799207e838 | ||
|
|
34866b4836 | ||
|
|
be530dfea2 | ||
|
|
d12a1a47d5 | ||
|
|
8d42e3501e | ||
|
|
2711e41bcd | ||
|
|
5e1eddb939 | ||
|
|
23e7f53bd3 | ||
|
|
000b6b5ae5 | ||
|
|
864f24bd2c | ||
|
|
5d8df28d27 | ||
|
|
f9a5affad9 | ||
|
|
ab81ef8fa7 | ||
|
|
95d8f7ea12 | ||
|
|
5316bf7487 | ||
|
|
a6f774e901 | ||
|
|
f171bc8b59 | ||
|
|
289bbb350e | ||
|
|
d247a2c8bf | ||
|
|
88ed52aec9 | ||
|
|
cb23bcba29 | ||
|
|
2c7ed24796 | ||
|
|
4c6bd5b5b6 | ||
|
|
aeb7b41d44 | ||
|
|
5bdec59de1 | ||
|
|
dfaba1ab95 | ||
|
|
a62fd1af27 | ||
|
|
7a89681722 | ||
|
|
51da40e621 | ||
|
|
d8f0a9ecea | ||
|
|
cf7e015f25 | ||
|
|
1af330f29f | ||
|
|
9afa1770d1 | ||
|
|
3ebbcce1c7 | ||
|
|
2c7c721933 | ||
|
|
7523647391 | ||
|
|
9700cd9097 | ||
|
|
eab7faa0c1 | ||
|
|
a56c1e38c7 | ||
|
|
40a2d17052 | ||
|
|
b14fa8e687 | ||
|
|
678e436f2e | ||
|
|
ff81c4c99c | ||
|
|
420658e6cb | ||
|
|
593ddd851b | ||
|
|
1243402657 | ||
|
|
1a117a7728 | ||
|
|
2b2ee140c3 | ||
|
|
d97f5cd795 | ||
|
|
f3f0b8e403 | ||
|
|
660f9459da | ||
|
|
10952eb2cf | ||
|
|
cdad742700 | ||
|
|
a9e8f60ef6 | ||
|
|
a8b7b26068 | ||
|
|
ba911137fa | ||
|
|
d3f007af18 | ||
|
|
2929fa0e79 | ||
|
|
297a564bee | ||
|
|
53b8247cb5 | ||
|
|
59db9f8018 | ||
|
|
b73b14f72c | ||
|
|
41597d9bed | ||
|
|
b37317d8b0 | ||
|
|
87dc451108 | ||
|
|
ca4456eda8 | ||
|
|
993df6bc22 | ||
|
|
61be92e26a | ||
|
|
c59b61c0da | ||
|
|
3e214851a4 | ||
|
|
a47b602b08 | ||
|
|
a083b859e4 | ||
|
|
948199deac | ||
|
|
c356620ec1 | ||
|
|
f79ebf09a2 | ||
|
|
c7620992d2 | ||
|
|
ce1bafdce9 | ||
|
|
9872e588c8 | ||
|
|
d609edf4f1 | ||
|
|
3a99d321a8 | ||
|
|
4bb3d999ac | ||
|
|
40101dc311 | ||
|
|
e9c6deffee | ||
|
|
9c29bc69f7 | ||
|
|
1e12429564 | ||
|
|
795704f0f1 | ||
|
|
981b9cdc8c | ||
|
|
3f724339db | ||
|
|
70c857b728 | ||
|
|
9e7e0dffd5 | ||
|
|
c3dea3f878 | ||
|
|
f57f84f606 | ||
|
|
c84683c88b | ||
|
|
b68a2613f8 | ||
|
|
28afa6e77a | ||
|
|
496ce6b349 | ||
|
|
ce9512b78b | ||
|
|
4eb59a6b1c | ||
|
|
80b1ee0a4c | ||
|
|
f993afb26d | ||
|
|
7c80519cbf | ||
|
|
8250c32f49 | ||
|
|
2fe1ff8582 | ||
|
|
17ee98e1a5 | ||
|
|
2ee8f5d80f | ||
|
|
3f302bca8c | ||
|
|
c909e5820e | ||
|
|
a1b85269a4 | ||
|
|
faa1f83ab4 | ||
|
|
308c505c3d | ||
|
|
0eacd2aaae | ||
|
|
18ae46ad4b | ||
|
|
65c2b21df1 | ||
|
|
772acaf31f | ||
|
|
f8d0745e27 | ||
|
|
d719c6a5ab | ||
|
|
769efa16af | ||
|
|
86b4e98ac6 | ||
|
|
3bf8c316a6 | ||
|
|
e37c92ec6d | ||
|
|
a5dd9a0c5d | ||
|
|
7a4a945f13 | ||
|
|
1d18e26eca | ||
|
|
ac4b8df5e4 | ||
|
|
3bc9fb5889 | ||
|
|
632cbb8efa | ||
|
|
789a12aaaf | ||
|
|
ecdbe09e10 | ||
|
|
1dc31c2786 | ||
|
|
32470bf619 | ||
|
|
8b61bfd638 | ||
|
|
8a7a208905 | ||
|
|
0215103e92 | ||
|
|
c2d1be8981 | ||
|
|
4951c9f821 | ||
|
|
726adc43ec | ||
|
|
3c6ae8b59e | ||
|
|
605be3f7f8 | ||
|
|
c51bc70e0f | ||
|
|
e89d7e3029 | ||
|
|
3c07a729a6 | ||
|
|
84c0ed50a5 | ||
|
|
02c126a7c2 | ||
|
|
114ed20e64 | ||
|
|
4b0f45f667 | ||
|
|
36068ae019 | ||
|
|
9d681c2bb3 | ||
|
|
3af1fac7b0 | ||
|
|
761ee0d827 | ||
|
|
fb8bc3f818 | ||
|
|
826a7da808 | ||
|
|
cbd55ade68 | ||
|
|
5705ee6ef8 | ||
|
|
3f5c6d0c1b | ||
|
|
bfed4813b2 | ||
|
|
e58066e244 | ||
|
|
ee48b6a88f | ||
|
|
9ac09ed4de | ||
|
|
22603348aa | ||
|
|
fec73daaa3 | ||
|
|
c6b68648f4 | ||
|
|
1ecb5d1d83 | ||
|
|
dc786d3db5 | ||
|
|
74fe23ec35 | ||
|
|
b0bff54b08 | ||
|
|
1b541d8d6e | ||
|
|
f29ac588dd | ||
|
|
0696667734 | ||
|
|
1793d71db6 | ||
|
|
4211e1941b | ||
|
|
4bdfef5a18 | ||
|
|
8a37f53685 | ||
|
|
4e1ad6e9a8 | ||
|
|
fb10e1aa57 | ||
|
|
3c283a381e | ||
|
|
dac4d5be12 | ||
|
|
530857182d | ||
|
|
9441f77faa | ||
|
|
3cc8b4c327 | ||
|
|
6b19647d57 | ||
|
|
7bd42d0d96 | ||
|
|
c60e8cfaf7 | ||
|
|
7fd002c006 | ||
|
|
db6c50f109 | ||
|
|
aa4789d632 | ||
|
|
ee8de13e14 | ||
|
|
7dde5f6a8d | ||
|
|
736f003f2e | ||
|
|
47af21e8f1 | ||
|
|
605cbef653 | ||
|
|
388ad0c05c | ||
|
|
2ebbb6f1f7 | ||
|
|
d54f1c7477 | ||
|
|
b78f5ec4c3 | ||
|
|
9fd3bf04b7 | ||
|
|
e97bb3de83 | ||
|
|
c2daf8dfa4 | ||
|
|
09b718c439 | ||
|
|
c177bb3a50 | ||
|
|
977a247a06 | ||
|
|
899a3e2f13 | ||
|
|
8ee4ecb48d | ||
|
|
f7e6f7fa23 | ||
|
|
1f80e360fc | ||
|
|
d7011316d0 | ||
|
|
d3671b344f | ||
|
|
a60cccbf9f | ||
|
|
3e72f5f10e | ||
|
|
b94b78971c | ||
|
|
4d08161ac2 | ||
|
|
8954e48140 | ||
|
|
aa99aa4e85 | ||
|
|
d79febcd06 | ||
|
|
13fc7f3a05 | ||
|
|
14309e1ddc | ||
|
|
5513967926 | ||
|
|
eacd875f3b | ||
|
|
c4fe07c7af | ||
|
|
1186e3f91a | ||
|
|
f354385bf5 | ||
|
|
cabe001590 | ||
|
|
89f691e141 | ||
|
|
4a63291144 | ||
|
|
593b77064c | ||
|
|
9fefc88656 | ||
|
|
eb08081330 | ||
|
|
a3bfddfa5e | ||
|
|
36da48798a | ||
|
|
a0f28f90fa | ||
|
|
851229a01f | ||
|
|
c9c854cea7 | ||
|
|
a38436e889 | ||
|
|
23fc384f2c | ||
|
|
1540119723 | ||
|
|
574f42d79a | ||
|
|
536b0700b0 | ||
|
|
5ba761eb85 | ||
|
|
611ac379bb | ||
|
|
03f32a7ead | ||
|
|
50ea2bb20d | ||
|
|
525daedd5a | ||
|
|
e118031ef8 | ||
|
|
45eedbe58c | ||
|
|
e37c932fca | ||
|
|
5eb778bf4d | ||
|
|
ab9b890b52 | ||
|
|
31c746e5dc | ||
|
|
f01f731107 | ||
|
|
70f0f5a8ca | ||
|
|
cc357c4db8 | ||
|
|
97f4aecfc1 | ||
|
|
2af0f87c8b | ||
|
|
b062d94eef | ||
|
|
6c1b0c0ed2 | ||
|
|
ddcdc684e2 | ||
|
|
eae89f92e6 | ||
|
|
01d115b06b | ||
|
|
79057965a8 | ||
|
|
dcd4d95c8e | ||
|
|
cf61d96df0 | ||
|
|
f8da79f828 | ||
|
|
9750e7d70e | ||
|
|
50aa2bb6b9 | ||
|
|
1d1dd597ed | ||
|
|
cfe5537ee5 | ||
|
|
7869eb3fc4 | ||
|
|
6dfa0602f0 | ||
|
|
f870544302 | ||
|
|
75a40b2251 | ||
|
|
28fb109ed0 | ||
|
|
48607afac5 | ||
|
|
b6ea9ef21a | ||
|
|
b8dd44baa9 | ||
|
|
c4f1fde75b | ||
|
|
667170e2c7 | ||
|
|
53429e6551 | ||
|
|
ac8f97f2b3 | ||
|
|
41c0d2f8cb | ||
|
|
1f3a43dbe6 | ||
|
|
369e195a44 | ||
|
|
15006fedb9 | ||
|
|
e35b23f54d | ||
|
|
f72b0a6032 | ||
|
|
ac9ed061ec | ||
|
|
d919fa3344 | ||
|
|
79913fde35 | ||
|
|
da634d0a8b | ||
|
|
fac54cb426 | ||
|
|
3f19b9b7c1 | ||
|
|
dc48695ab9 | ||
|
|
0a31a35098 | ||
|
|
86f2541695 | ||
|
|
181c4ccaaa | ||
|
|
ed848087d5 | ||
|
|
edd66be5be | ||
|
|
246995dbc8 | ||
|
|
b931fbe5ab | ||
|
|
e014ff015d | ||
|
|
4fa5f40232 | ||
|
|
9b15be97aa | ||
|
|
a7ada46bd9 | ||
|
|
9d16788ad9 | ||
|
|
6ce89aecc3 | ||
|
|
963d0ce7e3 | ||
|
|
0f08d7f851 | ||
|
|
44c514eb9c | ||
|
|
513cbdda93 | ||
|
|
e1ba152352 | ||
|
|
446e764500 | ||
|
|
901d00caa6 | ||
|
|
094790d2c9 | ||
|
|
1c0163a5cc | ||
|
|
8fa7e5817a | ||
|
|
01b89d5682 | ||
|
|
9f01c1a803 | ||
|
|
46f0f50016 | ||
|
|
b8070dbbd7 | ||
|
|
3b16d803c9 | ||
|
|
de195c23a6 | ||
|
|
d3b8908886 | ||
|
|
2688176c77 | ||
|
|
a5839317aa | ||
|
|
a0aab26a41 | ||
|
|
27713812a0 | ||
|
|
cf2c5fda4f | ||
|
|
a9684c0dbf | ||
|
|
c0bf5e1c4d | ||
|
|
a31e3e7dcb | ||
|
|
17b41a3337 | ||
|
|
89a683ae74 | ||
|
|
008661069b | ||
|
|
9296e92e1c | ||
|
|
a34af8d066 | ||
|
|
8726e04629 | ||
|
|
2a01c940ec | ||
|
|
4eab60cbd2 | ||
|
|
a0e060ac1e | ||
|
|
397a8ea96e | ||
|
|
15830339ef | ||
|
|
b29280285e | ||
|
|
1633491bff | ||
|
|
2b0fa1f7dd | ||
|
|
02b386f80a | ||
|
|
bf20b9c540 | ||
|
|
06a12933f3 | ||
|
|
6dd94d3a79 | ||
|
|
f2f89c762a | ||
|
|
e6c2d9ad29 | ||
|
|
83423254cc | ||
|
|
1c20ddc966 | ||
|
|
675e9f22ea | ||
|
|
77c6fb5b24 | ||
|
|
082a0140ef | ||
|
|
9e535ce055 | ||
|
|
d76dea001b | ||
|
|
af0f9b0e95 | ||
|
|
e2082ea942 | ||
|
|
68923e52a3 | ||
|
|
9281f6d253 | ||
|
|
4647845679 | ||
|
|
cf9cf7dd04 | ||
|
|
1316b54956 | ||
|
|
cbc1fadd6f | ||
|
|
4dd09c9add | ||
|
|
267dc07e6b | ||
|
|
d7b4d5dd50 | ||
|
|
7f220b2fac | ||
|
|
275c0423aa | ||
|
|
d3ee4bbc5a | ||
|
|
85a064861f | ||
|
|
d0b436bff2 | ||
|
|
92b2f18072 | ||
|
|
dfc4eca21f | ||
|
|
fc7ae675e2 | ||
|
|
804ad79985 | ||
|
|
da839880e9 | ||
|
|
e9d33454b5 | ||
|
|
d80891efc4 | ||
|
|
37c1e4025c | ||
|
|
59a83d3e5b | ||
|
|
13af92fdc4 | ||
|
|
0c20ee7d4b | ||
|
|
89d42c2c75 | ||
|
|
04611765a4 | ||
|
|
9dfc4fa1a1 | ||
|
|
43232d5c14 | ||
|
|
f7c272d4fa | ||
|
|
ede21449c8 | ||
|
|
bb8e553662 | ||
|
|
f5f4a27a96 | ||
|
|
d7c9a3e976 | ||
|
|
35eb649e9d | ||
|
|
e56a4c9e9b | ||
|
|
95506e37af | ||
|
|
e41840c522 | ||
|
|
2a46a27e6c | ||
|
|
0bcdc27653 | ||
|
|
ddf0f74de7 | ||
|
|
91b21b2334 | ||
|
|
66e568de3b | ||
|
|
f5ca97e393 | ||
|
|
8d06a62485 | ||
|
|
93f9420993 | ||
|
|
5b61070c70 | ||
|
|
dbe1a93526 | ||
|
|
aa5d9a79d6 | ||
|
|
86511ea417 | ||
|
|
1866432db7 | ||
|
|
cf2ac6df68 | ||
|
|
33f1f81b8b | ||
|
|
9d0b581fea | ||
|
|
c05724cb18 | ||
|
|
f0714c9f86 | ||
|
|
cf386750c9 | ||
|
|
54f428f645 | ||
|
|
dc2bd20e55 | ||
|
|
c608ee491f | ||
|
|
0130afb76e | ||
|
|
738b926322 | ||
|
|
bea41c7f3f | ||
|
|
1bbe660dfa | ||
|
|
c4bd188da4 | ||
|
|
5acfa126c8 | ||
|
|
67134eaba1 | ||
|
|
5414623791 | ||
|
|
c93d53f5e3 | ||
|
|
507683780e | ||
|
|
e8b9ee5e08 | ||
|
|
d16154d163 | ||
|
|
c342041fba | ||
|
|
bf42a9906d | ||
|
|
9603e8a7d9 | ||
|
|
c7c040b825 | ||
|
|
ac0474f89d | ||
|
|
bb512e57dc | ||
|
|
db652ea186 | ||
|
|
5a9cc19972 | ||
|
|
1a5fd4eebc | ||
|
|
8a1b49ff19 | ||
|
|
b971abe897 | ||
|
|
43b925ce74 | ||
|
|
62b742ece3 | ||
|
|
d16ef949ca | ||
|
|
23e7cba87f | ||
|
|
a8e6f30d8e | ||
|
|
9c49410898 | ||
|
|
802d74aa6b | ||
|
|
71f9e49e67 | ||
|
|
82ea1051b5 | ||
|
|
6c4d20cd6f | ||
|
|
04c27802c0 | ||
|
|
c3b7202f4f | ||
|
|
81103ef35d | ||
|
|
0eb5c1c62a | ||
|
|
a9de951744 | ||
|
|
a42a1bb09d | ||
|
|
9fbfc9bd4d | ||
|
|
242a998bdc | ||
|
|
9d1bf70234 | ||
|
|
b8c1cc1a51 | ||
|
|
eedd20ef96 | ||
|
|
7c197ad96d | ||
|
|
654fd03c73 | ||
|
|
cee16e0fa3 | ||
|
|
73c471e9ef | ||
|
|
533b99fbf9 | ||
|
|
f39eb98bab | ||
|
|
da77d856a1 | ||
|
|
b2575b38e7 | ||
|
|
0a3cf9ad3d | ||
|
|
00334d0de0 | ||
|
|
226b886ca8 | ||
|
|
bc93bdb5bb | ||
|
|
af214c3a79 | ||
|
|
4eb10f6621 | ||
|
|
7d7d469025 | ||
|
|
fd40bdc0be | ||
|
|
7e0480ae0e | ||
|
|
d80265ccd6 | ||
|
|
1b5a1ae257 | ||
|
|
d8d24a922a | ||
|
|
03339b7b5b | ||
|
|
2028c6e03d | ||
|
|
2988835af5 | ||
|
|
62cca96b72 | ||
|
|
b4dea075a3 | ||
|
|
533f67d3fa | ||
|
|
906e2f0eac | ||
|
|
b8091db6b9 | ||
|
|
381c067755 | ||
|
|
2182ab5187 | ||
|
|
a1593a4a0e | ||
|
|
aa5740fb61 | ||
|
|
da92eeae42 | ||
|
|
12e9e8445d | ||
|
|
8084be78c5 | ||
|
|
1ac1c4c26e | ||
|
|
d4f58034f7 | ||
|
|
f843300fe5 | ||
|
|
03b9c94437 | ||
|
|
a219d175c6 | ||
|
|
3c3b4176bd | ||
|
|
022383139b | ||
|
|
1a1251e877 | ||
|
|
18b5e1e534 | ||
|
|
2fece970b8 | ||
|
|
e20d0c1e69 | ||
|
|
a9dcf4a860 | ||
|
|
255f5694aa | ||
|
|
25701d5a2c | ||
|
|
a5158f38a3 | ||
|
|
c76799c555 | ||
|
|
2bb5b6d0a1 | ||
|
|
0bbba43ed0 | ||
|
|
98ca102441 | ||
|
|
3f3308cd75 | ||
|
|
6f96e308d0 | ||
|
|
756f574e4e | ||
|
|
78294e6a9c | ||
|
|
4e33577173 | ||
|
|
607841af64 | ||
|
|
396726244a | ||
|
|
c5895d5dbd | ||
|
|
b407e173e4 | ||
|
|
6a745c2c0f | ||
|
|
2da0cad6ae | ||
|
|
af1fa6234e | ||
|
|
c9ac7fa909 | ||
|
|
964afd0689 | ||
|
|
2a282a3b5f | ||
|
|
7bb23aeca4 | ||
|
|
de939d89eb | ||
|
|
77c975f536 | ||
|
|
75ab0ebcf5 | ||
|
|
10273d6e08 | ||
|
|
16d6973f8a | ||
|
|
edcd2d665b | ||
|
|
385c3e5e91 | ||
|
|
c8e337450b | ||
|
|
10464af5d1 | ||
|
|
cbcd1a5474 | ||
|
|
c9bebed294 | ||
|
|
d5552a3477 | ||
|
|
a8b081a052 | ||
|
|
9e96dc8b35 | ||
|
|
360075e28a | ||
|
|
accf79b107 | ||
|
|
4d58b24c15 | ||
|
|
c33a8639a7 | ||
|
|
25fa8d66e6 | ||
|
|
974a6146fe | ||
|
|
0392ac98d2 | ||
|
|
5e3915cbe3 | ||
|
|
29b809de68 | ||
|
|
8f73e89ca0 | ||
|
|
0d0d5d3717 | ||
|
|
a69e8bfdd9 | ||
|
|
062a3fdf36 | ||
|
|
028a33d7f2 | ||
|
|
14835de9fb | ||
|
|
447053668f | ||
|
|
f3aecb27a4 | ||
|
|
7f0172b3e5 | ||
|
|
79fe954d79 | ||
|
|
0501bfa159 | ||
|
|
a155b7e76c | ||
|
|
5228b756af | ||
|
|
04e7596680 | ||
|
|
f1e66cb2eb | ||
|
|
4fd35ee072 | ||
|
|
ee69799262 | ||
|
|
636a9637f4 | ||
|
|
9383e66f94 | ||
|
|
99e6833c85 | ||
|
|
c203be3fb4 | ||
|
|
02175a7986 | ||
|
|
8117df4cd9 | ||
|
|
7c7dd9dc7f | ||
|
|
054932f403 | ||
|
|
aed473ccf9 | ||
|
|
8268e94cd4 | ||
|
|
4af98ecdfb | ||
|
|
4b9f9010b0 | ||
|
|
2a0fcf6113 | ||
|
|
67d95f177c | ||
|
|
44773ad125 | ||
|
|
5774ef35c4 | ||
|
|
b95cfa9170 | ||
|
|
afa1ded425 | ||
|
|
00ac23e6e0 | ||
|
|
7d0c934a3e | ||
|
|
8f75761f24 | ||
|
|
9fd24e3a22 | ||
|
|
755a9d3d1a | ||
|
|
ac499cb61c | ||
|
|
180940e02d | ||
|
|
976b03c56b | ||
|
|
450d89ddc1 | ||
|
|
463b2e5542 | ||
|
|
70a2002399 | ||
|
|
a617b10075 | ||
|
|
0029071adb | ||
|
|
ad49fe7c8f | ||
|
|
49bc802f81 | ||
|
|
af9cdee9cb | ||
|
|
b4e1576aee | ||
|
|
78e2b74bb9 | ||
|
|
65d161c480 | ||
|
|
9fcbd5db2a | ||
|
|
4f3bf679f5 | ||
|
|
0072afca8e | ||
|
|
61aa5ba36e | ||
|
|
9f4323252a | ||
|
|
8b6c896c4b | ||
|
|
185dbc4974 | ||
|
|
3d535e0471 | ||
|
|
d22dec74ff | ||
|
|
9872d3110c | ||
|
|
b859971873 | ||
|
|
e5095f1198 | ||
|
|
499a077761 | ||
|
|
5da7177729 | ||
|
|
3507766bd0 | ||
|
|
f37bdbe537 | ||
|
|
2da09ff8b0 | ||
|
|
5ccddb7ecf | ||
|
|
954c1d0529 | ||
|
|
494f20cbdc | ||
|
|
29902c8ec0 | ||
|
|
9f15bdabc8 | ||
|
|
fff3455f58 | ||
|
|
87446dc618 | ||
|
|
99ac0390f5 | ||
|
|
ff0f0b9172 | ||
|
|
97b570a94c | ||
|
|
a9d56c6843 | ||
|
|
f98470df69 | ||
|
|
eb8be1fe76 | ||
|
|
8a1a26ce4c | ||
|
|
5bf3276e8d | ||
|
|
7ebd5376fe | ||
|
|
93dfcb9357 | ||
|
|
0c8662d2b6 | ||
|
|
d84f1d14b5 | ||
|
|
70219b0f43 | ||
|
|
bd5bc0cd5a | ||
|
|
6e054aacca | ||
|
|
9d581f3d52 | ||
|
|
9bf99891d0 | ||
|
|
d9cf48e81e | ||
|
|
e1b9322b09 | ||
|
|
627b964825 | ||
|
|
a55e36f48d | ||
|
|
01e21b89ee | ||
|
|
788be3313d | ||
|
|
e1ec93304d | ||
|
|
edb99d4c18 | ||
|
|
68477c3dab | ||
|
|
65ba8b23f4 | ||
|
|
621ed9f5f4 | ||
|
|
b26733ba7f | ||
|
|
9836cfb8d6 | ||
|
|
665b6c1236 | ||
|
|
9414338a48 | ||
|
|
de390ea077 | ||
|
|
717b0239fd | ||
|
|
d00735a0c5 | ||
|
|
c23d5ce926 | ||
|
|
b5a3c7f109 | ||
|
|
9c5f685ef1 | ||
|
|
08bb8ef201 | ||
|
|
865ab62f43 | ||
|
|
9948113590 | ||
|
|
c4ee87022b | ||
|
|
ffba4edb06 | ||
|
|
958d0b659b | ||
|
|
aacda28b28 | ||
|
|
29e7e0781b | ||
|
|
7012620e2b | ||
|
|
f1da861018 | ||
|
|
4da31bd566 | ||
|
|
05aa9c82d9 | ||
|
|
a9e58ecd3f | ||
|
|
223544552f | ||
|
|
3d8e9573a4 | ||
|
|
54eb81a087 | ||
|
|
c33c547d66 | ||
|
|
dfe7dd9bdb | ||
|
|
63ccf6474d | ||
|
|
e8ac61e840 | ||
|
|
f00a650705 | ||
|
|
4bde5ce992 | ||
|
|
d31573fa37 | ||
|
|
8b8cde2140 | ||
|
|
0e805e782b | ||
|
|
f5c78d118b | ||
|
|
9d4f213f90 | ||
|
|
168db222c6 | ||
|
|
3d6388e34e | ||
|
|
3ce9bc712a | ||
|
|
e52c0bd0eb | ||
|
|
56c837ccb7 | ||
|
|
423d2be5f8 | ||
|
|
453a1617aa | ||
|
|
b9258c6178 | ||
|
|
55e5841f14 | ||
|
|
ed15e9ba02 | ||
|
|
eedda32e6b | ||
|
|
4c8fea92f3 | ||
|
|
d073055dcd | ||
|
|
e4ac7bb1e5 | ||
|
|
9bac8c57e3 | ||
|
|
6800d3372f | ||
|
|
3153a2c98d | ||
|
|
15b74b94be | ||
|
|
687cb3ad35 | ||
|
|
8f94784124 | ||
|
|
23dd1fc74c | ||
|
|
fa971259e6 | ||
|
|
b0cda32f72 | ||
|
|
08b7968e28 | ||
|
|
4b5fe1349f | ||
|
|
d23da75b32 | ||
|
|
06e027992d | ||
|
|
b5597738d4 | ||
|
|
bc03e58565 | ||
|
|
a00234f1c5 | ||
|
|
34c0f95db2 | ||
|
|
fcb04bcaca | ||
|
|
9464a194db | ||
|
|
9f4b9118cc | ||
|
|
60158217ef | ||
|
|
923e79e2e4 | ||
|
|
866b296d0f | ||
|
|
4053ee9104 | ||
|
|
47fd8c2f76 | ||
|
|
96b9690985 | ||
|
|
df15ef8dab | ||
|
|
002c0fb511 | ||
|
|
7584e38ce4 | ||
|
|
eb47569f8a | ||
|
|
d2a9de78df | ||
|
|
c5138a7ce4 | ||
|
|
c5fa81fe81 | ||
|
|
a074e92296 | ||
|
|
1ddb9456c4 | ||
|
|
58bde34a23 | ||
|
|
339516072b | ||
|
|
931bc3c3a7 | ||
|
|
db1e9ee771 | ||
|
|
a2d971309b | ||
|
|
d05a1dbe70 | ||
|
|
a80601f8d9 | ||
|
|
1c22238756 | ||
|
|
9ff811c5cd | ||
|
|
1ebc05df91 | ||
|
|
386bdfa698 | ||
|
|
1ae7ff771b | ||
|
|
5196b98897 | ||
|
|
e6e63e91a7 | ||
|
|
b4dd98358f | ||
|
|
181c7053e3 | ||
|
|
4d454c5e4b | ||
|
|
5c2191a605 | ||
|
|
bba5bfc890 | ||
|
|
1a5b77dc21 | ||
|
|
b2cf6543b2 | ||
|
|
0385d64223 | ||
|
|
6ebdfe43e4 | ||
|
|
fafec39d41 | ||
|
|
670861bd20 | ||
|
|
08f7db20c1 | ||
|
|
605ec701b7 | ||
|
|
d6aa68ce75 | ||
|
|
eb6cb9fbe9 | ||
|
|
84e1e036c2 | ||
|
|
1498940b10 | ||
|
|
806598b94d | ||
|
|
e26be70bca | ||
|
|
ca45246627 | ||
|
|
f9355dc989 | ||
|
|
9e0b579128 | ||
|
|
ff4a1279f2 | ||
|
|
9b254aa177 | ||
|
|
703d78bbf5 | ||
|
|
d9446c7319 | ||
|
|
b25b645d51 | ||
|
|
d90b3854ca | ||
|
|
bf24c3d017 | ||
|
|
f0bfaa2d7d | ||
|
|
f9f3e3df9a | ||
|
|
f8d5e1cfb5 | ||
|
|
c23848b3c5 | ||
|
|
6d00a2dcd1 | ||
|
|
b535170b21 | ||
|
|
1434184c57 | ||
|
|
7a372b64df | ||
|
|
5406af92bc | ||
|
|
7d65242dc3 | ||
|
|
544a8693b7 | ||
|
|
35a4f24a37 | ||
|
|
ff305edd64 | ||
|
|
efec4358b9 | ||
|
|
db3ca36403 | ||
|
|
42833b44b5 | ||
|
|
5d0a33eebc | ||
|
|
ba2df04b41 | ||
|
|
c6bbdadd79 | ||
|
|
b885bae634 | ||
|
|
680f9744c4 | ||
|
|
2c935c0c72 | ||
|
|
7198063d96 | ||
|
|
d41ebe146b | ||
|
|
4b4e1af059 | ||
|
|
80240b347e | ||
|
|
04b3b3df05 | ||
|
|
2ad5708c43 | ||
|
|
63f3cab4ae | ||
|
|
8cdf03a7a2 | ||
|
|
d78c834ead | ||
|
|
05a976cd99 | ||
|
|
34fb7e46ad | ||
|
|
abac15f3c6 | ||
|
|
b700055ba4 | ||
|
|
23905927e1 | ||
|
|
56be5f1567 | ||
|
|
1807ae22dd | ||
|
|
71646e4653 | ||
|
|
1335c3aca8 | ||
|
|
30455ce255 | ||
|
|
9bf87ae3aa | ||
|
|
abca34cbc0 | ||
|
|
d386878af9 | ||
|
|
685c74d315 | ||
|
|
69e0f1b445 | ||
|
|
79979c6897 | ||
|
|
ba64547616 | ||
|
|
ed5a637d62 | ||
|
|
8a278a1d7e | ||
|
|
77d9cb2f04 | ||
|
|
0459432d96 | ||
|
|
43150d7ac3 | ||
|
|
afe8b594be | ||
|
|
878563c847 | ||
|
|
06947add03 | ||
|
|
5cd47a5e4f | ||
|
|
53de95da5e | ||
|
|
663004ac2b | ||
|
|
6ad9cb224a | ||
|
|
e7752cd578 | ||
|
|
4d2f42361e | ||
|
|
4d8ee01389 | ||
|
|
d01924f488 | ||
|
|
bc56355ec6 | ||
|
|
ac20d95f97 | ||
|
|
1a83c731bd | ||
|
|
ca57a59883 | ||
|
|
b0d619fde2 | ||
|
|
cc7051efd7 | ||
|
|
5137adb94d | ||
|
|
0b9f7cd074 | ||
|
|
2632941f32 | ||
|
|
137597b0ea | ||
|
|
051df9ad99 | ||
|
|
f670ef1c8e | ||
|
|
d9d747a06a | ||
|
|
b813d8caf1 | ||
|
|
ecee572411 | ||
|
|
1b0427e6c4 | ||
|
|
2aa64b89b3 | ||
|
|
484c9d2d5b | ||
|
|
5d8dcb5342 | ||
|
|
2328f2fe68 | ||
|
|
4f514c7e88 | ||
|
|
5bdc520cf1 | ||
|
|
fc6e75dd57 | ||
|
|
4a5a898a8f | ||
|
|
ba9d16291b | ||
|
|
725652e924 | ||
|
|
8da0e0e946 | ||
|
|
588b82bbf8 | ||
|
|
bc0f937b55 | ||
|
|
baa43cbaf0 | ||
|
|
adb6b1b316 | ||
|
|
1c18de0019 | ||
|
|
4d52f2eb7f | ||
|
|
363cf58645 | ||
|
|
7e760fc188 | ||
|
|
ef2dcbe4ad | ||
|
|
9354a5fad4 | ||
|
|
1c97b0a777 | ||
|
|
2f3bdab2b9 | ||
|
|
0d7f036429 | ||
|
|
2cda13213d | ||
|
|
70d0d43b5e | ||
|
|
25c3a7348f | ||
|
|
9123d64592 | ||
|
|
b827a6015c | ||
|
|
d40a3b5b55 | ||
|
|
ef28a6cb26 | ||
|
|
1436a6835e | ||
|
|
e8cfacae37 | ||
|
|
3a7382950b | ||
|
|
eeb23eb7ea | ||
|
|
34fe5a94ba | ||
|
|
6181864290 | ||
|
|
e9ca615a98 | ||
|
|
62c95fd5fc | ||
|
|
25f14e9f93 | ||
|
|
ae670a6ed8 | ||
|
|
a7b8467ac0 | ||
|
|
15da7ce7fb | ||
|
|
e9eaf3fbcf | ||
|
|
3884dcf313 | ||
|
|
c4fc559f45 | ||
|
|
2bc4330303 | ||
|
|
12675275a1 | ||
|
|
3a105f7b20 | ||
|
|
1ae72fb23d | ||
|
|
7ec676bb3d | ||
|
|
29ea57283e | ||
|
|
5488973961 | ||
|
|
96d45a5489 | ||
|
|
7a012d5a16 | ||
|
|
fa6a16996e | ||
|
|
82245a6de7 | ||
|
|
ff28ede2d1 | ||
|
|
98b8ec8616 | ||
|
|
88f9d8748c | ||
|
|
7d57d2e18b | ||
|
|
38caa00d18 | ||
|
|
c827d4cfdb | ||
|
|
509c630db8 | ||
|
|
fbff30d2db | ||
|
|
86c7fdb17c | ||
|
|
62bd6589c7 | ||
|
|
2cc6d13547 | ||
|
|
bb8ca1d112 | ||
|
|
8e59539752 | ||
|
|
372744c544 | ||
|
|
83880949a1 | ||
|
|
3749e36e9f | ||
|
|
0b4253fa37 | ||
|
|
86ec1e487c | ||
|
|
fd4eefed39 | ||
|
|
b480e7874b | ||
|
|
41333b97b9 | ||
|
|
c1c924abfe | ||
|
|
1c7e2e64f6 | ||
|
|
7dff03636a | ||
|
|
5332fd91bf | ||
|
|
d4b963d0a6 | ||
|
|
6d3f5935e5 | ||
|
|
968ee17677 | ||
|
|
81ed3bb9c0 | ||
|
|
5115652828 | ||
|
|
1f92865494 | ||
|
|
e41f450f28 | ||
|
|
97fcf1bbd0 | ||
|
|
13763ce599 | ||
|
|
7fcb605b82 | ||
|
|
70484b9f8a | ||
|
|
69b46b3d95 | ||
|
|
95c5534f8e | ||
|
|
370b39e8ec | ||
|
|
3da8038918 | ||
|
|
a6762c4a22 | ||
|
|
98c2c0febc | ||
|
|
63cbd19f50 | ||
|
|
1934f3a0ea | ||
|
|
a909e6ad43 | ||
|
|
1dcb52188d | ||
|
|
28ebef0b1b | ||
|
|
f03a8a3c4e | ||
|
|
03f760b1c0 | ||
|
|
f900dc3fb9 | ||
|
|
95eb1adda8 | ||
|
|
c6ddbdb66c | ||
|
|
3800b908b1 | ||
|
|
69fe3a5f09 | ||
|
|
754270313a | ||
|
|
057ebeaca3 | ||
|
|
480065172d | ||
|
|
f2e0056579 | ||
|
|
32fffff2cc | ||
|
|
3c47824d6b | ||
|
|
0892090a56 | ||
|
|
d592b42f5c | ||
|
|
3b5f65a64c | ||
|
|
5c0b2c16a8 | ||
|
|
d39e0f05db | ||
|
|
6d14d08e06 | ||
|
|
32060c6d6b | ||
|
|
3dbec410a0 | ||
|
|
de765f6c31 | ||
|
|
dc455a5f88 | ||
|
|
bab19a8e91 | ||
|
|
322915014f | ||
|
|
79998cd5af | ||
|
|
50b9013064 | ||
|
|
bb03fdae0d | ||
|
|
4384cf9e7d | ||
|
|
d47e980d0d | ||
|
|
fe373287eb | ||
|
|
cbe443362f | ||
|
|
2c0c9dc46c | ||
|
|
0ceab84749 | ||
|
|
34e7dc81a9 | ||
|
|
4e6e9d21bd | ||
|
|
d1feb30811 | ||
|
|
43837189c1 | ||
|
|
249962ffa2 | ||
|
|
541168039d | ||
|
|
a650110ba7 | ||
|
|
54b31d149e | ||
|
|
a745475808 | ||
|
|
7ef00afe9d | ||
|
|
156fc83a55 | ||
|
|
46be82b811 | ||
|
|
09b412dafa | ||
|
|
5268a05e47 | ||
|
|
406224be52 | ||
|
|
3799834dcf | ||
|
|
553e412bda | ||
|
|
f22834a372 | ||
|
|
bd349a8704 | ||
|
|
bc08873cff | ||
|
|
aafe273990 | ||
|
|
c09593c04e | ||
|
|
84bf31aaf8 | ||
|
|
05d5392cda | ||
|
|
d9a743d917 | ||
|
|
ac6c358c2a | ||
|
|
ad0c0ad3b4 | ||
|
|
1ed34f3dd6 | ||
|
|
6a8f9cd22e | ||
|
|
e8b9ab8957 | ||
|
|
74f728249f | ||
|
|
d6a1738892 | ||
|
|
b326b07adc | ||
|
|
07d2921c6d | ||
|
|
22e462c97a | ||
|
|
dcf8077906 | ||
|
|
3408f6e64a | ||
|
|
e10dc0e1f0 | ||
|
|
ce5c1ae517 | ||
|
|
bbe718c97f | ||
|
|
01e4b1ee14 | ||
|
|
815ac0293e | ||
|
|
6568382d6f | ||
|
|
f943b7ddce | ||
|
|
ff9d68e7be | ||
|
|
7212560f4d | ||
|
|
1aa43d77c0 | ||
|
|
e038d5c4e3 | ||
|
|
dfad3aac98 | ||
|
|
df8418ffcf | ||
|
|
50aa43b3ae | ||
|
|
a90552663e | ||
|
|
883340c107 | ||
|
|
0fe2ff78e6 | ||
|
|
dc1eed93be | ||
|
|
b2f82360d7 | ||
|
|
782e0568ef | ||
|
|
90b4b0eabe | ||
|
|
cec04ef3a6 | ||
|
|
71fa56b887 | ||
|
|
b9b3ab45ea | ||
|
|
957b794c26 | ||
|
|
8001607e90 | ||
|
|
3e7202c1bc | ||
|
|
848edeab89 | ||
|
|
1748d67aea | ||
|
|
5477ca8239 | ||
|
|
233c1c0e76 | ||
|
|
d0fd305023 | ||
|
|
8dab1e9072 | ||
|
|
963aea5279 | ||
|
|
0a64aa7355 | ||
|
|
0669c89c55 | ||
|
|
2699da8041 | ||
|
|
98727e123f | ||
|
|
b29e0000e6 | ||
|
|
b3ed15b760 | ||
|
|
666a9a2b95 | ||
|
|
a4bcaad773 | ||
|
|
e65e4c8874 | ||
|
|
21f6330274 | ||
|
|
38c6902b90 | ||
|
|
2ddcd88129 | ||
|
|
dd8920653c | ||
|
|
c938c35f95 | ||
|
|
2eb0192155 | ||
|
|
d948e09b61 | ||
|
|
89966a5aea | ||
|
|
8e3df9dfee | ||
|
|
5890eef6b0 | ||
|
|
083c1bb960 | ||
|
|
861e65eb05 | ||
|
|
650cfd0cb0 | ||
|
|
e68ae99a41 | ||
|
|
8683b4d8d9 | ||
|
|
1dbd717eb4 | ||
|
|
6a8422b942 | ||
|
|
cb202fd286 | ||
|
|
67fc8ecd53 | ||
|
|
df8301fef5 | ||
|
|
4070b458ec | ||
|
|
ffbc3901d2 | ||
|
|
7a03280df4 | ||
|
|
482a1258de | ||
|
|
cd298882cd | ||
|
|
e01c56f9e1 | ||
|
|
4d72df4031 | ||
|
|
f7f1df1d82 | ||
|
|
c4a21bc9db | ||
|
|
621ffe7bf4 | ||
|
|
8dd5418803 | ||
|
|
965cb8d530 | ||
|
|
b2e8e7dab5 | ||
|
|
59d814f793 | ||
|
|
bb865f3a5e | ||
|
|
9ee53a49f0 | ||
|
|
79adb09baa | ||
|
|
cf0649f8b7 | ||
|
|
f8690631e2 | ||
|
|
5456d78f0c | ||
|
|
cbbece96a2 | ||
|
|
9d8ba307ef | ||
|
|
ec7c1e85e0 | ||
|
|
e70c7568c0 | ||
|
|
39b62db116 | ||
|
|
2edce52584 | ||
|
|
10831b5ec9 | ||
|
|
3a0f0c263a | ||
|
|
2419a376b9 | ||
|
|
e206740fd7 | ||
|
|
290a5a8d85 | ||
|
|
e2dc351d25 | ||
|
|
c86b61428b | ||
|
|
40b96352c9 | ||
|
|
189ba90996 | ||
|
|
c8183e661d | ||
|
|
053c94f1b3 | ||
|
|
b9d76a9571 | ||
|
|
a01cfc2951 | ||
|
|
4eb5c65bee | ||
|
|
06d07c4000 | ||
|
|
74f8654a53 | ||
|
|
9e105a858c | ||
|
|
cd8a07a764 | ||
|
|
aa49acd15a | ||
|
|
642f23bd81 | ||
|
|
2e24e6bd17 | ||
|
|
2a09c1b8ab | ||
|
|
a5ebf77d87 | ||
|
|
b874495b1f | ||
|
|
b860f5dfd4 | ||
|
|
b19fc36c81 | ||
|
|
d2d8248f68 | ||
|
|
f54bab4d67 | ||
|
|
bf6427d2fb | ||
|
|
672f1bd849 | ||
|
|
529d26c3e1 | ||
|
|
857f00ed94 | ||
|
|
e4a5e772f2 | ||
|
|
a542e372ab | ||
|
|
0d1bd5d62f | ||
|
|
9f3fa89f7c | ||
|
|
92995e6265 | ||
|
|
a4196c3ea5 | ||
|
|
db37e0c273 | ||
|
|
d0aefec99a | ||
|
|
66be4b89d7 | ||
|
|
870744ce8f | ||
|
|
2ad978532b | ||
|
|
5090d93f2c | ||
|
|
c8ff645766 | ||
|
|
25f7d1beba | ||
|
|
09aa111918 | ||
|
|
10fb7710e8 | ||
|
|
c0ea8ebb9b | ||
|
|
31fd9c7601 | ||
|
|
ddbed36455 | ||
|
|
a9b0d4e1f4 | ||
|
|
4d6a3ff411 | ||
|
|
7fb993e1f4 | ||
|
|
02f502f435 | ||
|
|
4515cb43ca | ||
|
|
d740333224 | ||
|
|
c610f38ba9 | ||
|
|
6447353f52 | ||
|
|
b46ed49996 | ||
|
|
cd9fdccde0 | ||
|
|
2a8137272d | ||
|
|
762155cc90 | ||
|
|
f8610ba1ca | ||
|
|
c99f4098c4 | ||
|
|
3eec9fef30 | ||
|
|
8c8826176d | ||
|
|
14a2d6789f | ||
|
|
7513f298b0 | ||
|
|
c04c3e334c | ||
|
|
f8e51f60b3 | ||
|
|
33b066bda0 | ||
|
|
14f41bc2fb | ||
|
|
008bee0f50 | ||
|
|
29492f3332 | ||
|
|
bc94bd510b | ||
|
|
9dd8e46a2d | ||
|
|
8be2bdfabd | ||
|
|
b4c0806963 | ||
|
|
cc38fa6cfb | ||
|
|
6de5dbafee | ||
|
|
60bf45c80d | ||
|
|
eb0f3e7ec0 | ||
|
|
ed553379df | ||
|
|
5c1e6f69c4 | ||
|
|
757cda0a96 | ||
|
|
e94443de80 | ||
|
|
0954cd8aa4 | ||
|
|
da55dac047 | ||
|
|
13a11b195f | ||
|
|
92dcba1e1c | ||
|
|
2fe1b5bd2a | ||
|
|
f91e1a8739 | ||
|
|
24e21613b6 | ||
|
|
c6391cd587 | ||
|
|
006ce15a0c | ||
|
|
edf4216119 | ||
|
|
ae8953409e | ||
|
|
bda44f31a1 | ||
|
|
6621ca39a3 | ||
|
|
14f7abfa71 | ||
|
|
0f0b5736da | ||
|
|
6728187ac0 | ||
|
|
17c8675853 | ||
|
|
cfbee8a431 | ||
|
|
736785ab63 | ||
|
|
3ded7bac16 | ||
|
|
b524a001d6 | ||
|
|
7b071e317b | ||
|
|
a380509259 | ||
|
|
c0dea0a782 | ||
|
|
70947ea7b1 | ||
|
|
81cd954a51 | ||
|
|
feccf29c87 | ||
|
|
5b5fbc0867 | ||
|
|
f158799bbe | ||
|
|
8b0e8990c2 | ||
|
|
880ee801cf | ||
|
|
163965d861 | ||
|
|
6e218b3f9a | ||
|
|
cc9b9df0b6 | ||
|
|
31f224008e | ||
|
|
f32cb5cb14 | ||
|
|
fec2d97ca2 | ||
|
|
f2eeafb061 | ||
|
|
8f4e8bf280 | ||
|
|
cc36e2295a | ||
|
|
d47aeb2252 | ||
|
|
14523ed969 | ||
|
|
592e97e855 | ||
|
|
53faa3ca5f | ||
|
|
c62566971f | ||
|
|
902be27cf9 | ||
|
|
bf12cbe07c | ||
|
|
f52e66505a | ||
|
|
ca75235d3d | ||
|
|
ecc6bd1341 | ||
|
|
ce81b1411d | ||
|
|
7691a7a3bd | ||
|
|
214e74bf6f | ||
|
|
c5826a491b | ||
|
|
d8e7ef04dc | ||
|
|
08f2a92c9c | ||
|
|
3220c50f9a | ||
|
|
024ebb2706 | ||
|
|
f11554092b | ||
|
|
954352c4c0 | ||
|
|
4aec95f3c9 | ||
|
|
be531ef1ec | ||
|
|
65c1a750f5 | ||
|
|
5141249c59 | ||
|
|
6225984681 | ||
|
|
5cb91ceaa5 | ||
|
|
89c09e2a08 | ||
|
|
fbbb219409 | ||
|
|
820b064804 | ||
|
|
355c524bfa | ||
|
|
c052ce6cde | ||
|
|
c9a779695d | ||
|
|
a685ae511a | ||
|
|
5edea45fab | ||
|
|
8afff9f849 | ||
|
|
a2043572aa | ||
|
|
5d98908b26 | ||
|
|
d6fd958c5f | ||
|
|
d0eb724e22 | ||
|
|
afe4a8c769 | ||
|
|
9fc03aa87c | ||
|
|
c798f15b98 | ||
|
|
2dcc114f84 | ||
|
|
0dfe9bc9d2 | ||
|
|
4d1cdb5bfe | ||
|
|
9c5335a027 | ||
|
|
ae849ca170 | ||
|
|
94c1255782 | ||
|
|
476e1095fa | ||
|
|
8da1bb0418 | ||
|
|
01c58f8473 | ||
|
|
edfcf7abe2 | ||
|
|
37b44fe7c1 | ||
|
|
8f02ad4f12 | ||
|
|
51f1244600 | ||
|
|
7bd930368c | ||
|
|
fb69240ca0 | ||
|
|
830d53bfae | ||
|
|
c36a959549 | ||
|
|
e91b2d14e3 | ||
|
|
ac58e68bc3 | ||
|
|
504c1cedfe | ||
|
|
9a4d8fae82 | ||
|
|
7d2ba6394c | ||
|
|
b04b94da5f | ||
|
|
9933857f67 | ||
|
|
ed5641e249 | ||
|
|
a4257017ef | ||
|
|
18153f1b32 | ||
|
|
7a91d1fc43 | ||
|
|
af14ded75e | ||
|
|
65939effb5 | ||
|
|
66ee7b3234 | ||
|
|
cd47a628fc | ||
|
|
d7c78decb0 | ||
|
|
8749477ed0 | ||
|
|
7088f5b5fa | ||
|
|
5bb6328cb9 | ||
|
|
ce9f47de99 | ||
|
|
4c4780c25e | ||
|
|
64f1aba8f1 | ||
|
|
3359fb661f | ||
|
|
58a9f1b864 | ||
|
|
6ac41a4ef5 | ||
|
|
aa2af7ba74 | ||
|
|
ce73839fe4 | ||
|
|
1dc2726f8d | ||
|
|
af76e8174d | ||
|
|
402a3efc92 | ||
|
|
372f08c990 | ||
|
|
dd29eb7f81 | ||
|
|
bca788ab1d | ||
|
|
aef8fdba11 | ||
|
|
0a1603634b | ||
|
|
a662163fd5 | ||
|
|
bd7a6478a2 | ||
|
|
4a20c9f628 | ||
|
|
418c5cc3fc | ||
|
|
cc55d08832 | ||
|
|
de5c545648 | ||
|
|
a35099bd33 | ||
|
|
5f4b5cf044 | ||
|
|
beb10f843f | ||
|
|
29713e4268 | ||
|
|
8e4b83b96b | ||
|
|
ae603b500e | ||
|
|
d97aae7572 | ||
|
|
a55e2f04a0 | ||
|
|
6e53c91608 | ||
|
|
d2272fcf6e | ||
|
|
c7ac5dce8c | ||
|
|
5c1d459ae9 | ||
|
|
2e7daef502 | ||
|
|
6410229681 | ||
|
|
e40bd5f06b | ||
|
|
06b491eb7b | ||
|
|
3a9fadd6df | ||
|
|
0de9312a7e | ||
|
|
27fe5e3473 | ||
|
|
f67dcc09f5 | ||
|
|
fefc9d121d | ||
|
|
a319c33d8b | ||
|
|
218d6bcc05 | ||
|
|
7d25463972 | ||
|
|
aff84bec07 | ||
|
|
ac651e974e | ||
|
|
e21a55abcc | ||
|
|
bc03228ab5 | ||
|
|
f05d0e73c6 | ||
|
|
aed2d4b31e | ||
|
|
184a197441 | ||
|
|
ed676e8c0a | ||
|
|
8e1f937473 | ||
|
|
1a68d39211 | ||
|
|
4ba7d5b14c | ||
|
|
1a48181a9f | ||
|
|
6b70a4eb7d | ||
|
|
f01855813b | ||
|
|
4a3cdf81af | ||
|
|
f777397aca | ||
|
|
8fb2e5a4f5 | ||
|
|
4e8cc1e973 | ||
|
|
ff02a228e3 | ||
|
|
424266abb1 | ||
|
|
3fde134791 | ||
|
|
7c39a65543 | ||
|
|
8cf70de428 | ||
|
|
15ac8413c7 | ||
|
|
79c21abba7 | ||
|
|
d5c418f29f | ||
|
|
536b94e56f | ||
|
|
5c29dbd0c7 | ||
|
|
ba9e68f402 | ||
|
|
e9f65f8749 | ||
|
|
ae0dd4b298 | ||
|
|
f1ce35af1a | ||
|
|
6e617ed0b6 | ||
|
|
7cf97daf77 | ||
|
|
3d24d997ae | ||
|
|
115c281672 | ||
|
|
cce23e43a9 | ||
|
|
ff556f5c09 | ||
|
|
16fa01291b | ||
|
|
01534bf54f | ||
|
|
cd341b6e06 | ||
|
|
185a7e25e7 | ||
|
|
e81a474603 | ||
|
|
ff2be6e180 | ||
|
|
3da4b31359 | ||
|
|
4bbeb19fc7 | ||
|
|
a9cbab1735 | ||
|
|
6b7556a554 | ||
|
|
a3c7019e06 | ||
|
|
416b9c29f7 | ||
|
|
2ec8e04cac | ||
|
|
e03bfb30ce | ||
|
|
f5b669113f | ||
|
|
d08225edf4 | ||
|
|
8075d4f99d | ||
|
|
1a944d8a2a | ||
|
|
7cf02b6619 | ||
|
|
55cde6ef3c | ||
|
|
69c3af567d | ||
|
|
60e1fe0079 | ||
|
|
4669393070 | ||
|
|
ce3bfe5d57 | ||
|
|
2a0c2ca2b8 | ||
|
|
c89fbfb385 | ||
|
|
facecb84a1 | ||
|
|
ed06e9949b | ||
|
|
e15307a612 | ||
|
|
5cbb2699ee | ||
|
|
a2edf2e7ff | ||
|
|
1d31e7a2fc | ||
|
|
a2a4d5fa31 | ||
|
|
a28ccbabc6 | ||
|
|
edd7344820 | ||
|
|
c808ef81bb | ||
|
|
fd203fe357 | ||
|
|
5bb7ab9928 | ||
|
|
87270c8416 | ||
|
|
ebc2f7a2db | ||
|
|
7700207ec7 | ||
|
|
4d5d14f5cf | ||
|
|
72b249bf1f | ||
|
|
9b4774b21b | ||
|
|
2ddf083588 | ||
|
|
8343a03357 | ||
|
|
ad320e9b83 | ||
|
|
ecb750a446 | ||
|
|
5f88e02818 | ||
|
|
616af2f4b9 | ||
|
|
5a3b315b5f | ||
|
|
b7a2268e7b | ||
|
|
20d729228c | ||
|
|
af8c93086c | ||
|
|
79fd11ab8e | ||
|
|
cb88671e37 | ||
|
|
ff79552f13 | ||
|
|
643fe72717 | ||
|
|
4747e2183a | ||
|
|
c59e701e35 | ||
|
|
8e678af4ba | ||
|
|
70a1165b32 | ||
|
|
af14000215 | ||
|
|
998e6cdba0 | ||
|
|
2315fb5e5f | ||
|
|
157e9e5aa5 | ||
|
|
c496ec0848 | ||
|
|
15b67a268a | ||
|
|
31c4809827 | ||
|
|
ac0df2350a | ||
|
|
223b27f46c | ||
|
|
425142be60 | ||
|
|
7e17ec8c71 | ||
|
|
448830ce7b | ||
|
|
8896b614a9 | ||
|
|
a7fce980ad | ||
|
|
91757b0f37 | ||
|
|
fbfcc2972b | ||
|
|
db40364b87 | ||
|
|
094ce39c45 | ||
|
|
ae67d082fe | ||
|
|
8f76df7f37 | ||
|
|
5c19d18cbf | ||
|
|
838b93405b | ||
|
|
2676caf344 | ||
|
|
17941321ab | ||
|
|
48c971e073 | ||
|
|
f5e2efbbf0 | ||
|
|
5d1f0e607b | ||
|
|
b0872c19ea | ||
|
|
9f790b9901 | ||
|
|
c41a2ec4af | ||
|
|
575dad3c98 | ||
|
|
32d687f55e | ||
|
|
93f787070f | ||
|
|
f9544f6e8f | ||
|
|
336d19044c | ||
|
|
7866c9e173 | ||
|
|
1a4123de04 | ||
|
|
cf2e2eb1c0 | ||
|
|
2051acdeb2 | ||
|
|
cefdf970cc | ||
|
|
a1d0aa7b88 | ||
|
|
49aeedb8cb | ||
|
|
ef249a2cd7 | ||
|
|
a09141548a | ||
|
|
5379a2d40d | ||
|
|
c9450c7ab1 | ||
|
|
faa1b5c292 | ||
|
|
393d9fc6d2 | ||
|
|
4e6a228689 | ||
|
|
179d6678b1 | ||
|
|
85698c5086 | ||
|
|
a7d9ded45d | ||
|
|
531980d89c | ||
|
|
1887ecd4d6 | ||
|
|
cd32c2caba | ||
|
|
1c9a1457fc | ||
|
|
038b0eb1da | ||
|
|
f20bf146e2 | ||
|
|
01218f919b | ||
|
|
2684871bc1 | ||
|
|
ccf3960eec | ||
|
|
eecc0685c9 | ||
|
|
2ed849eccf | ||
|
|
3378d67a18 | ||
|
|
f3c0c667a6 | ||
|
|
0ae8bbac2d | ||
|
|
cbc3cfcab4 | ||
|
|
b30ef07c6c | ||
|
|
73900846b1 | ||
|
|
d1dc7e3991 | ||
|
|
3073a6d5e9 | ||
|
|
aae53774f2 | ||
|
|
7a757b7194 | ||
|
|
fa8ce26904 | ||
|
|
2c2c06e359 | ||
|
|
ee580538fa | ||
|
|
c3c5c31517 | ||
|
|
ed9a25dd61 | ||
|
|
9ef4f12b53 | ||
|
|
84f8101606 | ||
|
|
b1337948eb | ||
|
|
98f02fdde2 | ||
|
|
048fdc2292 | ||
|
|
2ca1c5aa9f | ||
|
|
674fb0fcc5 | ||
|
|
00bfe40e4d | ||
|
|
cd459b1d49 | ||
|
|
92a4793b3c | ||
|
|
dc03a42537 | ||
|
|
219da6bb68 | ||
|
|
0499cd866e | ||
|
|
13047f4135 | ||
|
|
af69cab21d | ||
|
|
d41a3fa1b4 | ||
|
|
733be371af | ||
|
|
576904bce6 | ||
|
|
cf47794f09 | ||
|
|
c06a9f8730 | ||
|
|
2e90dff2c2 | ||
|
|
90183a46d8 | ||
|
|
b68eedba23 | ||
|
|
d5b559393b | ||
|
|
1de4ac1385 | ||
|
|
39aa42ffbb | ||
|
|
ec1b9577ba | ||
|
|
3b4444f99a | ||
|
|
613b2d9dc6 | ||
|
|
8f4cc22455 | ||
|
|
7c42327e0e | ||
|
|
873383e9bd | ||
|
|
8508557e77 | ||
|
|
4d1652484f | ||
|
|
88cf6fb368 | ||
|
|
e7db87f700 | ||
|
|
2cb434e53e | ||
|
|
cd65491c30 | ||
|
|
082b1155a3 | ||
|
|
9202b1b787 | ||
|
|
a7e01c438d | ||
|
|
05be67e77d | ||
|
|
85741b9986 | ||
|
|
f247a199fe | ||
|
|
29171bc2d2 | ||
|
|
7be5a62ed7 | ||
|
|
3647136f24 | ||
|
|
13598940e3 | ||
|
|
0eb365868e | ||
|
|
28c6411e49 | ||
|
|
bba3fc7960 | ||
|
|
fcd877013e | ||
|
|
ba1d4c0488 | ||
|
|
517bcca299 | ||
|
|
1b53778175 | ||
|
|
b7a0304d92 | ||
|
|
545315a985 | ||
|
|
3f4327520c | ||
|
|
4a34f69ea6 | ||
|
|
fb7e68833c | ||
|
|
486dd09e0b | ||
|
|
054b99a330 | ||
|
|
65c5e044c7 | ||
|
|
11984c7467 | ||
|
|
3946864c8a | ||
|
|
b84037013e | ||
|
|
1dbfc62d75 | ||
|
|
d7d79106c7 | ||
|
|
1138491631 | ||
|
|
71705fa70d | ||
|
|
602814adab | ||
|
|
3a77719c5a | ||
|
|
7e195d0e92 | ||
|
|
e04793401d | ||
|
|
a3fbd18824 | ||
|
|
c6052b8c14 | ||
|
|
c792b5011f | ||
|
|
32aaeca775 | ||
|
|
1593194c63 | ||
|
|
614a7e1e23 | ||
|
|
2ebfeacabc | ||
|
|
f5d8f58a17 | ||
|
|
937daef4a7 | ||
|
|
dd77f14c64 | ||
|
|
c36cbe5a8a | ||
|
|
41b2194f86 | ||
|
|
d1e2e8f583 | ||
|
|
47fe42e1ab | ||
|
|
4c60393854 | ||
|
|
f848215dfc | ||
|
|
dcca581967 | ||
|
|
d475b3384c | ||
|
|
dd7831fe94 | ||
|
|
cc08b11d16 | ||
|
|
8bba753cca | ||
|
|
43d6280d0a | ||
|
|
e5a11a2293 | ||
|
|
f18ef2d144 | ||
|
|
1bb5c511a5 | ||
|
|
d55de57b67 | ||
|
|
a2aaf4dbc6 | ||
|
|
bdf6eee0ae | ||
|
|
8b910bda0c | ||
|
|
24993e3b39 | ||
|
|
11101076a1 | ||
|
|
f838875726 | ||
|
|
28778d6bae | ||
|
|
1132eae56d | ||
|
|
d34e79492d | ||
|
|
ab205b9dc8 | ||
|
|
7dcad95d4f | ||
|
|
8a48223a7b | ||
|
|
d47ae7f620 | ||
|
|
135c9c42bf | ||
|
|
0bf79ac455 | ||
|
|
98998cded6 | ||
|
|
14137b5781 | ||
|
|
a172d96292 | ||
|
|
23ba76bc0e | ||
|
|
61e00a9775 | ||
|
|
d1508cd68d | ||
|
|
9c85b5376d | ||
|
|
3c6f245083 | ||
|
|
f207019ce5 | ||
|
|
bd05aa4e24 | ||
|
|
8dc9d361c2 | ||
|
|
d0e958c71c | ||
|
|
a0bb7c5593 | ||
|
|
7feddd9fc7 | ||
|
|
55969016e9 | ||
|
|
9609f02e3c | ||
|
|
5c7495a194 | ||
|
|
5ee6fc974e | ||
|
|
c2ebea6580 | ||
|
|
12a129ec6d | ||
|
|
f28fe66970 | ||
|
|
123397317c | ||
|
|
dc570c4951 | ||
|
|
22d3628319 | ||
|
|
50c9949d7a | ||
|
|
376817c6d4 | ||
|
|
63fc800057 | ||
|
|
e0d0572b73 | ||
|
|
7fde87c77d | ||
|
|
938c3f65b6 | ||
|
|
2461f79d2a | ||
|
|
499bfcbfd0 | ||
|
|
07490f8017 | ||
|
|
91410c9bfa | ||
|
|
a7440261c5 | ||
|
|
76c73715fb | ||
|
|
c75f0b361a | ||
|
|
295df4edb9 | ||
|
|
562ceab13d | ||
|
|
2f0f6578c3 | ||
|
|
30cbd4e0d6 | ||
|
|
549e58069c | ||
|
|
7594be85ff | ||
|
|
3630034609 | ||
|
|
4e01501bbf | ||
|
|
1aa5172f56 | ||
|
|
f7e2ee8fa6 | ||
|
|
66dc9a3701 | ||
|
|
31bd39256b | ||
|
|
003c69a84b | ||
|
|
0134901108 | ||
|
|
eee6293d57 | ||
|
|
8237bec4f0 | ||
|
|
29cad7ad13 | ||
|
|
0d103de3b0 | ||
|
|
a0090691d0 | ||
|
|
6c87c2eea8 | ||
|
|
58c2ec6ab3 | ||
|
|
df5ae3eb16 | ||
|
|
efda2d7854 | ||
|
|
e143f5dae9 | ||
|
|
48218cdb97 | ||
|
|
e9fade72f3 | ||
|
|
0f2c0d335b | ||
|
|
40b077bc7e | ||
|
|
a931092cb3 | ||
|
|
bd3749ed69 | ||
|
|
4ffbf77886 | ||
|
|
781a7ef60a | ||
|
|
5b2949ee0b | ||
|
|
a0d646135a | ||
|
|
7862ad88b7 | ||
|
|
f3bff94cf9 | ||
|
|
0eba1e1782 | ||
|
|
e3216b82bf | ||
|
|
da419e2332 | ||
|
|
0d97ef43be | ||
|
|
1a2313a6f2 | ||
|
|
250a9bdfe2 | ||
|
|
6317a3e9da | ||
|
|
7ab7c9e932 | ||
|
|
e129c5bc0d | ||
|
|
2e241242a3 | ||
|
|
9724e5d336 | ||
|
|
63a562f95e | ||
|
|
5c340b0387 | ||
|
|
1c6510f57a | ||
|
|
2a15a98a6a | ||
|
|
72a406e7aa | ||
|
|
feccc3ff37 | ||
|
|
265bfa2c79 | ||
|
|
8faf9b9b41 | ||
|
|
84be7c230c | ||
|
|
3e675fabe0 | ||
|
|
cd5b4b0bc2 | ||
|
|
7ef822021b | ||
|
|
9a48926a57 | ||
|
|
13cd97f3df | ||
|
|
183139340b | ||
|
|
1c69bca258 | ||
|
|
c10ea454dc | ||
|
|
9504fc21b5 | ||
|
|
13d8fbef30 | ||
|
|
b8988b63a6 | ||
|
|
5eaaeb7c31 | ||
|
|
c4f8c453ae | ||
|
|
6f4ba54079 | ||
|
|
637570326b | ||
|
|
37f885650c | ||
|
|
c8c34ccb20 | ||
|
|
e765ed3a9c | ||
|
|
677063594e | ||
|
|
59c7cbd482 | ||
|
|
570311610e | ||
|
|
41b264e77c | ||
|
|
df4bd0d53f | ||
|
|
7f09a662a0 | ||
|
|
4f3b21e1c7 | ||
|
|
54233c9080 | ||
|
|
db8e13ef71 | ||
|
|
5a42414b9c | ||
|
|
9c665ab72e | ||
|
|
b665ba6aa6 | ||
|
|
ec5913b5cd | ||
|
|
25ac63ed71 | ||
|
|
99209c2916 | ||
|
|
1fbaa0a521 | ||
|
|
3037b91e05 | ||
|
|
ffdf972b91 | ||
|
|
459e5fbd5f | ||
|
|
bfc993cc91 | ||
|
|
4432db35d9 | ||
|
|
591ab1dff9 | ||
|
|
5bca2424bc | ||
|
|
bd61a9e770 | ||
|
|
3438e7acd2 | ||
|
|
09c200acf2 | ||
|
|
716889cab1 | ||
|
|
409693984f | ||
|
|
04e8c11080 | ||
|
|
80af2b73ab | ||
|
|
3cc57f9645 | ||
|
|
a65d4e7f14 | ||
|
|
b531cfc019 | ||
|
|
543ec2136b | ||
|
|
93b5071f73 | ||
|
|
ddc369f073 | ||
|
|
1b40dc92eb | ||
|
|
fcc3e6138b | ||
|
|
9fe6ef7ab2 | ||
|
|
c010af6f19 | ||
|
|
35b7982303 | ||
|
|
f311cfa231 | ||
|
|
80970e531b | ||
|
|
b7bb76df05 | ||
|
|
98c70d6fc7 | ||
|
|
ab84349b16 | ||
|
|
03091e372f | ||
|
|
4d17184817 | ||
|
|
e086e0eb6c | ||
|
|
314368c822 | ||
|
|
c5181ab410 | ||
|
|
ea5152cae1 | ||
|
|
255fca5eea | ||
|
|
4aeccadf4e | ||
|
|
93540ee10e | ||
|
|
8fb3ac3649 | ||
|
|
77b2986b5b | ||
|
|
62b013df0d | ||
|
|
fad6768bd1 | ||
|
|
a78125f925 | ||
|
|
a00a8bcc8a | ||
|
|
1e9a9e167d | ||
|
|
3da0db62e6 | ||
|
|
e14ced7918 | ||
|
|
ab9d02f53b | ||
|
|
a461a11989 | ||
|
|
1bd838608f | ||
|
|
365577f567 | ||
|
|
50efb383f0 | ||
|
|
5da6bd0083 | ||
|
|
5e9a033e6e | ||
|
|
fb7cb6823e | ||
|
|
dd0a58f5f0 | ||
|
|
a21420389e | ||
|
|
6140baf4e1 | ||
|
|
8fc642eb5b | ||
|
|
e66e1a0046 | ||
|
|
d5c69f1da4 | ||
|
|
f13b1e7d7f | ||
|
|
5c8a3f862a | ||
|
|
8807f1277f | ||
|
|
a3b9157f49 | ||
|
|
b88ba05356 | ||
|
|
b74d505577 | ||
|
|
9e2d7dca87 | ||
|
|
d236b37ac9 | ||
|
|
e880c66bd8 | ||
|
|
383456aa29 | ||
|
|
1a13940c8d | ||
|
|
3d54788495 | ||
|
|
71d53ace2f | ||
|
|
f37e3f99f0 | ||
|
|
bd03ffc16e | ||
|
|
1ac1af9b47 | ||
|
|
3bf5705316 | ||
|
|
1c2528c8a3 | ||
|
|
7bd15b1a03 | ||
|
|
6b961a85fd | ||
|
|
7707004043 | ||
|
|
a025d3c5a5 | ||
|
|
c460bdd56b | ||
|
|
b81a359eb6 | ||
|
|
d61aefb24c | ||
|
|
d305dd73a3 | ||
|
|
93a16ba238 | ||
|
|
4f7cea6c53 | ||
|
|
afbdd3acc3 | ||
|
|
85d5866177 | ||
|
|
9789d7535d | ||
|
|
d8443cd3f7 | ||
|
|
d47c26e168 | ||
|
|
01561da142 | ||
|
|
0af25f784b | ||
|
|
b9b42f2ea0 | ||
|
|
311c393838 | ||
|
|
18c1c42405 | ||
|
|
37dd5d4629 | ||
|
|
81975f4693 | ||
|
|
b8b928d5cb | ||
|
|
3eff81fbf7 | ||
|
|
785521bf4f | ||
|
|
6d1a55a521 | ||
|
|
9cad27008b | ||
|
|
11e611a7fa | ||
|
|
72c1f8de06 | ||
|
|
6e99868e4c | ||
|
|
4d278fde64 | ||
|
|
f21e915fb9 | ||
|
|
6f53c63df6 | ||
|
|
1def5f359e | ||
|
|
15ec669374 | ||
|
|
a3fa5da496 | ||
|
|
30965ac66a | ||
|
|
09ab40b7d1 | ||
|
|
edab9dbf4d | ||
|
|
9868ea4936 | ||
|
|
85920dd01d | ||
|
|
fa15607773 | ||
|
|
a91a2c1a83 | ||
|
|
16e7711e22 | ||
|
|
5cda4eda72 | ||
|
|
98f000409f | ||
|
|
bd7fe0cf66 | ||
|
|
48246541da | ||
|
|
4a8d4a53b1 | ||
|
|
4cd95bcbc3 | ||
|
|
be24c8697f | ||
|
|
0d93378887 | ||
|
|
4069766c52 | ||
|
|
7010577720 | ||
|
|
8ac27a68e6 | ||
|
|
46312e0b46 | ||
|
|
f9216ed6ad | ||
|
|
65bf37ef83 | ||
|
|
f740fae2a4 | ||
|
|
fbc503d696 | ||
|
|
662435f728 | ||
|
|
163d966707 | ||
|
|
85729c51af | ||
|
|
360e1ca5cc | ||
|
|
a1f2a06b34 | ||
|
|
c84dd8a90d | ||
|
|
65469a7f8b | ||
|
|
6b597516c1 | ||
|
|
b5857f62e2 | ||
|
|
a504ced097 | ||
|
|
1db5fbcfe3 | ||
|
|
59b8ab5834 | ||
|
|
a568180441 | ||
|
|
85e80f71cd | ||
|
|
bfa6bdcd8b | ||
|
|
03cd72b007 | ||
|
|
5bfd430f81 | ||
|
|
73fac4e911 | ||
|
|
8fb474fb17 | ||
|
|
f813928e4b | ||
|
|
b9c7a97318 | ||
|
|
9fb2f1cd6d | ||
|
|
6ca7732d5e | ||
|
|
b0ab0fac49 | ||
|
|
a294bce82f | ||
|
|
76d1466b08 | ||
|
|
1888d3f7b3 | ||
|
|
c2787701cc | ||
|
|
52e1d0ccc4 | ||
|
|
10e3c4c221 | ||
|
|
68f2d273bf | ||
|
|
7c86c21662 | ||
|
|
ae1580d790 | ||
|
|
3215c50f25 | ||
|
|
36f73e8044 | ||
|
|
a4f3d779db | ||
|
|
d9aa2b784d | ||
|
|
cffcbc02de | ||
|
|
9347fddbfc | ||
|
|
037e9437e4 | ||
|
|
36e7a4ca2e | ||
|
|
ae6423d704 | ||
|
|
7105440cec | ||
|
|
c80b9cd280 | ||
|
|
171ca612af | ||
|
|
c3d64fc1b3 | ||
|
|
7c24ce225d | ||
|
|
08b38d5401 | ||
|
|
024c53694d | ||
|
|
7e6011101f | ||
|
|
c40feaba77 | ||
|
|
5277f09dfc | ||
|
|
2d30521ab9 | ||
|
|
050fa43561 | ||
|
|
f36f92f4da | ||
|
|
124f3bc67d | ||
|
|
d304209a85 | ||
|
|
8367d3f3cb | ||
|
|
c56d7d899d | ||
|
|
ea5db8469e | ||
|
|
3811c567e7 | ||
|
|
8708d76425 | ||
|
|
054fe3cc40 | ||
|
|
af0d11f244 | ||
|
|
9650885be9 | ||
|
|
596ac6e31f | ||
|
|
612ee37365 | ||
|
|
442c37b7a9 | ||
|
|
04bbe41330 | ||
|
|
8f84f57183 | ||
|
|
6a78740211 | ||
|
|
c0e1a415fd | ||
|
|
bf8f082a90 | ||
|
|
2f543a2142 | ||
|
|
7e5db8c930 | ||
|
|
f7a211dcc8 | ||
|
|
845734773d | ||
|
|
347de4931c | ||
|
|
8829650513 | ||
|
|
c73fae1e2e | ||
|
|
834bf069d2 | ||
|
|
c06a9fa34f | ||
|
|
753fad4adc | ||
|
|
34814eb66e | ||
|
|
3a5bcd0326 | ||
|
|
99c2398bc6 | ||
|
|
28f1272870 | ||
|
|
f18e3a2fc0 | ||
|
|
c4c5dc27cb | ||
|
|
2caf182f37 | ||
|
|
43f244b6d5 | ||
|
|
1309b396d0 | ||
|
|
ba61796458 | ||
|
|
3255fe7141 | ||
|
|
e98b8e79ea | ||
|
|
196121c51b | ||
|
|
5269028951 | ||
|
|
f7bc056b5a | ||
|
|
a0f7198544 | ||
|
|
dd8930684e | ||
|
|
bdb186f3b0 | ||
|
|
64f9baa084 | ||
|
|
b29231c040 | ||
|
|
6128bf07a9 | ||
|
|
2ec19e9558 | ||
|
|
9ddb6925bf | ||
|
|
12931e1c6e | ||
|
|
41c23b0da5 | ||
|
|
2578ab19e4 | ||
|
|
d87ec897e9 | ||
|
|
3bd4bffb1c | ||
|
|
c36b09a502 | ||
|
|
641eb10d34 | ||
|
|
955c5505e7 | ||
|
|
69319969de | ||
|
|
a14292e848 | ||
|
|
5d678df64a | ||
|
|
8ca8cbe2bd | ||
|
|
ba322d8209 | ||
|
|
2f38289b79 | ||
|
|
f23a3ca699 | ||
|
|
77d2b106cc | ||
|
|
c0e46412e9 | ||
|
|
0161353d7d | ||
|
|
2b4ecde2c8 | ||
|
|
b3a286d69d | ||
|
|
467d3c9a0c | ||
|
|
ad5747bad1 | ||
|
|
d6eb66ed3c | ||
|
|
7f2a9f1b49 | ||
|
|
1e1896f2de | ||
|
|
c831973366 | ||
|
|
1a2548d9e9 | ||
|
|
3900eec27c | ||
|
|
a02d212638 | ||
|
|
9c91a8fa70 | ||
|
|
41469f335e | ||
|
|
67ce4f8820 | ||
|
|
bc63d56cca | ||
|
|
c893d70805 | ||
|
|
3ee6e02564 | ||
|
|
e3aaace400 | ||
|
|
300753a069 | ||
|
|
f13b88c616 | ||
|
|
60ca389c64 | ||
|
|
1b0f3919c1 | ||
|
|
6a348cf7d5 | ||
|
|
9e91449c8d | ||
|
|
25e5ebf382 | ||
|
|
7dfc356625 | ||
|
|
58ba6c0160 | ||
|
|
f076b63821 | ||
|
|
12f0454cd6 | ||
|
|
cd7342755f | ||
|
|
9bb8e0a3f9 | ||
|
|
1a6373ef39 | ||
|
|
f6c24009be | ||
|
|
d862042301 | ||
|
|
23d9ded655 | ||
|
|
4c1a017e69 | ||
|
|
ee623d9247 | ||
|
|
330537d08a | ||
|
|
2cf0ecac7b | ||
|
|
d200b11c7e | ||
|
|
d0eca21021 | ||
|
|
c1147c05e1 | ||
|
|
55898ad2cf | ||
|
|
a465808592 | ||
|
|
5c4862bad4 | ||
|
|
995029a142 | ||
|
|
a57b562cff | ||
|
|
531572578e | ||
|
|
3a4cca687f | ||
|
|
7d3d06a16c | ||
|
|
c21b1fbeeb | ||
|
|
f920ce295e | ||
|
|
7a7bd19c45 | ||
|
|
8f4b58d70e | ||
|
|
3fd45e03bf | ||
|
|
869b4aeff4 | ||
|
|
cc9ca3ba6e | ||
|
|
ea71034bd3 | ||
|
|
9fffd0469f | ||
|
|
ae7773942e | ||
|
|
469a64cebf | ||
|
|
aae3fdcfae | ||
|
|
6a66904f8e | ||
|
|
78271e3319 | ||
|
|
92bf0bcdf8 | ||
|
|
1283204917 | ||
|
|
6789defea9 | ||
|
|
acf2a6e97b | ||
|
|
8cfb6efe6f | ||
|
|
04edb9caf5 | ||
|
|
044131ba21 | ||
|
|
0a7055c90d | ||
|
|
9e3f19919a | ||
|
|
4a3da4ebdb | ||
|
|
027008b14e | ||
|
|
c6df692466 | ||
|
|
acf757f42e | ||
|
|
dd8982f19c | ||
|
|
654bd52f58 | ||
|
|
a9551e9020 | ||
|
|
4e980275b5 | ||
|
|
c172440ac5 | ||
|
|
e332772531 | ||
|
|
437cac8cc1 | ||
|
|
9f281cacd2 | ||
|
|
748a0fab8a | ||
|
|
c1f06d6307 | ||
|
|
c4e817ce4a | ||
|
|
9a3e5e6955 | ||
|
|
228d30ed06 | ||
|
|
057c0609fc | ||
|
|
17d2712d9c | ||
|
|
fc09240e24 | ||
|
|
146303136f | ||
|
|
96aded8d3d | ||
|
|
2886be15aa | ||
|
|
ca0f500ecf | ||
|
|
29aef5a33c | ||
|
|
9158b2b301 | ||
|
|
0196149c5b | ||
|
|
8f9312c387 | ||
|
|
439b9a9e9b | ||
|
|
8c72beb25e | ||
|
|
1ee94db2d0 | ||
|
|
e77d2975af | ||
|
|
e41b1f7385 | ||
|
|
cd596028d6 | ||
|
|
cc57bd33a8 | ||
|
|
6d593c3276 | ||
|
|
91755ee384 | ||
|
|
0692ef86ef | ||
|
|
439d9be27d | ||
|
|
b80505a409 | ||
|
|
e4c17d7274 | ||
|
|
2c58674e0e | ||
|
|
ef1269fb07 | ||
|
|
e525d9a3df | ||
|
|
20b4492c71 | ||
|
|
dee3f73787 | ||
|
|
d543bdc351 | ||
|
|
c7ff0c6422 | ||
|
|
01c46659c4 | ||
|
|
b04b885271 | ||
|
|
dc35bfd2d5 | ||
|
|
70fca8d694 | ||
|
|
a52c633536 | ||
|
|
7b6c60393e | ||
|
|
83e7a314b4 | ||
|
|
749f2ca044 | ||
|
|
5468ff4d91 | ||
|
|
1d2daaea63 | ||
|
|
52585fd6dc | ||
|
|
c03844a4ec | ||
|
|
6449cd807e | ||
|
|
e2a08185c6 | ||
|
|
5d6677ca28 | ||
|
|
5a8a29cfea | ||
|
|
c1708b89c0 | ||
|
|
83fddfd493 | ||
|
|
1798791df1 | ||
|
|
6ebb0dca9f | ||
|
|
cf8d6ec865 | ||
|
|
f452f72c6b | ||
|
|
3198291f26 | ||
|
|
02c1d5e285 | ||
|
|
ec4161a57d | ||
|
|
03d8d4df38 | ||
|
|
03d2d6d51b | ||
|
|
83fda3c000 | ||
|
|
4fe8495a23 | ||
|
|
a16f6643f0 | ||
|
|
adc0ae3ceb | ||
|
|
7bb3ceb4c7 | ||
|
|
75a4fc5b72 | ||
|
|
87673cd438 | ||
|
|
f345fe9db7 | ||
|
|
e683a48d0e | ||
|
|
a7a14d9586 | ||
|
|
219337990b | ||
|
|
376a770cc4 | ||
|
|
7e500dbd93 | ||
|
|
affd04a45d | ||
|
|
c84130e865 | ||
|
|
4f264c02c7 | ||
|
|
d205476103 | ||
|
|
367cc95aa7 | ||
|
|
206dba27a4 | ||
|
|
dcf53d4408 | ||
|
|
63be3b8989 | ||
|
|
18b4e9e79d | ||
|
|
cb454b333d | ||
|
|
e0d9f85aee | ||
|
|
b04fbd789c | ||
|
|
aad9556414 | ||
|
|
48a1e5141a | ||
|
|
0865f397ae | ||
|
|
796df3c631 | ||
|
|
a28383834b | ||
|
|
3a0d2f520a | ||
|
|
6348ad12a0 | ||
|
|
fe7710cbcc | ||
|
|
2103d038b3 | ||
|
|
6ca85be6f8 | ||
|
|
9f0df77ab1 | ||
|
|
e72c7e4123 | ||
|
|
2b1bd292ae | ||
|
|
71e7da6533 | ||
|
|
80a49d3d7b | ||
|
|
d862a4f94f | ||
|
|
a57e8ce658 | ||
|
|
96a53167fa | ||
|
|
6d2749aac4 | ||
|
|
b1b0b1ca30 | ||
|
|
3dee7826e7 | ||
|
|
c9326b38b8 | ||
|
|
d4f64cabf4 | ||
|
|
fe41ddbb28 | ||
|
|
ee69b99af6 | ||
|
|
767ff0a2d1 | ||
|
|
8604e882a8 | ||
|
|
cc1237f484 | ||
|
|
37f4ce538a | ||
|
|
7d346331b5 | ||
|
|
e1ccc04e9f | ||
|
|
881e6a1f5c | ||
|
|
baeaeffce5 | ||
|
|
c14e88f0f5 | ||
|
|
8940b8608e | ||
|
|
ec82d85acd | ||
|
|
cfb56d1af3 | ||
|
|
1e10802990 | ||
|
|
6695916045 | ||
|
|
7906d199a1 | ||
|
|
1070711d60 | ||
|
|
4b405cfc6e | ||
|
|
e5660ee6ae | ||
|
|
8011fba3ae | ||
|
|
587a9c2749 | ||
|
|
e1554a407d | ||
|
|
3fcfb8e9fa | ||
|
|
384b62028a | ||
|
|
b95aab8482 | ||
|
|
fc2d6abfe7 | ||
|
|
27de5625d4 | ||
|
|
6aa4f54d66 | ||
|
|
222516d97d | ||
|
|
a055469faf | ||
|
|
fdaaaaa878 | ||
|
|
12d1fb5aa9 | ||
|
|
48f00d15b1 | ||
|
|
3e055aa5c3 | ||
|
|
6896a52721 | ||
|
|
5779b3e1fe | ||
|
|
62cd676c74 | ||
|
|
0c17278843 | ||
|
|
d229ee70da | ||
|
|
26e274666d | ||
|
|
ebd46aed51 | ||
|
|
e793f7671c | ||
|
|
c2e64f71d0 | ||
|
|
0920e5830f | ||
|
|
bf7fa94ec7 | ||
|
|
6f58db8982 | ||
|
|
aa42e87340 | ||
|
|
649f7966f7 | ||
|
|
5f0d813d93 | ||
|
|
501f13fbf3 | ||
|
|
ba55168157 | ||
|
|
d79323136f | ||
|
|
08ff6ab07e | ||
|
|
ba655a0e4c | ||
|
|
b59c17e543 | ||
|
|
61ca9a80b3 | ||
|
|
317239b097 | ||
|
|
c2a30b250c | ||
|
|
c994e6bd63 | ||
|
|
3ee2aa7a16 | ||
|
|
083c9df93b | ||
|
|
50789175ed | ||
|
|
dc1b027cd4 | ||
|
|
f353cbdb2f | ||
|
|
73e449b226 | ||
|
|
b4a64c592b | ||
|
|
78111136db | ||
|
|
650ab5beeb | ||
|
|
7932de6352 | ||
|
|
240b9b7a5c | ||
|
|
bb6e38787d | ||
|
|
898c23c03f | ||
|
|
b55ee18ff3 | ||
|
|
e5763a7a7e | ||
|
|
8bb1bdfae9 | ||
|
|
c62b449765 | ||
|
|
bb0aa4cb3c | ||
|
|
d63528c8c7 | ||
|
|
c5db6bb32b | ||
|
|
c8dc41a6e7 | ||
|
|
47e0e1e0e2 | ||
|
|
efcddaebe9 | ||
|
|
5fe5112589 | ||
|
|
564bb5e964 | ||
|
|
2df54b4ba8 | ||
|
|
030aa5d9e7 | ||
|
|
c511f13f22 | ||
|
|
bd3cbe0716 | ||
|
|
fdb2ed7455 | ||
|
|
ba319696a9 | ||
|
|
910c552052 | ||
|
|
cce81f192c | ||
|
|
9d22a7dfb0 | ||
|
|
4f4f642822 | ||
|
|
2875cf01bb | ||
|
|
e205db3bcd | ||
|
|
31d4a6e212 | ||
|
|
aaeb86f682 | ||
|
|
9fa6ea2680 | ||
|
|
a9b6b5cd15 | ||
|
|
a45c0a5d67 | ||
|
|
c8dfe360eb | ||
|
|
4cfaf85c65 | ||
|
|
be5f2c192c | ||
|
|
c9ef44ce29 | ||
|
|
e92d4a11f5 | ||
|
|
f2cbc96c3e | ||
|
|
a69801e2c6 | ||
|
|
034206cec1 | ||
|
|
04e0bac233 | ||
|
|
fbef83f399 | ||
|
|
3d5f7a3947 | ||
|
|
a5fb718c50 | ||
|
|
227d4822ff | ||
|
|
5c4a81d934 | ||
|
|
263255eb8d | ||
|
|
8e2ec95575 | ||
|
|
8e7a9016d5 | ||
|
|
c85f368370 | ||
|
|
a0977064ce | ||
|
|
15aecd8711 | ||
|
|
20dd0b2d20 | ||
|
|
f934860a07 | ||
|
|
2aeb06d6dc | ||
|
|
6ccbb335d2 | ||
|
|
4340decad2 | ||
|
|
f3ff1a3696 | ||
|
|
aa24de39aa | ||
|
|
a798e64c15 | ||
|
|
6a5fa75490 | ||
|
|
8ad6b5ed9f | ||
|
|
d5bb814d34 | ||
|
|
d156a1d981 | ||
|
|
987493aef3 | ||
|
|
8bfa75451b | ||
|
|
c071733fd4 | ||
|
|
cd3063f3fa | ||
|
|
58b1f00d19 | ||
|
|
149f05c7b6 | ||
|
|
8a1b9b068e | ||
|
|
c5a59d9391 | ||
|
|
500b8b41c1 | ||
|
|
be4a824d74 | ||
|
|
ed3958d714 | ||
|
|
6ce08764a1 | ||
|
|
c80ede5f13 | ||
|
|
bc694039e4 | ||
|
|
3462af03e6 | ||
|
|
ea1d5bdcdd | ||
|
|
121c09c7be | ||
|
|
76bfaf6daf | ||
|
|
d89c6e336a | ||
|
|
776dc3992a | ||
|
|
27ca82ebc6 | ||
|
|
385f8ae468 | ||
|
|
b9f030cc26 | ||
|
|
52afb2ac1b | ||
|
|
43bc88903d | ||
|
|
6ef9f88299 | ||
|
|
f71fdb0acc | ||
|
|
c24dfef63c | ||
|
|
6271f1cad9 | ||
|
|
fb4b030aaf | ||
|
|
ff21a8e0ee | ||
|
|
904fffffeb | ||
|
|
51897bb77c | ||
|
|
bd1a281ede | ||
|
|
45598f1578 | ||
|
|
d02115f837 | ||
|
|
34c781a24d | ||
|
|
1302394603 | ||
|
|
dd622d7c4e | ||
|
|
d120e9013f | ||
|
|
b8da6b9fc6 | ||
|
|
4baea47c42 | ||
|
|
176cf9e0c3 | ||
|
|
7b6faddfc8 | ||
|
|
f90ad27375 | ||
|
|
230b2287dd | ||
|
|
754c838903 | ||
|
|
aa2fd59857 | ||
|
|
9932a65370 | ||
|
|
5e4166478d | ||
|
|
b0e87c3110 | ||
|
|
ff0813313a | ||
|
|
c0bdf32a3c | ||
|
|
92b065dc53 | ||
|
|
9298d4e3df | ||
|
|
740a7fcbc8 | ||
|
|
5fbf25a681 | ||
|
|
db6e625005 | ||
|
|
811cacdc2c | ||
|
|
ce08a86462 | ||
|
|
11497d5bba | ||
|
|
0217c78377 | ||
|
|
bd6b25ce0e | ||
|
|
d51a853d5c | ||
|
|
9ed99402f5 | ||
|
|
ec3a6a3137 | ||
|
|
796858a53f | ||
|
|
5b78caca94 | ||
|
|
bec2248141 | ||
|
|
211503c39f | ||
|
|
adb1307b9a | ||
|
|
99673f04bc | ||
|
|
e9a537774d | ||
|
|
367f539769 | ||
|
|
398133cf55 | ||
|
|
52fc3ba405 | ||
|
|
fdd6e18b75 | ||
|
|
58a84b8cb6 | ||
|
|
c5d666d374 | ||
|
|
5d8993b06a | ||
|
|
c758bf9fd7 | ||
|
|
900813a328 | ||
|
|
2bad0e5d20 | ||
|
|
ccc5842bc9 | ||
|
|
fd86c2026d | ||
|
|
e4a8eae701 | ||
|
|
75e51819d0 | ||
|
|
8ee341500d | ||
|
|
0590062925 | ||
|
|
799d88d3d8 | ||
|
|
760aea9a96 | ||
|
|
d6a31b1766 | ||
|
|
0b54a5b10a | ||
|
|
6309cb9b41 | ||
|
|
27a82a1b93 | ||
|
|
ecd1936695 | ||
|
|
76b3c61012 | ||
|
|
0df2dea73b | ||
|
|
f8bb576c4f | ||
|
|
ee61f6f3e2 | ||
|
|
f14f2a6d79 | ||
|
|
2c322cc5d6 | ||
|
|
3b8f3a1504 | ||
|
|
8f9529cd05 | ||
|
|
f4bca0b348 | ||
|
|
6291438073 | ||
|
|
18c3c15391 | ||
|
|
dda620e88c | ||
|
|
d7cc31b63e | ||
|
|
5e3e1c82d8 | ||
|
|
aa80652f47 | ||
|
|
9d247bbd2d | ||
|
|
93e40a7b2f | ||
|
|
03ff2cc1c4 | ||
|
|
a285b6377b | ||
|
|
cd791a5ea0 | ||
|
|
87830900a9 | ||
|
|
dfc9d9f50a | ||
|
|
75311a7e16 | ||
|
|
628bc4d1e7 | ||
|
|
a4c3f48639 | ||
|
|
bdf80aa542 | ||
|
|
adf3c58ad3 | ||
|
|
caf90bfaa5 | ||
|
|
2f985f4bb4 | ||
|
|
67c2bcdf4c | ||
|
|
1d2d0e3ff2 | ||
|
|
9fda6ee39f | ||
|
|
bc3e582fe4 | ||
|
|
bc1fc5ddbc | ||
|
|
63948fc62c | ||
|
|
f4858a7103 | ||
|
|
26886e6140 | ||
|
|
7a1818c99b | ||
|
|
2ccd1b10e5 | ||
|
|
788fa208c8 | ||
|
|
8848314c08 | ||
|
|
c11125f9ed | ||
|
|
95ceeec722 | ||
|
|
b68ff25917 | ||
|
|
3e3327ea17 | ||
|
|
b158bb8693 | ||
|
|
2bf098eda4 | ||
|
|
382e05fa56 | ||
|
|
19b05d886e | ||
|
|
e65566a9cc | ||
|
|
baa3c3f0f6 | ||
|
|
f4f339529c | ||
|
|
7d02fae85b | ||
|
|
6e46c3f1fd | ||
|
|
c7e675940c | ||
|
|
d26b1317ed | ||
|
|
a221f22969 | ||
|
|
817f786fbb | ||
|
|
62420c73cb | ||
|
|
2522a0b7da | ||
|
|
46d32a12c9 | ||
|
|
c491418526 | ||
|
|
c067545c17 | ||
|
|
823a155293 | ||
|
|
324b2c78fa | ||
|
|
d34f98289b | ||
|
|
644096b15c | ||
|
|
15cebcc363 | ||
|
|
faa4ea68c0 | ||
|
|
29a9385ff0 | ||
|
|
476eae0c2a | ||
|
|
8399267671 | ||
|
|
db546cf87f | ||
|
|
317639758a | ||
|
|
fdbabca85f | ||
|
|
6f790e5821 | ||
|
|
6f5cdeb611 | ||
|
|
9eb4f404cb | ||
|
|
f58487b392 | ||
|
|
5b9aefef77 | ||
|
|
defaf19f5d | ||
|
|
772fd5cc44 | ||
|
|
50a0f6df7e | ||
|
|
9f435c5f1c | ||
|
|
931e2d1d26 | ||
|
|
a42419da42 | ||
|
|
9a237b776c | ||
|
|
02ec32a1ef | ||
|
|
a1e9e6440f | ||
|
|
5878e6398c | ||
|
|
6c6f1408f2 | ||
|
|
b7a7319c38 | ||
|
|
68f705cac5 | ||
|
|
079d1dcd80 | ||
|
|
7b24bbdf49 | ||
|
|
f86d543ebb | ||
|
|
60e47a2699 | ||
|
|
b8bc7a696b | ||
|
|
7d900ef1bf | ||
|
|
1931a73f39 | ||
|
|
966ea3aebd | ||
|
|
b3013681ff | ||
|
|
416c7fcbce | ||
|
|
e83eebb12f | ||
|
|
a349873226 | ||
|
|
fccae2b911 | ||
|
|
3ee08848db | ||
|
|
0129b4dd45 | ||
|
|
1c57e7f1f4 | ||
|
|
d0caf3a11e | ||
|
|
a87bb090d9 | ||
|
|
beb95e7781 | ||
|
|
5435d7af91 | ||
|
|
0c0a70f4c6 | ||
|
|
e3947e2b7f | ||
|
|
da3f7fb7f8 | ||
|
|
429ddfd38d | ||
|
|
479514d015 | ||
|
|
355e41466d | ||
|
|
03d9aad87c | ||
|
|
3e2bcf530b | ||
|
|
6343a5f68e | ||
|
|
00de9a9828 | ||
|
|
7fc2cd819e | ||
|
|
974739aab5 | ||
|
|
0cc4f8e385 | ||
|
|
513fd2a872 | ||
|
|
ae6986fb89 | ||
|
|
e8e28989eb | ||
|
|
0fa629d05b | ||
|
|
ff7a07d5c4 | ||
|
|
5a18403057 | ||
|
|
1b7b1d6eac | ||
|
|
23cfa4ae45 | ||
|
|
e82def52a9 | ||
|
|
bcfe9db299 | ||
|
|
cf00ae7640 | ||
|
|
f9b9e88646 | ||
|
|
c2500434c3 | ||
|
|
f74b341dde | ||
|
|
461b00f34a | ||
|
|
4cda41ac7b | ||
|
|
6a1c4fbfcb | ||
|
|
31424c126f | ||
|
|
53096539dc | ||
|
|
2c0b475235 | ||
|
|
a542405200 | ||
|
|
3e2b085ef9 | ||
|
|
885e4384a1 | ||
|
|
2b8f151094 | ||
|
|
5ac71f0b27 | ||
|
|
39ac7c9435 | ||
|
|
ed7bdc8a90 | ||
|
|
55f0cab3a3 | ||
|
|
544dec6298 | ||
|
|
e0ae1814b1 | ||
|
|
9532d72371 | ||
|
|
1362bbbb4b | ||
|
|
f00fd51dae | ||
|
|
a8896c5ac2 | ||
|
|
5d3808524d | ||
|
|
c8f167823f | ||
|
|
70f6796e7d | ||
|
|
85d253af6b | ||
|
|
a86cbf5876 | ||
|
|
3f1399de8a | ||
|
|
1f809a8560 | ||
|
|
653d14e2f9 | ||
|
|
85fab7e47b | ||
|
|
3aa9176f08 | ||
|
|
33b53b6021 | ||
|
|
3f7421b71b | ||
|
|
ee45625290 | ||
|
|
2c2a42587b | ||
|
|
e2f65efcf9 | ||
|
|
081d6e4784 | ||
|
|
1d4247f64e | ||
|
|
1ff30d7b79 | ||
|
|
16ea817968 | ||
|
|
a2a4bae929 | ||
|
|
c58843b3a1 | ||
|
|
a22524b004 | ||
|
|
87c4c21e75 | ||
|
|
b9465395cb | ||
|
|
edf41477f0 | ||
|
|
5f627b4448 | ||
|
|
60e5428925 | ||
|
|
748ec66725 | ||
|
|
e54a3a2f01 | ||
|
|
0e4cb4f406 | ||
|
|
f7ffe72ac7 | ||
|
|
cd58dc3e56 | ||
|
|
c33bcf2051 | ||
|
|
7642c08763 | ||
|
|
fdc8000810 | ||
|
|
a91c9b15e3 | ||
|
|
27d67ea2ba | ||
|
|
d6a8160902 | ||
|
|
6e1b9395c6 | ||
|
|
b1ccbed3d4 | ||
|
|
37381350f8 | ||
|
|
7af808a5ef | ||
|
|
876bef5937 | ||
|
|
a16af51873 | ||
|
|
dc9a441bfa | ||
|
|
ee6dfe8308 | ||
|
|
2cb5b03e53 | ||
|
|
964b190350 | ||
|
|
13d27a42cc | ||
|
|
ec05fee43a | ||
|
|
b50e3bc67f | ||
|
|
ac78b5e97b | ||
|
|
17e0d63957 | ||
|
|
9209fe3878 | ||
|
|
84d84211ac | ||
|
|
b4116dcdd5 | ||
|
|
bb18d787b5 | ||
|
|
0647084f39 | ||
|
|
734ea11e3c | ||
|
|
3940450878 | ||
|
|
ccbfaa83b0 | ||
|
|
d86007873e | ||
|
|
4b7df0d30c | ||
|
|
caff59499c | ||
|
|
99a0f9824a | ||
|
|
3013bbb27d | ||
|
|
6f9b54933f | ||
|
|
1bbe317508 | ||
|
|
e97a534f13 | ||
|
|
8acb83d993 | ||
|
|
71b640cc5b | ||
|
|
4f026fafbc | ||
|
|
39f594d660 | ||
|
|
cae97f6521 | ||
|
|
6cbf345f28 | ||
|
|
a0ab29f8a1 | ||
|
|
4a4fbfc967 | ||
|
|
408b5839b1 | ||
|
|
60620368d7 | ||
|
|
4927de4f86 | ||
|
|
bad5c1a303 | ||
|
|
6f18cc9abc | ||
|
|
4d144be8b0 | ||
|
|
2128b696b8 | ||
|
|
a23669220a | ||
|
|
051c46256b | ||
|
|
d5524947b5 | ||
|
|
74f91c4af7 | ||
|
|
da4d4191a9 | ||
|
|
2564300e55 | ||
|
|
cb0713d2c9 | ||
|
|
ac265bef1e | ||
|
|
4a0132c570 | ||
|
|
1fa174692a | ||
|
|
04c9544187 | ||
|
|
8085fc15cc | ||
|
|
2f15832f56 | ||
|
|
1557ed153c | ||
|
|
a6620ac28d | ||
|
|
89e36657cc | ||
|
|
7129bed51b | ||
|
|
1cc79574fc | ||
|
|
20e35880bf | ||
|
|
5e1912cfc1 | ||
|
|
293f0f39ce | ||
|
|
0db261ba56 | ||
|
|
7668a2c5cb | ||
|
|
26c06f0c51 | ||
|
|
23d3608c6b | ||
|
|
baa7081d68 | ||
|
|
19bf2b4e88 | ||
|
|
6a1b20de2a | ||
|
|
3c864e930d | ||
|
|
dc5596ff54 | ||
|
|
46d9760f5e | ||
|
|
90d71d3f08 | ||
|
|
e9404524cc | ||
|
|
dc65a213fd | ||
|
|
4237ba10dc | ||
|
|
c3f3b29b92 | ||
|
|
1c985da0ca | ||
|
|
7a60322abf | ||
|
|
07bc9a3530 | ||
|
|
a099965bad | ||
|
|
146323a7f8 | ||
|
|
57e086dcea | ||
|
|
2101f5d4cc | ||
|
|
cc8c9281e6 | ||
|
|
cf372f0778 | ||
|
|
34bc0ae667 | ||
|
|
2865cf0419 | ||
|
|
58c1f6f0a7 | ||
|
|
7c7a0d395c | ||
|
|
8bdcb436f9 | ||
|
|
ff815fe65a | ||
|
|
da3a2d8137 | ||
|
|
13dcfd41bd | ||
|
|
e56190b378 | ||
|
|
a79553f39f | ||
|
|
b3efb3ebae | ||
|
|
68d301ffd4 | ||
|
|
3b0bec8d11 | ||
|
|
412c617d0f | ||
|
|
751536f5c8 | ||
|
|
025f30ba38 | ||
|
|
0d2fb1d193 | ||
|
|
82b34105d3 | ||
|
|
73aeb2dc56 | ||
|
|
c6973bd412 | ||
|
|
f8780e6d11 | ||
|
|
e2f89ec7aa | ||
|
|
62651c556a | ||
|
|
bf94e38d3d | ||
|
|
4f97852316 | ||
|
|
16040f46d6 | ||
|
|
d068ba24f3 | ||
|
|
f5e43bc695 | ||
|
|
6a5308ab49 | ||
|
|
63e0f29564 | ||
|
|
42bdd9d051 | ||
|
|
4e40de6e2a | ||
|
|
0fa2b899d1 | ||
|
|
f17e4c9c28 | ||
|
|
807962f4a1 | ||
|
|
9c1aa1d668 | ||
|
|
69f491f14e | ||
|
|
cb007f47c1 | ||
|
|
9abd500a74 | ||
|
|
cf68bcaeff | ||
|
|
cbe2bd914d | ||
|
|
75111274ed | ||
|
|
624dcebff6 | ||
|
|
9684f17cde | ||
|
|
e52a40abf7 | ||
|
|
0daa05961b | ||
|
|
158731f83e | ||
|
|
24270b0301 | ||
|
|
3c1b81b957 | ||
|
|
45c24df512 | ||
|
|
bf671b605e | ||
|
|
09c82fbc9a | ||
|
|
3bca0409fe | ||
|
|
d6f78a354d | ||
|
|
e0b9d47387 | ||
|
|
f8795e102b | ||
|
|
4bb4a18876 | ||
|
|
8560c61842 | ||
|
|
a81bbebf44 | ||
|
|
72e3ffeb74 | ||
|
|
2fc9f2b41d | ||
|
|
5f3544baa3 | ||
|
|
da27660014 | ||
|
|
b8a6114309 | ||
|
|
774e208f94 | ||
|
|
f20b52778b | ||
|
|
83e865a370 | ||
|
|
b89a938687 | ||
|
|
e89a2aabed | ||
|
|
f58766ce5c | ||
|
|
15644a40df | ||
|
|
d4800f3c3f | ||
|
|
09a5dd2d3b | ||
|
|
819039ee63 | ||
|
|
ce36339575 | ||
|
|
684712076f | ||
|
|
603c92080f | ||
|
|
16ae61f655 | ||
|
|
0ef4d4ab7e | ||
|
|
4542535f94 | ||
|
|
6a52eed80e | ||
|
|
acf5cbfe93 | ||
|
|
8d1c8cae9c | ||
|
|
c84890f708 | ||
|
|
6d0886204a | ||
|
|
04d02a9d57 | ||
|
|
6ac4e8065a | ||
|
|
b82f815f37 | ||
|
|
158f8cadc0 | ||
|
|
7d70cf4157 | ||
|
|
6591fdf51f | ||
|
|
47d7c64274 | ||
|
|
db175341c7 | ||
|
|
9ff6772790 | ||
|
|
5f9b83944d | ||
|
|
f6735be4da | ||
|
|
6a3e0103bb | ||
|
|
0b5cc1983e | ||
|
|
1a9f8b1ad4 | ||
|
|
754f0008ec | ||
|
|
7115599121 | ||
|
|
0df23ba9f9 | ||
|
|
58daf5ebed | ||
|
|
1a7c6c69d3 | ||
|
|
045c48847a | ||
|
|
e638e83662 | ||
|
|
90644a6843 | ||
|
|
d958fa9ff9 | ||
|
|
ebb6419960 | ||
|
|
122c2f87c1 | ||
|
|
a154eb3d15 | ||
|
|
81028ff9eb | ||
|
|
e8df5cee12 | ||
|
|
ab07963b5c | ||
|
|
7e26084d09 | ||
|
|
4349c07dd7 | ||
|
|
1139a54d9b | ||
|
|
b128c9ed68 | ||
|
|
2415951ead | ||
|
|
995ad69c54 | ||
|
|
225e4b9633 | ||
|
|
9776bc7f57 | ||
|
|
e703fc66c2 | ||
|
|
39c52bbd32 | ||
|
|
6219802165 | ||
|
|
8b97115358 | ||
|
|
810fb84d5e | ||
|
|
5f5e993dc6 | ||
|
|
191cc41ba4 | ||
|
|
abe70fa044 | ||
|
|
7f142293df | ||
|
|
d4e06d4a83 | ||
|
|
ecd7ea1e6b | ||
|
|
b92c548693 | ||
|
|
6ce2c6783b | ||
|
|
29f400b97d | ||
|
|
eecd6a467d | ||
|
|
dce2a3cf9e | ||
|
|
9095aa38ac | ||
|
|
0403b06985 | ||
|
|
de9bd74bc2 | ||
|
|
233d37fb6b | ||
|
|
c627f7d48c | ||
|
|
163c8babaa | ||
|
|
6708542099 | ||
|
|
ea2ee40357 | ||
|
|
62d8b56655 | ||
|
|
c492970b4b | ||
|
|
ac5633592a | ||
|
|
706d7d4ee7 | ||
|
|
752c8c9b76 | ||
|
|
b1399a144d | ||
|
|
05177b34a6 | ||
|
|
c41a9650c3 | ||
|
|
df015c69ea | ||
|
|
1434bffa1f | ||
|
|
94aa25b995 | ||
|
|
d128cfe393 | ||
|
|
954f36f890 | ||
|
|
19e92770c9 | ||
|
|
95c673a148 | ||
|
|
a196a53265 | ||
|
|
3266f0c68e | ||
|
|
1940fadd53 | ||
|
|
03fd72d996 | ||
|
|
f2b44a2513 | ||
|
|
c522adb1f0 | ||
|
|
7160532d41 | ||
|
|
4e62ebe250 | ||
|
|
4472f84f0c | ||
|
|
b766eb2707 | ||
|
|
10a404c335 | ||
|
|
c056efa2e3 | ||
|
|
283ac8d592 | ||
|
|
313d4572ce | ||
|
|
42939b6129 | ||
|
|
37ea8164d3 | ||
|
|
8c810a7db3 | ||
|
|
248a0b890f | ||
|
|
96b7c7fe3f | ||
|
|
e987e91fcc | ||
|
|
cb6444e197 | ||
|
|
93b8a10e3b | ||
|
|
4207558e8b | ||
|
|
ad0d800fc3 | ||
|
|
e232f787f6 | ||
|
|
155f9550c0 | ||
|
|
72476fcc42 | ||
|
|
29e950f7c8 | ||
|
|
7c8ea53b96 | ||
|
|
dcddc10a50 | ||
|
|
a1008af412 | ||
|
|
61c0663c1e | ||
|
|
81a7a521c5 | ||
|
|
e293711802 | ||
|
|
ceb3367320 | ||
|
|
a03aaaed2e | ||
|
|
e075a44afb | ||
|
|
8865bdeb37 | ||
|
|
3aa578cad2 | ||
|
|
d3b5101a91 | ||
|
|
5c32110114 | ||
|
|
24144e3b8d | ||
|
|
b3034f9df7 | ||
|
|
4c6d2ff8dc | ||
|
|
faf3494894 | ||
|
|
535a66ef66 | ||
|
|
5c40bba82f | ||
|
|
855dc479c2 | ||
|
|
0792d5634e | ||
|
|
e91cdcae1a | ||
|
|
27e1400f55 | ||
|
|
e0938e7731 | ||
|
|
b72823a0a4 | ||
|
|
673cf0e773 | ||
|
|
f8aace93cd | ||
|
|
80310134e0 | ||
|
|
4d2d638df4 | ||
|
|
0e44f90e18 | ||
|
|
15938ab67a | ||
|
|
ab4ee31eb1 | ||
|
|
b061ea6e9f | ||
|
|
4aae94f9d0 | ||
|
|
acda92f6bc | ||
|
|
ddfd0f2727 | ||
|
|
d0720e7118 | ||
|
|
4e262a8838 | ||
|
|
b9ed3af343 | ||
|
|
63c9b2c1d9 | ||
|
|
65f3a228b1 | ||
|
|
3004ae2c3a | ||
|
|
d9836a5917 | ||
|
|
be64b5b098 | ||
|
|
c3e74731c2 | ||
|
|
c920d7f00d | ||
|
|
0bbf12239c | ||
|
|
70d68eb46f | ||
|
|
c553fe5d29 | ||
|
|
f0c3d729d7 | ||
|
|
1cdedfee10 | ||
|
|
93129d9442 | ||
|
|
e8c8653e9d | ||
|
|
fab89c67c5 | ||
|
|
3d960a22fa | ||
|
|
51bbb084d3 | ||
|
|
2c25a2bd29 | ||
|
|
355682be01 | ||
|
|
00e9d396ab | ||
|
|
14d4e90eb1 | ||
|
|
b74e86f48a | ||
|
|
3d36cea4ac | ||
|
|
380b822003 | ||
|
|
b66e699877 | ||
|
|
27f8b0994e | ||
|
|
e311b6389a | ||
|
|
fab6d4c048 | ||
|
|
4ffc31033e | ||
|
|
c1777d5cb3 | ||
|
|
9e1a5b8455 | ||
|
|
784b6d3a9b | ||
|
|
c66bdc4869 | ||
|
|
2514d2635e | ||
|
|
8bcc875676 | ||
|
|
5f6a1245ff | ||
|
|
f3a3407226 | ||
|
|
598c218f7b | ||
|
|
4698b14b76 | ||
|
|
835a22ef3f | ||
|
|
7d4111ed14 | ||
|
|
d37cab2a9d | ||
|
|
d16abf434a | ||
|
|
a8363f3ab7 | ||
|
|
010cd3a3ee | ||
|
|
b9042def9d | ||
|
|
aa79ac0c82 | ||
|
|
88125905cf | ||
|
|
dd60be2bf9 | ||
|
|
119b3caa46 | ||
|
|
49f0da7ae1 | ||
|
|
2cead7e7bc | ||
|
|
9262867e86 | ||
|
|
b9272e8f8f | ||
|
|
021a0db8f7 | ||
|
|
e1e8b6897b | ||
|
|
53d1cd1f77 | ||
|
|
cad985ab4d | ||
|
|
c52331f30c | ||
|
|
42e1ff8665 | ||
|
|
2c64b8ba63 | ||
|
|
42e12102a9 | ||
|
|
6127693ed9 | ||
|
|
71069d2157 | ||
|
|
f3391db889 | ||
|
|
9b32eca3ce | ||
|
|
ec06f0f610 | ||
|
|
e6c9c8f6ee | ||
|
|
85b9275517 | ||
|
|
dfd5313afd | ||
|
|
be53e2a737 | ||
|
|
a1c68b9ef2 | ||
|
|
4d46c1c68c | ||
|
|
d6f714f321 | ||
|
|
8569f3d629 | ||
|
|
fed5d03260 | ||
|
|
6adeffa7c6 | ||
|
|
b244b5c3f9 | ||
|
|
f42c190769 | ||
|
|
c9bf41145f | ||
|
|
5239075bb6 | ||
|
|
84437adfa3 | ||
|
|
732ea2f09b | ||
|
|
aff2f4f4f5 | ||
|
|
3b9f631c41 | ||
|
|
3ba098a6a5 | ||
|
|
0cd64bd077 | ||
|
|
1394646a0a | ||
|
|
61ee5aeb73 | ||
|
|
07e378fa18 | ||
|
|
e07e931375 | ||
|
|
480b7c32a9 | ||
|
|
f56875f271 | ||
|
|
92120217eb | ||
|
|
37eddd3143 | ||
|
|
02a12f9fe6 | ||
|
|
6fcd6e0e21 | ||
|
|
0857baade3 | ||
|
|
469d4c8968 | ||
|
|
23ad44b57b | ||
|
|
f48d3e9bbc | ||
|
|
fbf94a7815 | ||
|
|
1921b24551 | ||
|
|
28e614de5c | ||
|
|
cd9ad1d7e8 | ||
|
|
162f54eca6 | ||
|
|
33a266f4ba | ||
|
|
6b592d93a2 | ||
|
|
4686ae4b64 | ||
|
|
8d05f2c16a | ||
|
|
a4bb83956c | ||
|
|
eb5376044c | ||
|
|
3cbcff8a2d | ||
|
|
e983cf5277 | ||
|
|
0ab1ca5501 | ||
|
|
4baafa229d | ||
|
|
7f3e33a147 | ||
|
|
b7558d9881 | ||
|
|
a0f59cdcb4 | ||
|
|
a4bc433619 | ||
|
|
b6b70730bf | ||
|
|
6a68bb574a | ||
|
|
0cf166ad4f | ||
|
|
2707b50ffe | ||
|
|
939fe70de0 | ||
|
|
89c15fe0b3 | ||
|
|
ec5f601670 | ||
|
|
8caa0c9779 | ||
|
|
e2548b5b25 | ||
|
|
bbefcf04bf | ||
|
|
c7b0add86f | ||
|
|
a0155d93d9 | ||
|
|
00d9ef0b70 | ||
|
|
0cc8888038 | ||
|
|
c735450e07 | ||
|
|
71f8c7ce7a | ||
|
|
5fee0eeac0 | ||
|
|
eb4157fd17 | ||
|
|
69ede8ef81 | ||
|
|
609a61e3e6 | ||
|
|
bf951c5e29 | ||
|
|
af63fed7d8 | ||
|
|
68d1d41c03 | ||
|
|
3deed1e91a | ||
|
|
11b28e93d3 | ||
|
|
c3d582985f | ||
|
|
4c0924bb24 | ||
|
|
3fa5bb3802 | ||
|
|
c47ec62b83 | ||
|
|
e4bdb37ec6 | ||
|
|
3e6e4999ca | ||
|
|
0e15e725a0 | ||
|
|
437f68d868 | ||
|
|
d91d124081 | ||
|
|
2d42905b68 | ||
|
|
cbe71cb41d | ||
|
|
894dd8682e | ||
|
|
9e05d039e0 | ||
|
|
bbd5f2de5e | ||
|
|
73689dafbf | ||
|
|
4b50ba0989 | ||
|
|
5ccaddf5b1 | ||
|
|
0b201a3134 | ||
|
|
ffe38646ca | ||
|
|
b703ab4d7f | ||
|
|
c6afed48ff | ||
|
|
732c848c14 | ||
|
|
9d2a4dae90 | ||
|
|
7009a9047a | ||
|
|
498942f187 | ||
|
|
28465df1ff | ||
|
|
ef89dba58f | ||
|
|
13ba3a6461 | ||
|
|
8f6ec4bbe6 | ||
|
|
c295490830 | ||
|
|
eb4cb42a02 | ||
|
|
7a8cbc72b2 | ||
|
|
2774852c2f | ||
|
|
bbcc21efd1 | ||
|
|
60526d6bcb | ||
|
|
1d4df56d09 | ||
|
|
a1cf99d03a | ||
|
|
3c6af203cc | ||
|
|
1a92e086a7 | ||
|
|
519c73f267 | ||
|
|
a6dae6c09c | ||
|
|
f866e474f3 | ||
|
|
8bb9b97c97 | ||
|
|
d6fdc38682 | ||
|
|
c2b61af548 | ||
|
|
2fdbf27ad8 | ||
|
|
3898c8a7b2 | ||
|
|
29ed169cd6 | ||
|
|
b868c972d1 | ||
|
|
9908e03528 | ||
|
|
1fe8fb8c20 | ||
|
|
5d63b0aa93 | ||
|
|
4164f0117e | ||
|
|
37aab27808 | ||
|
|
6110bbbfdd | ||
|
|
cde9b380e6 | ||
|
|
dab647a7b6 | ||
|
|
a316a83d2b | ||
|
|
81b22aee8b | ||
|
|
a80c96eab0 | ||
|
|
20436c30c9 | ||
|
|
3828505646 | ||
|
|
11fba1751d | ||
|
|
12ea2f30cf | ||
|
|
9c3e870393 | ||
|
|
44789f2457 | ||
|
|
711ede6e1b | ||
|
|
a32f253112 | ||
|
|
94bd361318 | ||
|
|
acd40f64ed | ||
|
|
766306450d | ||
|
|
e7642ab572 | ||
|
|
bdf9701729 | ||
|
|
b5af6fcdad | ||
|
|
278143df5b | ||
|
|
fdca55fe34 | ||
|
|
4f195f55f0 | ||
|
|
ac35c26686 | ||
|
|
982a58d049 | ||
|
|
42f7d2f588 | ||
|
|
39f0a2a6b7 | ||
|
|
ecc0c5ee01 | ||
|
|
451948b28c | ||
|
|
baa708036c | ||
|
|
8c25f81bee | ||
|
|
4c83c96795 | ||
|
|
9580711841 | ||
|
|
c30ae9594c | ||
|
|
ffae28ae18 | ||
|
|
d9116714f2 | ||
|
|
08965906a8 | ||
|
|
ccdd0ffb80 | ||
|
|
5263cdfcf9 | ||
|
|
b2a68d14cf | ||
|
|
6e1cff9c33 | ||
|
|
72975729c8 | ||
|
|
d319948b6a | ||
|
|
9a4bf889f9 | ||
|
|
2a834bdb21 | ||
|
|
0d2c141865 | ||
|
|
5ec39d8b96 | ||
|
|
7b6de3728a | ||
|
|
a51d3aa001 | ||
|
|
2c8e03d937 | ||
|
|
fbb21cf528 | ||
|
|
b8a618f898 | ||
|
|
feb74960eb | ||
|
|
d65d628613 | ||
|
|
ac645ac7d0 | ||
|
|
7d11297f3f | ||
|
|
6ad4013d40 | ||
|
|
dbd1283d31 | ||
|
|
c451d4f553 | ||
|
|
8abec2c8bb | ||
|
|
a9bad429b3 | ||
|
|
50c8266ef0 | ||
|
|
00edd4f9be | ||
|
|
ee966928af | ||
|
|
e5193599ec | ||
|
|
01d663bca3 | ||
|
|
e0c51cdadc | ||
|
|
9334f8f17a | ||
|
|
632256d9ec | ||
|
|
03df7baa6a | ||
|
|
3511266bc3 | ||
|
|
9fdece5d34 | ||
|
|
bbf1092ad0 | ||
|
|
9ef55c5bbc | ||
|
|
48a24ab746 | ||
|
|
68acdbda9d | ||
|
|
27c542c06f | ||
|
|
aaa399d2f6 | ||
|
|
b2e6a1c14c | ||
|
|
8cc3eba79a | ||
|
|
b0fb6d4db1 | ||
|
|
81515ad9f6 | ||
|
|
8112d4b284 | ||
|
|
bf7aa6301b | ||
|
|
aea856621f | ||
|
|
f24a5a2faa | ||
|
|
ecfe623422 | ||
|
|
4a6c94288a | ||
|
|
10e3d73472 | ||
|
|
15956b5aa1 | ||
|
|
586f7082ef | ||
|
|
d6d9186f0d | ||
|
|
2e9ff8f362 | ||
|
|
6407432333 | ||
|
|
f744c0f398 | ||
|
|
249efaf44b | ||
|
|
8d32abff9e | ||
|
|
94f052cbf4 | ||
|
|
446a03bd96 | ||
|
|
6009b69f81 | ||
|
|
3d6047113c | ||
|
|
9dec99303d | ||
|
|
7706927370 | ||
|
|
3adba6fa2a | ||
|
|
f46a8702cc | ||
|
|
8d11b59bbb | ||
|
|
cf501a23d2 | ||
|
|
2bcae58d46 | ||
|
|
c9f08154a3 | ||
|
|
526b276fd7 | ||
|
|
77ec444d9a | ||
|
|
bfc2bedcfc | ||
|
|
83855f3a1f | ||
|
|
50b51830fb | ||
|
|
3d6eed9b52 | ||
|
|
1a253e134c | ||
|
|
6194bb1419 | ||
|
|
37d66e7f1e | ||
|
|
70b7e3fbb6 | ||
|
|
0551a02b82 | ||
|
|
579657ad87 | ||
|
|
5f82b129e0 | ||
|
|
64269e4d01 | ||
|
|
d481699a7a | ||
|
|
5894a4f4ee | ||
|
|
09e5d6a6e5 | ||
|
|
274b12b5a8 | ||
|
|
23be51d8ce | ||
|
|
488447455d | ||
|
|
d28b517154 | ||
|
|
a7e97f6db1 | ||
|
|
639a422d21 | ||
|
|
f889cea109 | ||
|
|
1bdeb7be2e | ||
|
|
699151bcb1 | ||
|
|
911344e5ac | ||
|
|
03936f6e6d | ||
|
|
b13ccb1b87 | ||
|
|
f64f8a4662 | ||
|
|
681b9caa9c | ||
|
|
0eb9fb9f24 | ||
|
|
9a76f416ce | ||
|
|
603821161f | ||
|
|
d3c72db894 | ||
|
|
43d9718fb9 | ||
|
|
7fc54e5262 | ||
|
|
ec9c978481 | ||
|
|
d36cae46d8 | ||
|
|
fdfefa1b9c | ||
|
|
724d031893 | ||
|
|
63e0be3415 | ||
|
|
c64ed2a310 | ||
|
|
cdc5cb7c2b | ||
|
|
8efd06aa42 | ||
|
|
7f9ced64cb | ||
|
|
7608815cc2 | ||
|
|
5823eda139 | ||
|
|
e82c1e9a6e | ||
|
|
1ede5b2481 | ||
|
|
964ae0a122 | ||
|
|
98e1d28982 | ||
|
|
2c26df763c | ||
|
|
018e835594 | ||
|
|
e65e06fbe2 | ||
|
|
95ee84421e | ||
|
|
2acfe95f58 | ||
|
|
b5a14350b9 | ||
|
|
8d81f872fb | ||
|
|
36f1c90497 | ||
|
|
057a5206cc | ||
|
|
9e9bc793f3 | ||
|
|
25fadd06d0 | ||
|
|
7a47d07c6d | ||
|
|
5c565ac9e7 | ||
|
|
67500bf939 | ||
|
|
b1edd7a48a | ||
|
|
34e48bed3b | ||
|
|
2c63ccec78 | ||
|
|
f2f2c0c2c6 | ||
|
|
4661e243f8 | ||
|
|
f3cd403c2b | ||
|
|
ad5f53ac72 | ||
|
|
75da98e9e1 | ||
|
|
281d3f1d68 | ||
|
|
6283c10b1c | ||
|
|
85d7b76586 | ||
|
|
2399535fd1 | ||
|
|
52cffcb186 | ||
|
|
8f3b5397a7 | ||
|
|
9bbec55255 | ||
|
|
6b445558ff | ||
|
|
bfd91588f3 | ||
|
|
6bf6962062 | ||
|
|
40bca5f927 | ||
|
|
74214d35c5 | ||
|
|
1b10a011ec | ||
|
|
5a000b45b3 | ||
|
|
40b1cbafac | ||
|
|
4231235cda | ||
|
|
d24a2b20b4 | ||
|
|
8230018c20 | ||
|
|
cc98a3f096 | ||
|
|
ce519b747e | ||
|
|
16efb3695f | ||
|
|
4510d14f0a | ||
|
|
0f175a932f | ||
|
|
849b269273 | ||
|
|
95fa5fb569 | ||
|
|
77c3c5c5ed | ||
|
|
159444a668 | ||
|
|
f9befee1f5 | ||
|
|
9471c44405 | ||
|
|
013bfdd84c | ||
|
|
46fd0dd5a5 | ||
|
|
4698f0d858 | ||
|
|
355d074ff9 | ||
|
|
7da224c907 | ||
|
|
1723edb1a5 | ||
|
|
4740864508 | ||
|
|
09a42738fc | ||
|
|
df928d500f | ||
|
|
a72cbfacf0 | ||
|
|
7b61ac3ddf | ||
|
|
62a164e713 | ||
|
|
5f58165def | ||
|
|
a86c73cf80 | ||
|
|
bd4e40df1a | ||
|
|
1419fafd36 | ||
|
|
9b36dcbd65 | ||
|
|
2aefb886fa | ||
|
|
72961c2a8a | ||
|
|
4c1ce987b0 | ||
|
|
8a2300a597 | ||
|
|
1cc887cbf0 | ||
|
|
203fb43f36 | ||
|
|
4d7b03f1f2 | ||
|
|
72ebb5e4b4 | ||
|
|
8450c15c25 | ||
|
|
b88b45e46c | ||
|
|
2417dc1715 | ||
|
|
23d83ad4d5 | ||
|
|
772ece3571 | ||
|
|
2c9f31188b | ||
|
|
d18be55533 | ||
|
|
ac20fc047a | ||
|
|
b4c3c8c172 | ||
|
|
b1c3a49fff | ||
|
|
3357110a4c | ||
|
|
e29fdedb45 | ||
|
|
4828703f14 | ||
|
|
afe08e0d4a | ||
|
|
071420e136 | ||
|
|
f4cf848d1d | ||
|
|
b7b2ca6e2b | ||
|
|
1409704afa | ||
|
|
3741302a10 | ||
|
|
c8e390c2b0 | ||
|
|
823f1e015a | ||
|
|
3c06d3715e | ||
|
|
762958d5af | ||
|
|
53d9009bdb | ||
|
|
1b725173a5 | ||
|
|
0ca41c3d9c | ||
|
|
fc6861b175 | ||
|
|
b097b5f246 | ||
|
|
385009fc44 | ||
|
|
ced659bb4d | ||
|
|
842cca7d56 | ||
|
|
b3826f6c8d | ||
|
|
7bc8780c57 | ||
|
|
c59c3c84ed | ||
|
|
24f7fb5e1e | ||
|
|
3b700f8d43 | ||
|
|
31d06400ec | ||
|
|
642b76ac15 | ||
|
|
4c4de296d4 | ||
|
|
b10609d98c | ||
|
|
3ae165aa10 | ||
|
|
e4b85e35d0 | ||
|
|
bb0c206f59 | ||
|
|
b81f484b60 | ||
|
|
5e69192ef7 | ||
|
|
e9be9a6acd | ||
|
|
f47754f061 | ||
|
|
d838b1bd4a | ||
|
|
fe506288bd | ||
|
|
d397c0b3dd | ||
|
|
146c80e256 | ||
|
|
f78c01f68b | ||
|
|
8489578df4 | ||
|
|
10606050bc | ||
|
|
d9bf465200 | ||
|
|
01384d6e4b | ||
|
|
08d5230945 | ||
|
|
852f8641e8 | ||
|
|
18937a50a4 | ||
|
|
e4d6cca0c1 | ||
|
|
d5feab9aaa | ||
|
|
9e77c60c9a | ||
|
|
1414df5ce2 | ||
|
|
e80f40e5ca | ||
|
|
d3c9af84fc | ||
|
|
59d206ca2d | ||
|
|
fc66e4a0d5 | ||
|
|
e7b6d12254 | ||
|
|
410f3e73ab | ||
|
|
07e764439a | ||
|
|
f8fb4a7ca8 | ||
|
|
4644ac5527 | ||
|
|
e497a7f2ca | ||
|
|
a3b6be104d | ||
|
|
b7bb0df21e | ||
|
|
4dc19c0982 | ||
|
|
58ea7ec81e | ||
|
|
c0f64ac689 | ||
|
|
7a08ad7d59 | ||
|
|
2d29ac4f23 | ||
|
|
a7a747d687 | ||
|
|
c816336cbd | ||
|
|
fdb4d278bf | ||
|
|
59c03a9bfb | ||
|
|
e7db973328 | ||
|
|
99b67fecc5 | ||
|
|
89294b5f50 | ||
|
|
72d53356f6 | ||
|
|
9e1e67fc15 | ||
|
|
1e60e5546e | ||
|
|
457749a703 | ||
|
|
937f935db0 | ||
|
|
80bcefcd77 | ||
|
|
8c23945c72 | ||
|
|
989b4b2b86 | ||
|
|
2a7b4681c6 | ||
|
|
8157ae3904 | ||
|
|
e50e2fcd4d | ||
|
|
6be451f422 | ||
|
|
5e4f06197f | ||
|
|
761e1645e0 | ||
|
|
8ff14175e2 | ||
|
|
dbe3043cd6 | ||
|
|
a8eb5a8e61 | ||
|
|
6043f1df4e | ||
|
|
12548cd933 | ||
|
|
2593039522 | ||
|
|
35d3e63d24 | ||
|
|
27aede9074 | ||
|
|
f5b7e6a842 | ||
|
|
a1f934b171 | ||
|
|
a43ee88c6f | ||
|
|
e2dce53781 | ||
|
|
1770ed9e86 | ||
|
|
457ac58cc7 | ||
|
|
9c44d2429b | ||
|
|
d2e32f7df5 | ||
|
|
67077b182b | ||
|
|
5f4c318844 | ||
|
|
dfee83234b | ||
|
|
7f5c0c4a19 | ||
|
|
4bc77c8417 | ||
|
|
22dd3fad86 | ||
|
|
d6e6a42256 | ||
|
|
76e7d1e74b | ||
|
|
38c4d41b74 | ||
|
|
f0b8e3607d | ||
|
|
51ee08c4bb | ||
|
|
c841789772 | ||
|
|
c121a75b36 | ||
|
|
5a8b77551d | ||
|
|
0217aee154 | ||
|
|
b14f3a4c1d | ||
|
|
92f7963f6e | ||
|
|
88fbe4c2cc | ||
|
|
394599f422 | ||
|
|
ed9266db90 | ||
|
|
f4b1c7adb8 | ||
|
|
c95eeb7b80 | ||
|
|
5e43e3803c | ||
|
|
a89435a7a8 | ||
|
|
a0a90b3ba1 | ||
|
|
c664182323 | ||
|
|
6be1cd4ddb | ||
|
|
ee0d90707a | ||
|
|
f776d8f608 | ||
|
|
b3ac3a51ac | ||
|
|
0b75c2a88b | ||
|
|
7b7518124e | ||
|
|
68b0973046 | ||
|
|
3a203b8bfa | ||
|
|
70752ccefd | ||
|
|
0155549d6c | ||
|
|
b66745288e | ||
|
|
2a1325fdde | ||
|
|
2f9e8776df | ||
|
|
497339fa0e | ||
|
|
8e6f8051f0 | ||
|
|
11b3ce8509 | ||
|
|
6a5af6acb9 | ||
|
|
9a0d98bb40 | ||
|
|
fbd3162e49 | ||
|
|
54e9a4af95 | ||
|
|
8a32b82e46 | ||
|
|
fec02bcc90 | ||
|
|
c6e90caaa6 | ||
|
|
4bbf157794 | ||
|
|
6b08cdf626 | ||
|
|
b686fc18da | ||
|
|
0b97f3a936 | ||
|
|
eb73f2649f | ||
|
|
f0b5d6af74 | ||
|
|
2f771f6c99 | ||
|
|
3b2f933b01 | ||
|
|
cc746841e7 | ||
|
|
ac7553d031 | ||
|
|
cdc628a498 | ||
|
|
69ea8ca42c | ||
|
|
4bc3a23ec5 | ||
|
|
bd5650ac64 | ||
|
|
86916dae4b | ||
|
|
f7d159cf95 | ||
|
|
632e5684ce | ||
|
|
094d42fe44 | ||
|
|
63cddb6477 | ||
|
|
273dea4248 | ||
|
|
f90d95edeb | ||
|
|
45c85d7ba1 | ||
|
|
d0df92928b | ||
|
|
df8f53f752 | ||
|
|
e35cb78c40 | ||
|
|
3ef7d11acd | ||
|
|
224ce0d872 | ||
|
|
dd41e8c82b | ||
|
|
b509a4b176 | ||
|
|
b28c8403b2 | ||
|
|
7bd4b4229a | ||
|
|
72e450c555 | ||
|
|
522c55b7f2 | ||
|
|
58e7071a2c | ||
|
|
516812df41 | ||
|
|
752297631f | ||
|
|
34e14a9beb | ||
|
|
ffb5b05db1 | ||
|
|
3e8fcd9fa1 | ||
|
|
746c67d72f | ||
|
|
5aa38e75b2 | ||
|
|
532f5bff70 | ||
|
|
f566d9f1d5 | ||
|
|
7267bd536f | ||
|
|
589d3d7c7a | ||
|
|
46f74bcf5c | ||
|
|
37bfe8ace4 | ||
|
|
0529eef5a4 | ||
|
|
fd78a4d3e6 | ||
|
|
1de33fafd9 | ||
|
|
e2e5dae64d | ||
|
|
09b23c902b | ||
|
|
109a540e7a | ||
|
|
2914e5f00f | ||
|
|
2f834e9381 | ||
|
|
9296738f20 | ||
|
|
0e59b9fffb | ||
|
|
67abbe9527 | ||
|
|
944a3de278 | ||
|
|
5a13fe9ed2 | ||
|
|
6b6096d0b7 | ||
|
|
d0246d07f1 | ||
|
|
727a98c3ee | ||
|
|
997987d568 | ||
|
|
c001f939e4 | ||
|
|
e825c38082 | ||
|
|
a04aa7a9e6 | ||
|
|
7cdd5339b3 | ||
|
|
38349518f1 | ||
|
|
64892c0b79 | ||
|
|
dc9f356846 | ||
|
|
ed86ee3b4a | ||
|
|
7bb5df1cda | ||
|
|
37a81dff04 | ||
|
|
fc96eb4e21 | ||
|
|
ae369738b0 | ||
|
|
e2037b3f7d | ||
|
|
5419033935 | ||
|
|
2eebf060af | ||
|
|
acd9db5902 | ||
|
|
d0e8b3d59b | ||
|
|
c15dd15388 | ||
|
|
0003a5c416 | ||
|
|
21f2927f70 | ||
|
|
e5a79071a5 | ||
|
|
ca0e7a2b17 | ||
|
|
b523bb71ab | ||
|
|
a020a0dc20 | ||
|
|
6d1f2431bd | ||
|
|
fdea3abdf8 | ||
|
|
59d284c316 | ||
|
|
98703c7fbf | ||
|
|
b04c8f7358 | ||
|
|
56d1912f1d | ||
|
|
eb3bd7ba8d | ||
|
|
3b11e86eeb | ||
|
|
5ba693d082 | ||
|
|
11ab41658e | ||
|
|
ae91f6f99b | ||
|
|
3da0e1f8cd | ||
|
|
98676c08a1 | ||
|
|
5dbf3b5c60 | ||
|
|
b8d61935a0 | ||
|
|
20ff802c9b | ||
|
|
2bca84e345 | ||
|
|
e5a93354bc | ||
|
|
ceff3fd8ef | ||
|
|
984e8e14ea | ||
|
|
d05cfe0600 | ||
|
|
7e6a715380 | ||
|
|
d74bebd502 | ||
|
|
bf0ff93277 | ||
|
|
dc752ff442 | ||
|
|
3a36d3782e | ||
|
|
50317dbbad | ||
|
|
6539c91a78 | ||
|
|
4eefbfdbfd | ||
|
|
652f283135 | ||
|
|
2daabe4992 | ||
|
|
34a741a8ec | ||
|
|
78caa52aea | ||
|
|
310d75d141 | ||
|
|
67b7e712d8 | ||
|
|
1ad6efd9b6 | ||
|
|
c3c3fe4768 | ||
|
|
6f6ed04172 | ||
|
|
5309602106 | ||
|
|
9291475f7d | ||
|
|
81127aa55d | ||
|
|
9b583dca4c | ||
|
|
f4a3490cbc | ||
|
|
3d9fae1ed2 | ||
|
|
5c47fc6809 | ||
|
|
89fb6a9797 | ||
|
|
b734a87112 | ||
|
|
573585c234 | ||
|
|
da2e1f53e0 | ||
|
|
f24e740bb8 | ||
|
|
37419b4f99 | ||
|
|
64a450131b | ||
|
|
adf2c0989d | ||
|
|
8fb7ff25c5 | ||
|
|
473219a778 | ||
|
|
aa37e3d486 | ||
|
|
edb53e2dc3 | ||
|
|
f401a4173b | ||
|
|
de00ff6494 | ||
|
|
3616997929 | ||
|
|
eef93b0912 | ||
|
|
08d037309e | ||
|
|
6024b0f25e | ||
|
|
561266641f | ||
|
|
6899f2fe9e | ||
|
|
136c8bd275 | ||
|
|
1bf5423e82 | ||
|
|
2c5c1f48e9 | ||
|
|
d8e487fbd9 | ||
|
|
bc7ff0a8dd | ||
|
|
8e9da53140 | ||
|
|
f1d15e6dbc | ||
|
|
91ebb17ede | ||
|
|
c63b30901b | ||
|
|
f009f19ece | ||
|
|
68477e8839 | ||
|
|
0dc5365564 | ||
|
|
9face18d08 | ||
|
|
ff0ba8ce0f | ||
|
|
759c6293bd | ||
|
|
a8aa99442f | ||
|
|
94b539d155 | ||
|
|
b8874d4d4e | ||
|
|
3fbeb95e14 | ||
|
|
6e25f51cdf | ||
|
|
321c1e44f9 | ||
|
|
cc7fec5818 | ||
|
|
5fb9077e8c | ||
|
|
8e20f81c5b | ||
|
|
e154762c74 | ||
|
|
ba92ab3d05 | ||
|
|
a2f0cdc074 | ||
|
|
0933440086 | ||
|
|
70a1ecd2c1 | ||
|
|
88a23aef5a | ||
|
|
140d8d77b3 | ||
|
|
665cd96929 | ||
|
|
4d067a58ca | ||
|
|
1c1cff6a52 | ||
|
|
f063a04f07 | ||
|
|
af8812bb9b | ||
|
|
78149a962b | ||
|
|
f2d9e3a370 | ||
|
|
16e6f396b4 | ||
|
|
c6ec6b2e8b | ||
|
|
7bbc6428b6 | ||
|
|
c1a3c9ddb2 | ||
|
|
feec0f56f5 | ||
|
|
8029857d27 | ||
|
|
aa61802c1e | ||
|
|
f54aee0209 | ||
|
|
5df921b0e3 | ||
|
|
35d5b67876 | ||
|
|
674c869af4 | ||
|
|
10710ae386 | ||
|
|
a0e07d3161 | ||
|
|
88fc294f7f | ||
|
|
a232bb9551 | ||
|
|
eb833b7f5a | ||
|
|
f164038b79 | ||
|
|
f7a361c4f1 | ||
|
|
884ae74785 | ||
|
|
1dba4a2185 | ||
|
|
7d4d5f25ed | ||
|
|
33422c056d | ||
|
|
a7862a1bc8 | ||
|
|
3baa62e8d1 | ||
|
|
1bf8cf5c2c | ||
|
|
eade1d7eab | ||
|
|
1a94ff6865 | ||
|
|
b47ed50aaf | ||
|
|
1b8477729a | ||
|
|
ff6ade294c | ||
|
|
11fc065c57 | ||
|
|
94388f50b3 | ||
|
|
a444648202 | ||
|
|
7ca2e11f24 | ||
|
|
563f6dea59 | ||
|
|
e4039057be | ||
|
|
11342b54d6 | ||
|
|
49fa38adf2 | ||
|
|
9b330db7f0 | ||
|
|
d740f7e16f | ||
|
|
07e7dc4bdc | ||
|
|
4c59dc4c34 | ||
|
|
7260ea0705 | ||
|
|
35b1e44567 | ||
|
|
c9ea760e31 | ||
|
|
9ebf22b7d9 | ||
|
|
2582bebe06 | ||
|
|
c9cc0bf57b | ||
|
|
61edcfb0a2 | ||
|
|
a8be56ce3d | ||
|
|
329818484c | ||
|
|
8bdfddf641 | ||
|
|
36d65b61d4 | ||
|
|
7d48c06f27 | ||
|
|
d169e36f5c | ||
|
|
2d7af09487 | ||
|
|
48d4681efc | ||
|
|
9ea9b61448 | ||
|
|
04b4aa4a7b | ||
|
|
5a3f0d9aee | ||
|
|
1ed5b5c9c8 | ||
|
|
d10548b691 | ||
|
|
e990510e6b | ||
|
|
55f7bd2dcc | ||
|
|
f931e25959 | ||
|
|
ca9cd290c7 | ||
|
|
49e23e8b6a | ||
|
|
ae7246e7d5 | ||
|
|
43fd392413 | ||
|
|
3e7c12240c | ||
|
|
7eb21356f9 | ||
|
|
f30a38be8b | ||
|
|
2aebbccefc | ||
|
|
b170935a8f | ||
|
|
35241d05d1 | ||
|
|
be2dd0651e | ||
|
|
6a400a6339 | ||
|
|
7b53af7f70 | ||
|
|
ca7b3246b6 | ||
|
|
9c4c233b84 | ||
|
|
8a6c59865d | ||
|
|
1d57b2520c | ||
|
|
17b0b8a166 | ||
|
|
12c82cf9cb | ||
|
|
0bafcf6f46 | ||
|
|
bbc9dc56f6 | ||
|
|
72c65d39ff | ||
|
|
676e3ecf24 | ||
|
|
78272a076e | ||
|
|
723e04d0be | ||
|
|
08a36c3569 | ||
|
|
37709fae89 | ||
|
|
a81e4eb69d | ||
|
|
8e72edfb19 | ||
|
|
863f08a92e | ||
|
|
de2d9f5f1b | ||
|
|
a520c11241 | ||
|
|
b94744d157 | ||
|
|
753727cded | ||
|
|
daebaab692 | ||
|
|
3524cc25ca | ||
|
|
29a7e1f261 | ||
|
|
df53b6358d | ||
|
|
f1a9d64eea | ||
|
|
27f774862d | ||
|
|
b759a0d4d2 | ||
|
|
22a6f15061 | ||
|
|
259454525f | ||
|
|
ce6815aad3 | ||
|
|
4e408e479b | ||
|
|
a9d3890fcb | ||
|
|
2857084000 | ||
|
|
7798fad535 | ||
|
|
baf2907501 | ||
|
|
3c765c68c4 | ||
|
|
29153f49b3 | ||
|
|
071a236c5a | ||
|
|
10437550f4 | ||
|
|
2929b3e71d | ||
|
|
22449fa624 | ||
|
|
d36d3f420c | ||
|
|
60ac04e57c | ||
|
|
a7680bf330 | ||
|
|
6d3d3fc083 | ||
|
|
aff216edf4 | ||
|
|
1cb6dcdbbe | ||
|
|
3f514a353e | ||
|
|
da9ec3b932 | ||
|
|
191b7cbba9 | ||
|
|
e8c59b9642 | ||
|
|
6abb066128 | ||
|
|
8f1ea7cbb6 | ||
|
|
a204c85408 | ||
|
|
15a1f4b8fe | ||
|
|
c7bee2a725 | ||
|
|
dbc1366b50 | ||
|
|
704df56da7 | ||
|
|
33ac271ba7 | ||
|
|
0963f92f23 | ||
|
|
9a66c1079c | ||
|
|
f971dcbba0 | ||
|
|
0990305d2a | ||
|
|
bcc069a937 | ||
|
|
34708e1bb6 | ||
|
|
829476b80a | ||
|
|
1dd70fe330 | ||
|
|
067e922295 | ||
|
|
c28df2478f | ||
|
|
241f7a8ade | ||
|
|
b252735910 | ||
|
|
7adcbe7594 | ||
|
|
8d31fa3cce | ||
|
|
1f06864e9a | ||
|
|
348ae0a79e | ||
|
|
528d455632 | ||
|
|
ba5d51b340 | ||
|
|
7833d941bb | ||
|
|
a2360a4c80 | ||
|
|
a7cacbca2b | ||
|
|
c6b4132a0a | ||
|
|
ad260c90ab | ||
|
|
b8313f07bc | ||
|
|
92a17d28ac | ||
|
|
5f90042bd6 | ||
|
|
9480d1a566 | ||
|
|
36b0079f23 | ||
|
|
28028629b9 | ||
|
|
11f75cac3d | ||
|
|
e673db0194 | ||
|
|
ebab4520ff | ||
|
|
a71d1414eb | ||
|
|
423817c468 | ||
|
|
51ed9fce09 | ||
|
|
d43aeb1d00 | ||
|
|
4d805e063c | ||
|
|
24e5e24166 | ||
|
|
4d54ef20a2 | ||
|
|
54036b3991 | ||
|
|
e5402ac120 | ||
|
|
f56f8399c7 | ||
|
|
cf0c5fa3a1 | ||
|
|
8c2ccefae6 | ||
|
|
1f8b6af773 | ||
|
|
8f9b683eeb | ||
|
|
b5f4775b38 | ||
|
|
01d906ffe9 | ||
|
|
614582bcc4 | ||
|
|
e1ab5000b2 | ||
|
|
a5ed3e571e | ||
|
|
10eaeb20c5 | ||
|
|
fa8deaf38b | ||
|
|
6857590059 | ||
|
|
a3db22ebdf | ||
|
|
c8e9a235d9 | ||
|
|
30b871b0ca | ||
|
|
eb9da9b732 | ||
|
|
d769be6c96 | ||
|
|
a54bda3ae2 | ||
|
|
00558d9414 | ||
|
|
49f3c16543 | ||
|
|
2ef6fcb5d8 | ||
|
|
38fc045253 | ||
|
|
af1fd929c6 | ||
|
|
b7b04c9234 | ||
|
|
bc0bb6fd30 | ||
|
|
430826c9d4 | ||
|
|
68909f0c4e | ||
|
|
9d048a17d8 | ||
|
|
492641d10a | ||
|
|
2b9faf5542 | ||
|
|
ed2d6a1960 | ||
|
|
be843678b1 | ||
|
|
c71dfccc98 | ||
|
|
1a9ccac7c1 | ||
|
|
e330d59abb | ||
|
|
394df6d7d0 | ||
|
|
218f754940 | ||
|
|
a053c3493a | ||
|
|
50b294aab8 | ||
|
|
756b046f3e | ||
|
|
388ac0b18a | ||
|
|
ad06434bd3 | ||
|
|
bd9820c937 | ||
|
|
deda8ac376 | ||
|
|
e05f693942 | ||
|
|
b27295d2ab | ||
|
|
ace52c5713 | ||
|
|
e62e150f64 | ||
|
|
c44c0a775d | ||
|
|
5fcf2dbed0 | ||
|
|
91dff03217 | ||
|
|
a200f4cee2 | ||
|
|
ea6e8d5454 | ||
|
|
83d35817f5 | ||
|
|
76beff70a8 | ||
|
|
61882bf7c6 | ||
|
|
cab317a680 | ||
|
|
73159f99cc | ||
|
|
c15235cd07 | ||
|
|
12c3ec3382 | ||
|
|
55db73efdf | ||
|
|
af40ac054a | ||
|
|
a36819731b | ||
|
|
181c8655c7 | ||
|
|
3b95347bb6 | ||
|
|
3b88ee9a7d | ||
|
|
55c49908d2 | ||
|
|
db9b0b67b7 | ||
|
|
35f76e0061 | ||
|
|
3f338cd6de | ||
|
|
1d01f26ab1 | ||
|
|
266c71f971 | ||
|
|
e8ee972c6e | ||
|
|
f83dda12ad | ||
|
|
ca7a9c1bf7 | ||
|
|
696d49815e | ||
|
|
fe556f1b0c | ||
|
|
d5638d974f | ||
|
|
938dd254e5 | ||
|
|
6493f5d704 | ||
|
|
cd6b48365e | ||
|
|
4d9bd478f9 | ||
|
|
165250ff5e | ||
|
|
83317f6938 | ||
|
|
c1d293cfa6 | ||
|
|
247a5da704 | ||
|
|
49807b4ac6 | ||
|
|
d1b4617e1d | ||
|
|
c990bb3633 | ||
|
|
af8322d2f9 | ||
|
|
df866e7f2a | ||
|
|
664718ff63 | ||
|
|
74dcf42a85 | ||
|
|
a42c921598 | ||
|
|
3258263371 | ||
|
|
f96252b913 | ||
|
|
3cfafc4a9b | ||
|
|
6f600ff5d6 | ||
|
|
90e075da3a | ||
|
|
9572013de9 | ||
|
|
3a5beb0ca1 | ||
|
|
a6da7b6b96 | ||
|
|
173a7026d5 | ||
|
|
40a90862f4 | ||
|
|
511c4325dc | ||
|
|
85a699246a | ||
|
|
4dc5286e13 | ||
|
|
c767dc74b8 | ||
|
|
56ca04f662 | ||
|
|
eb3680123a | ||
|
|
f5273890ee | ||
|
|
c7a088a816 | ||
|
|
fb17b60811 | ||
|
|
04b89c9026 | ||
|
|
1e58804260 | ||
|
|
31bf213032 | ||
|
|
1cccc41ddc | ||
|
|
a91cf27767 | ||
|
|
64d02399d8 | ||
|
|
5961017202 | ||
|
|
d9760fd43c | ||
|
|
d42b2d2985 | ||
|
|
0c72eb9060 | ||
|
|
00cf122d7a | ||
|
|
cccfab6412 | ||
|
|
4665664c92 | ||
|
|
0adc996bc3 | ||
|
|
b42a2a720b | ||
|
|
37edd7dd4a | ||
|
|
f87b3500c5 | ||
|
|
66420a2db4 | ||
|
|
6b8492a782 | ||
|
|
f9f86b0c64 | ||
|
|
6de0595eb8 | ||
|
|
e48a2c646d | ||
|
|
0f831a1a92 | ||
|
|
1ce464aba9 | ||
|
|
6994e70651 | ||
|
|
3e510af38d | ||
|
|
0aed8df2bf | ||
|
|
5ecd7b0a92 | ||
|
|
a229909fa6 | ||
|
|
548f31d99c | ||
|
|
2f61fe4ccc | ||
|
|
03359e9864 | ||
|
|
78b296b0ff | ||
|
|
be79b07907 | ||
|
|
5537dce84d | ||
|
|
493987fefe | ||
|
|
c97797a737 | ||
|
|
8d7d9d3452 | ||
|
|
7a5e7b303c | ||
|
|
61aabb9d70 | ||
|
|
62af3a0eb5 | ||
|
|
60064c53f1 | ||
|
|
98eb1c3fa2 | ||
|
|
201e9eaa0e | ||
|
|
9afa6ede21 | ||
|
|
f4776371ae | ||
|
|
328a20bf9c | ||
|
|
5622f29ae4 | ||
|
|
b4f23afbd1 | ||
|
|
0138968a6a | ||
|
|
c7667c2d7f | ||
|
|
c3f0b12b0f | ||
|
|
4f31d0f2b7 | ||
|
|
bff74bdd1a | ||
|
|
10b04ff7f4 | ||
|
|
1f7ccb9014 | ||
|
|
c7b3209668 | ||
|
|
895ba7d1dd | ||
|
|
a2a1b0baa2 | ||
|
|
8646eb790e | ||
|
|
27ace98f51 | ||
|
|
a00d73c8c8 | ||
|
|
f036a6328e | ||
|
|
31bb8d3f51 | ||
|
|
4958ae2058 | ||
|
|
7e8d73c183 | ||
|
|
1a9b9649fb | ||
|
|
65bc504db8 | ||
|
|
0fc74a0d91 | ||
|
|
8d2cc6fbb1 | ||
|
|
a954584f63 | ||
|
|
cb3ff6fb01 | ||
|
|
71aa656d13 | ||
|
|
366b1f3cfe | ||
|
|
64ce58db38 | ||
|
|
11b85ce62e | ||
|
|
1220352ff7 | ||
|
|
8f3034d871 | ||
|
|
7fa547ab02 | ||
|
|
3182f3e2dc | ||
|
|
cbf915f3f6 | ||
|
|
b490b8849a | ||
|
|
5d2519e5bf | ||
|
|
c3415d1bac | ||
|
|
36f3542883 | ||
|
|
4cb71e9b6a | ||
|
|
4bc7009e8a | ||
|
|
16f8e9df8a | ||
|
|
b081cebefa | ||
|
|
916c145217 | ||
|
|
4192b51c7c | ||
|
|
052421ff09 | ||
|
|
4e99f48817 | ||
|
|
a11165ecc6 | ||
|
|
fbb2fc5580 | ||
|
|
2fe3d240cc | ||
|
|
42f4dcfe41 | ||
|
|
892e3192fb | ||
|
|
7272eab9d0 | ||
|
|
ebe832dc37 | ||
|
|
825abb8175 | ||
|
|
8944ec0109 | ||
|
|
c084c93402 | ||
|
|
8c778adc39 | ||
|
|
71b6065009 | ||
|
|
7e660ac113 | ||
|
|
d799b47b82 | ||
|
|
b7f8116406 | ||
|
|
6db274e057 | ||
|
|
0c92b57398 | ||
|
|
becafcbf0f | ||
|
|
92a86f4c1a | ||
|
|
dfe029a62c | ||
|
|
b0472057a3 | ||
|
|
c081b35c27 | ||
|
|
9f43890bcd | ||
|
|
94a20aa5f8 | ||
|
|
94e8df3a7e | ||
|
|
37e64addc8 | ||
|
|
d82ba23ba5 | ||
|
|
0fd7fd71b4 | ||
|
|
eae12e3fe3 | ||
|
|
798a2cad4f | ||
|
|
41c0849429 | ||
|
|
a4e5af1184 | ||
|
|
b090af5922 | ||
|
|
388841f819 | ||
|
|
1a2ecbfbc4 | ||
|
|
38e292b112 | ||
|
|
c4f731262d | ||
|
|
07cc63f386 | ||
|
|
e42a692f00 | ||
|
|
6ec7538bb4 | ||
|
|
2871d489a9 | ||
|
|
1771ddd85d | ||
|
|
5198bf68fc | ||
|
|
e00fc35dbe | ||
|
|
8904e979df | ||
|
|
53eb217661 | ||
|
|
9dcb8f3fc7 | ||
|
|
1e8ac8364b | ||
|
|
754d8a035e | ||
|
|
f1f725c6a0 | ||
|
|
06c155420f | ||
|
|
7dabd2ac45 | ||
|
|
df8ba0d2cf | ||
|
|
ff1956e07b | ||
|
|
caf5a8817b | ||
|
|
a850fde1d8 | ||
|
|
0e6ebc13d1 | ||
|
|
6f5342a201 | ||
|
|
264a7044f5 | ||
|
|
1a30deca50 | ||
|
|
d8624e6a80 | ||
|
|
4f95d455ed | ||
|
|
468d19a9c1 | ||
|
|
9aeaf730ad | ||
|
|
db964a33a1 | ||
|
|
da8fb85859 | ||
|
|
54330a1c3c | ||
|
|
9732d77ed2 | ||
|
|
199ece7eb8 | ||
|
|
1997eb0078 | ||
|
|
eef4a7a304 | ||
|
|
246168bd72 | ||
|
|
7fbf54dc62 | ||
|
|
351f373865 | ||
|
|
72e785f36a | ||
|
|
727d2930f2 | ||
|
|
c13bf7c836 | ||
|
|
f3308e138d | ||
|
|
29546b345b | ||
|
|
2c57c7fa5a | ||
|
|
b6ea11b967 | ||
|
|
b8c74d606a | ||
|
|
a5d524ef46 | ||
|
|
cceb5ec237 | ||
|
|
71a6eaff83 | ||
|
|
7fd48d0413 | ||
|
|
1b38b5be86 | ||
|
|
decf2ae400 | ||
|
|
0d989011ff | ||
|
|
01b4b74574 | ||
|
|
70f767dc65 | ||
|
|
e75c24e889 | ||
|
|
0cb2056304 | ||
|
|
8adec2b9e0 | ||
|
|
604f292ab7 | ||
|
|
23d3c422ab | ||
|
|
0c1ffe980d | ||
|
|
5e95cb27d6 | ||
|
|
3b86f936c5 | ||
|
|
e0942e37aa | ||
|
|
c45a6caa95 | ||
|
|
61bbddbaa6 | ||
|
|
5425626790 | ||
|
|
5dc3552d85 | ||
|
|
3fbd27f73e | ||
|
|
0382ecb78d | ||
|
|
72edb6fc8c | ||
|
|
66149e3f2b | ||
|
|
6e74521d98 | ||
|
|
cf01013161 | ||
|
|
1e179c7528 | ||
|
|
530ed178b7 | ||
|
|
74aa18f68f | ||
|
|
d9222264a8 | ||
|
|
ca14211e93 | ||
|
|
b1d65c3369 | ||
|
|
b4c538b02b | ||
|
|
13059bceb2 | ||
|
|
d8894e24a4 | ||
|
|
3b09757bac | ||
|
|
2f97f76877 | ||
|
|
43f0537c06 | ||
|
|
a816da0dc3 | ||
|
|
7bb49d1057 | ||
|
|
1aa42fedee | ||
|
|
66aa382eae | ||
|
|
ee90ddab94 | ||
|
|
172240c0a4 | ||
|
|
ad25aee245 | ||
|
|
bd1f325b42 | ||
|
|
00a82ea805 | ||
|
|
b1b01841af | ||
|
|
816930c485 | ||
|
|
76233cda34 | ||
|
|
9dcea39985 | ||
|
|
10d00a756a | ||
|
|
eb50741129 | ||
|
|
3804b01276 | ||
|
|
b1298d8e06 | ||
|
|
c065fd35ae | ||
|
|
6a46dc8db7 | ||
|
|
36cb99f958 | ||
|
|
81650f95e2 | ||
|
|
34dbcb8505 | ||
|
|
c993c829e2 | ||
|
|
0d90e0f067 | ||
|
|
678f58de4b | ||
|
|
c961a0e63e | ||
|
|
aaefb347c0 | ||
|
|
09018e19a5 | ||
|
|
345e37831c | ||
|
|
00ac799b68 | ||
|
|
133af9385b | ||
|
|
40c696e5c6 | ||
|
|
d6d5028922 | ||
|
|
38ad119f97 | ||
|
|
4e415288d7 | ||
|
|
fada438acf | ||
|
|
1df0ae2170 | ||
|
|
d96b9d40f0 | ||
|
|
fa19dfccf9 | ||
|
|
cdc22cb886 | ||
|
|
04c77a54b0 | ||
|
|
64a8c39a1f | ||
|
|
3d55f2806e | ||
|
|
1eb867f33f | ||
|
|
e93f4f7578 | ||
|
|
45ead916d1 | ||
|
|
3a0879c8c8 | ||
|
|
ebf361ce18 | ||
|
|
953b358668 | ||
|
|
3dfd25b3aa | ||
|
|
6f66eedc5d | ||
|
|
4094b6e36d | ||
|
|
c09cbf0ed9 | ||
|
|
391d53e1dd | ||
|
|
f64ebfe3e5 | ||
|
|
fc040bfd05 | ||
|
|
c8bf86d50d | ||
|
|
61989fb5e9 | ||
|
|
6f9d4d542f | ||
|
|
b3a8878080 | ||
|
|
f4d66a99cf | ||
|
|
537ba6f381 | ||
|
|
411f691b21 | ||
|
|
d6aa1967ad | ||
|
|
6e1e0e4b5b | ||
|
|
3941669d69 | ||
|
|
1aac03797e | ||
|
|
459af43494 | ||
|
|
f4f7e3cf41 | ||
|
|
1fd015516e | ||
|
|
76bafa8ffe | ||
|
|
8d5797b00f | ||
|
|
7571c02c8a | ||
|
|
49cbe7c8e3 | ||
|
|
ba4133c9eb | ||
|
|
b67f1840a1 | ||
|
|
165c46690f | ||
|
|
16bc9ab601 | ||
|
|
15ce1338b4 | ||
|
|
0ff30c5333 | ||
|
|
6feb2d5e80 | ||
|
|
1e07fea200 | ||
|
|
7aeb67b39b | ||
|
|
93881db22a | ||
|
|
64ed7a38f9 | ||
|
|
2fd466fcfc | ||
|
|
dc2fc73691 | ||
|
|
c4808c6009 | ||
|
|
c67f584eb3 | ||
|
|
29f6ed78e8 | ||
|
|
7807ee664d | ||
|
|
d518d06efd | ||
|
|
25a0cc44b9 | ||
|
|
825cdcec3c | ||
|
|
41b610acab | ||
|
|
0364fa8b65 | ||
|
|
849086a1ae | ||
|
|
36fbc6887f | ||
|
|
a8a98e43f2 | ||
|
|
57bdc730e2 | ||
|
|
31a196d7f5 | ||
|
|
9b27e6c3b4 | ||
|
|
62f1f9507f | ||
|
|
ee8dda41ae | ||
|
|
01ba178097 | ||
|
|
78ff59d052 | ||
|
|
f3f1cd6b3b | ||
|
|
803540e811 | ||
|
|
458ade6361 | ||
|
|
a69969ee05 | ||
|
|
f2b8db57eb | ||
|
|
331ae266ff | ||
|
|
4242001863 | ||
|
|
78338f71ca | ||
|
|
f5172a3084 | ||
|
|
c7df67edbd | ||
|
|
d410fee91d | ||
|
|
ba7aa464de | ||
|
|
8333034dce | ||
|
|
637b6af80f | ||
|
|
1044f8afd2 | ||
|
|
2f775107f9 | ||
|
|
85342674b2 | ||
|
|
fd69098a45 | ||
|
|
8867f908fc | ||
|
|
b7c33124c8 | ||
|
|
89a8c423c7 | ||
|
|
cea2582df2 | ||
|
|
e423e0baaa | ||
|
|
60b2dd1285 | ||
|
|
36ddd8b3f7 | ||
|
|
7575d52a73 | ||
|
|
9a2dc4f7ac | ||
|
|
c5cd249e41 | ||
|
|
8940c1c058 | ||
|
|
27ec04b232 | ||
|
|
d2824416aa | ||
|
|
18061bbab0 | ||
|
|
4ecbbcbcea | ||
|
|
55c97a03e1 | ||
|
|
98aeac6ea9 | ||
|
|
8bfb6723cb | ||
|
|
a20575e8ae | ||
|
|
7724572519 | ||
|
|
d763637f6a | ||
|
|
c26e9ac4b2 | ||
|
|
896bf55352 | ||
|
|
a23ba9b53c | ||
|
|
38a9339baf | ||
|
|
def8b4039f | ||
|
|
a14e1538fe | ||
|
|
5f28a1acad | ||
|
|
25e9953c6f | ||
|
|
f9df094ca5 | ||
|
|
b60a469023 | ||
|
|
7012631257 | ||
|
|
e6c9f80c48 | ||
|
|
895ce482b1 | ||
|
|
e5da4021eb | ||
|
|
2371053565 | ||
|
|
33bf9033e0 | ||
|
|
35eacd0dae | ||
|
|
96bef88f5f | ||
|
|
5524b242a7 | ||
|
|
a013eba65f | ||
|
|
36755d40b4 | ||
|
|
7d568f5ab8 | ||
|
|
a7207cd580 | ||
|
|
e8ef659cd9 | ||
|
|
b0adbe98fb | ||
|
|
0c361c41b8 | ||
|
|
e66ab17a36 | ||
|
|
cb437dc2ad | ||
|
|
0d933b2ad5 | ||
|
|
c5469e046a | ||
|
|
4d2f143ce5 | ||
|
|
8f93030c85 | ||
|
|
fdb9aebead | ||
|
|
3141feb73b | ||
|
|
9706f3f802 | ||
|
|
d5e944359e | ||
|
|
826ec77fb2 | ||
|
|
2656f4eb6a | ||
|
|
2b88feedf7 | ||
|
|
23566e0d78 | ||
|
|
828553b614 | ||
|
|
3048e82a94 | ||
|
|
09ffa08ba1 | ||
|
|
e0b4cc489f | ||
|
|
15e423407f | ||
|
|
702e522044 | ||
|
|
77abae55df | ||
|
|
617c0b2239 | ||
|
|
814d4257df | ||
|
|
23ae281b31 | ||
|
|
94128d6b0d | ||
|
|
059009c592 | ||
|
|
9cc977f104 | ||
|
|
1c0ade7afa | ||
|
|
f2741c8d3a | ||
|
|
6ab8f3584a | ||
|
|
8ae5ce1726 | ||
|
|
eb92077720 | ||
|
|
90e0fd4bad | ||
|
|
05741e05d9 | ||
|
|
9aa6637644 | ||
|
|
d30d28156d | ||
|
|
be6d722904 | ||
|
|
d551980823 | ||
|
|
f0a6c3d2bc | ||
|
|
4e0fb1280a | ||
|
|
24f5251cce | ||
|
|
ac1390eee8 | ||
|
|
4a5b4d34dc | ||
|
|
63adb0cc61 | ||
|
|
3c80377b69 | ||
|
|
24577db241 | ||
|
|
566bd96da8 | ||
|
|
ebdb64d605 | ||
|
|
a6ffb92f0b | ||
|
|
3217377b3c | ||
|
|
24da5893fc | ||
|
|
087ca2cb07 | ||
|
|
b4e7447458 | ||
|
|
a45e6aadd7 | ||
|
|
70e322695d | ||
|
|
6a15923b77 | ||
|
|
7ffad0af5a | ||
|
|
0e3ae92441 | ||
|
|
b3ae826f7a | ||
|
|
dede691aca | ||
|
|
fb6a5b965b | ||
|
|
6340716b3a | ||
|
|
b675b32e6b | ||
|
|
6a3fa81ffb | ||
|
|
df53a98f2b | ||
|
|
db23d8d2a2 | ||
|
|
0d69795014 | ||
|
|
3374f3fdc2 | ||
|
|
4bf0727b1f | ||
|
|
263bd4ec50 | ||
|
|
b7e8b6e37a | ||
|
|
ceb7a17f34 | ||
|
|
1a2f2e1e66 | ||
|
|
6803016858 | ||
|
|
9b7c4fd981 | ||
|
|
dc31942f42 | ||
|
|
1f6b8f3115 | ||
|
|
9c7b79acd9 | ||
|
|
9168308579 | ||
|
|
37e3cbe22e | ||
|
|
7e8fdb1aae | ||
|
|
386ba39cac | ||
|
|
236d0cd07c | ||
|
|
ed86f38a11 | ||
|
|
6db80ad2db | ||
|
|
14470ac87b | ||
|
|
0cdf576d86 | ||
|
|
4ffeca4ea2 | ||
|
|
211fd6c674 | ||
|
|
6ebb46c106 | ||
|
|
0f97c9a06f | ||
|
|
77fb72646f | ||
|
|
aae74e3832 | ||
|
|
894e730911 | ||
|
|
63961d87a6 | ||
|
|
87fe568c28 | ||
|
|
46531b374d | ||
|
|
9e8753911c | ||
|
|
5c6b1e578c | ||
|
|
8f0c8fb452 | ||
|
|
b702ecebf0 | ||
|
|
950dc95e97 | ||
|
|
d9dd3584e1 | ||
|
|
15a9f36849 | ||
|
|
d0087d4ff2 | ||
|
|
cc5ada6f4c | ||
|
|
dfb2e1a325 | ||
|
|
65bab327b4 | ||
|
|
9eeb7abc6b | ||
|
|
c70df21099 | ||
|
|
418424e5f5 | ||
|
|
8477466125 | ||
|
|
865dbd4a26 | ||
|
|
b1e6f55912 | ||
|
|
4d78f3b770 | ||
|
|
7f739999e9 | ||
|
|
0f8a01d4f3 | ||
|
|
e2bf499b14 | ||
|
|
7cf4547ab6 | ||
|
|
8ae980807a | ||
|
|
eec4d8ef96 | ||
|
|
610134730a | ||
|
|
212a5e28ba | ||
|
|
1c783bca88 | ||
|
|
ac73651f66 | ||
|
|
ee1a7032d5 | ||
|
|
e5ceb3bfda | ||
|
|
c2ef29234c | ||
|
|
1a1826c1af | ||
|
|
c7c6d43fe1 | ||
|
|
2902d44f99 | ||
|
|
d6e4ba287b | ||
|
|
7ed806d241 | ||
|
|
dd06c95e43 | ||
|
|
e5c3a4b549 | ||
|
|
f50ee8d1c3 | ||
|
|
0e67ab0d8e | ||
|
|
1d0668ed5a | ||
|
|
d415299a80 | ||
|
|
77541837e5 | ||
|
|
48fbb1003d | ||
|
|
e3a6576f35 | ||
|
|
89bb8e97ee | ||
|
|
3442b30ab2 | ||
|
|
375696b1b1 | ||
|
|
4ea5c7b70d | ||
|
|
305d068362 | ||
|
|
a231ce87b5 | ||
|
|
a84d20fc14 | ||
|
|
9e30092361 | ||
|
|
10d5c7aa5f | ||
|
|
412f356e04 | ||
|
|
8dfa187b8a | ||
|
|
c1ed1f7055 | ||
|
|
1514f74967 | ||
|
|
2e8323e3f7 | ||
|
|
69f8364042 | ||
|
|
79981f039b | ||
|
|
34d863f3fc | ||
|
|
91994c2c81 | ||
|
|
3ee4b60d56 | ||
|
|
76e92371ac | ||
|
|
08af0205f9 | ||
|
|
a725fb1f43 | ||
|
|
05ee2b6dad | ||
|
|
b74feacac5 | ||
|
|
426b52fc5d | ||
|
|
5c30b26846 | ||
|
|
f07b74fc18 | ||
|
|
a5a45015ba | ||
|
|
beee53de06 | ||
|
|
8712f2bea7 | ||
|
|
ea102818c9 | ||
|
|
0a871f6880 | ||
|
|
481efc84a8 | ||
|
|
01ed5c9be3 | ||
|
|
ad3bc6acd5 | ||
|
|
5afa7f8bee | ||
|
|
ec8deefc27 | ||
|
|
a2d5a4ee64 | ||
|
|
dffcc2ea0c | ||
|
|
1800eeefed | ||
|
|
d7e7dedbde | ||
|
|
d19bb9c0aa | ||
|
|
3ef79a974a | ||
|
|
bc6800fbed | ||
|
|
65314dccf8 | ||
|
|
feb7221209 | ||
|
|
56a94d8cbb | ||
|
|
24e6ec8ac8 | ||
|
|
87724af7a8 | ||
|
|
b65c3e77e8 | ||
|
|
5301304bf2 | ||
|
|
948bcc60df | ||
|
|
25dfe0eb10 | ||
|
|
8e71456a81 | ||
|
|
ccdd34ed78 | ||
|
|
26d886354f | ||
|
|
a172b258ac | ||
|
|
7b93c2c204 | ||
|
|
57c7411f46 | ||
|
|
d0a122348e | ||
|
|
e4cbb5f382 | ||
|
|
c1bce22f23 | ||
|
|
e3abbbe301 | ||
|
|
55b36e3710 | ||
|
|
877bea9ce1 | ||
|
|
33c7ff861e | ||
|
|
749fe60c1e | ||
|
|
63b31b059c | ||
|
|
1476b497eb | ||
|
|
e399853d0c | ||
|
|
fdb205b19e | ||
|
|
fbe8053120 | ||
|
|
ea783d01e1 | ||
|
|
b7d73595dc | ||
|
|
e97e53eeed | ||
|
|
342f630dbf | ||
|
|
69c8fb9e5d | ||
|
|
5f0f8013ac | ||
|
|
b5368acee8 | ||
|
|
f71959fcf5 | ||
|
|
5c9f3b8b16 | ||
|
|
bebd6f9308 | ||
|
|
84a2806c16 | ||
|
|
d0111a7409 | ||
|
|
aab8874c55 | ||
|
|
fcf5b01746 | ||
|
|
4de9e9a6db | ||
|
|
0067d6c4be | ||
|
|
2099125333 | ||
|
|
b48f147d5a | ||
|
|
4f3e943080 | ||
|
|
7558830fa3 | ||
|
|
867274e997 | ||
|
|
6515778305 | ||
|
|
3b1dfc0f2f | ||
|
|
d664de44b7 | ||
|
|
bbe99d26ec | ||
|
|
50fc59968e | ||
|
|
b8b01bb92a | ||
|
|
eb45133451 | ||
|
|
10c0e2d818 | ||
|
|
669f0e7cda | ||
|
|
32fd27ec98 | ||
|
|
0c13f378de | ||
|
|
0049594efb | ||
|
|
113c7d3eb0 | ||
|
|
549371fc99 | ||
|
|
957f27e5bb | ||
|
|
1f8c19767b | ||
|
|
a383a98af6 | ||
|
|
acd69589a5 | ||
|
|
b30b8698ea | ||
|
|
f1f25be6db | ||
|
|
deab8c1960 | ||
|
|
c57f775710 | ||
|
|
e75cafe9fb | ||
|
|
33ab8453c4 | ||
|
|
ebd3c7b370 | ||
|
|
29645a1d44 | ||
|
|
22d99a801a | ||
|
|
57b8d84cd9 | ||
|
|
65e4ad5bfe | ||
|
|
98b7d476d9 | ||
|
|
201e3c99b9 | ||
|
|
8a7a4a9796 | ||
|
|
df297c8794 | ||
|
|
3f53a75f02 | ||
|
|
7c360e3a04 | ||
|
|
d2176c8011 | ||
|
|
aa92f06308 | ||
|
|
e00c9cf599 | ||
|
|
ba60a3ebe0 | ||
|
|
efb7e11988 | ||
|
|
a55c8b7aac | ||
|
|
a980bc4324 | ||
|
|
4b10aadffc | ||
|
|
5bec574859 | ||
|
|
d11271dd29 | ||
|
|
1d9d26d09b | ||
|
|
c0292e8ab7 | ||
|
|
f44e5d8b43 | ||
|
|
6ea74538e3 | ||
|
|
24b8924b46 | ||
|
|
86a3c67112 | ||
|
|
8be874370d | ||
|
|
aec74dd95a | ||
|
|
6890574256 | ||
|
|
d03745c684 | ||
|
|
28746fbd59 | ||
|
|
0321213c11 | ||
|
|
3f0aae4244 | ||
|
|
48099643cc | ||
|
|
621f33c9d0 | ||
|
|
f07a9f6f43 | ||
|
|
e51880fd32 | ||
|
|
88ce273da4 | ||
|
|
b9ba5dfa28 | ||
|
|
4086f11929 | ||
|
|
478c2c6193 | ||
|
|
d2d6481afb | ||
|
|
43acb120f3 | ||
|
|
e8f2025edf | ||
|
|
a4eb9578af | ||
|
|
fa35cdad02 | ||
|
|
d1b9c912a4 | ||
|
|
edec83a025 | ||
|
|
c0a7c60815 | ||
|
|
117a7d1944 | ||
|
|
a40e0dd434 | ||
|
|
188b086dd9 | ||
|
|
1f27d2c0e1 | ||
|
|
7560096db5 | ||
|
|
282cb9c7ba | ||
|
|
3a9d6790ad | ||
|
|
0610a3e0b2 | ||
|
|
7f9c31df88 | ||
|
|
3fa6b6e293 | ||
|
|
3c50b99ab4 | ||
|
|
52fadd5fb2 | ||
|
|
5367fe7f4d | ||
|
|
427588f6e7 | ||
|
|
51745be312 | ||
|
|
d7f1e7c88f | ||
|
|
4145a257be | ||
|
|
525dc9809e | ||
|
|
1bf3210816 | ||
|
|
e6c6d10d99 | ||
|
|
f270256e06 | ||
|
|
f401c6f69f | ||
|
|
b075d25bed | ||
|
|
3d1bb6b4dd | ||
|
|
1db2666916 | ||
|
|
8f5c0218d8 | ||
|
|
d7666dff82 | ||
|
|
2d4c98dbd1 | ||
|
|
fd50bf623c | ||
|
|
d360a14678 | ||
|
|
d0f2ab6969 | ||
|
|
de906ef543 | ||
|
|
2fb3deeca1 | ||
|
|
66398056f1 | ||
|
|
77477fa4c9 | ||
|
|
a169e18ce1 | ||
|
|
381640e3ac | ||
|
|
37e3410137 | ||
|
|
97b5196960 | ||
|
|
6a4f3528c8 | ||
|
|
b9c76aa1a9 | ||
|
|
0d3070d364 | ||
|
|
7753cadbfa | ||
|
|
3950450342 | ||
|
|
c82b1fdad6 | ||
|
|
b0fb63abe8 | ||
|
|
3ab34c603e | ||
|
|
7d6413341a | ||
|
|
140012d0f6 | ||
|
|
4be9f8c814 | ||
|
|
5c802bac37 | ||
|
|
6c30ff756a | ||
|
|
62749e4708 | ||
|
|
6b7dee4b38 | ||
|
|
ef2041eb4e | ||
|
|
29e3e682af | ||
|
|
f983c44199 | ||
|
|
e4db19511a | ||
|
|
c47d21da80 | ||
|
|
269aecd0c0 | ||
|
|
aafddb2b0a | ||
|
|
6262ac8ac5 | ||
|
|
89938c719e | ||
|
|
ec0fafbb19 | ||
|
|
a5863bdf33 | ||
|
|
b58ddb32ba | ||
|
|
b9e12a8140 | ||
|
|
104aa7388a | ||
|
|
c3855d28b0 | ||
|
|
734f90bb41 | ||
|
|
91a6addeeb | ||
|
|
9afb76c5ad | ||
|
|
dfb2cb5cfd | ||
|
|
650d688d10 | ||
|
|
0ba77818f3 | ||
|
|
09baa7da7e | ||
|
|
85e787f51d | ||
|
|
2a9e1e453a | ||
|
|
ee1e199685 | ||
|
|
17c5a00774 | ||
|
|
15c0e8e7b2 | ||
|
|
cca37fba48 | ||
|
|
9d0993ec4a | ||
|
|
342f33bf9e | ||
|
|
7cd3bc5f99 | ||
|
|
931055e6cb | ||
|
|
d0e4cf82f1 | ||
|
|
6f88df2c57 | ||
|
|
4479bf2762 | ||
|
|
1ff7c0f7d8 | ||
|
|
610e47c87e | ||
|
|
50f566076f | ||
|
|
92810ff497 | ||
|
|
60ccc59a1c | ||
|
|
91745595d3 | ||
|
|
d6e40507d0 | ||
|
|
deed48b472 | ||
|
|
e4d41bfca5 | ||
|
|
a355b70f27 | ||
|
|
f8514f6186 | ||
|
|
e09b8fcd9d | ||
|
|
7d1b527ff9 | ||
|
|
f943c7b622 | ||
|
|
676eb3f2dd | ||
|
|
98b7cf1ace | ||
|
|
c465afd736 | ||
|
|
b84d6e7fc4 | ||
|
|
2efd5d78c1 | ||
|
|
c8edf47b3a | ||
|
|
3b4c26a428 | ||
|
|
1525148114 | ||
|
|
9e0c5791c1 | ||
|
|
29a1ab2afc | ||
|
|
fa387d2d99 | ||
|
|
6d0d573eca | ||
|
|
bb799e811b | ||
|
|
04ee53eca1 | ||
|
|
659eb98a53 | ||
|
|
ca6aada48e | ||
|
|
43df5a7e71 | ||
|
|
88f1c6de7b | ||
|
|
65a40ab82b | ||
|
|
4b9cced103 | ||
|
|
5c38625259 | ||
|
|
6344fa04bb | ||
|
|
e3ced9ed61 | ||
|
|
5075d598bc | ||
|
|
68eb8e90e6 | ||
|
|
d3a96346c4 | ||
|
|
0e518e2fea | ||
|
|
1e0a235f39 | ||
|
|
9ad400f75e | ||
|
|
3537b93d8a | ||
|
|
56eca2e956 | ||
|
|
2ad4d1ba07 | ||
|
|
4853de808b | ||
|
|
6ff5f12218 | ||
|
|
52a180684f | ||
|
|
b21e25702f | ||
|
|
983af2600f | ||
|
|
f34e6a2cd6 | ||
|
|
a9f304031b | ||
|
|
9271bc8355 | ||
|
|
d1b3e3dd75 | ||
|
|
968ed2a777 | ||
|
|
24de5d2556 | ||
|
|
d26e981df4 | ||
|
|
e45d40b171 | ||
|
|
4a419b8851 | ||
|
|
5fbd672c38 | ||
|
|
bec1fad223 | ||
|
|
177fed41bc | ||
|
|
b900e7cba4 | ||
|
|
14cb4979f0 | ||
|
|
69e61e30fe | ||
|
|
cce929eaac | ||
|
|
b6cfde99b7 | ||
|
|
1be99f052d | ||
|
|
2410c43d83 | ||
|
|
aea6e7fc3c | ||
|
|
91a76c40c0 | ||
|
|
d2b194607c | ||
|
|
f6177462db | ||
|
|
9ddaf4ef8c | ||
|
|
97b5573848 | ||
|
|
18c95c1ab0 | ||
|
|
0479c625a4 | ||
|
|
f659951e22 | ||
|
|
5853a7316e | ||
|
|
a612753db9 | ||
|
|
c8fc3fb524 | ||
|
|
5912c639df | ||
|
|
017e4dd58c | ||
|
|
651486621d | ||
|
|
28d9032c88 | ||
|
|
16f4eb723a | ||
|
|
1cbd410620 | ||
|
|
d41ac5f5dc | ||
|
|
9c1fc022ae | ||
|
|
83d548ef0f | ||
|
|
c72477bd32 | ||
|
|
9a7b072e38 | ||
|
|
cbc4a6cc7e | ||
|
|
cd7481a39e | ||
|
|
acd213ed6d | ||
|
|
77ffa95701 | ||
|
|
2b25cb5d76 | ||
|
|
62fec3b2ff | ||
|
|
e79162558e | ||
|
|
2da67107ee | ||
|
|
2ff7f8975e | ||
|
|
87a2566048 | ||
|
|
986f56736b | ||
|
|
2583a0308b | ||
|
|
40c716d2a2 | ||
|
|
79bfd01001 | ||
|
|
f2bcdd8e02 | ||
|
|
8c5850eeb4 | ||
|
|
bd3e077a2d | ||
|
|
7e70ac36b3 | ||
|
|
2cc0082dc0 | ||
|
|
056b56688a | ||
|
|
b17418313f | ||
|
|
e9a6fd6a68 | ||
|
|
bf30f3bd9d | ||
|
|
330edf2d84 | ||
|
|
43f775e4ca | ||
|
|
8f6562448c | ||
|
|
263f4b514b | ||
|
|
f0da3f1ef9 | ||
|
|
cb3ac1c610 | ||
|
|
8efd15f477 | ||
|
|
d26ebe990f | ||
|
|
28acf5500a | ||
|
|
214c22c704 | ||
|
|
8cdafb47b9 | ||
|
|
0dae5083f1 | ||
|
|
4c89bbd22c | ||
|
|
e2b06e76c1 | ||
|
|
e9c076c317 | ||
|
|
6c072e7d25 | ||
|
|
ac6c104871 | ||
|
|
69c01a9f68 | ||
|
|
e55213ce35 | ||
|
|
24a2aac445 | ||
|
|
784763c565 | ||
|
|
39c68260c0 | ||
|
|
149254d0d5 | ||
|
|
0c14e2fbe3 | ||
|
|
98acdc895b | ||
|
|
bd3b5b8b10 | ||
|
|
9a90636805 | ||
|
|
6a66ae96ed | ||
|
|
2c8a4ba6b5 | ||
|
|
ad8915b729 | ||
|
|
34cbc7ee8d | ||
|
|
a59e40a1ea | ||
|
|
ad0a75db6b | ||
|
|
1d0e49e1c7 | ||
|
|
b4461b6ebe | ||
|
|
80959224fe | ||
|
|
865cbf4fc5 | ||
|
|
196f061cac | ||
|
|
99b380c33b | ||
|
|
02e4482e22 | ||
|
|
b8a792de80 | ||
|
|
fac55558ad | ||
|
|
b2799ff96d | ||
|
|
7a249480b4 | ||
|
|
f605128d13 | ||
|
|
ba40a74666 | ||
|
|
fb8ae2d438 | ||
|
|
893f8832b5 | ||
|
|
878d11ec29 | ||
|
|
515bbe4b5b | ||
|
|
75f2e25ba9 | ||
|
|
0d466d34a3 | ||
|
|
6949d81095 | ||
|
|
f847ca02d3 | ||
|
|
510243ba58 | ||
|
|
b540697a8a | ||
|
|
0d3641e589 | ||
|
|
72546c831e | ||
|
|
d26db9269d | ||
|
|
4c0941853a | ||
|
|
c11726364e | ||
|
|
c577d735c6 | ||
|
|
9f0375f61a | ||
|
|
5e114e4bfe | ||
|
|
83622b6d2f | ||
|
|
3d87426c2d | ||
|
|
ce328530a9 | ||
|
|
f70daac108 | ||
|
|
912b38b428 | ||
|
|
6e25c58ed7 | ||
|
|
51fb2e98d2 | ||
|
|
38d63d846e | ||
|
|
07cec9776e | ||
|
|
ea38e55fff | ||
|
|
257cfebfe6 | ||
|
|
6eefe53329 | ||
|
|
1986025d2b | ||
|
|
c9aa111b4f | ||
|
|
bfcb6e3917 | ||
|
|
2c1396073e | ||
|
|
401983c6a0 | ||
|
|
391dc3ee07 | ||
|
|
be3b8fa30f | ||
|
|
9f5809b3e8 | ||
|
|
0320ddc192 | ||
|
|
56dd55721c | ||
|
|
231f76b530 | ||
|
|
55442a7812 | ||
|
|
43b81eb98a | ||
|
|
bfd718793c | ||
|
|
a9c2896e22 | ||
|
|
278229d195 | ||
|
|
fa154d1dbe | ||
|
|
7e2ede9891 | ||
|
|
74af99fc2f | ||
|
|
0f2a2ba14b | ||
|
|
e24b5a8610 | ||
|
|
750f9020ae | ||
|
|
f82863851e | ||
|
|
933a5b3792 | ||
|
|
aa488e1385 | ||
|
|
d77650525d | ||
|
|
3e50c29984 | ||
|
|
64e7ad6045 | ||
|
|
23f4a93bb4 | ||
|
|
6f13b055f1 | ||
|
|
1f91bd15c3 | ||
|
|
11a15be4ce | ||
|
|
14e17e18cb | ||
|
|
1b124d1942 | ||
|
|
747373d4ae | ||
|
|
18d367c0a5 | ||
|
|
a1a530b067 | ||
|
|
cb9722cb3f | ||
|
|
773c0b4bb8 | ||
|
|
23c322a531 | ||
|
|
7e8c0af004 | ||
|
|
d2983ccb25 | ||
|
|
f24e9833dc | ||
|
|
bc2bdf5709 | ||
|
|
627a209f74 | ||
|
|
1a4895453a | ||
|
|
aab74fa106 | ||
|
|
2bd9efd4c2 | ||
|
|
39a743fb9b | ||
|
|
4966a0b22d | ||
|
|
fc26023120 | ||
|
|
8d7c0cca13 | ||
|
|
f66ede4328 | ||
|
|
cc88b90ec8 | ||
|
|
b6c5fa9a0b | ||
|
|
dff10eaa77 | ||
|
|
4e6f9aeca1 | ||
|
|
e68301af21 | ||
|
|
17286a96f2 | ||
|
|
0892363e6d | ||
|
|
f102372b5f | ||
|
|
ecbe1ad207 | ||
|
|
410afb2003 | ||
|
|
9d840c43b5 | ||
|
|
6f50f63382 | ||
|
|
ff14fc4964 | ||
|
|
e125c21531 | ||
|
|
93d020dd65 | ||
|
|
a7515ec265 | ||
|
|
b6c1ceccc2 | ||
|
|
4056ad8f36 | ||
|
|
6563837ee1 | ||
|
|
fd5e6f7ef2 | ||
|
|
685052fc7b | ||
|
|
15fd51b37c | ||
|
|
d95e35d659 | ||
|
|
1439073049 | ||
|
|
1f7659dbe9 | ||
|
|
f1cef7a9ff | ||
|
|
8264223511 | ||
|
|
bc6d597828 | ||
|
|
aba77bbfc2 | ||
|
|
955c451456 | ||
|
|
e5de3f6c89 | ||
|
|
2a1db721d4 | ||
|
|
1e0eb60f1a | ||
|
|
87a29e6f25 | ||
|
|
c3d36f134f | ||
|
|
84769e708c | ||
|
|
9d2ecdbc71 | ||
|
|
9b69af5342 | ||
|
|
c21215b421 | ||
|
|
cddcfd90b4 | ||
|
|
f36aacba0f | ||
|
|
355271fb61 | ||
|
|
2a5b502364 | ||
|
|
98ff9d82d4 | ||
|
|
b1ff87224c | ||
|
|
b461641fb9 | ||
|
|
b047de6f6e | ||
|
|
34ca5d9ba0 | ||
|
|
60cc4dc4b4 | ||
|
|
db95dc13a1 | ||
|
|
777ac90791 | ||
|
|
04f9bebbcb | ||
|
|
4ea3137e41 | ||
|
|
a0792b738e | ||
|
|
19a41fc613 | ||
|
|
3ee52157fb | ||
|
|
c4d197ee2d | ||
|
|
a33932cfe3 | ||
|
|
bcf89ce62c | ||
|
|
e3899d0e00 | ||
|
|
dcb00da49c | ||
|
|
aa51d20d19 | ||
|
|
ae7ed92057 | ||
|
|
e45b31d9bd | ||
|
|
5a25f39653 | ||
|
|
963d7ec412 | ||
|
|
e712d94adf | ||
|
|
6a72423955 | ||
|
|
4126826b10 | ||
|
|
b773ead7fd | ||
|
|
855e2750bc | ||
|
|
805ef3c60b | ||
|
|
fbc2dcb40b | ||
|
|
5375d7ad84 | ||
|
|
90f3476180 | ||
|
|
ee95c09333 | ||
|
|
75d06db9fc | ||
|
|
439a1fffcb | ||
|
|
9d9d70c462 | ||
|
|
b4a186b7be | ||
|
|
bdebf51c8f | ||
|
|
264b86f9b4 | ||
|
|
9e55e37a2e | ||
|
|
1471956573 | ||
|
|
27865b2169 | ||
|
|
6d07ce0162 | ||
|
|
edb7fc5435 | ||
|
|
31f77343f2 | ||
|
|
63ad031583 | ||
|
|
957688cee6 | ||
|
|
806d6c2e8c | ||
|
|
0ef68e04d9 | ||
|
|
a496524db2 | ||
|
|
935c7360cc | ||
|
|
340b046876 | ||
|
|
cc1db7f9b7 | ||
|
|
a4ff6c4762 | ||
|
|
1060425cbb | ||
|
|
e9c092f125 | ||
|
|
22ff5d2105 | ||
|
|
136db7881b | ||
|
|
dae313e725 | ||
|
|
b74fa8cd2c | ||
|
|
94eae04c94 | ||
|
|
16ff7ebc77 | ||
|
|
c361c505b0 | ||
|
|
d37c07c575 | ||
|
|
9d6105c9f0 | ||
|
|
8dec03ecba | ||
|
|
826547870b | ||
|
|
52d6a9a61d | ||
|
|
ad242b5fbc | ||
|
|
3524175625 | ||
|
|
7b9965ea93 | ||
|
|
0a5bce566f | ||
|
|
8012bd2424 | ||
|
|
f55a1f0a88 | ||
|
|
bacac173a9 | ||
|
|
ca1fee34f2 | ||
|
|
6dadaa9930 | ||
|
|
553f6e4633 | ||
|
|
652bee05f0 | ||
|
|
d63516e9cd | ||
|
|
e477dcf649 | ||
|
|
9d3f7781f3 | ||
|
|
c7095dada3 | ||
|
|
607dbbad76 | ||
|
|
17b75c0de1 | ||
|
|
ab24f4f3be | ||
|
|
e1a52d9e10 | ||
|
|
d0ff838433 | ||
|
|
b37b94501c | ||
|
|
cb3bb2cfef | ||
|
|
e2cc7983e9 | ||
|
|
c9ae7b9565 | ||
|
|
86fb4347f7 | ||
|
|
2fcec131f5 | ||
|
|
9f62eaf4ef | ||
|
|
f92259c026 | ||
|
|
0afef30b23 | ||
|
|
dcdfd1c711 | ||
|
|
2acc1f8f50 | ||
|
|
2c39b0c695 | ||
|
|
e77c5b4f63 | ||
|
|
409a16cb72 | ||
|
|
94d5e90b4f | ||
|
|
2d73b45805 | ||
|
|
271a2dbfa2 | ||
|
|
bf4adcac66 | ||
|
|
fb8b8fdd62 | ||
|
|
5a0b26252e | ||
|
|
7d78f0cc48 | ||
|
|
f00fc78674 | ||
|
|
392017874c | ||
|
|
c3cb92d1ab | ||
|
|
aa5590fa07 | ||
|
|
8cfb5bbf92 | ||
|
|
69bb54ebf9 | ||
|
|
ca97a56e4b | ||
|
|
fc26f3b4c2 | ||
|
|
f604c93c64 | ||
|
|
dc3727b65c | ||
|
|
aba3231de1 | ||
|
|
9193bab91d | ||
|
|
fbcf3e416d | ||
|
|
c0e5d85631 | ||
|
|
ca7fa3dcb3 | ||
|
|
4ccfba28d9 | ||
|
|
abb82f1ddc | ||
|
|
cda008cff1 | ||
|
|
1877a14049 | ||
|
|
546582ec3e | ||
|
|
4534485586 | ||
|
|
a9ab8855e4 | ||
|
|
8a44ef6868 | ||
|
|
0c7214c404 | ||
|
|
4cf9654693 | ||
|
|
50a138d95c | ||
|
|
1b86cc41cf | ||
|
|
91346358b0 | ||
|
|
f3783d4b77 | ||
|
|
89ef304bed | ||
|
|
83cebb8b7a | ||
|
|
9e68f9fdf1 | ||
|
|
2acea5c03d | ||
|
|
978177527e | ||
|
|
2648c436f3 | ||
|
|
33f1f2c455 | ||
|
|
995befe0e9 | ||
|
|
1bb92aff55 | ||
|
|
b8e1471d3a | ||
|
|
60daf7f0bb | ||
|
|
a83a3139d1 | ||
|
|
fdb7ca3b8d | ||
|
|
0d7caf5cdf | ||
|
|
a339d7ba91 | ||
|
|
7216de55d6 | ||
|
|
2437fbca64 | ||
|
|
7d75d06b78 | ||
|
|
13ef5648c4 | ||
|
|
5b2478e2ba | ||
|
|
8b286571c3 | ||
|
|
f3ac523794 | ||
|
|
020cf5ebfd | ||
|
|
54ab193970 | ||
|
|
8f563f32ab | ||
|
|
151bae3566 | ||
|
|
76df418cba | ||
|
|
d0a72674c6 | ||
|
|
1d430674c7 | ||
|
|
70cb73922b | ||
|
|
344400951c | ||
|
|
ea5a0be811 | ||
|
|
3c7fd0bdb2 | ||
|
|
6cadf8c858 | ||
|
|
27579b9e4c | ||
|
|
4d756a9cc0 | ||
|
|
3e668e05be | ||
|
|
60d3a2e0f8 | ||
|
|
cc3a3b6b47 | ||
|
|
eda1d49a62 | ||
|
|
62e609ab77 | ||
|
|
2bfe4ead4b | ||
|
|
b1c6c32f78 | ||
|
|
f6acbdecf4 | ||
|
|
f1c9dfcc01 | ||
|
|
ce78943ae1 | ||
|
|
d6f0d86649 | ||
|
|
5bb67dbfea | ||
|
|
47610c4d3e | ||
|
|
b732f3581f | ||
|
|
9e57ce716f | ||
|
|
cd7ee7aa44 | ||
|
|
3cfe791473 | ||
|
|
973f2532f5 | ||
|
|
bc3be21d59 | ||
|
|
0bf5cf9886 | ||
|
|
919052d094 | ||
|
|
a2dafe2887 | ||
|
|
92661c994b | ||
|
|
ffe8fe356a | ||
|
|
bc2f773b4f | ||
|
|
f919201ecc | ||
|
|
7ff5d5c2e2 | ||
|
|
9b77f951c7 | ||
|
|
a25f2f990a | ||
|
|
78b373975d | ||
|
|
2fcc873c4c | ||
|
|
23c2baadb3 | ||
|
|
521ee82334 | ||
|
|
1df96e59ce | ||
|
|
3e123c1e28 | ||
|
|
f38da66731 | ||
|
|
06aabfc422 | ||
|
|
1052d2bfec | ||
|
|
5e0b652344 | ||
|
|
0f8f097183 | ||
|
|
491ed3dda2 | ||
|
|
af284c6d1b | ||
|
|
41d3ec5fba | ||
|
|
0568c352f3 | ||
|
|
2e7b4cb714 | ||
|
|
9767726b66 | ||
|
|
9ddfd84e41 | ||
|
|
1cf563d84b | ||
|
|
7928024f57 | ||
|
|
3eb38acb43 | ||
|
|
f7300c5c90 | ||
|
|
3489b7d26c | ||
|
|
acd2bcc384 | ||
|
|
43e77ca455 | ||
|
|
da36297988 | ||
|
|
dbb94fb044 | ||
|
|
d68f0cdb23 | ||
|
|
eae16eb67b | ||
|
|
4fc946b546 | ||
|
|
280bc5dad6 | ||
|
|
f43770d8c9 | ||
|
|
98c4b8fa1b | ||
|
|
ccb079ee67 | ||
|
|
2ea237472c | ||
|
|
0d4b4865cc | ||
|
|
fe52f9f956 | ||
|
|
882907a818 | ||
|
|
572a89cc4e | ||
|
|
c377110539 | ||
|
|
a9c7198a0b | ||
|
|
f6f01ea17b | ||
|
|
f2d0fc6823 | ||
|
|
f7000f3a1b | ||
|
|
c7f0177fa7 | ||
|
|
09c4d50944 | ||
|
|
2eb5d315d4 | ||
|
|
ad5976b4d9 | ||
|
|
a0dfcdce5e | ||
|
|
96d1637082 | ||
|
|
960f317171 | ||
|
|
4412ca751d | ||
|
|
cbffec0c95 | ||
|
|
0cea52cc18 | ||
|
|
6d784e87f4 | ||
|
|
ae6cae78f1 | ||
|
|
0f99566c01 | ||
|
|
2db806b4aa | ||
|
|
3f32c0ba4c | ||
|
|
541cb26c0d | ||
|
|
5544e038ab | ||
|
|
9032dc28a6 | ||
|
|
03635e2a71 | ||
|
|
00cf938aa5 | ||
|
|
a5f707c495 | ||
|
|
1824b48169 | ||
|
|
07ad22b8af | ||
|
|
b53466e168 | ||
|
|
6a7a389679 | ||
|
|
4edff78531 | ||
|
|
99043c2ea5 | ||
|
|
e68abba910 | ||
|
|
3165dc4d9f | ||
|
|
66c43a53e4 | ||
|
|
463b334616 | ||
|
|
b71dbc57c4 | ||
|
|
72ca1d7f45 | ||
|
|
76e461f395 | ||
|
|
1074982e6e | ||
|
|
29b2aaf035 | ||
|
|
6f90d098c5 | ||
|
|
0715161450 | ||
|
|
896583517f | ||
|
|
713d31fac8 | ||
|
|
96cb10a5f5 | ||
|
|
c207c1044e | ||
|
|
79629ec717 | ||
|
|
008fda0f08 | ||
|
|
0ae6b01937 | ||
|
|
def630e523 | ||
|
|
c5ba203e23 | ||
|
|
2317e6b2b3 | ||
|
|
cb38928974 | ||
|
|
fa78f13302 | ||
|
|
18395217c4 | ||
|
|
34bd987811 | ||
|
|
af6ba6a1c4 | ||
|
|
85409a0c69 | ||
|
|
ebfe352b62 | ||
|
|
fde56d2f17 | ||
|
|
3501423dfe | ||
|
|
0de668af51 | ||
|
|
2a584ea90a | ||
|
|
0f6ed94a15 | ||
|
|
bcb891e82b | ||
|
|
ac6e4ca1ed | ||
|
|
2e20bba708 | ||
|
|
e70dc1d14b | ||
|
|
0793a7b3c7 | ||
|
|
026fcc0495 | ||
|
|
81c2f20b53 | ||
|
|
1afe753462 | ||
|
|
524c2c716a | ||
|
|
b542d4bbd7 | ||
|
|
cf1eb45153 | ||
|
|
a97bcd80ba | ||
|
|
17968e444c | ||
|
|
2e3fd9ec2f | ||
|
|
d6a283b025 | ||
|
|
9766538124 | ||
|
|
98dbee8681 | ||
|
|
e421491b3b | ||
|
|
6828d37c41 | ||
|
|
bf5f610099 | ||
|
|
8b7f73404a | ||
|
|
85cacb2f51 | ||
|
|
b3fa3917e2 | ||
|
|
082c6c867a | ||
|
|
03fcf1ab57 | ||
|
|
3b00dea5eb | ||
|
|
8bc6c8e3c0 | ||
|
|
79bc27b53a | ||
|
|
84dd703199 | ||
|
|
c6fdba23a6 | ||
|
|
b19fe521a9 | ||
|
|
c1e672d121 | ||
|
|
f4371f4784 | ||
|
|
d914d9d187 | ||
|
|
845d14d377 | ||
|
|
4a9540b6d2 | ||
|
|
9f31be7000 | ||
|
|
41fa1b627d | ||
|
|
c0c4e66b29 | ||
|
|
cd8662de22 | ||
|
|
3587159614 | ||
|
|
d67cc9fa7c | ||
|
|
bf3a2fe923 | ||
|
|
e9ea0bf123 | ||
|
|
63424b6233 | ||
|
|
0bf35c5cf5 | ||
|
|
95c29381eb | ||
|
|
94c4abce7f | ||
|
|
f2dffe55f8 | ||
|
|
46a073bfac | ||
|
|
df872ec4e7 | ||
|
|
5de90176d9 | ||
|
|
dcf3eec47a | ||
|
|
e9e4f30d26 | ||
|
|
83cebd73d4 | ||
|
|
1df4229bd7 | ||
|
|
3c995527e9 | ||
|
|
7c62b568a2 | ||
|
|
ccf9114e84 | ||
|
|
d8061908bb | ||
|
|
211e17dd43 | ||
|
|
6cb38a9994 | ||
|
|
fa7df757a7 | ||
|
|
8c82077619 | ||
|
|
e5d1f9e50a | ||
|
|
7ee50ae7b5 | ||
|
|
de563c9da0 | ||
|
|
50451f2a18 | ||
|
|
9bc70948e1 | ||
|
|
5dc733f071 | ||
|
|
bc4850908c | ||
|
|
20650c8654 | ||
|
|
56dced2670 | ||
|
|
eef726c04b | ||
|
|
acf1555d76 | ||
|
|
22e7f1a6ec | ||
|
|
3c49325658 | ||
|
|
bb1cd2bea1 | ||
|
|
fdf1f8d4ce | ||
|
|
117c8c6b97 | ||
|
|
5cef4ff09b | ||
|
|
91264ce572 | ||
|
|
c79ef8e1ae | ||
|
|
58d915df51 | ||
|
|
7881a64499 | ||
|
|
90159f5561 | ||
|
|
99877772d0 | ||
|
|
b0268cb6ce | ||
|
|
4edff4cfa8 | ||
|
|
1eac553e7e | ||
|
|
9d3ac7444d | ||
|
|
588128d054 | ||
|
|
8e93b9b9aa | ||
|
|
b4bcffefa3 | ||
|
|
2b39af9b4f | ||
|
|
23fe495feb | ||
|
|
b5dbe89bba | ||
|
|
dbe80ca7ad | ||
|
|
009a3408f5 | ||
|
|
b58e3c8918 | ||
|
|
56b6faf91e | ||
|
|
7ac1f877a7 | ||
|
|
d55433bbfd | ||
|
|
f0ce2bc1c5 | ||
|
|
c3bc00b90e | ||
|
|
ff6b7b049b | ||
|
|
f46359121f | ||
|
|
37c1525c17 | ||
|
|
c85e4cf7b4 | ||
|
|
c66dcda287 | ||
|
|
6d845922ab | ||
|
|
2949cbe036 | ||
|
|
c3309a7774 | ||
|
|
7aed837595 | ||
|
|
0eb799bae9 | ||
|
|
4baff4a4ae | ||
|
|
45d7bc2f8b | ||
|
|
c0c2ddddcd | ||
|
|
a96ed91610 | ||
|
|
c1206423c4 | ||
|
|
659aa21ba1 | ||
|
|
efd02e858a | ||
|
|
3bf8bc7f37 | ||
|
|
8ccda826d5 | ||
|
|
b9381e43c2 | ||
|
|
fcdea2666d | ||
|
|
c4db377cbb | ||
|
|
90dc5e8693 | ||
|
|
c81a855b0f | ||
|
|
c8d8ec8567 | ||
|
|
4f879a5be0 | ||
|
|
1a0648b4a9 | ||
|
|
3c1b4669d0 | ||
|
|
24b3d5e538 | ||
|
|
ab083b08ab | ||
|
|
89acb96927 | ||
|
|
79752e18b1 | ||
|
|
55b41c723c | ||
|
|
9f8928d032 | ||
|
|
3effa7ceaa | ||
|
|
ed9cc2f1e0 | ||
|
|
975fa541c2 | ||
|
|
251974e44c | ||
|
|
38a40276ec | ||
|
|
57b6288358 | ||
|
|
c3f51436bf | ||
|
|
0c708f11cb | ||
|
|
fb2a706d11 | ||
|
|
0b76600deb | ||
|
|
245b612a36 | ||
|
|
d882161d5a | ||
|
|
d4a21e0b49 | ||
|
|
26a78d4bbf | ||
|
|
8db69786c2 | ||
|
|
b11cec4162 | ||
|
|
7eeb5bef24 | ||
|
|
9d2032932c | ||
|
|
6490306017 | ||
|
|
ceb2b7d257 | ||
|
|
459a53c2c2 | ||
|
|
adc267eebf | ||
|
|
ffe8f62d27 | ||
|
|
ed85007039 | ||
|
|
5aaca50d60 | ||
|
|
869baf3565 | ||
|
|
e299f6d27f | ||
|
|
4a192f817e | ||
|
|
bc1d1a5a71 | ||
|
|
456895d9cf | ||
|
|
218c15ab59 | ||
|
|
17ab4d3b5e | ||
|
|
31ef0ff038 | ||
|
|
37e3b90d59 | ||
|
|
00ff8f92a5 | ||
|
|
4857beba3a | ||
|
|
c1e60cc2bf | ||
|
|
98669ed79c | ||
|
|
a3978a6159 | ||
|
|
e3a9f32f52 | ||
|
|
87fac3238d | ||
|
|
a2fb2a2134 | ||
|
|
9e8ee54553 | ||
|
|
117bec936c | ||
|
|
1547c8cc88 | ||
|
|
075911d48e | ||
|
|
b21a918984 | ||
|
|
f9b8549609 | ||
|
|
d1b30713fb | ||
|
|
e2ba07024f | ||
|
|
9b05bd42e5 | ||
|
|
b6d3a99678 | ||
|
|
96d7b8873a | ||
|
|
efc867775e | ||
|
|
5ab772f09c | ||
|
|
2a89386232 | ||
|
|
4d9be98dbc | ||
|
|
6737907826 | ||
|
|
c060b77446 | ||
|
|
7e8caf30c0 | ||
|
|
ca3e054750 | ||
|
|
1da1558f46 | ||
|
|
25c67d257c | ||
|
|
a17d16d59c | ||
|
|
d16076ff3e | ||
|
|
6c57e8a063 | ||
|
|
db1f388878 | ||
|
|
0f2999fe2b | ||
|
|
53bfd6b24c | ||
|
|
5700e7792a | ||
|
|
38c2e5b8d5 | ||
|
|
48f9678a32 | ||
|
|
beddbc2ad1 | ||
|
|
f89197d73e | ||
|
|
944d65c762 | ||
|
|
f945612bd0 | ||
|
|
59188de113 | ||
|
|
352d08e3e5 | ||
|
|
bacb5e4f44 | ||
|
|
008af8660b | ||
|
|
886fa72324 | ||
|
|
2c5bae429a | ||
|
|
f265fc1238 | ||
|
|
1394ce65b4 | ||
|
|
67ccb77197 | ||
|
|
63ef36e8d8 | ||
|
|
0b65e5d40f | ||
|
|
629be17af4 | ||
|
|
fd28827864 | ||
|
|
8c61d9a9b1 | ||
|
|
975d35dbab | ||
|
|
8b769664c4 | ||
|
|
76f270a46a | ||
|
|
9dab1b7f28 | ||
|
|
d3e5bbf437 | ||
|
|
18a25c5d78 | ||
|
|
924f47f7b6 | ||
|
|
22ff1c4a93 | ||
|
|
35409e1101 | ||
|
|
65d781128a | ||
|
|
c35b1b07e2 | ||
|
|
066f6a0630 | ||
|
|
12ed57418c | ||
|
|
8b1be5cd73 | ||
|
|
780083dbc6 | ||
|
|
4919603f66 | ||
|
|
dd26ced164 | ||
|
|
bd2d82a5d3 | ||
|
|
c4cd138b92 | ||
|
|
65697b3bf3 | ||
|
|
50317b111d | ||
|
|
d7975ea287 | ||
|
|
714d709a31 | ||
|
|
11577ec054 | ||
|
|
79bf58f9b5 | ||
|
|
cd8a562267 | ||
|
|
de3ef3ed58 | ||
|
|
8908741806 | ||
|
|
ba7678f9cc | ||
|
|
a70c83768e | ||
|
|
04b4d394d9 | ||
|
|
130f12985a | ||
|
|
4ca5d43cd8 | ||
|
|
4bbf139aa7 | ||
|
|
47739636a9 | ||
|
|
407ae733ab | ||
|
|
c39f7013e1 | ||
|
|
a4a028323e | ||
|
|
780ee4e501 | ||
|
|
d7b51547c0 | ||
|
|
43030f36db | ||
|
|
48c63f1653 | ||
|
|
90f479b6d5 | ||
|
|
6fd2957163 | ||
|
|
d3a1c71917 | ||
|
|
af1588c05f | ||
|
|
2250865fb0 | ||
|
|
99f770caa8 | ||
|
|
00122de6a9 | ||
|
|
a70515c0fd | ||
|
|
398edd0689 | ||
|
|
6562df768d | ||
|
|
06769acd71 | ||
|
|
32dac6943d | ||
|
|
90834c78fe | ||
|
|
47917f24c4 | ||
|
|
d614aa40e3 | ||
|
|
bc4ba05fcb | ||
|
|
8d9453b9e8 | ||
|
|
e4f320a4d0 | ||
|
|
ef9f2ba7af | ||
|
|
4a3b72771f | ||
|
|
913f32929b | ||
|
|
9834872bf6 | ||
|
|
94a23d2a1e | ||
|
|
608bf69880 | ||
|
|
032b3df5af | ||
|
|
9d11a41fe4 | ||
|
|
2989501131 | ||
|
|
7b0817e8e1 | ||
|
|
9d4288b2d4 | ||
|
|
3486df383b | ||
|
|
b60016e831 | ||
|
|
5aafe895fc | ||
|
|
b853d2e155 | ||
|
|
b7ab059084 | ||
|
|
c91778f8c0 | ||
|
|
5016f3eac8 | ||
|
|
efb1bb90a0 | ||
|
|
4cf393bb4b | ||
|
|
ce4e242a6f | ||
|
|
b27bec212f | ||
|
|
704519c7e3 | ||
|
|
6b79f40c3d | ||
|
|
dd27fd1739 | ||
|
|
dfa50793d8 | ||
|
|
2a7c35dd46 | ||
|
|
f2ffd10bb2 | ||
|
|
8da531359e | ||
|
|
e2b944cf43 | ||
|
|
3ec05685f7 | ||
|
|
e103fd46ca | ||
|
|
877bfd69d1 | ||
|
|
e0ef49f205 | ||
|
|
f68cd00fe3 | ||
|
|
ca70d215cf | ||
|
|
d0390a0c92 | ||
|
|
dd2535c38a | ||
|
|
b78d180170 | ||
|
|
26dca1661e | ||
|
|
f853f8594d | ||
|
|
8307aa73fb | ||
|
|
d0da491e1e | ||
|
|
6e249060cf | ||
|
|
fbcd7b5f83 | ||
|
|
9ac0a67581 | ||
|
|
befdc8f3b6 | ||
|
|
bb198c95e2 | ||
|
|
c1195541b7 | ||
|
|
26844eb57b | ||
|
|
a7732b672e | ||
|
|
677b3ce82f | ||
|
|
fabfe17d5e | ||
|
|
82696d5d5d | ||
|
|
9eea4fb835 | ||
|
|
484aaeb204 | ||
|
|
8e589a8a47 | ||
|
|
2f21eb2db6 | ||
|
|
c11529618a | ||
|
|
58c3c7ae38 | ||
|
|
c8650f7ecd | ||
|
|
14e7543a5a | ||
|
|
bf6705f584 | ||
|
|
a9f53ce7ea | ||
|
|
a45ea17042 | ||
|
|
4950f30890 | ||
|
|
7df7f00385 | ||
|
|
d2250ea7fd | ||
|
|
17093b83ca | ||
|
|
5d8683a5cd | ||
|
|
cede88e5bb | ||
|
|
aadc71642a | ||
|
|
67d28bff12 | ||
|
|
7ee40b5d1c | ||
|
|
db22af36ec | ||
|
|
f8b5ab8cfa | ||
|
|
298f16f954 | ||
|
|
3d97cbbdaf | ||
|
|
ce6b9a2dba | ||
|
|
c3197e3e5c | ||
|
|
d420d8dd1b | ||
|
|
3fabeaa1f4 | ||
|
|
35aa7098cd | ||
|
|
9d6192a5b8 | ||
|
|
76b1bd672d | ||
|
|
469ec9416a | ||
|
|
70af3439e9 | ||
|
|
bb3c20965e | ||
|
|
5f59ee7942 | ||
|
|
8f89e68781 | ||
|
|
10bff13a66 | ||
|
|
166ff8a3c7 | ||
|
|
b4622a328b | ||
|
|
cc253000e4 | ||
|
|
42e4fcf23a | ||
|
|
9c63128668 | ||
|
|
9933b57430 | ||
|
|
84c92dc00f | ||
|
|
42154ad5bc | ||
|
|
96f1b0741c | ||
|
|
bac268e243 | ||
|
|
3798eadccd | ||
|
|
2537186d43 | ||
|
|
0eecc6a417 | ||
|
|
0dc13f4c4a | ||
|
|
f577e0ce15 | ||
|
|
bd1b906527 | ||
|
|
ecfef3e5bf | ||
|
|
3d3538e422 | ||
|
|
0cdad20c75 | ||
|
|
50144133c5 | ||
|
|
089cb705e8 | ||
|
|
525e1076ad | ||
|
|
282962bd36 | ||
|
|
c93c2ab1c3 | ||
|
|
7b09a4d847 | ||
|
|
73a25b30ea | ||
|
|
ac260dd81e | ||
|
|
48a2034671 | ||
|
|
a9ce0c631e | ||
|
|
afc7bc33cb | ||
|
|
168da92b9a | ||
|
|
d70ad093af | ||
|
|
2a2e2770cc | ||
|
|
42cc71e80b | ||
|
|
496c19234c | ||
|
|
4f81667d76 | ||
|
|
56327689a2 | ||
|
|
ad84831537 | ||
|
|
5f263296ea | ||
|
|
89650ea3a6 | ||
|
|
79f8295303 | ||
|
|
400e58103d | ||
|
|
fcee8ee784 | ||
|
|
9148eb002b | ||
|
|
559e370f44 | ||
|
|
cdeb10b5cd | ||
|
|
e6162a90e6 | ||
|
|
9a6422a81e | ||
|
|
fcea44c6d5 | ||
|
|
5d73273f6f | ||
|
|
c11a0611d9 | ||
|
|
796495886e | ||
|
|
fa27f667c8 | ||
|
|
fc9713a1d2 | ||
|
|
62bcfa8c57 | ||
|
|
7f9886379c | ||
|
|
c6e4b225b1 | ||
|
|
1c0f31f9f7 | ||
|
|
41292a3827 | ||
|
|
20f1be02df | ||
|
|
a339e5cfb5 | ||
|
|
f46f4a995b | ||
|
|
4ddba33f78 | ||
|
|
e3b7aa8428 | ||
|
|
d981cef6b9 | ||
|
|
6fa81ee96e | ||
|
|
a1a337ade9 | ||
|
|
c774b3c696 | ||
|
|
3e34db3170 | ||
|
|
317d4edfa8 | ||
|
|
9b12003c35 | ||
|
|
4ea170b8a0 | ||
|
|
49f2bf76a8 | ||
|
|
01c62591d1 | ||
|
|
1e91866f77 | ||
|
|
9656ee5d1d | ||
|
|
a5f1e12a02 | ||
|
|
ca9e792253 | ||
|
|
aff24732b9 | ||
|
|
455fa214b6 | ||
|
|
a9c5e5ca6e | ||
|
|
cefcb9fde3 | ||
|
|
bca4e93076 | ||
|
|
67c20aebb7 | ||
|
|
448711e39f | ||
|
|
8bf48f237d | ||
|
|
7c0578dc86 | ||
|
|
55033ffb0a | ||
|
|
b4a9bf701a | ||
|
|
a015dce0e2 | ||
|
|
28ab2e48ae | ||
|
|
6febd1c1df | ||
|
|
6350728be2 | ||
|
|
a7c26e7338 | ||
|
|
c880557666 | ||
|
|
85689a531f | ||
|
|
cc14dfb8ec | ||
|
|
91d7d0b333 | ||
|
|
9887c9b2d6 | ||
|
|
d2fee313ec | ||
|
|
fa7f58e433 | ||
|
|
71cd2a571e | ||
|
|
7c094bfe2f | ||
|
|
0f30658329 | ||
|
|
31c1cf5a9d | ||
|
|
e63fc1bed4 | ||
|
|
efa1739b74 | ||
|
|
5ffecde73f | ||
|
|
08d13955dd | ||
|
|
531147dd5e | ||
|
|
a17c95f5e4 | ||
|
|
eadaf08c16 | ||
|
|
4a9c9b6fdb | ||
|
|
b969ab48d9 | ||
|
|
8fa8a6299b | ||
|
|
b2b0870b3a | ||
|
|
4fb757d1e0 | ||
|
|
241bce7aaf | ||
|
|
33ec2ae8d9 | ||
|
|
c801b2051a | ||
|
|
7976fcac55 | ||
|
|
e9f9a10fba | ||
|
|
1cdfc31e1f | ||
|
|
19dab5e6cc | ||
|
|
c0f9969b9e | ||
|
|
a0ddb8a2fa | ||
|
|
c1d1facd06 | ||
|
|
b26559878f | ||
|
|
fd46a318a2 | ||
|
|
5d4f3985be | ||
|
|
360babf799 | ||
|
|
a1b92edbb3 | ||
|
|
12c978739a | ||
|
|
4bc60dafeb | ||
|
|
bf5b0a1bfb | ||
|
|
bfe9de8510 | ||
|
|
5ecd3c6a09 | ||
|
|
608d11f515 | ||
|
|
c7f8537dd9 | ||
|
|
723f839911 | ||
|
|
61224dbcdd | ||
|
|
c3afc93a69 | ||
|
|
7b8af56340 | ||
|
|
539179f45b | ||
|
|
7217e148fb | ||
|
|
d29b5e812b | ||
|
|
1e923b0d29 | ||
|
|
f7e9d77f34 | ||
|
|
41cc67c542 | ||
|
|
c645c7658d | ||
|
|
b874fe2da8 | ||
|
|
c7deaa4c74 | ||
|
|
e6812ac99d | ||
|
|
719d3927d7 | ||
|
|
55e663a8d7 | ||
|
|
2c62dc26c8 | ||
|
|
3d4a70b821 | ||
|
|
4bcc7bd1f2 | ||
|
|
f49d89ee04 | ||
|
|
dabc127362 | ||
|
|
c25c991809 | ||
|
|
f45f96f8f8 | ||
|
|
1538eff6d8 | ||
|
|
00b2685b9c | ||
|
|
8e3e03229e | ||
|
|
9d8d675e0e | ||
|
|
933605d7e8 | ||
|
|
b3d9ef88ec | ||
|
|
8958b6916c | ||
|
|
9fc3bef87a | ||
|
|
d80044c235 | ||
|
|
bc2103f3bf | ||
|
|
f82b18efc1 | ||
|
|
504c668d3b | ||
|
|
466617f539 | ||
|
|
196938835a | ||
|
|
a94e129a65 | ||
|
|
5d681e960d | ||
|
|
c7b487d96b | ||
|
|
7dbf5ae587 | ||
|
|
8d0bdeba18 | ||
|
|
1b969041d7 | ||
|
|
e302f9ce32 | ||
|
|
5a94982abe | ||
|
|
7115ca84aa | ||
|
|
04ff34ab89 | ||
|
|
bbafbe20c2 | ||
|
|
c4d55a33fc | ||
|
|
147e4aece0 | ||
|
|
bd1488ae64 | ||
|
|
79fed2a4df | ||
|
|
304cbe981e | ||
|
|
3fefbf50e3 | ||
|
|
f65c1d2be0 | ||
|
|
aa94a6d315 | ||
|
|
768df74538 | ||
|
|
1f9da9049b | ||
|
|
c0d0b01f0e | ||
|
|
7c86a5b864 | ||
|
|
97e302a419 | ||
|
|
71507a11c8 | ||
|
|
a51e37af62 | ||
|
|
1fb8f09273 | ||
|
|
6c6db72ed4 | ||
|
|
0cc83dc54b | ||
|
|
5ce54a8205 | ||
|
|
8c21b7c647 | ||
|
|
77aa6b329d | ||
|
|
62d68c43ed | ||
|
|
bfaae0a768 | ||
|
|
e56f22ae20 | ||
|
|
dbd1988ed9 | ||
|
|
4ea3be0a5c | ||
|
|
3e78514568 | ||
|
|
e029b8bd43 | ||
|
|
f5567e401c | ||
|
|
9b8aaeed85 | ||
|
|
6086d121cb | ||
|
|
7de6e075b4 | ||
|
|
946135aa2a | ||
|
|
42393ce234 | ||
|
|
d6c7a367e8 | ||
|
|
cecaaf3f58 | ||
|
|
f09828b4e1 | ||
|
|
29eb517403 | ||
|
|
44c471c3b8 | ||
|
|
46374a56b2 | ||
|
|
ec98946ef9 | ||
|
|
fa77b742ac | ||
|
|
8b4e274610 | ||
|
|
d6756d3758 | ||
|
|
11b68f6e1b | ||
|
|
88bb52ee18 | ||
|
|
d90df974c3 | ||
|
|
5c541b2cb7 | ||
|
|
87a28127d2 | ||
|
|
ebce53b3d8 | ||
|
|
83c632dc43 | ||
|
|
ff07a05575 | ||
|
|
f25571ffbf | ||
|
|
f7a6892572 | ||
|
|
8fe56478f8 | ||
|
|
0e2a436dce | ||
|
|
24050dd11c | ||
|
|
8c8e3eec79 | ||
|
|
7ebc9dee69 | ||
|
|
ee3e63e477 | ||
|
|
e9c424c144 | ||
|
|
0a9ce268ba | ||
|
|
4b2da48ea7 | ||
|
|
e64eaaa97d | ||
|
|
780603027f | ||
|
|
00902cd601 | ||
|
|
d67b0b1596 | ||
|
|
d7dda16888 | ||
|
|
a19fd00cc4 | ||
|
|
d66152a898 | ||
|
|
8c5f0c9fbc | ||
|
|
6888a874a1 | ||
|
|
09dacfa57f | ||
|
|
b2ae513586 | ||
|
|
e4a0489f6e | ||
|
|
b83be81d27 | ||
|
|
6f5dcd4eee | ||
|
|
1bb2fc98e0 | ||
|
|
e3946f989e | ||
|
|
8863d0de91 | ||
|
|
7b6fefc9d4 | ||
|
|
525ef9227f | ||
|
|
c0ba0f4859 | ||
|
|
b466b7029d | ||
|
|
fa3ae234e0 | ||
|
|
48462108f3 | ||
|
|
f8b56e95b8 | ||
|
|
5fe18bdbde | ||
|
|
dca02c80bc | ||
|
|
9ee859b683 | ||
|
|
8e05c870b4 | ||
|
|
5d574e143f | ||
|
|
2a203a6cda | ||
|
|
dadb8184e4 | ||
|
|
7a563df90a | ||
|
|
24b173fa5c | ||
|
|
9b17ba0fa5 | ||
|
|
211f555d4c | ||
|
|
4d2ebb6bd7 | ||
|
|
df53747436 | ||
|
|
3bc2ddccc8 | ||
|
|
8ab470f1b2 | ||
|
|
f2c36ee43e | ||
|
|
00381b4ccb | ||
|
|
fca1ef19c1 | ||
|
|
357ddadbf5 | ||
|
|
08d03235f9 | ||
|
|
1825836235 | ||
|
|
a0088bdf93 | ||
|
|
48ad51b243 | ||
|
|
5458b4cefb | ||
|
|
7c86cd5ab1 | ||
|
|
df1d7da2af | ||
|
|
cbfc470228 | ||
|
|
f67ca84d4a | ||
|
|
e2b38da931 | ||
|
|
a30a60d8eb | ||
|
|
5a3ea17c94 | ||
|
|
475700acfe | ||
|
|
45598aab08 | ||
|
|
26e6393134 | ||
|
|
49929a20a7 | ||
|
|
f8bd0194a7 | ||
|
|
77526143e7 | ||
|
|
4ff50ef846 | ||
|
|
caefb1de87 | ||
|
|
1e1f84dac9 | ||
|
|
1d87e3a1c6 | ||
|
|
df8ae1e3a2 | ||
|
|
f7d8d4a116 | ||
|
|
1c088fa89d | ||
|
|
de2dd4c502 | ||
|
|
395293a889 | ||
|
|
db4da14027 | ||
|
|
2101830c0d | ||
|
|
977887469c | ||
|
|
ffa8f0df0a | ||
|
|
693b8b2d31 | ||
|
|
a0d96c9843 | ||
|
|
2a18bc9a4b | ||
|
|
eaa1a7bde3 | ||
|
|
0783b09b92 | ||
|
|
ffe62508e4 | ||
|
|
ac79fa02b8 | ||
|
|
7cc3570e53 | ||
|
|
baa7b1978b | ||
|
|
ac5118bcb9 | ||
|
|
5adb818947 | ||
|
|
52defb0c9b | ||
|
|
56a8ab7d60 | ||
|
|
22686b91f0 | ||
|
|
31812a9e0e | ||
|
|
11bf848191 | ||
|
|
d4df5ed14c | ||
|
|
303b479e0a | ||
|
|
4c52160646 | ||
|
|
a213880aaf | ||
|
|
42d3bf844a | ||
|
|
b860967ce4 | ||
|
|
8ca6b8fba1 | ||
|
|
c4d9e6731a | ||
|
|
0d9ec5d963 | ||
|
|
870fc4e578 | ||
|
|
f623530d6e | ||
|
|
ca9e02dc00 | ||
|
|
fb30ec22fd | ||
|
|
5cc14c2fd7 | ||
|
|
d349cd2240 | ||
|
|
0b6a9f639f | ||
|
|
715c8e7bdb | ||
|
|
7d4afc557f | ||
|
|
563e405411 | ||
|
|
f53c966a73 | ||
|
|
336c3a69bd | ||
|
|
4e76179476 | ||
|
|
ef4fd84857 | ||
|
|
72135030d1 | ||
|
|
3514813d5b | ||
|
|
9e60602084 | ||
|
|
19e3dfc9f8 | ||
|
|
a1ef7e85d6 | ||
|
|
ef2fac6f4a | ||
|
|
7fc3fa0545 | ||
|
|
673d1273ff | ||
|
|
b9a2c53833 | ||
|
|
e9bf7479d2 | ||
|
|
bfb9f7bc4c | ||
|
|
6a656a843a | ||
|
|
29030c0a4c | ||
|
|
c0ade33e16 | ||
|
|
671c0f151d | ||
|
|
27dcce1904 | ||
|
|
8aff7b9bc4 | ||
|
|
55f6597c67 | ||
|
|
d494389821 | ||
|
|
1dcc4c0cad | ||
|
|
84db81815a | ||
|
|
fb7abb31af | ||
|
|
ce93879a9b | ||
|
|
938384c587 | ||
|
|
e9d8e302aa | ||
|
|
cb7fb54600 | ||
|
|
cf6758d204 | ||
|
|
731e3dde29 | ||
|
|
a0eaa341e1 | ||
|
|
fb27c2295e | ||
|
|
1b753cb334 | ||
|
|
36a826a50d | ||
|
|
8796857429 | ||
|
|
aaebed13a8 | ||
|
|
25939ffe56 | ||
|
|
5270d8cb13 | ||
|
|
0037e02921 | ||
|
|
6ad14cab59 | ||
|
|
a9be0cc736 | ||
|
|
55a10eab48 | ||
|
|
e344693b65 | ||
|
|
355e4fd07e | ||
|
|
5e09d6abbd | ||
|
|
0a688bc0b2 | ||
|
|
b138de72f2 | ||
|
|
06dcbb71d8 | ||
|
|
c5171c454b | ||
|
|
323ec6ae56 | ||
|
|
befd88b786 | ||
|
|
a3fb4675fb | ||
|
|
5f077efcb1 | ||
|
|
9986238ba9 | ||
|
|
e1f900d6a4 | ||
|
|
acf37ca151 | ||
|
|
17769d5a6c | ||
|
|
677c18092d | ||
|
|
3862402ff3 | ||
|
|
b03d0d064c | ||
|
|
d8d6148628 | ||
|
|
2be54167d0 | ||
|
|
4e0084d92e | ||
|
|
fc9e1cc697 | ||
|
|
f8f60d2793 | ||
|
|
ea07dbb8b1 | ||
|
|
2a275ab007 | ||
|
|
a2e6db365c | ||
|
|
9d93e7da6c | ||
|
|
0e44d8381a | ||
|
|
35907e23ec | ||
|
|
76d1700b28 | ||
|
|
dcca796ce4 | ||
|
|
4b19e38954 | ||
|
|
5f09bbff4d | ||
|
|
c1f9c59d11 | ||
|
|
652cdaa269 | ||
|
|
e26f871228 | ||
|
|
6e47b51eef | ||
|
|
4a98cdbf3b | ||
|
|
c5ed4e8f7e | ||
|
|
c2e52508cc | ||
|
|
d8ec4959c8 | ||
|
|
d31209a144 | ||
|
|
529a2e2cc3 | ||
|
|
781a7d0546 | ||
|
|
fb04e40396 | ||
|
|
d9b011f201 | ||
|
|
b0b9eaa196 | ||
|
|
8b134b1062 | ||
|
|
0c75c3fa7a | ||
|
|
a3927cf7ee | ||
|
|
1a62c18f65 | ||
|
|
2a15e7063b | ||
|
|
d46cc192d7 | ||
|
|
bb2bebdbe1 | ||
|
|
5db07df634 | ||
|
|
ea36cbac5e | ||
|
|
d0d2b49ab7 | ||
|
|
31cb6d8fef | ||
|
|
daa0dd2973 | ||
|
|
de79c46c8f | ||
|
|
94ccb6fa2e | ||
|
|
07e4035879 | ||
|
|
d0efb9ec9a | ||
|
|
ac05067d3d | ||
|
|
113577e155 | ||
|
|
79d09f47c2 | ||
|
|
c059bdd432 | ||
|
|
02dbf93f0e | ||
|
|
1fb2bcbbf7 | ||
|
|
16e055849e | ||
|
|
66cfab4226 | ||
|
|
6d88bc37a3 | ||
|
|
b7553b2554 | ||
|
|
e03db0a077 | ||
|
|
a1ee09e815 | ||
|
|
267ed0c5d3 | ||
|
|
f459d17018 | ||
|
|
dc65dcbb6d | ||
|
|
d214fdb8fe | ||
|
|
138df537ff | ||
|
|
0c7c19d6bc | ||
|
|
eaaafc59c2 | ||
|
|
382ed50e0e | ||
|
|
66ec019240 | ||
|
|
bd49928f7a | ||
|
|
23e6d50d73 | ||
|
|
2e767313e4 | ||
|
|
38b2db6a66 | ||
|
|
13ebea791f | ||
|
|
4c9c57428f | ||
|
|
8bf9319e9c | ||
|
|
4914120727 | ||
|
|
36de0a0e1a | ||
|
|
e5c146d586 | ||
|
|
52ad14aeb0 | ||
|
|
43afe28588 | ||
|
|
a87b0615aa | ||
|
|
d7386f6276 | ||
|
|
081640940e | ||
|
|
7012b23c94 | ||
|
|
d3b30148ed | ||
|
|
9f79463803 | ||
|
|
d35dc6d3b5 | ||
|
|
50123be421 | ||
|
|
3f8ced5144 | ||
|
|
00ea0f11eb | ||
|
|
dca0872056 | ||
|
|
0b63aed8df | ||
|
|
15c3adbb16 | ||
|
|
f143a42fe6 | ||
|
|
241650c7ff | ||
|
|
bfe7439a20 | ||
|
|
cffa6aa107 | ||
|
|
02e4ebbbad | ||
|
|
ab009f59ef | ||
|
|
0980426559 | ||
|
|
b1c9c66936 | ||
|
|
a6a173c2fd | ||
|
|
2bb683c201 | ||
|
|
64bb5187f5 | ||
|
|
9e4f50a8ae | ||
|
|
0190eecc00 | ||
|
|
ca872a4c0b | ||
|
|
f2e87ef4fa | ||
|
|
0ad97bbc05 | ||
|
|
c4864091a1 | ||
|
|
9a98a466b3 | ||
|
|
f99e0f1ed6 | ||
|
|
d323bcb152 | ||
|
|
da6a795fdb | ||
|
|
c5edcde21f | ||
|
|
15ff3c831e | ||
|
|
100959a6d9 | ||
|
|
0a120f74b2 | ||
|
|
8f05351984 | ||
|
|
4eb92208a3 | ||
|
|
71791f414c | ||
|
|
f3682997d7 | ||
|
|
cc13cc0251 | ||
|
|
86bd5f2ca9 | ||
|
|
8694c60000 | ||
|
|
9d1538182f | ||
|
|
5904088811 | ||
|
|
69545c2aff | ||
|
|
495da337ae | ||
|
|
34b3afc7be | ||
|
|
00373a4c5d | ||
|
|
cb7dfeeac4 | ||
|
|
efd6c574a2 | ||
|
|
4113e6ab56 | ||
|
|
9a942a4671 | ||
|
|
9906d397a0 | ||
|
|
ae8f787141 | ||
|
|
a81b4d5c8f | ||
|
|
887c6acdf2 | ||
|
|
83aa529330 | ||
|
|
96b31b6533 | ||
|
|
fccd377198 | ||
|
|
2b35c9ef74 | ||
|
|
73c566695f | ||
|
|
63b7b7224a | ||
|
|
ce80c8b8ee | ||
|
|
749febf4d1 | ||
|
|
bdde425cbe | ||
|
|
746f491f82 | ||
|
|
1672647ade | ||
|
|
90b6bbc38c | ||
|
|
ce02ed60f2 | ||
|
|
1e5b9a95fd | ||
|
|
1d699755e0 | ||
|
|
ddf49c6344 | ||
|
|
ba3881dffd | ||
|
|
d1c252048b | ||
|
|
eab2724138 | ||
|
|
21ea3e06c9 | ||
|
|
52d703d3d1 | ||
|
|
ce152341a1 | ||
|
|
f058e34011 | ||
|
|
b5349e8721 | ||
|
|
7150858d49 | ||
|
|
91c7271aab | ||
|
|
aa13b2dffd | ||
|
|
fc2ef392be | ||
|
|
463a908705 | ||
|
|
d24ffe1cfa | ||
|
|
78fb87b283 | ||
|
|
ab2d524780 | ||
|
|
85d61685f1 | ||
|
|
b9643eed7c | ||
|
|
feee2ecfa9 | ||
|
|
a25a5cfeec | ||
|
|
0e145dd541 | ||
|
|
9f9be844fc | ||
|
|
e3b9ab5e18 | ||
|
|
c66d2baa9c | ||
|
|
08bc37cdd0 | ||
|
|
9771cceb2c | ||
|
|
ca715127a2 | ||
|
|
ea7a7af1d4 | ||
|
|
880e1c529d | ||
|
|
dcbb45803f | ||
|
|
80b9bbce86 | ||
|
|
d37936386f | ||
|
|
c3a3028f9f | ||
|
|
6c5ad80cdc | ||
|
|
b5bdc2699a | ||
|
|
384b98cd8f | ||
|
|
eb9b5bffef | ||
|
|
0bd59f3723 | ||
|
|
8b8cbd8f6d | ||
|
|
72b18c5d34 | ||
|
|
eb0a839866 | ||
|
|
1777d5a952 | ||
|
|
d4b7da84c3 | ||
|
|
801dbbdffd | ||
|
|
0ed05a1d2d | ||
|
|
1008bebade | ||
|
|
ae84f879d7 | ||
|
|
be6dfd1b49 | ||
|
|
231516b6c9 | ||
|
|
fb53d58dcf | ||
|
|
2a9e9b210b | ||
|
|
897d6cc43a | ||
|
|
f470c6c812 | ||
|
|
566d4e0425 | ||
|
|
81be02d2f9 | ||
|
|
c2b6a482d5 | ||
|
|
12c167c881 | ||
|
|
20aafee7fa | ||
|
|
be07375b66 | ||
|
|
c8434e8316 | ||
|
|
4894fe8c5b | ||
|
|
dd5bcdc4c9 | ||
|
|
6161d17579 | ||
|
|
4ac5306ae7 | ||
|
|
b1a80ec1a9 | ||
|
|
672fe94dcb | ||
|
|
51040b72ed | ||
|
|
4f045eef8f | ||
|
|
5d7b253ea0 | ||
|
|
b0759f0c19 | ||
|
|
065472936a | ||
|
|
fc4a0c2aec | ||
|
|
eeb165e674 | ||
|
|
9ee2b5f6f2 | ||
|
|
da54be877a | ||
|
|
50a886b7ab | ||
|
|
76e67c2cb6 | ||
|
|
5137ebac0b | ||
|
|
a8eeb0597b | ||
|
|
4ed3e51080 | ||
|
|
7f34001d57 | ||
|
|
2dcf7d8f99 | ||
|
|
19b0668251 | ||
|
|
e7e6b54d8a | ||
|
|
2a1a8ffe41 | ||
|
|
08fb86c49b | ||
|
|
3633d77c0f | ||
|
|
165e179764 | ||
|
|
12ebdd1506 | ||
|
|
1baf9a5938 | ||
|
|
a56f9de156 | ||
|
|
fa5d47af4b | ||
|
|
d607038753 | ||
|
|
9ac6a01aaf | ||
|
|
be97abc247 | ||
|
|
9103bbc5cd | ||
|
|
b6c45014ae | ||
|
|
a3dd924871 | ||
|
|
137bbb3e37 | ||
|
|
86ad94bb2e | ||
|
|
3e56add7c9 | ||
|
|
f52f01b5d2 | ||
|
|
98d7efb537 | ||
|
|
cf51923545 | ||
|
|
38fcd4597a | ||
|
|
165e3bb67a | ||
|
|
38db46794f | ||
|
|
a9a3876d55 | ||
|
|
1f343eaabb | ||
|
|
72a5b4f702 | ||
|
|
0a43ddf320 | ||
|
|
31366066bd | ||
|
|
aa2484e390 | ||
|
|
8eddf3e91d | ||
|
|
60d142aa8d | ||
|
|
66cf3ac342 | ||
|
|
ab4e151347 | ||
|
|
ac2547f5ff | ||
|
|
5f1ea943ab | ||
|
|
0ef7ad5cd4 | ||
|
|
9f1109a564 | ||
|
|
33b1d9595d | ||
|
|
7193498811 | ||
|
|
72321ead7b | ||
|
|
b5d0d817bc | ||
|
|
94badb2599 | ||
|
|
b9a836515f | ||
|
|
21c924f406 | ||
|
|
e54fd4b23b | ||
|
|
57dd9a8f2f | ||
|
|
912cbf5d4e | ||
|
|
43d7895ea0 | ||
|
|
f7ff55aa78 | ||
|
|
795f28f871 | ||
|
|
f6cc16f5d8 | ||
|
|
321a01f971 | ||
|
|
646e17a53d | ||
|
|
dd508b7c4f | ||
|
|
2563bcc85c | ||
|
|
702665c085 | ||
|
|
dcc2a706ef | ||
|
|
2bc67c35ac | ||
|
|
77ae65877e | ||
|
|
32a35e4418 | ||
|
|
369a759acc | ||
|
|
79b3f61228 | ||
|
|
216d71d001 | ||
|
|
78a3a9f89e | ||
|
|
a7685f3bf4 | ||
|
|
f088ea5486 | ||
|
|
1003d108d5 | ||
|
|
8abeeb9449 | ||
|
|
c1002e96e9 | ||
|
|
77d0a82fef | ||
|
|
ebc14f251c | ||
|
|
d41e6efc85 | ||
|
|
8ffa13e03e | ||
|
|
db477d3a37 | ||
|
|
750e9833b8 | ||
|
|
82f0ac657c | ||
|
|
eb6a2277a2 | ||
|
|
f8778fb0fa | ||
|
|
e2f9de207c | ||
|
|
a93cc0d943 | ||
|
|
7d8c2e07f2 | ||
|
|
efb4c36b18 | ||
|
|
29526d0d2b | ||
|
|
198e370f23 | ||
|
|
c19f7764a5 | ||
|
|
bc63d9d329 | ||
|
|
aa929c37d5 | ||
|
|
af4d506eb3 | ||
|
|
5da0549581 | ||
|
|
749a4fd2fd | ||
|
|
6f71ef580c | ||
|
|
67874aeffa | ||
|
|
3e6a330d38 | ||
|
|
aee5e18c8f | ||
|
|
5b11143d05 | ||
|
|
7b2212e954 | ||
|
|
71865091ab | ||
|
|
125cfd78e8 | ||
|
|
8cb57d9b91 | ||
|
|
14e10b2b6e | ||
|
|
6e76104d66 | ||
|
|
1d45a23b74 | ||
|
|
7df286540f | ||
|
|
5d0c97541a | ||
|
|
49a25557b0 | ||
|
|
b5936c0059 | ||
|
|
600cc1a4f0 | ||
|
|
ea32fbacc8 | ||
|
|
00fe14fc75 | ||
|
|
fcc28edb2f | ||
|
|
fac6be2dd5 | ||
|
|
1cf64ee468 | ||
|
|
cdec0190c4 | ||
|
|
2450bcb28b | ||
|
|
3126050c0f | ||
|
|
93b22c7828 | ||
|
|
0a89b2852e | ||
|
|
55b3e45bba | ||
|
|
365bcf6d97 | ||
|
|
71907db3ba | ||
|
|
6803655ced | ||
|
|
df1c39ec5c | ||
|
|
80f55a9511 | ||
|
|
7853cc5ae1 | ||
|
|
586a91b67f | ||
|
|
b028e96144 | ||
|
|
ce68b5907c | ||
|
|
fe7e0c9825 | ||
|
|
12893efe01 | ||
|
|
a6387bfd3c | ||
|
|
f6a54188c2 | ||
|
|
cbbd9a9c69 | ||
|
|
685a9cd2f1 | ||
|
|
182a107877 | ||
|
|
8c51aa6506 | ||
|
|
3fd39e37f2 | ||
|
|
49e86983e7 | ||
|
|
a9c58ad945 | ||
|
|
f8b45beacc | ||
|
|
9d92015d43 | ||
|
|
50a6150ed9 | ||
|
|
d5a9bb4ea9 | ||
|
|
b0505eb611 | ||
|
|
284acd57d6 | ||
|
|
8ed6b34477 | ||
|
|
f6f1fc9286 | ||
|
|
8e590a117f | ||
|
|
d5594202aa | ||
|
|
b186d949cf | ||
|
|
3d2986063c | ||
|
|
41fd7c7e60 | ||
|
|
fdefe96bf2 | ||
|
|
16f36a6fc9 | ||
|
|
f44415360e | ||
|
|
cce722b79c | ||
|
|
82697fb2ab | ||
|
|
53c1d3ef49 | ||
|
|
8e55e9abfc | ||
|
|
7c58ef3275 | ||
|
|
416a5efce7 | ||
|
|
f4d96df0f1 | ||
|
|
5d254f776a | ||
|
|
1c1218fefc | ||
|
|
d21ab29200 | ||
|
|
54ed626cf8 | ||
|
|
a733eb6c53 | ||
|
|
591454798d | ||
|
|
38604f1a4f | ||
|
|
2d0efe70a6 | ||
|
|
bfd14b1b2f | ||
|
|
76965512da | ||
|
|
996d1c3242 | ||
|
|
8abbf43f21 | ||
|
|
10eaae48ff | ||
|
|
9d4660cab1 | ||
|
|
9d74e308f7 | ||
|
|
e772692ffd | ||
|
|
8381a92120 | ||
|
|
cd054fc491 | ||
|
|
f219743e33 | ||
|
|
4f41664de8 | ||
|
|
a4fd04158e | ||
|
|
44a5f1718a | ||
|
|
a623df4c7b | ||
|
|
7cf67fbe29 | ||
|
|
3ddf1a6d01 | ||
|
|
850555c484 | ||
|
|
9ed3bdc64d | ||
|
|
c45aa56080 | ||
|
|
7394b8db3b | ||
|
|
f9b3d7af47 | ||
|
|
ea62a2da46 | ||
|
|
7468b6b71d | ||
|
|
1fb07d10a3 | ||
|
|
9378ae6e1d | ||
|
|
06723d47c4 | ||
|
|
69a0c470b5 | ||
|
|
c40f5cf45c | ||
|
|
4b7b839f24 | ||
|
|
3d60d33773 | ||
|
|
d7e66d39a0 | ||
|
|
d3f46b9aa5 | ||
|
|
f5e54a1fda | ||
|
|
4eb7f1d12e | ||
|
|
0f6d12e43c | ||
|
|
b4cdc245cf | ||
|
|
3283533149 | ||
|
|
8032e31f2d | ||
|
|
d2f9cdb205 | ||
|
|
8016c92297 | ||
|
|
e028d0d1e3 | ||
|
|
79819f58f2 | ||
|
|
6ff000b888 | ||
|
|
99e206d508 | ||
|
|
dd82ffea0c | ||
|
|
3823342d9d | ||
|
|
91dbaef406 | ||
|
|
9026dd3858 | ||
|
|
81d7f1928c | ||
|
|
bc4f29170f | ||
|
|
cb354c8f62 | ||
|
|
1cbb27b151 | ||
|
|
0ab4ff6378 | ||
|
|
63da13e829 | ||
|
|
4193a453c2 | ||
|
|
2e1fa03bf5 | ||
|
|
8f1ae18a18 | ||
|
|
57da92b7df | ||
|
|
df4f632dbc | ||
|
|
a34c2faae4 | ||
|
|
1d368c7589 | ||
|
|
88bd97e34c | ||
|
|
2ae3edb1cf | ||
|
|
b2ad967e45 | ||
|
|
a27b9e8bd5 | ||
|
|
4481a754e4 | ||
|
|
faa6ef6bc8 | ||
|
|
15870e90b0 | ||
|
|
8e4f824365 | ||
|
|
387ae5f30b | ||
|
|
ad7a071ab6 | ||
|
|
1310bf2474 | ||
|
|
b24f347190 | ||
|
|
ee6c9f95e1 | ||
|
|
2a69c6b879 | ||
|
|
cfadd183c4 | ||
|
|
e484c81f0c | ||
|
|
7e5e8306fd | ||
|
|
41e8bca4d0 | ||
|
|
8dbe9899a9 | ||
|
|
f4aac741d5 | ||
|
|
c1c9a79c49 | ||
|
|
226113c880 | ||
|
|
8932a66e49 | ||
|
|
79cfb46d42 | ||
|
|
00fcc17aee | ||
|
|
e94b783c74 | ||
|
|
97dae9ae07 | ||
|
|
ca215e0a4f | ||
|
|
91a26ca559 | ||
|
|
1ece880d7c | ||
|
|
400afddaf4 | ||
|
|
c3fef636b5 | ||
|
|
46e28a84ca | ||
|
|
17ad2b3fb1 | ||
|
|
5e2a60db4a | ||
|
|
cd214418f6 | ||
|
|
ba2d9f213e | ||
|
|
7f8ae73a5d | ||
|
|
466880f531 | ||
|
|
9f1f6d2437 | ||
|
|
9e0f897f6b | ||
|
|
c0f6aa876f | ||
|
|
d93bdee9a6 | ||
|
|
f13d09332d | ||
|
|
2f5865cc6d | ||
|
|
deefc05b88 | ||
|
|
0d8cb1cc14 | ||
|
|
a90b9fd209 | ||
|
|
829493439a | ||
|
|
73b4fafd82 | ||
|
|
b039775057 | ||
|
|
5c1d63b737 | ||
|
|
3cd022f6e6 | ||
|
|
abefd1f7c4 | ||
|
|
c21315f273 | ||
|
|
9ab1018b1a | ||
|
|
da0a5d2d6e | ||
|
|
ee6adb166c | ||
|
|
be8fe32c92 | ||
|
|
c38b1e776d | ||
|
|
4f8bf17f23 | ||
|
|
ca40186c75 | ||
|
|
a8c6b24155 | ||
|
|
bd8e5c7ca2 | ||
|
|
7c61bd36bb | ||
|
|
c54283824c | ||
|
|
52f15da2ca | ||
|
|
44d466559e | ||
|
|
05751eb047 | ||
|
|
f10503db67 | ||
|
|
adfeafe9e1 | ||
|
|
4c62a16f4f | ||
|
|
c0de39e6d4 | ||
|
|
fa55675593 | ||
|
|
d4d9920a26 | ||
|
|
47192f92d8 | ||
|
|
722076a123 | ||
|
|
bb4aa62cf7 | ||
|
|
843530568f | ||
|
|
138a5454b5 | ||
|
|
d279037036 | ||
|
|
46353f6783 | ||
|
|
70922df8b5 | ||
|
|
9c15e9de84 | ||
|
|
123c10608d | ||
|
|
0b7c2485b6 | ||
|
|
9abb32045a | ||
|
|
f490e77e77 | ||
|
|
2dc592991a | ||
|
|
0a60edcfa9 | ||
|
|
c53f9d30c8 | ||
|
|
509f398292 | ||
|
|
74bab3f0a4 | ||
|
|
8574862991 | ||
|
|
2de957c7e1 | ||
|
|
920de7a27d | ||
|
|
63efc427cd | ||
|
|
ce65fb6c76 | ||
|
|
4de1994b6e | ||
|
|
592882aa9f | ||
|
|
b98d6a1e19 | ||
|
|
29c7a63df8 | ||
|
|
8b25323ae2 | ||
|
|
f426de8460 | ||
|
|
695dc094ab | ||
|
|
e80d861064 | ||
|
|
2cdeb20135 | ||
|
|
7f74773254 | ||
|
|
f2c327fd39 | ||
|
|
e35e4ddc9a | ||
|
|
c3c88a2664 | ||
|
|
bb0eee71e7 | ||
|
|
6f56389b88 | ||
|
|
5b333c1ce6 | ||
|
|
a825f33030 | ||
|
|
92f618f2e2 | ||
|
|
81ec7c7901 | ||
|
|
dd5d2eb03c | ||
|
|
4ae720042c | ||
|
|
c705320f48 | ||
|
|
d2d8f89531 | ||
|
|
bdde940e90 | ||
|
|
45f4a76dbc | ||
|
|
13dc64ce74 | ||
|
|
c35f9e72ce | ||
|
|
f8061589e6 | ||
|
|
0ca96d48c7 | ||
|
|
4ba146f35d | ||
|
|
edf3e38ebd | ||
|
|
c4417ddb61 | ||
|
|
4a2080e407 | ||
|
|
2f2ffea9ca | ||
|
|
ba552f542f | ||
|
|
8379969834 | ||
|
|
95dbd2f990 | ||
|
|
a7177865b1 | ||
|
|
e0df6211cc | ||
|
|
b00ca882a4 | ||
|
|
39baacc49f | ||
|
|
3a1d48d6de | ||
|
|
34308b30d6 | ||
|
|
bc1506f8c0 | ||
|
|
b61067fa4f | ||
|
|
69b227a9bc | ||
|
|
0fd49457f5 | ||
|
|
58f289d013 | ||
|
|
3d60bb96e1 | ||
|
|
38d025b3f0 | ||
|
|
c40c6aaaaa | ||
|
|
1a810f0d4e | ||
|
|
63037593c0 | ||
|
|
7a878d47fa | ||
|
|
bc4b900898 | ||
|
|
c5e743f66f | ||
|
|
6c36d8d6fb | ||
|
|
71c82637e7 | ||
|
|
2dad310e2c | ||
|
|
d0ae9e3a8d | ||
|
|
a19413c311 | ||
|
|
1ef80b55dd | ||
|
|
eb03f4dad3 | ||
|
|
830dd1944a | ||
|
|
cc6943e86a | ||
|
|
1237c9a3a5 | ||
|
|
8f77093262 | ||
|
|
5d13df79a5 | ||
|
|
d79a0e233a | ||
|
|
6523223a4c | ||
|
|
4a67aafb7e | ||
|
|
f3f34c5b0f | ||
|
|
6ae8ee3f54 | ||
|
|
e8f8e80097 | ||
|
|
4dc0ff3ecf | ||
|
|
4b6462fc1e | ||
|
|
c4ece78564 | ||
|
|
0761d02b0b | ||
|
|
71c107fc57 | ||
|
|
7459e3a290 | ||
|
|
f9e66fb993 | ||
|
|
6c603ccce3 | ||
|
|
ef66b0c6ef | ||
|
|
22b50ecb2f | ||
|
|
5a6fecc3de | ||
|
|
cdbccafed9 | ||
|
|
e69ae5b9e7 | ||
|
|
92790f4e54 | ||
|
|
471a5ee908 | ||
|
|
19e1d35989 | ||
|
|
0b7f31184d | ||
|
|
fad84d50fe | ||
|
|
9a1c32dc54 | ||
|
|
a921f40799 | ||
|
|
74ac9bdd82 | ||
|
|
94518f2087 | ||
|
|
535f59bbcf | ||
|
|
71cedb3c0c | ||
|
|
dd01d6558a | ||
|
|
ce85f022d2 | ||
|
|
ad94a6fe44 | ||
|
|
353ba14060 | ||
|
|
83de794223 | ||
|
|
bfd5c93af9 | ||
|
|
c247d87ef3 | ||
|
|
07ac9e2cc2 | ||
|
|
6bc520c207 | ||
|
|
f1d20fa39f | ||
|
|
e3dc22ca3a | ||
|
|
d665f8d3cb | ||
|
|
055e6f3657 | ||
|
|
ac4f319ba1 | ||
|
|
542cca0e8c | ||
|
|
6a2449df3b | ||
|
|
7fad1c6328 | ||
|
|
d82134c339 | ||
|
|
54d39d8b2f | ||
|
|
de7f3446e0 | ||
|
|
f8e52269c1 | ||
|
|
cf1dd0c59e | ||
|
|
22c8b52545 | ||
|
|
1f7dc42cd0 | ||
|
|
aa8f2641da | ||
|
|
648d25d43d | ||
|
|
df3e61003a | ||
|
|
6b361ad5ee | ||
|
|
5d8afe69f7 | ||
|
|
a1ab553858 | ||
|
|
07463ea162 | ||
|
|
6d2d21f713 | ||
|
|
061b2889a9 | ||
|
|
8963d9c266 | ||
|
|
890f62e868 | ||
|
|
8f362589a5 | ||
|
|
a27a2470cd | ||
|
|
72836fcee4 | ||
|
|
a7130543fa | ||
|
|
a490fda746 | ||
|
|
7e77275293 | ||
|
|
d6e203b3dc | ||
|
|
e3ea479087 | ||
|
|
faab1d3836 | ||
|
|
8851a574a3 | ||
|
|
59282080c8 | ||
|
|
98f3da4040 | ||
|
|
1d213233cd | ||
|
|
fd9cf73836 | ||
|
|
0638ad9999 | ||
|
|
1eb527692a | ||
|
|
09bb17e108 | ||
|
|
1cf911bc82 | ||
|
|
f4b052321b | ||
|
|
a636203ea5 | ||
|
|
c215217e39 | ||
|
|
08e291b54d | ||
|
|
6b95b065be | ||
|
|
9363169b67 | ||
|
|
085bea4513 | ||
|
|
150f20828b | ||
|
|
08523ee20a | ||
|
|
5d5171d26a | ||
|
|
96fb5605b2 | ||
|
|
7011de0bc2 | ||
|
|
c3dd69eab4 | ||
|
|
025171c476 | ||
|
|
c8dbccde30 | ||
|
|
4ff7a0f1f6 | ||
|
|
9c2ade40de | ||
|
|
aa32314d09 | ||
|
|
52afe99665 | ||
|
|
b0446d6a33 | ||
|
|
8e4e89f1c2 | ||
|
|
6c758d79de | ||
|
|
691008087b | ||
|
|
85f03346eb | ||
|
|
bdc6b3fc64 | ||
|
|
847f582290 | ||
|
|
10f5c016ec | ||
|
|
2e756879f1 | ||
|
|
c7a7750d3b | ||
|
|
9193c1eede | ||
|
|
b3f0e53048 | ||
|
|
3243d0f7b6 | ||
|
|
23b00bc0e4 | ||
|
|
52e1eea18b | ||
|
|
ee80d66727 | ||
|
|
f1fb2d12b3 | ||
|
|
deb2c73212 | ||
|
|
8928491074 | ||
|
|
545434670b | ||
|
|
54fda45bac | ||
|
|
c7bf7366bc | ||
|
|
b7052e5087 | ||
|
|
0d75ae2ce3 | ||
|
|
b5ba7b9dcf | ||
|
|
483e0ddd4d | ||
|
|
2891932bf0 | ||
|
|
591078babf | ||
|
|
9868c781a1 | ||
|
|
c257baff85 | ||
|
|
878e83c5a4 | ||
|
|
0012690aae | ||
|
|
6e74bc41ca | ||
|
|
cba892fa1f | ||
|
|
550bfd4cbd | ||
|
|
920ef0779b | ||
|
|
48ea9cea77 | ||
|
|
ccf4b799df | ||
|
|
f143d86ad2 | ||
|
|
8ae97d76ee | ||
|
|
f8b362739e | ||
|
|
6d69d03bac | ||
|
|
204da0d3e3 | ||
|
|
c496ca96e7 | ||
|
|
67b22dd036 | ||
|
|
ce6a696e4d | ||
|
|
a5caba1eb0 | ||
|
|
cd9c100963 | ||
|
|
edde6c56ac | ||
|
|
b7f89fe692 | ||
|
|
ae3531adf9 | ||
|
|
8cf5ee7831 | ||
|
|
aa3e950764 | ||
|
|
1301a0dd42 | ||
|
|
af8bd6a82d | ||
|
|
6d38616e67 | ||
|
|
4f5f18acb9 | ||
|
|
3e223834d9 | ||
|
|
a1bb0f8773 | ||
|
|
0e283428f7 | ||
|
|
2eabb80254 | ||
|
|
44586389e4 | ||
|
|
06a401c845 | ||
|
|
273f603efb | ||
|
|
1619e22f40 | ||
|
|
88a79ce6a6 | ||
|
|
acebc9cd6b | ||
|
|
443c12a703 | ||
|
|
7f3c4f4f65 | ||
|
|
0bc56fa66a | ||
|
|
1a582dd49d | ||
|
|
c5b921b597 | ||
|
|
e86ea47c02 | ||
|
|
aa5a63a5b5 | ||
|
|
2a7b4da9b2 | ||
|
|
069d098f84 | ||
|
|
b3889f7023 | ||
|
|
65883c8dbd | ||
|
|
341ca8d74c | ||
|
|
99859d436c | ||
|
|
1b01e2b085 | ||
|
|
976fc7d137 | ||
|
|
c3b7b29c23 | ||
|
|
627a91a9a8 | ||
|
|
6dc6302599 | ||
|
|
7a20e2e1f8 | ||
|
|
90648143c3 | ||
|
|
5c6658d4dd | ||
|
|
9585f890f8 | ||
|
|
0838239e8e | ||
|
|
36399e8576 | ||
|
|
9460db832c | ||
|
|
d68730a56e | ||
|
|
f2aeefe29c | ||
|
|
39c6f507df | ||
|
|
d2d1eb5b0a | ||
|
|
8ae7be3ef4 | ||
|
|
306170518f | ||
|
|
aa6a10c44a | ||
|
|
9af73dc4fc | ||
|
|
fc483bb6af | ||
|
|
53b0f3e4e2 | ||
|
|
4353cf51a0 | ||
|
|
ce34e9ce5e | ||
|
|
d4051a8e05 | ||
|
|
df3df7fb64 | ||
|
|
9e9c164052 | ||
|
|
066090dd3f | ||
|
|
614d9c19c1 | ||
|
|
bd2dee6c67 | ||
|
|
74e6672beb | ||
|
|
02bcf0d389 | ||
|
|
18b4e04f1c | ||
|
|
10204dc898 | ||
|
|
1865ed31b9 | ||
|
|
3669cdba10 | ||
|
|
939fbd26ac | ||
|
|
b4e60dac23 | ||
|
|
e6ddb4e7af | ||
|
|
83390b83d9 | ||
|
|
ff2424595a | ||
|
|
adeb9c73d6 | ||
|
|
cd0abcc0bb | ||
|
|
4a55479fa9 | ||
|
|
f527115b5f | ||
|
|
75e1b46add | ||
|
|
05a2926c5c | ||
|
|
7070b83687 | ||
|
|
8d212e604a | ||
|
|
063fcc9676 | ||
|
|
8403612258 | ||
|
|
25b51c7816 | ||
|
|
9779b63bb6 | ||
|
|
d81aef3adf | ||
|
|
5af7e056a7 | ||
|
|
45ed795cb0 | ||
|
|
683e98a8a4 | ||
|
|
e0cfeb2ea7 | ||
|
|
75340ee383 | ||
|
|
668de34c6b | ||
|
|
a91b954bb4 | ||
|
|
a3f62b8255 | ||
|
|
37b6d5f684 | ||
|
|
b7a6838407 | ||
|
|
cde846b3d3 | ||
|
|
6c3e6e88d3 | ||
|
|
739674cd77 | ||
|
|
4b2d7cae11 | ||
|
|
7fea7156cb | ||
|
|
3093468977 | ||
|
|
79cb25776f | ||
|
|
87f78946a5 | ||
|
|
211fbc1328 | ||
|
|
836a086ce9 | ||
|
|
90d3989b99 | ||
|
|
d741e55a42 | ||
|
|
17d3aaaf16 | ||
|
|
ea55b2a4ca | ||
|
|
3f0537dd4a | ||
|
|
943f7f7a39 | ||
|
|
12e895fc5a | ||
|
|
bda2c49d75 | ||
|
|
01b32990da | ||
|
|
dbda1b5147 | ||
|
|
ddf3bd328b | ||
|
|
b9c37b92cf | ||
|
|
5a27ecdd2e | ||
|
|
f9c3c90ca8 | ||
|
|
6daccbe317 | ||
|
|
71ea844c0e | ||
|
|
3a7256697e | ||
|
|
d1ba998274 | ||
|
|
718ced8d8c | ||
|
|
e1842025d0 | ||
|
|
2b9213cdc1 | ||
|
|
e3a88568b0 | ||
|
|
0577177e3e | ||
|
|
298f833b16 | ||
|
|
97b3656c2e | ||
|
|
f3bcebb1d2 | ||
|
|
0f399e6e5e | ||
|
|
5b075e27cb | ||
|
|
8a9d86a2a7 | ||
|
|
d80a064eff | ||
|
|
d468a09789 | ||
|
|
9f4ab73d7f | ||
|
|
02cf62e240 | ||
|
|
d55de6eec2 | ||
|
|
69df680b97 | ||
|
|
447591e1ae | ||
|
|
33eb0ce4c4 | ||
|
|
505c28aac9 | ||
|
|
67fb0c5495 | ||
|
|
4efba05c56 | ||
|
|
8377574c9c | ||
|
|
0f90943e45 | ||
|
|
526e638c8a | ||
|
|
372297e713 | ||
|
|
356e067390 | ||
|
|
e2f48f9643 | ||
|
|
b513a251f8 | ||
|
|
953e32b2c1 | ||
|
|
5898e28272 | ||
|
|
67dfbc0cb9 | ||
|
|
36cb11f068 | ||
|
|
7a4c6cc92f | ||
|
|
7edcb8f39c | ||
|
|
d5b00ee6e0 | ||
|
|
461cead4f7 | ||
|
|
b5a6d40818 | ||
|
|
968b5e0112 | ||
|
|
39b782b390 | ||
|
|
577664c8e8 | ||
|
|
bba12cec89 | ||
|
|
70c4c03cb8 | ||
|
|
f5791ed136 | ||
|
|
4ec929dc9b | ||
|
|
fbf189a6ee | ||
|
|
09825cb5c0 | ||
|
|
ed27d35674 | ||
|
|
fd5539eb41 | ||
|
|
04bca64bde | ||
|
|
03cc7c20c1 | ||
|
|
4075311d94 | ||
|
|
6624a2b07d | ||
|
|
6d3a7d03e1 | ||
|
|
95fdc7d69c | ||
|
|
86fe61c8f9 | ||
|
|
9bb6d2f21d | ||
|
|
e3f4593e76 | ||
|
|
1d043b93cf | ||
|
|
b15d4f624f | ||
|
|
4aa16a50f5 | ||
|
|
bbcbf4d459 | ||
|
|
930ad9eecc | ||
|
|
b072a9defd | ||
|
|
75952c6e3d | ||
|
|
05afc96b73 | ||
|
|
fa80026915 | ||
|
|
2bc3de0f28 | ||
|
|
99c7bc94af | ||
|
|
152c8f349d | ||
|
|
d75654c15e | ||
|
|
0725f584e1 | ||
|
|
8cda9241d1 | ||
|
|
a3124ba49f | ||
|
|
579e2691fe | ||
|
|
63f05de10b | ||
|
|
caeefc29eb | ||
|
|
a3c736def2 | ||
|
|
58261235f0 | ||
|
|
da70877a1b | ||
|
|
5c468ca8a8 | ||
|
|
aedd6bb97d | ||
|
|
733d9cacb8 | ||
|
|
42f2805e48 | ||
|
|
0ffcb7c6fc | ||
|
|
27669bd11d | ||
|
|
6625f82940 | ||
|
|
d0866f0bb4 | ||
|
|
09eeb75130 | ||
|
|
0a99956f71 | ||
|
|
12ef6aefa8 | ||
|
|
e93aa81aa6 | ||
|
|
755eb0320e | ||
|
|
43ba5456b1 | ||
|
|
156d5ad6da | ||
|
|
c626a3d9fa | ||
|
|
b2e8bc1b20 | ||
|
|
771822ebb8 | ||
|
|
eb6a41ba0f | ||
|
|
7d2392691c | ||
|
|
c216c1894d | ||
|
|
3e1ad508eb | ||
|
|
a052c1d785 | ||
|
|
16484d4923 | ||
|
|
32a09b4382 | ||
|
|
870a7e6156 | ||
|
|
239e3e0cca | ||
|
|
b1ca5e3ffa | ||
|
|
b9a1252c96 | ||
|
|
fc492de31d | ||
|
|
a9c0f9bc63 | ||
|
|
b7cc9f5026 | ||
|
|
252580c561 | ||
|
|
acc47c1a3f | ||
|
|
70fa830e4d | ||
|
|
a7af0ebaf5 | ||
|
|
67ae7b4760 | ||
|
|
de48addae2 | ||
|
|
ddbfd0f0c5 | ||
|
|
d7ae0639b4 | ||
|
|
6804038d06 | ||
|
|
2f799533ae | ||
|
|
88ae5991cd | ||
|
|
5d51a883c2 | ||
|
|
c4a91be726 | ||
|
|
0382435990 | ||
|
|
b390d85d95 | ||
|
|
be925dc64c | ||
|
|
de7a91bfe3 | ||
|
|
a4358cbabd | ||
|
|
177ed935a9 | ||
|
|
c364f15ff1 | ||
|
|
e1f6e61e6a | ||
|
|
0932300e3a | ||
|
|
3f40217704 | ||
|
|
f631c3311a | ||
|
|
ad433bb372 | ||
|
|
3e0b3a1428 | ||
|
|
444b116597 | ||
|
|
2aea08eda1 | ||
|
|
8e5e059d7d | ||
|
|
2b1b511f6b | ||
|
|
233ad24ecf | ||
|
|
c4949c50f9 | ||
|
|
b6ef402905 | ||
|
|
ccf365475a | ||
|
|
e1fb245690 | ||
|
|
5a76c6517e | ||
|
|
1bb9568776 | ||
|
|
ecd1c2f7e9 | ||
|
|
466de68801 | ||
|
|
88d4111cfa | ||
|
|
51fb64bab1 | ||
|
|
be547e1d3b | ||
|
|
bf85454116 | ||
|
|
5910724b11 | ||
|
|
7e24b09da9 | ||
|
|
f085f960e7 | ||
|
|
f38de77f6e | ||
|
|
58e7d46d1b | ||
|
|
2a5201638d | ||
|
|
fe6fad1242 | ||
|
|
ec00e1d8a0 | ||
|
|
de29c4144e | ||
|
|
f3bab0044e | ||
|
|
ffd1833b87 | ||
|
|
896d5b63e8 | ||
|
|
67de24e449 | ||
|
|
66400c470c | ||
|
|
7665010267 | ||
|
|
5d9b75051a | ||
|
|
ab2f744b90 | ||
|
|
300fcad8a6 | ||
|
|
f7e025958a | ||
|
|
0ab5531363 | ||
|
|
b4444d5ca2 | ||
|
|
0025da15cf | ||
|
|
b9d3e1635f | ||
|
|
aa6b734e02 | ||
|
|
73b57f0ccb | ||
|
|
3c4e6d8337 | ||
|
|
36034aecc2 | ||
|
|
ffca4b5c32 | ||
|
|
b0e72bcf34 | ||
|
|
7fd930c0c8 | ||
|
|
2e78b2bead | ||
|
|
44dbe89035 | ||
|
|
2d5a8b5512 | ||
|
|
159736c1b8 | ||
|
|
46720279c2 | ||
|
|
d8269e1dfb | ||
|
|
cbdbb76665 | ||
|
|
6543f0dca5 | ||
|
|
232eb88bfe | ||
|
|
a95967f8b7 | ||
|
|
2ef648d3d3 | ||
|
|
33f6830fd5 | ||
|
|
606d7e67fd | ||
|
|
fd87ff26b9 | ||
|
|
85347e1cb6 | ||
|
|
41897817cc | ||
|
|
45ff2d51d0 | ||
|
|
5de3ece225 | ||
|
|
df50a41289 | ||
|
|
59ae56fad5 | ||
|
|
690e872c51 | ||
|
|
81082e046e | ||
|
|
3fa9550837 | ||
|
|
b1082f01a6 | ||
|
|
f35b84c807 | ||
|
|
117adb0f0f | ||
|
|
abb285fb1b | ||
|
|
a431154706 | ||
|
|
cfe50f04ed | ||
|
|
a7055eb956 | ||
|
|
0a1be1e997 | ||
|
|
c93898dae9 | ||
|
|
ebdf2af727 | ||
|
|
c108eb73cc | ||
|
|
3a1375dacf | ||
|
|
41bece30b4 | ||
|
|
16ea58cbda | ||
|
|
99e350d902 | ||
|
|
13e06d298c | ||
|
|
56c7366547 | ||
|
|
81f0259b9e | ||
|
|
fefcb5d314 | ||
|
|
345b0c9b46 | ||
|
|
20c3893f0e | ||
|
|
29293c1e09 | ||
|
|
5fe3a3c3fb | ||
|
|
b04621d155 | ||
|
|
b227060388 | ||
|
|
d93e4dcbb7 | ||
|
|
73e79f2a1b | ||
|
|
fc79158de2 | ||
|
|
7763b04e5f | ||
|
|
9d7b44b4cc | ||
|
|
897f36d179 | ||
|
|
94c3637f6d | ||
|
|
04cc96173c | ||
|
|
fbaaad49d7 | ||
|
|
b29f3b250d | ||
|
|
fa343954d4 | ||
|
|
2491f5898e | ||
|
|
b27c856fbc | ||
|
|
9941ceb331 | ||
|
|
c536d38059 | ||
|
|
8de64cac98 | ||
|
|
6d6d286539 | ||
|
|
5d2eac9eba | ||
|
|
9826925a20 | ||
|
|
24a267b562 | ||
|
|
d4da3d6116 | ||
|
|
d5a62e4f5f | ||
|
|
9a82b2389f | ||
|
|
8dba13f7e8 | ||
|
|
deacef651f | ||
|
|
2e1b3afeca | ||
|
|
652e776893 | ||
|
|
d055fe4cb0 | ||
|
|
131842bb0b | ||
|
|
59fc531f78 | ||
|
|
5c44c15438 | ||
|
|
62067cb9b8 | ||
|
|
0f81866329 | ||
|
|
2db67bc0f4 | ||
|
|
7dba9cd039 | ||
|
|
75dff0eef7 | ||
|
|
d828f3a550 | ||
|
|
bcd6e4bd07 | ||
|
|
53936f3d57 | ||
|
|
0beb3add18 | ||
|
|
f9bd64c098 | ||
|
|
d7f44b5bdb | ||
|
|
48bfb5f238 | ||
|
|
97ebe8dcaf | ||
|
|
d4409747ba | ||
|
|
37b6a6617f | ||
|
|
ca1c9cfe11 | ||
|
|
adeb4d7469 | ||
|
|
50587ee8ec | ||
|
|
8244288dfe | ||
|
|
6ffe72835a | ||
|
|
8ba5e990a5 | ||
|
|
9afb1afcc6 | ||
|
|
0e21093a8f | ||
|
|
9c5cd0948f | ||
|
|
1083705fe8 | ||
|
|
f3d294617f | ||
|
|
de33a30858 | ||
|
|
887a227953 | ||
|
|
705f6f35bc | ||
|
|
e648b22dbd | ||
|
|
257a2501fa | ||
|
|
99afb3ddd4 | ||
|
|
a3c776203f | ||
|
|
53f350c165 | ||
|
|
f46d31f948 | ||
|
|
bf64ff72db | ||
|
|
bc2884afc1 | ||
|
|
023fa8c440 | ||
|
|
427023a1e6 | ||
|
|
a924876fed | ||
|
|
3f223f7b2e | ||
|
|
fc2c063e1e | ||
|
|
20db33e299 | ||
|
|
c0109aa497 | ||
|
|
ba7a1de04d | ||
|
|
4269e78a80 | ||
|
|
6f5ac90cf3 | ||
|
|
de282fc217 | ||
|
|
ddbd903576 | ||
|
|
0c56a3f773 | ||
|
|
9d069c4778 | ||
|
|
0d843f796b | ||
|
|
67f51b3d8c | ||
|
|
5c5de1c79a | ||
|
|
0821771466 | ||
|
|
83f6f68e79 | ||
|
|
27473d18da | ||
|
|
0c6c096c20 | ||
|
|
52c8ade4ad | ||
|
|
0e853ca4c4 | ||
|
|
41beccbab0 | ||
|
|
2eb88d953f | ||
|
|
1f0483b4b1 | ||
|
|
6b47c7f24e | ||
|
|
d798e1c7a9 | ||
|
|
3a8736bd74 | ||
|
|
c8c5163618 | ||
|
|
500f3d2432 | ||
|
|
ed4a915e08 | ||
|
|
b8f7b1579a | ||
|
|
ed54491c60 | ||
|
|
e4decf2750 | ||
|
|
c90f13d106 | ||
|
|
62008f69c1 | ||
|
|
e88f5e0b4e | ||
|
|
769fda3c5a | ||
|
|
23300d7149 | ||
|
|
f5756f388a | ||
|
|
ee313cdcbf | ||
|
|
8b50fed04b | ||
|
|
5b66de8859 | ||
|
|
e38af9e00c | ||
|
|
6b37f0be55 | ||
|
|
6e5d5f2fc1 | ||
|
|
75c9481224 | ||
|
|
5746f9da99 | ||
|
|
112da0a0ce | ||
|
|
bcd606c0fe | ||
|
|
ed92bc9f6e | ||
|
|
9b0756f8f2 | ||
|
|
aa0c87391c | ||
|
|
b1dfdc51b1 | ||
|
|
2e32528012 | ||
|
|
f64e7695a1 | ||
|
|
5abeaf0650 | ||
|
|
8bcc355972 | ||
|
|
6b4642fae3 | ||
|
|
d1bd37deac | ||
|
|
405ec05cb2 | ||
|
|
52e8e1dc88 | ||
|
|
b98a6b2f72 | ||
|
|
0ca45b233f | ||
|
|
65cceef8f4 | ||
|
|
b004821fa9 | ||
|
|
81b42336ad | ||
|
|
c6c1974672 | ||
|
|
a545d1d262 | ||
|
|
037fcd0047 | ||
|
|
318452bc0c | ||
|
|
d746cd88c2 | ||
|
|
9c42603b5a | ||
|
|
ea93cce4f6 | ||
|
|
f4daa18152 | ||
|
|
9caa687d81 | ||
|
|
3b58c6fb54 | ||
|
|
5926c10690 | ||
|
|
df725153d2 | ||
|
|
d662896090 | ||
|
|
db241e8645 | ||
|
|
ead28ff30a | ||
|
|
515d7a5e73 | ||
|
|
14fbdc9cdd | ||
|
|
98bcd2834a | ||
|
|
f7ab6cbe16 | ||
|
|
28ef06f7c2 | ||
|
|
577d02370d | ||
|
|
50be92c11c | ||
|
|
d18596baf4 | ||
|
|
7ce7e39476 | ||
|
|
93eb15c573 | ||
|
|
9f4d83e3b1 | ||
|
|
1c251cd948 | ||
|
|
70d1924f8b | ||
|
|
7b4948b05f | ||
|
|
878b5d9f0d | ||
|
|
2bc1820660 | ||
|
|
8bf8b5a577 | ||
|
|
8222d8de88 | ||
|
|
c7253e2e8c | ||
|
|
d69cf69a6a | ||
|
|
d02ecdefab | ||
|
|
bc857bfce0 | ||
|
|
f8bf74575a | ||
|
|
964ac8b584 | ||
|
|
a3522dfddd | ||
|
|
d3a8613b6e | ||
|
|
200b388752 | ||
|
|
dabcaf3b06 | ||
|
|
e646ffe795 | ||
|
|
b0dcc3c47f | ||
|
|
b07d9c23c5 | ||
|
|
d71cae62cc | ||
|
|
633a50cf4b | ||
|
|
825e0984e2 | ||
|
|
d1cade5ade | ||
|
|
190717e31f | ||
|
|
0824c28c8b | ||
|
|
c59b4aaeef | ||
|
|
f9c6cbf002 | ||
|
|
b8fe71ab86 | ||
|
|
cb10cded2a | ||
|
|
cd8b830292 | ||
|
|
1ac4004f3a | ||
|
|
e17d368ae2 | ||
|
|
27110b0567 | ||
|
|
9fe4de3471 | ||
|
|
d26d440e19 | ||
|
|
9f5daf0006 | ||
|
|
eb1634cbf8 | ||
|
|
01c10ca26e | ||
|
|
45aef47281 | ||
|
|
ae287755b7 | ||
|
|
a37f27ae99 | ||
|
|
49f5f315fd | ||
|
|
97d2db017c | ||
|
|
2c64df0399 | ||
|
|
828400422a | ||
|
|
c3c77cec30 | ||
|
|
1183b85f50 | ||
|
|
0143dc029c | ||
|
|
e10e576fed | ||
|
|
78af8eb1d1 | ||
|
|
79e93125d0 | ||
|
|
48db0b1f4a | ||
|
|
8f0578f0fc | ||
|
|
250f557872 | ||
|
|
462dc88b17 | ||
|
|
570fa151fc | ||
|
|
9c286cfa00 | ||
|
|
80cbb6ddbb | ||
|
|
9fd5ce0cbe | ||
|
|
1736dec629 | ||
|
|
b8a360837a | ||
|
|
fc28721960 | ||
|
|
51ce3a75c9 | ||
|
|
335056663a | ||
|
|
5b286728de | ||
|
|
291a168bcc | ||
|
|
fda7d31aa0 | ||
|
|
cbf46c737c | ||
|
|
7beb36a529 | ||
|
|
153697660d | ||
|
|
60a72e8d45 | ||
|
|
426ff04282 | ||
|
|
a50e1b32e4 | ||
|
|
9eae41ddef | ||
|
|
aad0d6d5ba | ||
|
|
7aca14a1ec | ||
|
|
d1596ef439 | ||
|
|
ea63e4998b | ||
|
|
a08dfd27a8 | ||
|
|
f58848011e | ||
|
|
934858ad86 | ||
|
|
3c25b9abae | ||
|
|
3fc03845a1 | ||
|
|
9b122384e9 | ||
|
|
9f4e6bbaeb | ||
|
|
b05654f0e3 | ||
|
|
9b3a760bbb | ||
|
|
d5822b96b0 | ||
|
|
b3d14cbfa7 | ||
|
|
d6039175e5 | ||
|
|
97d6faaced | ||
|
|
219b8130df | ||
|
|
38cbc40a64 | ||
|
|
93d3a642a9 | ||
|
|
c5e8d7af0e | ||
|
|
d6983cb460 | ||
|
|
dd9829292e | ||
|
|
89cb0eb0b6 | ||
|
|
9b5fffb149 | ||
|
|
1f90438025 | ||
|
|
a130adb25b | ||
|
|
8756c5fe7a | ||
|
|
828dba2983 | ||
|
|
6b3f5a329b | ||
|
|
63ef586b05 | ||
|
|
383a6a61b1 | ||
|
|
4fdd4e6f6f | ||
|
|
01ba4b80a7 | ||
|
|
de66764e4e | ||
|
|
1037d53988 | ||
|
|
c3ab8f866c | ||
|
|
94eb2dd1fe | ||
|
|
346b5ce8fd | ||
|
|
b37fbb990b | ||
|
|
ef75f76f5c | ||
|
|
e296100005 | ||
|
|
953dd93a48 | ||
|
|
e704f4d378 | ||
|
|
77d0f05f71 | ||
|
|
50d2376769 | ||
|
|
759d525301 | ||
|
|
fcfa188548 | ||
|
|
f4c8bbcfc2 | ||
|
|
31eead52e7 | ||
|
|
038a3a1a61 | ||
|
|
587c68b2cd | ||
|
|
377fdf5dde | ||
|
|
5c67601931 | ||
|
|
68f54207a3 | ||
|
|
bb47437686 | ||
|
|
213b715893 | ||
|
|
449d5c910c | ||
|
|
0251f9c9c0 | ||
|
|
8bc7c3d858 | ||
|
|
af44c94862 | ||
|
|
36ed7177f0 | ||
|
|
32aa88bcae | ||
|
|
51090d636b | ||
|
|
31513ea6b9 | ||
|
|
88cebbd7b8 | ||
|
|
fb8f7280bc | ||
|
|
f380401bbd | ||
|
|
9abc6c8b31 | ||
|
|
8cd252f115 | ||
|
|
53f72b11e5 | ||
|
|
ee55fcbe12 | ||
|
|
78d3442b12 | ||
|
|
979a9dd4c4 | ||
|
|
d5979c5d55 | ||
|
|
8027175600 | ||
|
|
3054ff0cbe | ||
|
|
cd453d38bb | ||
|
|
f5a290eed9 | ||
|
|
ecb3e676a5 | ||
|
|
8b59a98610 | ||
|
|
8409501206 | ||
|
|
be95cac157 | ||
|
|
476203d025 | ||
|
|
468e2e926b | ||
|
|
ac3e9394e7 | ||
|
|
868d62a509 | ||
|
|
157b864a01 | ||
|
|
951b9dfd94 | ||
|
|
1142d31164 | ||
|
|
9131bde941 | ||
|
|
1132c10dc2 | ||
|
|
c978a96c02 | ||
|
|
71e458d437 | ||
|
|
57bde0d9c7 | ||
|
|
50b4d25980 | ||
|
|
eda60e8251 | ||
|
|
c794cbbb19 | ||
|
|
4a76d1dbe5 | ||
|
|
418f734a58 | ||
|
|
dc1c355b72 | ||
|
|
1b2b22ed9f | ||
|
|
f2cd958c0a | ||
|
|
57adeaea87 | ||
|
|
8f3f1aef05 | ||
|
|
51d2453c7a | ||
|
|
45014296be | ||
|
|
afef36c950 | ||
|
|
b31756c18e | ||
|
|
f008688520 | ||
|
|
5b68ea215b | ||
|
|
b1d568f0bc | ||
|
|
17bd1b2f41 | ||
|
|
5b0d3cc0cd | ||
|
|
d4f76f1674 | ||
|
|
340fa21198 | ||
|
|
de5d66d431 | ||
|
|
7bdb17d4d5 | ||
|
|
419c64b107 | ||
|
|
99a5ae3f8e | ||
|
|
c7563c528b | ||
|
|
e30e9318da | ||
|
|
5c51028d38 | ||
|
|
c1d58e1c67 | ||
|
|
02030ff7fe | ||
|
|
f45c185fa9 | ||
|
|
1bd96c3a60 | ||
|
|
929f85d851 | ||
|
|
98d4a4e6bc | ||
|
|
fb2f83360c | ||
|
|
3c5e7729e1 | ||
|
|
5a853e1423 | ||
|
|
2f58b12dad | ||
|
|
59f4fd4dc6 | ||
|
|
5738240ee8 | ||
|
|
86fd453ea8 | ||
|
|
c83411b9ee | ||
|
|
057c9938a1 | ||
|
|
9259966132 | ||
|
|
b08980412e | ||
|
|
532a1e0429 | ||
|
|
2a36c352a0 | ||
|
|
1a2adf3f49 | ||
|
|
43b62accbb | ||
|
|
be74864ace | ||
|
|
0ae456f08a | ||
|
|
0f75d25991 | ||
|
|
67129e4a15 | ||
|
|
dfb9323cf9 | ||
|
|
7f5bd09baf | ||
|
|
02d5eb935f | ||
|
|
94ca71b7cc | ||
|
|
b338f1b154 | ||
|
|
486f0c9476 | ||
|
|
d96680f58d | ||
|
|
f8602d3242 | ||
|
|
0c021ad171 | ||
|
|
086d7b4500 | ||
|
|
891629c84a | ||
|
|
ea6d901e51 | ||
|
|
4539dd30e6 | ||
|
|
c43e57242e | ||
|
|
db8fd71ca9 | ||
|
|
f4f316881d | ||
|
|
0e16f09474 | ||
|
|
09dd418f53 | ||
|
|
decd1d1737 | ||
|
|
180e689f7e | ||
|
|
7da5556ac2 | ||
|
|
f23a03a89b | ||
|
|
84e4682f0e | ||
|
|
1f99511210 | ||
|
|
0d94f2474c | ||
|
|
480b6c1e8b | ||
|
|
95464f14d1 | ||
|
|
c34407d16c | ||
|
|
5e34d2ebbf | ||
|
|
815dd2ffa8 | ||
|
|
ecd5fb49c5 | ||
|
|
b86174e7a3 | ||
|
|
2e2038dc35 | ||
|
|
46bfb42258 | ||
|
|
feecf22511 | ||
|
|
4c4f15eb78 | ||
|
|
104ccdb8b4 | ||
|
|
6ccff79594 | ||
|
|
aed523ecc1 | ||
|
|
d496a75d0a | ||
|
|
5c01dd1e73 | ||
|
|
11d9224e3b | ||
|
|
34c29ba1d7 | ||
|
|
6cd657f9f2 | ||
|
|
4ae9e55822 | ||
|
|
8749b71273 | ||
|
|
dbc50fdf82 | ||
|
|
b1d2ef9255 | ||
|
|
5fb16555af | ||
|
|
ba7c775a04 | ||
|
|
fe348844d9 | ||
|
|
767e00277f | ||
|
|
6ce533a220 | ||
|
|
08b2ac745a | ||
|
|
46a127eecb | ||
|
|
fc63faf070 | ||
|
|
9665577802 | ||
|
|
434aca5b14 | ||
|
|
e31852aba9 | ||
|
|
37254abc36 | ||
|
|
a11ea50319 | ||
|
|
81df121dd3 | ||
|
|
50f6412eb8 | ||
|
|
bf50b0383e | ||
|
|
bd55852517 | ||
|
|
4c9f7a9988 | ||
|
|
aba8df23ed | ||
|
|
3820df0106 | ||
|
|
e74c504f91 | ||
|
|
fa70605db2 | ||
|
|
0d173446ff | ||
|
|
320e26a0af | ||
|
|
a3d689cfb3 | ||
|
|
59cc5d9380 | ||
|
|
28535652ab | ||
|
|
7b670a4483 | ||
|
|
69fc019f26 | ||
|
|
613bf66939 | ||
|
|
9edb0916f4 | ||
|
|
f4b659f782 | ||
|
|
c70446c7df | ||
|
|
c76cb6d548 | ||
|
|
71f37e90ef | ||
|
|
75b5c590a8 | ||
|
|
4469666780 | ||
|
|
c15e024141 | ||
|
|
8cb94542f4 | ||
|
|
c681a03918 | ||
|
|
30f2999962 | ||
|
|
74e3452b9e | ||
|
|
9e1cf0c200 | ||
|
|
e11eb11906 | ||
|
|
c04bca6f60 | ||
|
|
b0936ef423 | ||
|
|
41a6eb949a | ||
|
|
f17ce13a92 | ||
|
|
8c416ad29a | ||
|
|
c72938240e | ||
|
|
e905b6f80e | ||
|
|
6de8f1afb7 | ||
|
|
9341212642 | ||
|
|
f7a9721e16 | ||
|
|
089e843b0f | ||
|
|
c8056d866a | ||
|
|
49da66e459 | ||
|
|
fb6c319904 | ||
|
|
5a8d13199c | ||
|
|
dce9027045 | ||
|
|
feba604e92 | ||
|
|
d22f65413a | ||
|
|
0599ef8c08 | ||
|
|
bfdf469295 | ||
|
|
32c96387c1 | ||
|
|
c8c5443bb5 | ||
|
|
a60b854d90 | ||
|
|
b8ad4f02a2 | ||
|
|
d281274bf2 | ||
|
|
b625bc2c31 | ||
|
|
f4381ab88a | ||
|
|
744435f2a4 | ||
|
|
855703e55e | ||
|
|
927c8c4924 | ||
|
|
0ba994e9e3 | ||
|
|
af9ad45cd4 | ||
|
|
e0fee250c3 | ||
|
|
72ca05016d | ||
|
|
844d1f9fa1 | ||
|
|
213c31ae16 | ||
|
|
04f3d551a0 | ||
|
|
e8600d69fd | ||
|
|
b03d65c237 | ||
|
|
8743974189 | ||
|
|
dc36bc9434 | ||
|
|
bce878a7c1 | ||
|
|
532d797824 | ||
|
|
146c12a2da | ||
|
|
d39919c03e | ||
|
|
df2dedeefb | ||
|
|
adb029ed81 | ||
|
|
43ff1a347d | ||
|
|
14294236bf | ||
|
|
c2b293ba30 | ||
|
|
37cd9f522f | ||
|
|
f33154cd39 | ||
|
|
bafeed9f5d | ||
|
|
ef767f9fd5 | ||
|
|
bc97f6d60c | ||
|
|
90a99c1b5e | ||
|
|
f375d4b7de | ||
|
|
fa41fbd318 | ||
|
|
6a205c8876 | ||
|
|
0fb3756409 | ||
|
|
fbbdf475b1 | ||
|
|
c238be3e3a | ||
|
|
1bf2801e6a | ||
|
|
c9c8402093 | ||
|
|
6060788083 | ||
|
|
e3700fc9e4 | ||
|
|
b693216d8d | ||
|
|
46b9d8295d | ||
|
|
7decf8951c | ||
|
|
1f46c15262 | ||
|
|
0cd358676c | ||
|
|
43113d92cc | ||
|
|
7eab8dc750 | ||
|
|
44e939514e | ||
|
|
95506f1235 | ||
|
|
a91556fd74 | ||
|
|
1447f728b5 | ||
|
|
d2c690828a | ||
|
|
cfa90f4adc | ||
|
|
898280a056 | ||
|
|
59b4a2f0e4 | ||
|
|
1ee9778405 | ||
|
|
db74c11d2b | ||
|
|
5011cded16 | ||
|
|
f10b2a9c14 | ||
|
|
5cb3c0b319 | ||
|
|
b9fc428494 | ||
|
|
c0ba104674 | ||
|
|
2a4093eaf3 | ||
|
|
9e62bc4439 | ||
|
|
553d097442 | ||
|
|
ae608b8076 | ||
|
|
c397187061 | ||
|
|
e32b06e977 | ||
|
|
8c42c506cd | ||
|
|
8cc83b8dbe | ||
|
|
51af426d89 | ||
|
|
08ec0af7c6 | ||
|
|
3b221c5406 | ||
|
|
3d3423574d | ||
|
|
e5edd51de4 | ||
|
|
64c78d50cc | ||
|
|
b3bcca0844 | ||
|
|
61e40c88a9 | ||
|
|
40634747f7 | ||
|
|
c2e21f2f0d | ||
|
|
47dcd621c0 | ||
|
|
a0d6fe7b92 | ||
|
|
c9fa1cbab6 | ||
|
|
8a38a194fb | ||
|
|
6ac7f082c4 | ||
|
|
f6e6da9525 | ||
|
|
597cc8a455 | ||
|
|
3370abd509 | ||
|
|
631f73978c | ||
|
|
e5f30ade10 | ||
|
|
6622d22c79 | ||
|
|
4e1582f372 | ||
|
|
967897fd22 | ||
|
|
f918ec7ea2 | ||
|
|
a2ae43a55f | ||
|
|
7ae153ee9c | ||
|
|
f7b567ff84 | ||
|
|
f2e237adc8 | ||
|
|
2e5457be1d | ||
|
|
7f9d41a55e | ||
|
|
8207626bbe | ||
|
|
df8db1aa21 | ||
|
|
691db5ba02 | ||
|
|
acb8752f80 | ||
|
|
679790eee1 | ||
|
|
6bf48bd866 | ||
|
|
790d4fcbe1 | ||
|
|
89de9eb125 | ||
|
|
6324fd1d74 | ||
|
|
9e07cf2955 | ||
|
|
f03b88b3fb | ||
|
|
97d0365f49 | ||
|
|
12887875a2 | ||
|
|
450e709972 | ||
|
|
9befce2b8c | ||
|
|
cb99797798 | ||
|
|
f82b28146a | ||
|
|
4dc72b830c | ||
|
|
ea05129ebd | ||
|
|
35d217133f | ||
|
|
d1b7a24354 | ||
|
|
c85538dba1 | ||
|
|
60bd48b175 | ||
|
|
4be0aa3539 | ||
|
|
f636c34481 | ||
|
|
3bf79c752e | ||
|
|
cdb130b09a | ||
|
|
2e5d60b7db | ||
|
|
8271226a55 | ||
|
|
1013186a17 | ||
|
|
7c038b3c32 | ||
|
|
c8cd8e5f55 | ||
|
|
471cf47796 | ||
|
|
d8f64574a4 | ||
|
|
e711babbd1 | ||
|
|
a72b0f2b6f | ||
|
|
434eb6f26b | ||
|
|
197080b10b | ||
|
|
7796e8c2cb | ||
|
|
6d4363368a | ||
|
|
414638cd50 | ||
|
|
2a9983b78f | ||
|
|
b17c974a88 | ||
|
|
5717d91ab7 | ||
|
|
79eb0287ab | ||
|
|
58994225bc | ||
|
|
59d4c2fe1b | ||
|
|
3a468f2d8b | ||
|
|
1ad5d872b9 | ||
|
|
355fc8e944 | ||
|
|
380a29dbf7 | ||
|
|
1528d6642d | ||
|
|
7311fef854 | ||
|
|
906417c7c5 | ||
|
|
6aabe82035 | ||
|
|
f0877a445e | ||
|
|
da06e2daf8 | ||
|
|
d3f5f9f6b9 | ||
|
|
bfc6ea7935 | ||
|
|
8edc2cf8ca | ||
|
|
fb778e66df | ||
|
|
3a9918d37f | ||
|
|
ccb0cae134 | ||
|
|
085c8b75a6 | ||
|
|
dbf2ba3d61 | ||
|
|
b47bbac393 | ||
|
|
229cac754a | ||
|
|
0e33684194 | ||
|
|
9e982f9e4e | ||
|
|
c7a725cfad | ||
|
|
450a30cae8 | ||
|
|
9cd5e4fce8 | ||
|
|
edba5137b8 | ||
|
|
233a22960a | ||
|
|
3b024e17af | ||
|
|
a32b573ccb | ||
|
|
ec71c13ab8 | ||
|
|
f0bad2b026 | ||
|
|
25580f3251 | ||
|
|
da4de959df | ||
|
|
d0d51a8afa | ||
|
|
c67598c3e1 | ||
|
|
811d253bc2 | ||
|
|
c3a1642ead | ||
|
|
ccf65f9dee | ||
|
|
b954070d70 | ||
|
|
30e9f4496b | ||
|
|
271d3fbdaa | ||
|
|
6df40dcbe0 | ||
|
|
97f194c1fb | ||
|
|
4da769ccca | ||
|
|
253d96f2e2 | ||
|
|
bbc3e2753a | ||
|
|
67353612ba | ||
|
|
bffbd5f038 | ||
|
|
d8bbf2018e | ||
|
|
187f491ad2 | ||
|
|
335959e778 | ||
|
|
3b83bf8f6a | ||
|
|
51719893bf | ||
|
|
1841f65e64 | ||
|
|
bb28998920 | ||
|
|
fbc5f99db9 | ||
|
|
ca0a0bbeec | ||
|
|
6119f78cb9 | ||
|
|
539679c7f9 | ||
|
|
b642cd44c1 | ||
|
|
fffec3b9d9 | ||
|
|
3446dfb7cb | ||
|
|
db16276b7c | ||
|
|
629fcdd135 | ||
|
|
64ce2aada8 | ||
|
|
565f751967 | ||
|
|
6017964580 | ||
|
|
1d16b0c3fe | ||
|
|
7851b37993 | ||
|
|
d81edc573e | ||
|
|
ef0c8d5f9f | ||
|
|
db30f02b50 | ||
|
|
4ba7262467 | ||
|
|
67d0c25eab | ||
|
|
09f9552b40 | ||
|
|
142d38f776 | ||
|
|
6dd3471900 | ||
|
|
280d67896a | ||
|
|
510e6f6dc1 | ||
|
|
712e86b999 | ||
|
|
74fdba620d | ||
|
|
dc1c479a6f | ||
|
|
119d536e07 | ||
|
|
fa1bf9c653 | ||
|
|
814eed0ea1 | ||
|
|
0aa3068e9e | ||
|
|
db2d6124b1 | ||
|
|
039dc61bd2 | ||
|
|
4b879984ea | ||
|
|
55e286ba55 | ||
|
|
9450bfa26e | ||
|
|
18be482a6f | ||
|
|
ca6710ee41 | ||
|
|
9314810243 | ||
|
|
7717ae19fa | ||
|
|
32635ec685 | ||
|
|
caec7618a1 | ||
|
|
7e7ab2815c | ||
|
|
d7744f2219 | ||
|
|
7161829de5 | ||
|
|
991ba7fae3 | ||
|
|
a7539296ce | ||
|
|
258d5850c9 | ||
|
|
20759b340a | ||
|
|
8e5f761870 | ||
|
|
26714799c9 | ||
|
|
5e9d042d8f | ||
|
|
9cf98a2bcc | ||
|
|
f5ebb61495 | ||
|
|
431d88dd31 | ||
|
|
876f1a86af | ||
|
|
01951dda7a | ||
|
|
6e3dba168b | ||
|
|
d851e895d5 | ||
|
|
b962b76f43 | ||
|
|
26cf040827 | ||
|
|
8e241d1a1a | ||
|
|
3a648b209c | ||
|
|
c80f0a417a | ||
|
|
4fcca4bb18 | ||
|
|
511eda8eda | ||
|
|
5f9551719c | ||
|
|
d830b7c297 | ||
|
|
1c256f7047 | ||
|
|
a34dd63beb | ||
|
|
4aeae91f86 | ||
|
|
c073e35b1e | ||
|
|
5c892b0ba9 | ||
|
|
6985325e01 | ||
|
|
911ee27e83 | ||
|
|
2069acc6a4 | ||
|
|
278986ea0f | ||
|
|
6535e9511f | ||
|
|
60c7520a51 | ||
|
|
deb594a9a0 | ||
|
|
e314ba675b | ||
|
|
0214ce7c75 | ||
|
|
95fedbf86b | ||
|
|
b7769a05ec | ||
|
|
067f6a3536 | ||
|
|
8cad53e84c | ||
|
|
d5ed35b664 | ||
|
|
f427df17ab | ||
|
|
4e38899e97 | ||
|
|
cb6ff87fbb | ||
|
|
0deac3a2d8 | ||
|
|
92e3e18a1d | ||
|
|
3bb6165927 | ||
|
|
d0d4f277da | ||
|
|
99b0a1292b | ||
|
|
dc23886a77 | ||
|
|
b7298b6e2a | ||
|
|
3e6c3f52a9 | ||
|
|
0c0074328b | ||
|
|
f0648fc18c | ||
|
|
a7c0f8602e | ||
|
|
21a9c6aaac | ||
|
|
162e3c5261 | ||
|
|
6b3aef80ce | ||
|
|
77c4beab8a | ||
|
|
1a2c3c0f3e | ||
|
|
0eaf520d77 | ||
|
|
056d857571 | ||
|
|
69a3883199 | ||
|
|
0dcfb234ed | ||
|
|
43e8fafd49 | ||
|
|
314d506b96 | ||
|
|
af42895612 | ||
|
|
bfa6389b74 | ||
|
|
9b14f51a3e | ||
|
|
f4bfd65ff2 | ||
|
|
3cc687d486 | ||
|
|
cdb3076445 | ||
|
|
8a2f13c304 | ||
|
|
77bd7968ea | ||
|
|
993693aa79 | ||
|
|
ce4be3a91d | ||
|
|
937021133f | ||
|
|
f7b111b7d1 | ||
|
|
80d3177e5c | ||
|
|
5e5ddcfbcf | ||
|
|
5910e210f4 | ||
|
|
b375c8b946 | ||
|
|
88f6c78b02 | ||
|
|
4096b60948 | ||
|
|
2ab1c5ed1a | ||
|
|
0b40544f29 | ||
|
|
187da2c093 | ||
|
|
9a2cf56d51 | ||
|
|
0be41ec241 | ||
|
|
f1171f7c2d | ||
|
|
28ca6b5afa | ||
|
|
bec102a843 | ||
|
|
8f6f40d991 | ||
|
|
e2a8ff24a9 | ||
|
|
8588a86f9e | ||
|
|
5cb9c3129b | ||
|
|
4cc3d07426 | ||
|
|
5d01a64719 | ||
|
|
a276e06080 | ||
|
|
fd5ff02042 | ||
|
|
2b5b2cb84c | ||
|
|
ca6849e65d | ||
|
|
1535ac2ae9 | ||
|
|
a4680a590f | ||
|
|
fedb6816cd | ||
|
|
f6152b4b64 | ||
|
|
4b618047ce | ||
|
|
2c6945be30 | ||
|
|
9a6f4429a0 | ||
|
|
4c21c56bfe | ||
|
|
2a298b72eb | ||
|
|
55c0539872 | ||
|
|
9789a05c20 | ||
|
|
d050de77f9 | ||
|
|
95eb771dcd | ||
|
|
4fb1acc212 | ||
|
|
d3d3199870 | ||
|
|
1ca63e3ae3 | ||
|
|
59ce201915 | ||
|
|
8d5d3a5d00 | ||
|
|
37c8fd4842 | ||
|
|
3c6ffbaedb | ||
|
|
c7287a3caf | ||
|
|
5a304a7637 | ||
|
|
4c1d273e88 | ||
|
|
a9d2f7e894 | ||
|
|
682407f2d5 | ||
|
|
bdff345529 | ||
|
|
23109d6a9c | ||
|
|
4bb028f48e | ||
|
|
fec89790b1 | ||
|
|
a5741a3f5e | ||
|
|
863baa16ec | ||
|
|
c7214f9a6f | ||
|
|
8fd3afd56c | ||
|
|
f9b2f2b955 | ||
|
|
633b4a5ff6 | ||
|
|
b4cd069d5e | ||
|
|
0f8d03f81c | ||
|
|
077174f4ed | ||
|
|
e387eb5aba | ||
|
|
4083bf81a0 | ||
|
|
796173d08b | ||
|
|
e575b6821e | ||
|
|
d78be7e331 | ||
|
|
15c8d83358 | ||
|
|
e91d2338d8 | ||
|
|
4b235346d6 | ||
|
|
ad348291bb | ||
|
|
2f1765c4ea | ||
|
|
3c5b63d2d6 | ||
|
|
cc51a7d4e0 | ||
|
|
8af4ed7b4f | ||
|
|
8192ebe1f8 | ||
|
|
20ba04267c | ||
|
|
743b28ce11 | ||
|
|
caaa47d372 | ||
|
|
10f100ac8a | ||
|
|
8176041605 | ||
|
|
87bec4c715 | ||
|
|
190e8e27d8 | ||
|
|
4efe62a016 | ||
|
|
c64de2c980 | ||
|
|
6ad98fb3fd | ||
|
|
b08e09c370 | ||
|
|
cdab8aa389 | ||
|
|
3cd69a54b2 | ||
|
|
627dcfff39 | ||
|
|
df5cff3751 | ||
|
|
79ae0a06d5 | ||
|
|
2d2fa229ec | ||
|
|
5a59fd6392 | ||
|
|
0eb0faa26f | ||
|
|
32761d863c | ||
|
|
799c076384 | ||
|
|
f1cb5bcad2 | ||
|
|
9e8056d5a7 | ||
|
|
c6f3620859 | ||
|
|
59ae15a507 | ||
|
|
40b35b4aa6 | ||
|
|
be0f77d075 | ||
|
|
0f00efed4c | ||
|
|
e6137fd61d | ||
|
|
8cd10ac4ef | ||
|
|
64a57846d3 | ||
|
|
72f976701a | ||
|
|
5bd9cc7a6a | ||
|
|
f660c89d51 | ||
|
|
73dce4b2e4 | ||
|
|
9f37a95941 | ||
|
|
a130bc6d02 | ||
|
|
348d0a7a18 | ||
|
|
03f9daab34 | ||
|
|
a8156c1d2e | ||
|
|
3e669f369f | ||
|
|
da779b4924 | ||
|
|
89fb51dd2d | ||
|
|
01ba00ca42 | ||
|
|
e08bee320e | ||
|
|
96731798db | ||
|
|
c116339ddb | ||
|
|
e643e2c6b7 | ||
|
|
c63cc10ffa | ||
|
|
dae7c920f6 | ||
|
|
f462df021a | ||
|
|
1a84d8675b | ||
|
|
18ea0cefc3 | ||
|
|
c806f804d8 | ||
|
|
03c5b0fbd4 | ||
|
|
95649b3936 | ||
|
|
3aeb78ea4e | ||
|
|
dd109dee8e | ||
|
|
b514df2034 | ||
|
|
0969bdd305 | ||
|
|
1a9c655e3b | ||
|
|
88db5ef279 | ||
|
|
f8d8b39bba | ||
|
|
dcd60025f8 | ||
|
|
7e4674830e | ||
|
|
9ce5d9ee75 | ||
|
|
b49e75ff9a | ||
|
|
abe7a3ac2a | ||
|
|
717b1f72ed | ||
|
|
26396311b5 | ||
|
|
dffe658bac | ||
|
|
33d94a6c99 | ||
|
|
4d47921c9e | ||
|
|
d94adc2638 | ||
|
|
5c5d06d31d | ||
|
|
cc872b68a8 | ||
|
|
17cb14a336 | ||
|
|
877f4c45d3 | ||
|
|
02531431f2 | ||
|
|
e02066e7ff | ||
|
|
c9128b353d | ||
|
|
e7c6f1a2dc | ||
|
|
1a911e60a4 | ||
|
|
46cbda0be4 | ||
|
|
fa59f4b6a9 | ||
|
|
4a702f3819 | ||
|
|
6bac102a4d | ||
|
|
958a22b7cf | ||
|
|
97cd3afc75 | ||
|
|
aa2a94ed81 | ||
|
|
c7032546f1 | ||
|
|
56781d3d2e | ||
|
|
feb22fe5fe | ||
|
|
d8dddb7c02 | ||
|
|
4408d996fb | ||
|
|
ed7516c69d | ||
|
|
89af8e9d32 | ||
|
|
36a9c0b5ff | ||
|
|
9fb3bfb45a | ||
|
|
d479e34043 | ||
|
|
240089e5df | ||
|
|
1c469a9480 | ||
|
|
71f36332dd | ||
|
|
8179d2ba74 | ||
|
|
df4bad3245 | ||
|
|
a7b5c8d6a8 | ||
|
|
92b91c1878 | ||
|
|
7ec1a206ea | ||
|
|
51937c0869 | ||
|
|
6b50761222 | ||
|
|
6571408dc6 | ||
|
|
b6fab35b9f | ||
|
|
baec15387c | ||
|
|
297d7fd9c0 | ||
|
|
5002aea371 | ||
|
|
5f7ad21633 | ||
|
|
089d47f8d5 | ||
|
|
74033a662d | ||
|
|
fdef722fa1 | ||
|
|
110d4f4c91 | ||
|
|
0526e4f55a | ||
|
|
39973a0236 | ||
|
|
5d40a470a2 | ||
|
|
4cc391461a | ||
|
|
bf95333e5e | ||
|
|
b7a34316d2 | ||
|
|
74e453bdea | ||
|
|
156a59e7a9 | ||
|
|
aeca861f22 | ||
|
|
42cb53fcfa | ||
|
|
fe4d68e196 | ||
|
|
25b7fd9c01 | ||
|
|
e79e8b7dc4 | ||
|
|
965a8b2bc4 | ||
|
|
a8ac2f8664 | ||
|
|
fb0e99b884 | ||
|
|
9c6e9a4532 | ||
|
|
67af74992e | ||
|
|
103c508ffa | ||
|
|
2876773381 | ||
|
|
f06eaa873e | ||
|
|
ece34e8951 | ||
|
|
2262a32dd7 | ||
|
|
c6c0e23a32 | ||
|
|
02b324a23d | ||
|
|
b8005afc20 | ||
|
|
073522bc6c | ||
|
|
9248cb0549 | ||
|
|
6b41b61119 | ||
|
|
591bbe9c90 | ||
|
|
fc7376016c | ||
|
|
97a37c2319 | ||
|
|
3afed78a6a | ||
|
|
4279a0ca98 | ||
|
|
edcc7d2dd3 | ||
|
|
7f60b5aa40 | ||
|
|
65adb79fb6 | ||
|
|
aeeb29a356 | ||
|
|
902b2a0a45 | ||
|
|
6d9c22cd26 | ||
|
|
729baf58b2 | ||
|
|
4c9afeca34 | ||
|
|
6da7877bf5 | ||
|
|
b4e5de51ec | ||
|
|
a4b5f22554 | ||
|
|
ff08984246 | ||
|
|
137c5803c3 | ||
|
|
3eec021a1f | ||
|
|
5a33b73309 | ||
|
|
0b4e98490b | ||
|
|
80a846e119 | ||
|
|
434d60cd95 | ||
|
|
efe8902f0b | ||
|
|
44fb345437 | ||
|
|
9993976ae4 | ||
|
|
b387fb0385 | ||
|
|
10daa766a1 | ||
|
|
7b107eea51 | ||
|
|
646b885cbf | ||
|
|
0bfd0b598a | ||
|
|
fd873c69a4 | ||
|
|
d64db7409b | ||
|
|
27fec0e3bd | ||
|
|
65f934dc93 | ||
|
|
d51d784f85 | ||
|
|
aa85963987 | ||
|
|
413575f7a5 | ||
|
|
b7b4796bf2 | ||
|
|
fcbc8c830e | ||
|
|
f48ce130c7 | ||
|
|
13e69f546c | ||
|
|
63ec7b7479 | ||
|
|
7b6d7001d8 | ||
|
|
39ce6e79e7 | ||
|
|
5c961d89df | ||
|
|
3c4d6c9eba | ||
|
|
349e2e3e21 | ||
|
|
551fa9dfbf | ||
|
|
ce3674430b | ||
|
|
5cdfaeb37b | ||
|
|
38612b4edc | ||
|
|
6c5b442a9b | ||
|
|
5a5523698d | ||
|
|
05a2c206be | ||
|
|
8ca21983d8 | ||
|
|
20326b8b1b | ||
|
|
5d534e2fe6 | ||
|
|
234e230c87 | ||
|
|
34ae0f9d20 | ||
|
|
df09e5f9e1 | ||
|
|
3af2f7656c | ||
|
|
74e716bb64 | ||
|
|
85f76ac90b | ||
|
|
7f36e39676 | ||
|
|
ebe3f89ea4 | ||
|
|
b5de8af234 | ||
|
|
eb817499b0 | ||
|
|
e2af9232b2 | ||
|
|
9ca667065e | ||
|
|
ae16f68f4a | ||
|
|
3cd98c7894 | ||
|
|
2866e68838 | ||
|
|
be8786a6a4 | ||
|
|
0e841bdc54 | ||
|
|
225dceb046 | ||
|
|
b0d4f95899 | ||
|
|
d443aca863 | ||
|
|
2ebc6e6a92 | ||
|
|
f2ad10a97d | ||
|
|
ea46fe2dd4 | ||
|
|
202e76cfb0 | ||
|
|
3a68d7b467 | ||
|
|
795cc5059a | ||
|
|
5dc846fad0 | ||
|
|
d5c4c4c10e | ||
|
|
1ac3e3315e | ||
|
|
0e4dc2fc74 | ||
|
|
9bb8dc8e42 | ||
|
|
154b55dae3 | ||
|
|
6de7ef9b8d | ||
|
|
392105265c | ||
|
|
51661d8600 | ||
|
|
b5809a68bf | ||
|
|
7733d455c8 | ||
|
|
0a98b09bc2 | ||
|
|
302efc19ea | ||
|
|
55a1fa8a56 | ||
|
|
dce1088450 | ||
|
|
a171dbfc27 | ||
|
|
11a141dec9 | ||
|
|
818282710b | ||
|
|
7a7c093ab0 | ||
|
|
ce7b2a40d0 | ||
|
|
cfcec69331 | ||
|
|
91645066e2 | ||
|
|
dee5d76923 | ||
|
|
363a4e1114 | ||
|
|
ef0c08cdfe | ||
|
|
3210735c49 | ||
|
|
aab4fca422 | ||
|
|
891d7f2329 | ||
|
|
b24676ce88 | ||
|
|
cca4828ac9 | ||
|
|
bae611f216 | ||
|
|
d4e16d3e97 | ||
|
|
65dc7d0272 | ||
|
|
5404179338 | ||
|
|
7df97fb59f | ||
|
|
3187e42a23 | ||
|
|
f1927d71e4 | ||
|
|
eeeb4daabc | ||
|
|
3c4fc580bb | ||
|
|
17f3c40a31 | ||
|
|
505ed3088f | ||
|
|
0b976545c7 | ||
|
|
a047951477 | ||
|
|
6ab92c8b62 | ||
|
|
f36cd07685 | ||
|
|
668d975039 | ||
|
|
9ab3406ddb | ||
|
|
1b91a2e2cf | ||
|
|
2c288bda42 | ||
|
|
0b8c922da9 | ||
|
|
3fe294e4ef | ||
|
|
921a145592 | ||
|
|
0c24eed73a | ||
|
|
29ce2c1201 | ||
|
|
532c74ae86 | ||
|
|
9beb5af82e | ||
|
|
9e6dd23876 | ||
|
|
7a8501e307 | ||
|
|
781cc523af | ||
|
|
c6f45d4314 | ||
|
|
d11d05d07a | ||
|
|
e179aadfdf | ||
|
|
d6a9615347 | ||
|
|
c6306eb798 | ||
|
|
bcfde70d73 | ||
|
|
53e893615d | ||
|
|
303692b5ed | ||
|
|
58ca755f40 | ||
|
|
770234afa2 | ||
|
|
d77c3dfd02 | ||
|
|
c23d8a74dc | ||
|
|
74a5ff5f43 | ||
|
|
071940680f | ||
|
|
69d3b2d824 | ||
|
|
d891ff9fd9 | ||
|
|
6af22cf0ef | ||
|
|
fff24d5e35 | ||
|
|
ceba827e9a | ||
|
|
a0432a1e80 | ||
|
|
cfcf32d038 | ||
|
|
a67bdc34fa | ||
|
|
b3a653c245 | ||
|
|
4a34b7252e | ||
|
|
7e45ec57a8 | ||
|
|
afbaa80b8b | ||
|
|
115d243428 | ||
|
|
7151f63a5f | ||
|
|
597e7b1805 | ||
|
|
2934c2ce43 | ||
|
|
0f6e296a8e | ||
|
|
9c228928b6 | ||
|
|
ff3a2b8eab | ||
|
|
c4105fa035 | ||
|
|
871dbd3c92 | ||
|
|
c9ed14e6d6 | ||
|
|
1ad85e5061 | ||
|
|
09fbc6c952 | ||
|
|
895ec266bb | ||
|
|
d85448f3bb | ||
|
|
99d46e8c27 | ||
|
|
4afdff39d7 |
32
.gitignore
vendored
32
.gitignore
vendored
@@ -1,3 +1,35 @@
|
||||
*.pyc
|
||||
*.pyo
|
||||
*~
|
||||
*.DS_Store
|
||||
wine-py2exe/
|
||||
py2exe.log
|
||||
*.kate-swp
|
||||
build/
|
||||
dist/
|
||||
MANIFEST
|
||||
README.txt
|
||||
youtube-dl.1
|
||||
youtube-dl.bash-completion
|
||||
youtube-dl.fish
|
||||
youtube-dl
|
||||
youtube-dl.exe
|
||||
youtube-dl.tar.gz
|
||||
.coverage
|
||||
cover/
|
||||
updates_key.pem
|
||||
*.egg-info
|
||||
*.srt
|
||||
*.sbv
|
||||
*.vtt
|
||||
*.flv
|
||||
*.mp4
|
||||
*.m4a
|
||||
*.m4v
|
||||
*.part
|
||||
*.swp
|
||||
test/testdata
|
||||
.tox
|
||||
youtube-dl.zsh
|
||||
.idea
|
||||
.idea/*
|
||||
19
.travis.yml
Normal file
19
.travis.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
language: python
|
||||
python:
|
||||
- "2.6"
|
||||
- "2.7"
|
||||
- "3.2"
|
||||
- "3.3"
|
||||
- "3.4"
|
||||
- "3.5"
|
||||
sudo: false
|
||||
script: nosetests test --verbose
|
||||
notifications:
|
||||
email:
|
||||
- filippo.valsorda@gmail.com
|
||||
- phihag@phihag.de
|
||||
- yasoob.khld@gmail.com
|
||||
# irc:
|
||||
# channels:
|
||||
# - "irc.freenode.org#youtube-dl"
|
||||
# skip_join: true
|
||||
149
AUTHORS
Normal file
149
AUTHORS
Normal file
@@ -0,0 +1,149 @@
|
||||
Ricardo Garcia Gonzalez
|
||||
Danny Colligan
|
||||
Benjamin Johnson
|
||||
Vasyl' Vavrychuk
|
||||
Witold Baryluk
|
||||
Paweł Paprota
|
||||
Gergely Imreh
|
||||
Rogério Brito
|
||||
Philipp Hagemeister
|
||||
Sören Schulze
|
||||
Kevin Ngo
|
||||
Ori Avtalion
|
||||
shizeeg
|
||||
Filippo Valsorda
|
||||
Christian Albrecht
|
||||
Dave Vasilevsky
|
||||
Jaime Marquínez Ferrándiz
|
||||
Jeff Crouse
|
||||
Osama Khalid
|
||||
Michael Walter
|
||||
M. Yasoob Ullah Khalid
|
||||
Julien Fraichard
|
||||
Johny Mo Swag
|
||||
Axel Noack
|
||||
Albert Kim
|
||||
Pierre Rudloff
|
||||
Huarong Huo
|
||||
Ismael Mejía
|
||||
Steffan 'Ruirize' James
|
||||
Andras Elso
|
||||
Jelle van der Waa
|
||||
Marcin Cieślak
|
||||
Anton Larionov
|
||||
Takuya Tsuchida
|
||||
Sergey M.
|
||||
Michael Orlitzky
|
||||
Chris Gahan
|
||||
Saimadhav Heblikar
|
||||
Mike Col
|
||||
Oleg Prutz
|
||||
pulpe
|
||||
Andreas Schmitz
|
||||
Michael Kaiser
|
||||
Niklas Laxström
|
||||
David Triendl
|
||||
Anthony Weems
|
||||
David Wagner
|
||||
Juan C. Olivares
|
||||
Mattias Harrysson
|
||||
phaer
|
||||
Sainyam Kapoor
|
||||
Nicolas Évrard
|
||||
Jason Normore
|
||||
Hoje Lee
|
||||
Adam Thalhammer
|
||||
Georg Jähnig
|
||||
Ralf Haring
|
||||
Koki Takahashi
|
||||
Ariset Llerena
|
||||
Adam Malcontenti-Wilson
|
||||
Tobias Bell
|
||||
Naglis Jonaitis
|
||||
Charles Chen
|
||||
Hassaan Ali
|
||||
Dobrosław Żybort
|
||||
David Fabijan
|
||||
Sebastian Haas
|
||||
Alexander Kirk
|
||||
Erik Johnson
|
||||
Keith Beckman
|
||||
Ole Ernst
|
||||
Aaron McDaniel (mcd1992)
|
||||
Magnus Kolstad
|
||||
Hari Padmanaban
|
||||
Carlos Ramos
|
||||
5moufl
|
||||
lenaten
|
||||
Dennis Scheiba
|
||||
Damon Timm
|
||||
winwon
|
||||
Xavier Beynon
|
||||
Gabriel Schubiner
|
||||
xantares
|
||||
Jan Matějka
|
||||
Mauroy Sébastien
|
||||
William Sewell
|
||||
Dao Hoang Son
|
||||
Oskar Jauch
|
||||
Matthew Rayfield
|
||||
t0mm0
|
||||
Tithen-Firion
|
||||
Zack Fernandes
|
||||
cryptonaut
|
||||
Adrian Kretz
|
||||
Mathias Rav
|
||||
Petr Kutalek
|
||||
Will Glynn
|
||||
Max Reimann
|
||||
Cédric Luthi
|
||||
Thijs Vermeir
|
||||
Joel Leclerc
|
||||
Christopher Krooss
|
||||
Ondřej Caletka
|
||||
Dinesh S
|
||||
Johan K. Jensen
|
||||
Yen Chi Hsuan
|
||||
Enam Mijbah Noor
|
||||
David Luhmer
|
||||
Shaya Goldberg
|
||||
Paul Hartmann
|
||||
Frans de Jonge
|
||||
Robin de Rooij
|
||||
Ryan Schmidt
|
||||
Leslie P. Polzer
|
||||
Duncan Keall
|
||||
Alexander Mamay
|
||||
Devin J. Pohly
|
||||
Eduardo Ferro Aldama
|
||||
Jeff Buchbinder
|
||||
Amish Bhadeshia
|
||||
Joram Schrijver
|
||||
Will W.
|
||||
Mohammad Teimori Pabandi
|
||||
Roman Le Négrate
|
||||
Matthias Küch
|
||||
Julian Richen
|
||||
Ping O.
|
||||
Mister Hat
|
||||
Peter Ding
|
||||
jackyzy823
|
||||
George Brighton
|
||||
Remita Amine
|
||||
Aurélio A. Heckert
|
||||
Bernhard Minks
|
||||
sceext
|
||||
Zach Bruggeman
|
||||
Tjark Saul
|
||||
slangangular
|
||||
Behrouz Abbasi
|
||||
ngld
|
||||
nyuszika7h
|
||||
Shaun Walbridge
|
||||
Lee Jenkins
|
||||
Anssi Hannula
|
||||
Lukáš Lalinský
|
||||
Qijiang Fan
|
||||
Rémy Léone
|
||||
Marco Ferragina
|
||||
reiv
|
||||
155
CONTRIBUTING.md
Normal file
155
CONTRIBUTING.md
Normal file
@@ -0,0 +1,155 @@
|
||||
**Please include the full output of youtube-dl when run with `-v`**, i.e. add `-v` flag to your command line, copy the **whole** output and post it in the issue body wrapped in \`\`\` for better formatting. It should look similar to this:
|
||||
```
|
||||
$ youtube-dl -v http://www.youtube.com/watch?v=BaW_jenozKcj
|
||||
[debug] System config: []
|
||||
[debug] User config: []
|
||||
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
|
||||
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
|
||||
[debug] youtube-dl version 2015.12.06
|
||||
[debug] Git HEAD: 135392e
|
||||
[debug] Python version 2.6.6 - Windows-2003Server-5.2.3790-SP2
|
||||
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
||||
[debug] Proxy map: {}
|
||||
...
|
||||
```
|
||||
**Do not post screenshots of verbose log only plain text is acceptable.**
|
||||
|
||||
The output (including the first lines) contains important debugging information. Issues without the full output are often not reproducible and therefore do not get solved in short order, if ever.
|
||||
|
||||
Please re-read your issue once again to avoid a couple of common mistakes (you can and should use this as a checklist):
|
||||
|
||||
### Is the description of the issue itself sufficient?
|
||||
|
||||
We often get issue reports that we cannot really decipher. While in most cases we eventually get the required information after asking back multiple times, this poses an unnecessary drain on our resources. Many contributors, including myself, are also not native speakers, so we may misread some parts.
|
||||
|
||||
So please elaborate on what feature you are requesting, or what bug you want to be fixed. Make sure that it's obvious
|
||||
|
||||
- What the problem is
|
||||
- How it could be fixed
|
||||
- How your proposed solution would look like
|
||||
|
||||
If your report is shorter than two lines, it is almost certainly missing some of these, which makes it hard for us to respond to it. We're often too polite to close the issue outright, but the missing info makes misinterpretation likely. As a commiter myself, I often get frustrated by these issues, since the only possible way for me to move forward on them is to ask for clarification over and over.
|
||||
|
||||
For bug reports, this means that your report should contain the *complete* output of youtube-dl when called with the `-v` flag. The error message you get for (most) bugs even says so, but you would not believe how many of our bug reports do not contain this information.
|
||||
|
||||
If your server has multiple IPs or you suspect censorship, adding `--call-home` may be a good idea to get more diagnostics. If the error is `ERROR: Unable to extract ...` and you cannot reproduce it from multiple countries, add `--dump-pages` (warning: this will yield a rather large output, redirect it to the file `log.txt` by adding `>log.txt 2>&1` to your command-line) or upload the `.dump` files you get when you add `--write-pages` [somewhere](https://gist.github.com/).
|
||||
|
||||
**Site support requests must contain an example URL**. An example URL is a URL you might want to download, like http://www.youtube.com/watch?v=BaW_jenozKc . There should be an obvious video present. Except under very special circumstances, the main page of a video service (e.g. http://www.youtube.com/ ) is *not* an example URL.
|
||||
|
||||
### Are you using the latest version?
|
||||
|
||||
Before reporting any issue, type `youtube-dl -U`. This should report that you're up-to-date. About 20% of the reports we receive are already fixed, but people are using outdated versions. This goes for feature requests as well.
|
||||
|
||||
### Is the issue already documented?
|
||||
|
||||
Make sure that someone has not already opened the issue you're trying to open. Search at the top of the window or at https://github.com/rg3/youtube-dl/search?type=Issues . If there is an issue, feel free to write something along the lines of "This affects me as well, with version 2015.01.01. Here is some more information on the issue: ...". While some issues may be old, a new post into them often spurs rapid activity.
|
||||
|
||||
### Why are existing options not enough?
|
||||
|
||||
Before requesting a new feature, please have a quick peek at [the list of supported options](https://github.com/rg3/youtube-dl/blob/master/README.md#synopsis). Many feature requests are for features that actually exist already! Please, absolutely do show off your work in the issue report and detail how the existing similar options do *not* solve your problem.
|
||||
|
||||
### Is there enough context in your bug report?
|
||||
|
||||
People want to solve problems, and often think they do us a favor by breaking down their larger problems (e.g. wanting to skip already downloaded files) to a specific request (e.g. requesting us to look whether the file exists before downloading the info page). However, what often happens is that they break down the problem into two steps: One simple, and one impossible (or extremely complicated one).
|
||||
|
||||
We are then presented with a very complicated request when the original problem could be solved far easier, e.g. by recording the downloaded video IDs in a separate file. To avoid this, you must include the greater context where it is non-obvious. In particular, every feature request that does not consist of adding support for a new site should contain a use case scenario that explains in what situation the missing feature would be useful.
|
||||
|
||||
### Does the issue involve one problem, and one problem only?
|
||||
|
||||
Some of our users seem to think there is a limit of issues they can or should open. There is no limit of issues they can or should open. While it may seem appealing to be able to dump all your issues into one ticket, that means that someone who solves one of your issues cannot mark the issue as closed. Typically, reporting a bunch of issues leads to the ticket lingering since nobody wants to attack that behemoth, until someone mercifully splits the issue into multiple ones.
|
||||
|
||||
In particular, every site support request issue should only pertain to services at one site (generally under a common domain, but always using the same backend technology). Do not request support for vimeo user videos, Whitehouse podcasts, and Google Plus pages in the same issue. Also, make sure that you don't post bug reports alongside feature requests. As a rule of thumb, a feature request does not include outputs of youtube-dl that are not immediately related to the feature at hand. Do not post reports of a network error alongside the request for a new video service.
|
||||
|
||||
### Is anyone going to need the feature?
|
||||
|
||||
Only post features that you (or an incapacitated friend you can personally talk to) require. Do not post features because they seem like a good idea. If they are really useful, they will be requested by someone who requires them.
|
||||
|
||||
### Is your question about youtube-dl?
|
||||
|
||||
It may sound strange, but some bug reports we receive are completely unrelated to youtube-dl and relate to a different or even the reporter's own application. Please make sure that you are actually using youtube-dl. If you are using a UI for youtube-dl, report the bug to the maintainer of the actual application providing the UI. On the other hand, if your UI for youtube-dl fails in some way you believe is related to youtube-dl, by all means, go ahead and report the bug.
|
||||
|
||||
# DEVELOPER INSTRUCTIONS
|
||||
|
||||
Most users do not need to build youtube-dl and can [download the builds](http://rg3.github.io/youtube-dl/download.html) or get them from their distribution.
|
||||
|
||||
To run youtube-dl as a developer, you don't need to build anything either. Simply execute
|
||||
|
||||
python -m youtube_dl
|
||||
|
||||
To run the test, simply invoke your favorite test runner, or execute a test file directly; any of the following work:
|
||||
|
||||
python -m unittest discover
|
||||
python test/test_download.py
|
||||
nosetests
|
||||
|
||||
If you want to create a build of youtube-dl yourself, you'll need
|
||||
|
||||
* python
|
||||
* make
|
||||
* pandoc
|
||||
* zip
|
||||
* nosetests
|
||||
|
||||
### Adding support for a new site
|
||||
|
||||
If you want to add support for a new site, you can follow this quick list (assuming your service is called `yourextractor`):
|
||||
|
||||
1. [Fork this repository](https://github.com/rg3/youtube-dl/fork)
|
||||
2. Check out the source code with `git clone git@github.com:YOUR_GITHUB_USERNAME/youtube-dl.git`
|
||||
3. Start a new git branch with `cd youtube-dl; git checkout -b yourextractor`
|
||||
4. Start with this simple template and save it to `youtube_dl/extractor/yourextractor.py`:
|
||||
```python
|
||||
# coding: utf-8
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .common import InfoExtractor
|
||||
|
||||
|
||||
class YourExtractorIE(InfoExtractor):
|
||||
_VALID_URL = r'https?://(?:www\.)?yourextractor\.com/watch/(?P<id>[0-9]+)'
|
||||
_TEST = {
|
||||
'url': 'http://yourextractor.com/watch/42',
|
||||
'md5': 'TODO: md5 sum of the first 10241 bytes of the video file (use --test)',
|
||||
'info_dict': {
|
||||
'id': '42',
|
||||
'ext': 'mp4',
|
||||
'title': 'Video title goes here',
|
||||
'thumbnail': 're:^https?://.*\.jpg$',
|
||||
# TODO more properties, either as:
|
||||
# * A value
|
||||
# * MD5 checksum; start the string with md5:
|
||||
# * A regular expression; start the string with re:
|
||||
# * Any Python type (for example int or float)
|
||||
}
|
||||
}
|
||||
|
||||
def _real_extract(self, url):
|
||||
video_id = self._match_id(url)
|
||||
webpage = self._download_webpage(url, video_id)
|
||||
|
||||
# TODO more code goes here, for example ...
|
||||
title = self._html_search_regex(r'<h1>(.+?)</h1>', webpage, 'title')
|
||||
|
||||
return {
|
||||
'id': video_id,
|
||||
'title': title,
|
||||
'description': self._og_search_description(webpage),
|
||||
'uploader': self._search_regex(r'<div[^>]+id="uploader"[^>]*>([^<]+)<', webpage, 'uploader', fatal=False),
|
||||
# TODO more properties (see youtube_dl/extractor/common.py)
|
||||
}
|
||||
```
|
||||
5. Add an import in [`youtube_dl/extractor/__init__.py`](https://github.com/rg3/youtube-dl/blob/master/youtube_dl/extractor/__init__.py).
|
||||
6. Run `python test/test_download.py TestDownload.test_YourExtractor`. This *should fail* at first, but you can continually re-run it until you're done. If you decide to add more than one test, then rename ``_TEST`` to ``_TESTS`` and make it into a list of dictionaries. The tests will then be named `TestDownload.test_YourExtractor`, `TestDownload.test_YourExtractor_1`, `TestDownload.test_YourExtractor_2`, etc.
|
||||
7. Have a look at [`youtube_dl/extractor/common.py`](https://github.com/rg3/youtube-dl/blob/master/youtube_dl/extractor/common.py) for possible helper methods and a [detailed description of what your extractor should and may return](https://github.com/rg3/youtube-dl/blob/master/youtube_dl/extractor/common.py#L62-L200). Add tests and code for as many as you want.
|
||||
8. If you can, check the code with [flake8](https://pypi.python.org/pypi/flake8).
|
||||
9. When the tests pass, [add](http://git-scm.com/docs/git-add) the new files and [commit](http://git-scm.com/docs/git-commit) them and [push](http://git-scm.com/docs/git-push) the result, like this:
|
||||
|
||||
$ git add youtube_dl/extractor/__init__.py
|
||||
$ git add youtube_dl/extractor/yourextractor.py
|
||||
$ git commit -m '[yourextractor] Add new extractor'
|
||||
$ git push origin yourextractor
|
||||
|
||||
10. Finally, [create a pull request](https://help.github.com/articles/creating-a-pull-request). We'll then review and merge it.
|
||||
|
||||
In any case, thank you very much for your contributions!
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
2012.01.08b
|
||||
24
LICENSE
Normal file
24
LICENSE
Normal file
@@ -0,0 +1,24 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
7
MANIFEST.in
Normal file
7
MANIFEST.in
Normal file
@@ -0,0 +1,7 @@
|
||||
include README.md
|
||||
include test/*.py
|
||||
include test/*.json
|
||||
include youtube-dl.bash-completion
|
||||
include youtube-dl.fish
|
||||
include youtube-dl.1
|
||||
recursive-include docs Makefile conf.py *.rst
|
||||
124
Makefile
124
Makefile
@@ -1,23 +1,111 @@
|
||||
default: update
|
||||
all: youtube-dl README.md CONTRIBUTING.md README.txt youtube-dl.1 youtube-dl.bash-completion youtube-dl.zsh youtube-dl.fish supportedsites
|
||||
|
||||
update: compile update-readme update-latest
|
||||
clean:
|
||||
rm -rf youtube-dl.1.temp.md youtube-dl.1 youtube-dl.bash-completion README.txt MANIFEST build/ dist/ .coverage cover/ youtube-dl.tar.gz youtube-dl.zsh youtube-dl.fish *.dump *.part *.info.json *.mp4 *.flv *.mp3 *.avi CONTRIBUTING.md.tmp youtube-dl youtube-dl.exe
|
||||
find . -name "*.pyc" -delete
|
||||
|
||||
update-latest:
|
||||
./youtube-dl.dev --version > LATEST_VERSION
|
||||
PREFIX ?= /usr/local
|
||||
BINDIR ?= $(PREFIX)/bin
|
||||
MANDIR ?= $(PREFIX)/man
|
||||
SHAREDIR ?= $(PREFIX)/share
|
||||
PYTHON ?= /usr/bin/env python
|
||||
|
||||
update-readme:
|
||||
@options=$$(COLUMNS=80 ./youtube-dl.dev --help | sed -e '1,/.*General Options.*/ d' -e 's/^\W\{2\}\(\w\)/### \1/') && \
|
||||
header=$$(sed -e '/.*## OPTIONS/,$$ d' README.md) && \
|
||||
footer=$$(sed -e '1,/.*## FAQ/ d' README.md) && \
|
||||
echo "$${header}" > README.md && \
|
||||
echo >> README.md && \
|
||||
echo '## OPTIONS' >> README.md && \
|
||||
echo "$${options}" >> README.md&& \
|
||||
echo >> README.md && \
|
||||
echo '## FAQ' >> README.md && \
|
||||
echo "$${footer}" >> README.md
|
||||
# set SYSCONFDIR to /etc if PREFIX=/usr or PREFIX=/usr/local
|
||||
ifeq ($(PREFIX),/usr)
|
||||
SYSCONFDIR=/etc
|
||||
else
|
||||
ifeq ($(PREFIX),/usr/local)
|
||||
SYSCONFDIR=/etc
|
||||
else
|
||||
SYSCONFDIR=$(PREFIX)/etc
|
||||
endif
|
||||
endif
|
||||
|
||||
compile:
|
||||
cp youtube_dl/__init__.py youtube-dl
|
||||
install: youtube-dl youtube-dl.1 youtube-dl.bash-completion youtube-dl.zsh youtube-dl.fish
|
||||
install -d $(DESTDIR)$(BINDIR)
|
||||
install -m 755 youtube-dl $(DESTDIR)$(BINDIR)
|
||||
install -d $(DESTDIR)$(MANDIR)/man1
|
||||
install -m 644 youtube-dl.1 $(DESTDIR)$(MANDIR)/man1
|
||||
install -d $(DESTDIR)$(SYSCONFDIR)/bash_completion.d
|
||||
install -m 644 youtube-dl.bash-completion $(DESTDIR)$(SYSCONFDIR)/bash_completion.d/youtube-dl
|
||||
install -d $(DESTDIR)$(SHAREDIR)/zsh/site-functions
|
||||
install -m 644 youtube-dl.zsh $(DESTDIR)$(SHAREDIR)/zsh/site-functions/_youtube-dl
|
||||
install -d $(DESTDIR)$(SYSCONFDIR)/fish/completions
|
||||
install -m 644 youtube-dl.fish $(DESTDIR)$(SYSCONFDIR)/fish/completions/youtube-dl.fish
|
||||
|
||||
.PHONY: default compile update update-latest update-readme
|
||||
codetest:
|
||||
flake8 .
|
||||
|
||||
test:
|
||||
#nosetests --with-coverage --cover-package=youtube_dl --cover-html --verbose --processes 4 test
|
||||
nosetests --verbose test
|
||||
$(MAKE) codetest
|
||||
|
||||
ot: offlinetest
|
||||
|
||||
offlinetest: codetest
|
||||
nosetests --verbose test --exclude test_download.py --exclude test_age_restriction.py --exclude test_subtitles.py --exclude test_write_annotations.py --exclude test_youtube_lists.py
|
||||
|
||||
tar: youtube-dl.tar.gz
|
||||
|
||||
.PHONY: all clean install test tar bash-completion pypi-files zsh-completion fish-completion ot offlinetest codetest supportedsites
|
||||
|
||||
pypi-files: youtube-dl.bash-completion README.txt youtube-dl.1 youtube-dl.fish
|
||||
|
||||
youtube-dl: youtube_dl/*.py youtube_dl/*/*.py
|
||||
zip --quiet youtube-dl youtube_dl/*.py youtube_dl/*/*.py
|
||||
zip --quiet --junk-paths youtube-dl youtube_dl/__main__.py
|
||||
echo '#!$(PYTHON)' > youtube-dl
|
||||
cat youtube-dl.zip >> youtube-dl
|
||||
rm youtube-dl.zip
|
||||
chmod a+x youtube-dl
|
||||
|
||||
README.md: youtube_dl/*.py youtube_dl/*/*.py
|
||||
COLUMNS=80 $(PYTHON) youtube_dl/__main__.py --help | $(PYTHON) devscripts/make_readme.py
|
||||
|
||||
CONTRIBUTING.md: README.md
|
||||
$(PYTHON) devscripts/make_contributing.py README.md CONTRIBUTING.md
|
||||
|
||||
supportedsites:
|
||||
$(PYTHON) devscripts/make_supportedsites.py docs/supportedsites.md
|
||||
|
||||
README.txt: README.md
|
||||
pandoc -f markdown -t plain README.md -o README.txt
|
||||
|
||||
youtube-dl.1: README.md
|
||||
$(PYTHON) devscripts/prepare_manpage.py >youtube-dl.1.temp.md
|
||||
pandoc -s -f markdown -t man youtube-dl.1.temp.md -o youtube-dl.1
|
||||
rm -f youtube-dl.1.temp.md
|
||||
|
||||
youtube-dl.bash-completion: youtube_dl/*.py youtube_dl/*/*.py devscripts/bash-completion.in
|
||||
$(PYTHON) devscripts/bash-completion.py
|
||||
|
||||
bash-completion: youtube-dl.bash-completion
|
||||
|
||||
youtube-dl.zsh: youtube_dl/*.py youtube_dl/*/*.py devscripts/zsh-completion.in
|
||||
$(PYTHON) devscripts/zsh-completion.py
|
||||
|
||||
zsh-completion: youtube-dl.zsh
|
||||
|
||||
youtube-dl.fish: youtube_dl/*.py youtube_dl/*/*.py devscripts/fish-completion.in
|
||||
$(PYTHON) devscripts/fish-completion.py
|
||||
|
||||
fish-completion: youtube-dl.fish
|
||||
|
||||
youtube-dl.tar.gz: youtube-dl README.md README.txt youtube-dl.1 youtube-dl.bash-completion youtube-dl.zsh youtube-dl.fish
|
||||
@tar -czf youtube-dl.tar.gz --transform "s|^|youtube-dl/|" --owner 0 --group 0 \
|
||||
--exclude '*.DS_Store' \
|
||||
--exclude '*.kate-swp' \
|
||||
--exclude '*.pyc' \
|
||||
--exclude '*.pyo' \
|
||||
--exclude '*~' \
|
||||
--exclude '__pycache' \
|
||||
--exclude '.git' \
|
||||
--exclude 'testdata' \
|
||||
--exclude 'docs/_build' \
|
||||
-- \
|
||||
bin devscripts test youtube_dl docs \
|
||||
LICENSE README.md README.txt \
|
||||
Makefile MANIFEST.in youtube-dl.1 youtube-dl.bash-completion \
|
||||
youtube-dl.zsh youtube-dl.fish setup.py \
|
||||
youtube-dl
|
||||
|
||||
942
README.md
942
README.md
@@ -1,129 +1,877 @@
|
||||
# youtube-dl
|
||||
youtube-dl - download videos from youtube.com or other video platforms
|
||||
|
||||
## USAGE
|
||||
youtube-dl [options] url [url...]
|
||||
- [INSTALLATION](#installation)
|
||||
- [DESCRIPTION](#description)
|
||||
- [OPTIONS](#options)
|
||||
- [CONFIGURATION](#configuration)
|
||||
- [OUTPUT TEMPLATE](#output-template)
|
||||
- [FORMAT SELECTION](#format-selection)
|
||||
- [VIDEO SELECTION](#video-selection)
|
||||
- [FAQ](#faq)
|
||||
- [DEVELOPER INSTRUCTIONS](#developer-instructions)
|
||||
- [EMBEDDING YOUTUBE-DL](#embedding-youtube-dl)
|
||||
- [BUGS](#bugs)
|
||||
- [COPYRIGHT](#copyright)
|
||||
|
||||
## DESCRIPTION
|
||||
# INSTALLATION
|
||||
|
||||
To install it right away for all UNIX users (Linux, OS X, etc.), type:
|
||||
|
||||
sudo curl https://yt-dl.org/latest/youtube-dl -o /usr/local/bin/youtube-dl
|
||||
sudo chmod a+rx /usr/local/bin/youtube-dl
|
||||
|
||||
If you do not have curl, you can alternatively use a recent wget:
|
||||
|
||||
sudo wget https://yt-dl.org/downloads/latest/youtube-dl -O /usr/local/bin/youtube-dl
|
||||
sudo chmod a+rx /usr/local/bin/youtube-dl
|
||||
|
||||
Windows users can [download a .exe file](https://yt-dl.org/latest/youtube-dl.exe) and place it in their home directory or any other location on their [PATH](http://en.wikipedia.org/wiki/PATH_%28variable%29).
|
||||
|
||||
OS X users can install **youtube-dl** with [Homebrew](http://brew.sh/).
|
||||
|
||||
brew install youtube-dl
|
||||
|
||||
You can also use pip:
|
||||
|
||||
sudo pip install youtube-dl
|
||||
|
||||
Alternatively, refer to the [developer instructions](#developer-instructions) for how to check out and work with the git repository. For further options, including PGP signatures, see https://rg3.github.io/youtube-dl/download.html .
|
||||
|
||||
# DESCRIPTION
|
||||
**youtube-dl** is a small command-line program to download videos from
|
||||
YouTube.com and a few more sites. It requires the Python interpreter, version
|
||||
2.x (x being at least 5), and it is not platform specific. It should work in
|
||||
your Unix box, in Windows or in Mac OS X. It is released to the public domain,
|
||||
2.6, 2.7, or 3.2+, and it is not platform specific. It should work on
|
||||
your Unix box, on Windows or on Mac OS X. It is released to the public domain,
|
||||
which means you can modify it, redistribute it or use it however you like.
|
||||
|
||||
## OPTIONS
|
||||
-h, --help print this help text and exit
|
||||
-v, --version print program version and exit
|
||||
-U, --update update this program to latest version
|
||||
-i, --ignore-errors continue on download errors
|
||||
-r, --rate-limit LIMIT download rate limit (e.g. 50k or 44.6m)
|
||||
-R, --retries RETRIES number of retries (default is 10)
|
||||
--dump-user-agent display the current browser identification
|
||||
--list-extractors List all supported extractors and the URLs they
|
||||
would handle
|
||||
youtube-dl [OPTIONS] URL [URL...]
|
||||
|
||||
### Video Selection:
|
||||
--playlist-start NUMBER playlist video to start at (default is 1)
|
||||
--playlist-end NUMBER playlist video to end at (default is last)
|
||||
--match-title REGEX download only matching titles (regex or caseless
|
||||
sub-string)
|
||||
--reject-title REGEX skip download for matching titles (regex or
|
||||
caseless sub-string)
|
||||
--max-downloads NUMBER Abort after downloading NUMBER files
|
||||
# OPTIONS
|
||||
-h, --help Print this help text and exit
|
||||
--version Print program version and exit
|
||||
-U, --update Update this program to latest version. Make
|
||||
sure that you have sufficient permissions
|
||||
(run with sudo if needed)
|
||||
-i, --ignore-errors Continue on download errors, for example to
|
||||
skip unavailable videos in a playlist
|
||||
--abort-on-error Abort downloading of further videos (in the
|
||||
playlist or the command line) if an error
|
||||
occurs
|
||||
--dump-user-agent Display the current browser identification
|
||||
--list-extractors List all supported extractors
|
||||
--extractor-descriptions Output descriptions of all supported
|
||||
extractors
|
||||
--force-generic-extractor Force extraction to use the generic
|
||||
extractor
|
||||
--default-search PREFIX Use this prefix for unqualified URLs. For
|
||||
example "gvsearch2:" downloads two videos
|
||||
from google videos for youtube-dl "large
|
||||
apple". Use the value "auto" to let
|
||||
youtube-dl guess ("auto_warning" to emit a
|
||||
warning when guessing). "error" just throws
|
||||
an error. The default value "fixup_error"
|
||||
repairs broken URLs, but emits an error if
|
||||
this is not possible instead of searching.
|
||||
--ignore-config Do not read configuration files. When given
|
||||
in the global configuration file /etc
|
||||
/youtube-dl.conf: Do not read the user
|
||||
configuration in ~/.config/youtube-
|
||||
dl/config (%APPDATA%/youtube-dl/config.txt
|
||||
on Windows)
|
||||
--flat-playlist Do not extract the videos of a playlist,
|
||||
only list them.
|
||||
--no-color Do not emit color codes in output
|
||||
|
||||
### Filesystem Options:
|
||||
-t, --title use title in file name
|
||||
-l, --literal use literal title in file name
|
||||
-A, --auto-number number downloaded files starting from 00000
|
||||
-o, --output TEMPLATE output filename template. Use %(stitle)s to get the
|
||||
title, %(uploader)s for the uploader name,
|
||||
%(autonumber)s to get an automatically incremented
|
||||
number, %(ext)s for the filename extension,
|
||||
%(upload_date)s for the upload date (YYYYMMDD), and
|
||||
%% for a literal percent. Use - to output to
|
||||
stdout.
|
||||
-a, --batch-file FILE file containing URLs to download ('-' for stdin)
|
||||
-w, --no-overwrites do not overwrite files
|
||||
-c, --continue resume partially downloaded files
|
||||
--no-continue do not resume partially downloaded files (restart
|
||||
from beginning)
|
||||
--cookies FILE file to read cookies from and dump cookie jar in
|
||||
--no-part do not use .part files
|
||||
--no-mtime do not use the Last-modified header to set the file
|
||||
modification time
|
||||
--write-description write video description to a .description file
|
||||
--write-info-json write video metadata to a .info.json file
|
||||
## Network Options:
|
||||
--proxy URL Use the specified HTTP/HTTPS proxy. Pass in
|
||||
an empty string (--proxy "") for direct
|
||||
connection
|
||||
--socket-timeout SECONDS Time to wait before giving up, in seconds
|
||||
--source-address IP Client-side IP address to bind to
|
||||
(experimental)
|
||||
-4, --force-ipv4 Make all connections via IPv4
|
||||
(experimental)
|
||||
-6, --force-ipv6 Make all connections via IPv6
|
||||
(experimental)
|
||||
--cn-verification-proxy URL Use this proxy to verify the IP address for
|
||||
some Chinese sites. The default proxy
|
||||
specified by --proxy (or none, if the
|
||||
options is not present) is used for the
|
||||
actual downloading. (experimental)
|
||||
|
||||
### Verbosity / Simulation Options:
|
||||
-q, --quiet activates quiet mode
|
||||
-s, --simulate do not download the video and do not write anything
|
||||
to disk
|
||||
--skip-download do not download the video
|
||||
-g, --get-url simulate, quiet but print URL
|
||||
-e, --get-title simulate, quiet but print title
|
||||
--get-thumbnail simulate, quiet but print thumbnail URL
|
||||
--get-description simulate, quiet but print video description
|
||||
--get-filename simulate, quiet but print output filename
|
||||
--get-format simulate, quiet but print output format
|
||||
--no-progress do not print progress bar
|
||||
--console-title display progress in console titlebar
|
||||
## Video Selection:
|
||||
--playlist-start NUMBER Playlist video to start at (default is 1)
|
||||
--playlist-end NUMBER Playlist video to end at (default is last)
|
||||
--playlist-items ITEM_SPEC Playlist video items to download. Specify
|
||||
indices of the videos in the playlist
|
||||
separated by commas like: "--playlist-items
|
||||
1,2,5,8" if you want to download videos
|
||||
indexed 1, 2, 5, 8 in the playlist. You can
|
||||
specify range: "--playlist-items
|
||||
1-3,7,10-13", it will download the videos
|
||||
at index 1, 2, 3, 7, 10, 11, 12 and 13.
|
||||
--match-title REGEX Download only matching titles (regex or
|
||||
caseless sub-string)
|
||||
--reject-title REGEX Skip download for matching titles (regex or
|
||||
caseless sub-string)
|
||||
--max-downloads NUMBER Abort after downloading NUMBER files
|
||||
--min-filesize SIZE Do not download any videos smaller than
|
||||
SIZE (e.g. 50k or 44.6m)
|
||||
--max-filesize SIZE Do not download any videos larger than SIZE
|
||||
(e.g. 50k or 44.6m)
|
||||
--date DATE Download only videos uploaded in this date
|
||||
--datebefore DATE Download only videos uploaded on or before
|
||||
this date (i.e. inclusive)
|
||||
--dateafter DATE Download only videos uploaded on or after
|
||||
this date (i.e. inclusive)
|
||||
--min-views COUNT Do not download any videos with less than
|
||||
COUNT views
|
||||
--max-views COUNT Do not download any videos with more than
|
||||
COUNT views
|
||||
--match-filter FILTER Generic video filter (experimental).
|
||||
Specify any key (see help for -o for a list
|
||||
of available keys) to match if the key is
|
||||
present, !key to check if the key is not
|
||||
present,key > NUMBER (like "comment_count >
|
||||
12", also works with >=, <, <=, !=, =) to
|
||||
compare against a number, and & to require
|
||||
multiple matches. Values which are not
|
||||
known are excluded unless you put a
|
||||
question mark (?) after the operator.For
|
||||
example, to only match videos that have
|
||||
been liked more than 100 times and disliked
|
||||
less than 50 times (or the dislike
|
||||
functionality is not available at the given
|
||||
service), but who also have a description,
|
||||
use --match-filter "like_count > 100 &
|
||||
dislike_count <? 50 & description" .
|
||||
--no-playlist Download only the video, if the URL refers
|
||||
to a video and a playlist.
|
||||
--yes-playlist Download the playlist, if the URL refers to
|
||||
a video and a playlist.
|
||||
--age-limit YEARS Download only videos suitable for the given
|
||||
age
|
||||
--download-archive FILE Download only videos not listed in the
|
||||
archive file. Record the IDs of all
|
||||
downloaded videos in it.
|
||||
--include-ads Download advertisements as well
|
||||
(experimental)
|
||||
|
||||
### Video Format Options:
|
||||
-f, --format FORMAT video format code
|
||||
--all-formats download all available video formats
|
||||
--prefer-free-formats prefer free video formats unless a specific one is
|
||||
requested
|
||||
--max-quality FORMAT highest quality format to download
|
||||
-F, --list-formats list all available formats (currently youtube only)
|
||||
## Download Options:
|
||||
-r, --rate-limit LIMIT Maximum download rate in bytes per second
|
||||
(e.g. 50K or 4.2M)
|
||||
-R, --retries RETRIES Number of retries (default is 10), or
|
||||
"infinite".
|
||||
--buffer-size SIZE Size of download buffer (e.g. 1024 or 16K)
|
||||
(default is 1024)
|
||||
--no-resize-buffer Do not automatically adjust the buffer
|
||||
size. By default, the buffer size is
|
||||
automatically resized from an initial value
|
||||
of SIZE.
|
||||
--playlist-reverse Download playlist videos in reverse order
|
||||
--xattr-set-filesize Set file xattribute ytdl.filesize with
|
||||
expected filesize (experimental)
|
||||
--hls-prefer-native Use the native HLS downloader instead of
|
||||
ffmpeg (experimental)
|
||||
--external-downloader COMMAND Use the specified external downloader.
|
||||
Currently supports
|
||||
aria2c,axel,curl,httpie,wget
|
||||
--external-downloader-args ARGS Give these arguments to the external
|
||||
downloader
|
||||
|
||||
### Authentication Options:
|
||||
-u, --username USERNAME account username
|
||||
-p, --password PASSWORD account password
|
||||
-n, --netrc use .netrc authentication data
|
||||
## Filesystem Options:
|
||||
-a, --batch-file FILE File containing URLs to download ('-' for
|
||||
stdin)
|
||||
--id Use only video ID in file name
|
||||
-o, --output TEMPLATE Output filename template. Use %(title)s to
|
||||
get the title, %(uploader)s for the
|
||||
uploader name, %(uploader_id)s for the
|
||||
uploader nickname if different,
|
||||
%(autonumber)s to get an automatically
|
||||
incremented number, %(ext)s for the
|
||||
filename extension, %(format)s for the
|
||||
format description (like "22 - 1280x720" or
|
||||
"HD"), %(format_id)s for the unique id of
|
||||
the format (like YouTube's itags: "137"),
|
||||
%(upload_date)s for the upload date
|
||||
(YYYYMMDD), %(extractor)s for the provider
|
||||
(youtube, metacafe, etc), %(id)s for the
|
||||
video id, %(playlist_title)s,
|
||||
%(playlist_id)s, or %(playlist)s (=title if
|
||||
present, ID otherwise) for the playlist the
|
||||
video is in, %(playlist_index)s for the
|
||||
position in the playlist. %(height)s and
|
||||
%(width)s for the width and height of the
|
||||
video format. %(resolution)s for a textual
|
||||
description of the resolution of the video
|
||||
format. %% for a literal percent. Use - to
|
||||
output to stdout. Can also be used to
|
||||
download to a different directory, for
|
||||
example with -o '/my/downloads/%(uploader)s
|
||||
/%(title)s-%(id)s.%(ext)s' .
|
||||
--autonumber-size NUMBER Specify the number of digits in
|
||||
%(autonumber)s when it is present in output
|
||||
filename template or --auto-number option
|
||||
is given
|
||||
--restrict-filenames Restrict filenames to only ASCII
|
||||
characters, and avoid "&" and spaces in
|
||||
filenames
|
||||
-A, --auto-number [deprecated; use -o
|
||||
"%(autonumber)s-%(title)s.%(ext)s" ] Number
|
||||
downloaded files starting from 00000
|
||||
-t, --title [deprecated] Use title in file name
|
||||
(default)
|
||||
-l, --literal [deprecated] Alias of --title
|
||||
-w, --no-overwrites Do not overwrite files
|
||||
-c, --continue Force resume of partially downloaded files.
|
||||
By default, youtube-dl will resume
|
||||
downloads if possible.
|
||||
--no-continue Do not resume partially downloaded files
|
||||
(restart from beginning)
|
||||
--no-part Do not use .part files - write directly
|
||||
into output file
|
||||
--no-mtime Do not use the Last-modified header to set
|
||||
the file modification time
|
||||
--write-description Write video description to a .description
|
||||
file
|
||||
--write-info-json Write video metadata to a .info.json file
|
||||
--write-annotations Write video annotations to a
|
||||
.annotations.xml file
|
||||
--load-info FILE JSON file containing the video information
|
||||
(created with the "--write-info-json"
|
||||
option)
|
||||
--cookies FILE File to read cookies from and dump cookie
|
||||
jar in
|
||||
--cache-dir DIR Location in the filesystem where youtube-dl
|
||||
can store some downloaded information
|
||||
permanently. By default $XDG_CACHE_HOME
|
||||
/youtube-dl or ~/.cache/youtube-dl . At the
|
||||
moment, only YouTube player files (for
|
||||
videos with obfuscated signatures) are
|
||||
cached, but that may change.
|
||||
--no-cache-dir Disable filesystem caching
|
||||
--rm-cache-dir Delete all filesystem cache files
|
||||
|
||||
### Post-processing Options:
|
||||
--extract-audio convert video files to audio-only files (requires
|
||||
ffmpeg and ffprobe)
|
||||
--audio-format FORMAT "best", "aac", "vorbis", "mp3", "m4a", or "wav";
|
||||
best by default
|
||||
--audio-quality QUALITY ffmpeg audio bitrate specification, 128k by default
|
||||
-k, --keep-video keeps the video file on disk after the post-
|
||||
processing; the video is erased by default
|
||||
## Thumbnail images:
|
||||
--write-thumbnail Write thumbnail image to disk
|
||||
--write-all-thumbnails Write all thumbnail image formats to disk
|
||||
--list-thumbnails Simulate and list all available thumbnail
|
||||
formats
|
||||
|
||||
## FAQ
|
||||
## Verbosity / Simulation Options:
|
||||
-q, --quiet Activate quiet mode
|
||||
--no-warnings Ignore warnings
|
||||
-s, --simulate Do not download the video and do not write
|
||||
anything to disk
|
||||
--skip-download Do not download the video
|
||||
-g, --get-url Simulate, quiet but print URL
|
||||
-e, --get-title Simulate, quiet but print title
|
||||
--get-id Simulate, quiet but print id
|
||||
--get-thumbnail Simulate, quiet but print thumbnail URL
|
||||
--get-description Simulate, quiet but print video description
|
||||
--get-duration Simulate, quiet but print video length
|
||||
--get-filename Simulate, quiet but print output filename
|
||||
--get-format Simulate, quiet but print output format
|
||||
-j, --dump-json Simulate, quiet but print JSON information.
|
||||
See --output for a description of available
|
||||
keys.
|
||||
-J, --dump-single-json Simulate, quiet but print JSON information
|
||||
for each command-line argument. If the URL
|
||||
refers to a playlist, dump the whole
|
||||
playlist information in a single line.
|
||||
--print-json Be quiet and print the video information as
|
||||
JSON (video is still being downloaded).
|
||||
--newline Output progress bar as new lines
|
||||
--no-progress Do not print progress bar
|
||||
--console-title Display progress in console titlebar
|
||||
-v, --verbose Print various debugging information
|
||||
--dump-pages Print downloaded pages encoded using base64
|
||||
to debug problems (very verbose)
|
||||
--write-pages Write downloaded intermediary pages to
|
||||
files in the current directory to debug
|
||||
problems
|
||||
--print-traffic Display sent and read HTTP traffic
|
||||
-C, --call-home Contact the youtube-dl server for debugging
|
||||
--no-call-home Do NOT contact the youtube-dl server for
|
||||
debugging
|
||||
|
||||
### Can you please put the -b option back?
|
||||
## Workarounds:
|
||||
--encoding ENCODING Force the specified encoding (experimental)
|
||||
--no-check-certificate Suppress HTTPS certificate validation
|
||||
--prefer-insecure Use an unencrypted connection to retrieve
|
||||
information about the video. (Currently
|
||||
supported only for YouTube)
|
||||
--user-agent UA Specify a custom user agent
|
||||
--referer URL Specify a custom referer, use if the video
|
||||
access is restricted to one domain
|
||||
--add-header FIELD:VALUE Specify a custom HTTP header and its value,
|
||||
separated by a colon ':'. You can use this
|
||||
option multiple times
|
||||
--bidi-workaround Work around terminals that lack
|
||||
bidirectional text support. Requires bidiv
|
||||
or fribidi executable in PATH
|
||||
--sleep-interval SECONDS Number of seconds to sleep before each
|
||||
download.
|
||||
|
||||
Most people asking this question are not aware that youtube-dl now defaults to downloading the highest available quality as reported by YouTube, which will be 1080p or 720p in some cases, so you no longer need the -b option. For some specific videos, maybe YouTube does not report them to be available in a specific high quality format you''re interested in. In that case, simply request it with the -f option and youtube-dl will try to download it.
|
||||
## Video Format Options:
|
||||
-f, --format FORMAT Video format code, see the "FORMAT
|
||||
SELECTION" for all the info
|
||||
--all-formats Download all available video formats
|
||||
--prefer-free-formats Prefer free video formats unless a specific
|
||||
one is requested
|
||||
-F, --list-formats List all available formats of requested
|
||||
videos
|
||||
--youtube-skip-dash-manifest Do not download the DASH manifests and
|
||||
related data on YouTube videos
|
||||
--merge-output-format FORMAT If a merge is required (e.g.
|
||||
bestvideo+bestaudio), output to given
|
||||
container format. One of mkv, mp4, ogg,
|
||||
webm, flv. Ignored if no merge is required
|
||||
|
||||
## Subtitle Options:
|
||||
--write-sub Write subtitle file
|
||||
--write-auto-sub Write automatically generated subtitle file
|
||||
(YouTube only)
|
||||
--all-subs Download all the available subtitles of the
|
||||
video
|
||||
--list-subs List all available subtitles for the video
|
||||
--sub-format FORMAT Subtitle format, accepts formats
|
||||
preference, for example: "srt" or
|
||||
"ass/srt/best"
|
||||
--sub-lang LANGS Languages of the subtitles to download
|
||||
(optional) separated by commas, use IETF
|
||||
language tags like 'en,pt'
|
||||
|
||||
## Authentication Options:
|
||||
-u, --username USERNAME Login with this account ID
|
||||
-p, --password PASSWORD Account password. If this option is left
|
||||
out, youtube-dl will ask interactively.
|
||||
-2, --twofactor TWOFACTOR Two-factor auth code
|
||||
-n, --netrc Use .netrc authentication data
|
||||
--video-password PASSWORD Video password (vimeo, smotri, youku)
|
||||
|
||||
## Post-processing Options:
|
||||
-x, --extract-audio Convert video files to audio-only files
|
||||
(requires ffmpeg or avconv and ffprobe or
|
||||
avprobe)
|
||||
--audio-format FORMAT Specify audio format: "best", "aac",
|
||||
"vorbis", "mp3", "m4a", "opus", or "wav";
|
||||
"best" by default
|
||||
--audio-quality QUALITY Specify ffmpeg/avconv audio quality, insert
|
||||
a value between 0 (better) and 9 (worse)
|
||||
for VBR or a specific bitrate like 128K
|
||||
(default 5)
|
||||
--recode-video FORMAT Encode the video to another format if
|
||||
necessary (currently supported:
|
||||
mp4|flv|ogg|webm|mkv|avi)
|
||||
--postprocessor-args ARGS Give these arguments to the postprocessor
|
||||
-k, --keep-video Keep the video file on disk after the post-
|
||||
processing; the video is erased by default
|
||||
--no-post-overwrites Do not overwrite post-processed files; the
|
||||
post-processed files are overwritten by
|
||||
default
|
||||
--embed-subs Embed subtitles in the video (only for mkv
|
||||
and mp4 videos)
|
||||
--embed-thumbnail Embed thumbnail in the audio as cover art
|
||||
--add-metadata Write metadata to the video file
|
||||
--metadata-from-title FORMAT Parse additional metadata like song title /
|
||||
artist from the video title. The format
|
||||
syntax is the same as --output, the parsed
|
||||
parameters replace existing values.
|
||||
Additional templates: %(album)s,
|
||||
%(artist)s. Example: --metadata-from-title
|
||||
"%(artist)s - %(title)s" matches a title
|
||||
like "Coldplay - Paradise"
|
||||
--xattrs Write metadata to the video file's xattrs
|
||||
(using dublin core and xdg standards)
|
||||
--fixup POLICY Automatically correct known faults of the
|
||||
file. One of never (do nothing), warn (only
|
||||
emit a warning), detect_or_warn (the
|
||||
default; fix file if we can, warn
|
||||
otherwise)
|
||||
--prefer-avconv Prefer avconv over ffmpeg for running the
|
||||
postprocessors (default)
|
||||
--prefer-ffmpeg Prefer ffmpeg over avconv for running the
|
||||
postprocessors
|
||||
--ffmpeg-location PATH Location of the ffmpeg/avconv binary;
|
||||
either the path to the binary or its
|
||||
containing directory.
|
||||
--exec CMD Execute a command on the file after
|
||||
downloading, similar to find's -exec
|
||||
syntax. Example: --exec 'adb push {}
|
||||
/sdcard/Music/ && rm {}'
|
||||
--convert-subtitles FORMAT Convert the subtitles to other format
|
||||
(currently supported: srt|ass|vtt)
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
You can configure youtube-dl by placing any supported command line option to a configuration file. On Linux, the system wide configuration file is located at `/etc/youtube-dl.conf` and the user wide configuration file at `~/.config/youtube-dl/config`. On Windows, the user wide configuration file locations are `%APPDATA%\youtube-dl\config.txt` or `C:\Users\<user name>\youtube-dl.conf`. For example, with the following configuration file youtube-dl will always extract the audio, not copy the mtime and use a proxy:
|
||||
```
|
||||
--extract-audio
|
||||
--no-mtime
|
||||
--proxy 127.0.0.1:3128
|
||||
```
|
||||
|
||||
You can use `--ignore-config` if you want to disable the configuration file for a particular youtube-dl run.
|
||||
|
||||
### Authentication with `.netrc` file ###
|
||||
|
||||
You may also want to configure automatic credentials storage for extractors that support authentication (by providing login and password with `--username` and `--password`) in order not to pass credentials as command line arguments on every youtube-dl execution and prevent tracking plain text passwords in the shell command history. You can achieve this using a [`.netrc` file](http://stackoverflow.com/tags/.netrc/info) on per extractor basis. For that you will need to create a`.netrc` file in your `$HOME` and restrict permissions to read/write by you only:
|
||||
```
|
||||
touch $HOME/.netrc
|
||||
chmod a-rwx,u+rw $HOME/.netrc
|
||||
```
|
||||
After that you can add credentials for extractor in the following format, where *extractor* is the name of extractor in lowercase:
|
||||
```
|
||||
machine <extractor> login <login> password <password>
|
||||
```
|
||||
For example:
|
||||
```
|
||||
machine youtube login myaccount@gmail.com password my_youtube_password
|
||||
machine twitch login my_twitch_account_name password my_twitch_password
|
||||
```
|
||||
To activate authentication with the `.netrc` file you should pass `--netrc` to youtube-dl or place it in the [configuration file](#configuration).
|
||||
|
||||
On Windows you may also need to setup the `%HOME%` environment variable manually.
|
||||
|
||||
# OUTPUT TEMPLATE
|
||||
|
||||
The `-o` option allows users to indicate a template for the output file names. The basic usage is not to set any template arguments when downloading a single file, like in `youtube-dl -o funny_video.flv "http://some/video"`. However, it may contain special sequences that will be replaced when downloading each video. The special sequences have the format `%(NAME)s`. To clarify, that is a percent symbol followed by a name in parentheses, followed by a lowercase S. Allowed names are:
|
||||
|
||||
- `id`: The sequence will be replaced by the video identifier.
|
||||
- `url`: The sequence will be replaced by the video URL.
|
||||
- `uploader`: The sequence will be replaced by the nickname of the person who uploaded the video.
|
||||
- `upload_date`: The sequence will be replaced by the upload date in YYYYMMDD format.
|
||||
- `title`: The sequence will be replaced by the video title.
|
||||
- `ext`: The sequence will be replaced by the appropriate extension (like flv or mp4).
|
||||
- `epoch`: The sequence will be replaced by the Unix epoch when creating the file.
|
||||
- `autonumber`: The sequence will be replaced by a five-digit number that will be increased with each download, starting at zero.
|
||||
- `playlist`: The sequence will be replaced by the name or the id of the playlist that contains the video.
|
||||
- `playlist_index`: The sequence will be replaced by the index of the video in the playlist padded with leading zeros according to the total length of the playlist.
|
||||
- `format_id`: The sequence will be replaced by the format code specified by `--format`.
|
||||
- `duration`: The sequence will be replaced by the length of the video in seconds.
|
||||
|
||||
The current default template is `%(title)s-%(id)s.%(ext)s`.
|
||||
|
||||
In some cases, you don't want special characters such as 中, spaces, or &, such as when transferring the downloaded filename to a Windows system or the filename through an 8bit-unsafe channel. In these cases, add the `--restrict-filenames` flag to get a shorter title:
|
||||
|
||||
```bash
|
||||
$ youtube-dl --get-filename -o "%(title)s.%(ext)s" BaW_jenozKc
|
||||
youtube-dl test video ''_ä↭𝕐.mp4 # All kinds of weird characters
|
||||
$ youtube-dl --get-filename -o "%(title)s.%(ext)s" BaW_jenozKc --restrict-filenames
|
||||
youtube-dl_test_video_.mp4 # A simple file name
|
||||
```
|
||||
|
||||
# FORMAT SELECTION
|
||||
|
||||
By default youtube-dl tries to download the best quality, but sometimes you may want to download in a different format.
|
||||
The simplest case is requesting a specific format, for example `-f 22`. You can get the list of available formats using `--list-formats`, you can also use a file extension (currently it supports aac, m4a, mp3, mp4, ogg, wav, webm) or the special names `best`, `bestvideo`, `bestaudio` and `worst`.
|
||||
|
||||
If you want to download multiple videos and they don't have the same formats available, you can specify the order of preference using slashes, as in `-f 22/17/18`. You can also filter the video results by putting a condition in brackets, as in `-f "best[height=720]"` (or `-f "[filesize>10M]"`). This works for filesize, height, width, tbr, abr, vbr, asr, and fps and the comparisons <, <=, >, >=, =, != and for ext, acodec, vcodec, container, and protocol and the comparisons =, != . Formats for which the value is not known are excluded unless you put a question mark (?) after the operator. You can combine format filters, so `-f "[height <=? 720][tbr>500]"` selects up to 720p videos (or videos where the height is not known) with a bitrate of at least 500 KBit/s. Use commas to download multiple formats, such as `-f 136/137/mp4/bestvideo,140/m4a/bestaudio`. You can merge the video and audio of two formats into a single file using `-f <video-format>+<audio-format>` (requires ffmpeg or avconv), for example `-f bestvideo+bestaudio`. Format selectors can also be grouped using parentheses, for example if you want to download the best mp4 and webm formats with a height lower than 480 you can use `-f '(mp4,webm)[height<480]'`.
|
||||
|
||||
Since the end of April 2015 and version 2015.04.26 youtube-dl uses `-f bestvideo+bestaudio/best` as default format selection (see #5447, #5456). If ffmpeg or avconv are installed this results in downloading `bestvideo` and `bestaudio` separately and muxing them together into a single file giving the best overall quality available. Otherwise it falls back to `best` and results in downloading the best available quality served as a single file. `best` is also needed for videos that don't come from YouTube because they don't provide the audio and video in two different files. If you want to only download some dash formats (for example if you are not interested in getting videos with a resolution higher than 1080p), you can add `-f bestvideo[height<=?1080]+bestaudio/best` to your configuration file. Note that if you use youtube-dl to stream to `stdout` (and most likely to pipe it to your media player then), i.e. you explicitly specify output template as `-o -`, youtube-dl still uses `-f best` format selection in order to start content delivery immediately to your player and not to wait until `bestvideo` and `bestaudio` are downloaded and muxed.
|
||||
|
||||
If you want to preserve the old format selection behavior (prior to youtube-dl 2015.04.26), i.e. you want to download the best available quality media served as a single file, you should explicitly specify your choice with `-f best`. You may want to add it to the [configuration file](#configuration) in order not to type it every time you run youtube-dl.
|
||||
|
||||
# VIDEO SELECTION
|
||||
|
||||
Videos can be filtered by their upload date using the options `--date`, `--datebefore` or `--dateafter`. They accept dates in two formats:
|
||||
|
||||
- Absolute dates: Dates in the format `YYYYMMDD`.
|
||||
- Relative dates: Dates in the format `(now|today)[+-][0-9](day|week|month|year)(s)?`
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
# Download only the videos uploaded in the last 6 months
|
||||
$ youtube-dl --dateafter now-6months
|
||||
|
||||
# Download only the videos uploaded on January 1, 1970
|
||||
$ youtube-dl --date 19700101
|
||||
|
||||
$ # Download only the videos uploaded in the 200x decade
|
||||
$ youtube-dl --dateafter 20000101 --datebefore 20091231
|
||||
```
|
||||
|
||||
# FAQ
|
||||
|
||||
### How do I update youtube-dl?
|
||||
|
||||
If you've followed [our manual installation instructions](http://rg3.github.io/youtube-dl/download.html), you can simply run `youtube-dl -U` (or, on Linux, `sudo youtube-dl -U`).
|
||||
|
||||
If you have used pip, a simple `sudo pip install -U youtube-dl` is sufficient to update.
|
||||
|
||||
If you have installed youtube-dl using a package manager like *apt-get* or *yum*, use the standard system update mechanism to update. Note that distribution packages are often outdated. As a rule of thumb, youtube-dl releases at least once a month, and often weekly or even daily. Simply go to http://yt-dl.org/ to find out the current version. Unfortunately, there is nothing we youtube-dl developers can do if your distribution serves a really outdated version. You can (and should) complain to your distribution in their bugtracker or support forum.
|
||||
|
||||
As a last resort, you can also uninstall the version installed by your package manager and follow our manual installation instructions. For that, remove the distribution's package, with a line like
|
||||
|
||||
sudo apt-get remove -y youtube-dl
|
||||
|
||||
Afterwards, simply follow [our manual installation instructions](http://rg3.github.io/youtube-dl/download.html):
|
||||
|
||||
```
|
||||
sudo wget https://yt-dl.org/latest/youtube-dl -O /usr/local/bin/youtube-dl
|
||||
sudo chmod a+x /usr/local/bin/youtube-dl
|
||||
hash -r
|
||||
```
|
||||
|
||||
Again, from then on you'll be able to update with `sudo youtube-dl -U`.
|
||||
|
||||
### I'm getting an error `Unable to extract OpenGraph title` on YouTube playlists
|
||||
|
||||
YouTube changed their playlist format in March 2014 and later on, so you'll need at least youtube-dl 2014.07.25 to download all YouTube videos.
|
||||
|
||||
If you have installed youtube-dl with a package manager, pip, setup.py or a tarball, please use that to update. Note that Ubuntu packages do not seem to get updated anymore. Since we are not affiliated with Ubuntu, there is little we can do. Feel free to [report bugs](https://bugs.launchpad.net/ubuntu/+source/youtube-dl/+filebug) to the [Ubuntu packaging guys](mailto:ubuntu-motu@lists.ubuntu.com?subject=outdated%20version%20of%20youtube-dl) - all they have to do is update the package to a somewhat recent version. See above for a way to update.
|
||||
|
||||
### Do I always have to pass `-citw`?
|
||||
|
||||
By default, youtube-dl intends to have the best options (incidentally, if you have a convincing case that these should be different, [please file an issue where you explain that](https://yt-dl.org/bug)). Therefore, it is unnecessary and sometimes harmful to copy long option strings from webpages. In particular, the only option out of `-citw` that is regularly useful is `-i`.
|
||||
|
||||
### Can you please put the `-b` option back?
|
||||
|
||||
Most people asking this question are not aware that youtube-dl now defaults to downloading the highest available quality as reported by YouTube, which will be 1080p or 720p in some cases, so you no longer need the `-b` option. For some specific videos, maybe YouTube does not report them to be available in a specific high quality format you're interested in. In that case, simply request it with the `-f` option and youtube-dl will try to download it.
|
||||
|
||||
### I get HTTP error 402 when trying to download a video. What's this?
|
||||
|
||||
Apparently YouTube requires you to pass a CAPTCHA test if you download too much. We''re [considering to provide a way to let you solve the CAPTCHA](https://github.com/rg3/youtube-dl/issues/154), but at the moment, your best course of action is pointing a webbrowser to the youtube URL, solving the CAPTCHA, and restart youtube-dl.
|
||||
Apparently YouTube requires you to pass a CAPTCHA test if you download too much. We're [considering to provide a way to let you solve the CAPTCHA](https://github.com/rg3/youtube-dl/issues/154), but at the moment, your best course of action is pointing a webbrowser to the youtube URL, solving the CAPTCHA, and restart youtube-dl.
|
||||
|
||||
### Do I need any other programs?
|
||||
|
||||
youtube-dl works fine on its own on most sites. However, if you want to convert video/audio, you'll need [avconv](https://libav.org/) or [ffmpeg](https://www.ffmpeg.org/). On some sites - most notably YouTube - videos can be retrieved in a higher quality format without sound. youtube-dl will detect whether avconv/ffmpeg is present and automatically pick the best option.
|
||||
|
||||
Videos or video formats streamed via RTMP protocol can only be downloaded when [rtmpdump](https://rtmpdump.mplayerhq.hu/) is installed. Downloading MMS and RTSP videos requires either [mplayer](http://mplayerhq.hu/) or [mpv](https://mpv.io/) to be installed.
|
||||
|
||||
### I have downloaded a video but how can I play it?
|
||||
|
||||
Once the video is fully downloaded, use any video player, such as [vlc](http://www.videolan.org) or [mplayer](http://www.mplayerhq.hu/).
|
||||
|
||||
### The links provided by youtube-dl -g are not working anymore
|
||||
### I extracted a video URL with `-g`, but it does not play on another machine / in my webbrowser.
|
||||
|
||||
The URLs youtube-dl outputs require the downloader to have the correct cookies. Use the `--cookies` option to write the required cookies into a file, and advise your downloader to read cookies from that file.
|
||||
It depends a lot on the service. In many cases, requests for the video (to download/play it) must come from the same IP address and with the same cookies. Use the `--cookies` option to write the required cookies into a file, and advise your downloader to read cookies from that file. Some sites also require a common user agent to be used, use `--dump-user-agent` to see the one in use by youtube-dl.
|
||||
|
||||
It may be beneficial to use IPv6; in some cases, the restrictions are only applied to IPv4. Some services (sometimes only for a subset of videos) do not restrict the video URL by IP address, cookie, or user-agent, but these are the exception rather than the rule.
|
||||
|
||||
Please bear in mind that some URL protocols are **not** supported by browsers out of the box, including RTMP. If you are using `-g`, your own downloader must support these as well.
|
||||
|
||||
If you want to play the video on a machine that is not running youtube-dl, you can relay the video content from the machine that runs youtube-dl. You can use `-o -` to let youtube-dl stream a video to stdout, or simply allow the player to download the files written by youtube-dl in turn.
|
||||
|
||||
### ERROR: no fmt_url_map or conn information found in video info
|
||||
|
||||
youtube has switched to a new video info format in July 2011 which is not supported by old versions of youtube-dl. You can update youtube-dl with `sudo youtube-dl --update`.
|
||||
YouTube has switched to a new video info format in July 2011 which is not supported by old versions of youtube-dl. See [above](#how-do-i-update-youtube-dl) for how to update youtube-dl.
|
||||
|
||||
## COPYRIGHT
|
||||
### ERROR: unable to download video ###
|
||||
|
||||
YouTube requires an additional signature since September 2012 which is not supported by old versions of youtube-dl. See [above](#how-do-i-update-youtube-dl) for how to update youtube-dl.
|
||||
|
||||
### Video URL contains an ampersand and I'm getting some strange output `[1] 2839` or `'v' is not recognized as an internal or external command` ###
|
||||
|
||||
That's actually the output from your shell. Since ampersand is one of the special shell characters it's interpreted by the shell preventing you from passing the whole URL to youtube-dl. To disable your shell from interpreting the ampersands (or any other special characters) you have to either put the whole URL in quotes or escape them with a backslash (which approach will work depends on your shell).
|
||||
|
||||
For example if your URL is https://www.youtube.com/watch?t=4&v=BaW_jenozKc you should end up with following command:
|
||||
|
||||
```youtube-dl 'https://www.youtube.com/watch?t=4&v=BaW_jenozKc'```
|
||||
|
||||
or
|
||||
|
||||
```youtube-dl https://www.youtube.com/watch?t=4\&v=BaW_jenozKc```
|
||||
|
||||
For Windows you have to use the double quotes:
|
||||
|
||||
```youtube-dl "https://www.youtube.com/watch?t=4&v=BaW_jenozKc"```
|
||||
|
||||
### ExtractorError: Could not find JS function u'OF'
|
||||
|
||||
In February 2015, the new YouTube player contained a character sequence in a string that was misinterpreted by old versions of youtube-dl. See [above](#how-do-i-update-youtube-dl) for how to update youtube-dl.
|
||||
|
||||
### HTTP Error 429: Too Many Requests or 402: Payment Required
|
||||
|
||||
These two error codes indicate that the service is blocking your IP address because of overuse. Contact the service and ask them to unblock your IP address, or - if you have acquired a whitelisted IP address already - use the [`--proxy` or `--source-address` options](#network-options) to select another IP address.
|
||||
|
||||
### SyntaxError: Non-ASCII character ###
|
||||
|
||||
The error
|
||||
|
||||
File "youtube-dl", line 2
|
||||
SyntaxError: Non-ASCII character '\x93' ...
|
||||
|
||||
means you're using an outdated version of Python. Please update to Python 2.6 or 2.7.
|
||||
|
||||
### What is this binary file? Where has the code gone?
|
||||
|
||||
Since June 2012 (#342) youtube-dl is packed as an executable zipfile, simply unzip it (might need renaming to `youtube-dl.zip` first on some systems) or clone the git repository, as laid out above. If you modify the code, you can run it by executing the `__main__.py` file. To recompile the executable, run `make youtube-dl`.
|
||||
|
||||
### The exe throws a *Runtime error from Visual C++*
|
||||
|
||||
To run the exe you need to install first the [Microsoft Visual C++ 2008 Redistributable Package](http://www.microsoft.com/en-us/download/details.aspx?id=29).
|
||||
|
||||
### On Windows, how should I set up ffmpeg and youtube-dl? Where should I put the exe files?
|
||||
|
||||
If you put youtube-dl and ffmpeg in the same directory that you're running the command from, it will work, but that's rather cumbersome.
|
||||
|
||||
To make a different directory work - either for ffmpeg, or for youtube-dl, or for both - simply create the directory (say, `C:\bin`, or `C:\Users\<User name>\bin`), put all the executables directly in there, and then [set your PATH environment variable](https://www.java.com/en/download/help/path.xml) to include that directory.
|
||||
|
||||
From then on, after restarting your shell, you will be able to access both youtube-dl and ffmpeg (and youtube-dl will be able to find ffmpeg) by simply typing `youtube-dl` or `ffmpeg`, no matter what directory you're in.
|
||||
|
||||
### How do I put downloads into a specific folder?
|
||||
|
||||
Use the `-o` to specify an [output template](#output-template), for example `-o "/home/user/videos/%(title)s-%(id)s.%(ext)s"`. If you want this for all of your downloads, put the option into your [configuration file](#configuration).
|
||||
|
||||
### How do I download a video starting with a `-` ?
|
||||
|
||||
Either prepend `http://www.youtube.com/watch?v=` or separate the ID from the options with `--`:
|
||||
|
||||
youtube-dl -- -wNyEUrxzFU
|
||||
youtube-dl "http://www.youtube.com/watch?v=-wNyEUrxzFU"
|
||||
|
||||
### How do I pass cookies to youtube-dl?
|
||||
|
||||
Use the `--cookies` option, for example `--cookies /path/to/cookies/file.txt`. Note that the cookies file must be in Mozilla/Netscape format and the first line of the cookies file must be either `# HTTP Cookie File` or `# Netscape HTTP Cookie File`. Make sure you have correct [newline format](https://en.wikipedia.org/wiki/Newline) in the cookies file and convert newlines if necessary to correspond with your OS, namely `CRLF` (`\r\n`) for Windows, `LF` (`\n`) for Linux and `CR` (`\r`) for Mac OS. `HTTP Error 400: Bad Request` when using `--cookies` is a good sign of invalid newline format.
|
||||
|
||||
Passing cookies to youtube-dl is a good way to workaround login when a particular extractor does not implement it explicitly.
|
||||
|
||||
### Can you add support for this anime video site, or site which shows current movies for free?
|
||||
|
||||
As a matter of policy (as well as legality), youtube-dl does not include support for services that specialize in infringing copyright. As a rule of thumb, if you cannot easily find a video that the service is quite obviously allowed to distribute (i.e. that has been uploaded by the creator, the creator's distributor, or is published under a free license), the service is probably unfit for inclusion to youtube-dl.
|
||||
|
||||
A note on the service that they don't host the infringing content, but just link to those who do, is evidence that the service should **not** be included into youtube-dl. The same goes for any DMCA note when the whole front page of the service is filled with videos they are not allowed to distribute. A "fair use" note is equally unconvincing if the service shows copyright-protected videos in full without authorization.
|
||||
|
||||
Support requests for services that **do** purchase the rights to distribute their content are perfectly fine though. If in doubt, you can simply include a source that mentions the legitimate purchase of content.
|
||||
|
||||
### How can I speed up work on my issue?
|
||||
|
||||
(Also known as: Help, my important issue not being solved!) The youtube-dl core developer team is quite small. While we do our best to solve as many issues as possible, sometimes that can take quite a while. To speed up your issue, here's what you can do:
|
||||
|
||||
First of all, please do report the issue [at our issue tracker](https://yt-dl.org/bugs). That allows us to coordinate all efforts by users and developers, and serves as a unified point. Unfortunately, the youtube-dl project has grown too large to use personal email as an effective communication channel.
|
||||
|
||||
Please read the [bug reporting instructions](#bugs) below. A lot of bugs lack all the necessary information. If you can, offer proxy, VPN, or shell access to the youtube-dl developers. If you are able to, test the issue from multiple computers in multiple countries to exclude local censorship or misconfiguration issues.
|
||||
|
||||
If nobody is interested in solving your issue, you are welcome to take matters into your own hands and submit a pull request (or coerce/pay somebody else to do so).
|
||||
|
||||
Feel free to bump the issue from time to time by writing a small comment ("Issue is still present in youtube-dl version ...from France, but fixed from Belgium"), but please not more than once a month. Please do not declare your issue as `important` or `urgent`.
|
||||
|
||||
### How can I detect whether a given URL is supported by youtube-dl?
|
||||
|
||||
For one, have a look at the [list of supported sites](docs/supportedsites.md). Note that it can sometimes happen that the site changes its URL scheme (say, from http://example.com/video/1234567 to http://example.com/v/1234567 ) and youtube-dl reports an URL of a service in that list as unsupported. In that case, simply report a bug.
|
||||
|
||||
It is *not* possible to detect whether a URL is supported or not. That's because youtube-dl contains a generic extractor which matches **all** URLs. You may be tempted to disable, exclude, or remove the generic extractor, but the generic extractor not only allows users to extract videos from lots of websites that embed a video from another service, but may also be used to extract video from a service that it's hosting itself. Therefore, we neither recommend nor support disabling, excluding, or removing the generic extractor.
|
||||
|
||||
If you want to find out whether a given URL is supported, simply call youtube-dl with it. If you get no videos back, chances are the URL is either not referring to a video or unsupported. You can find out which by examining the output (if you run youtube-dl on the console) or catching an `UnsupportedError` exception if you run it from a Python program.
|
||||
|
||||
# DEVELOPER INSTRUCTIONS
|
||||
|
||||
Most users do not need to build youtube-dl and can [download the builds](http://rg3.github.io/youtube-dl/download.html) or get them from their distribution.
|
||||
|
||||
To run youtube-dl as a developer, you don't need to build anything either. Simply execute
|
||||
|
||||
python -m youtube_dl
|
||||
|
||||
To run the test, simply invoke your favorite test runner, or execute a test file directly; any of the following work:
|
||||
|
||||
python -m unittest discover
|
||||
python test/test_download.py
|
||||
nosetests
|
||||
|
||||
If you want to create a build of youtube-dl yourself, you'll need
|
||||
|
||||
* python
|
||||
* make
|
||||
* pandoc
|
||||
* zip
|
||||
* nosetests
|
||||
|
||||
### Adding support for a new site
|
||||
|
||||
If you want to add support for a new site, you can follow this quick list (assuming your service is called `yourextractor`):
|
||||
|
||||
1. [Fork this repository](https://github.com/rg3/youtube-dl/fork)
|
||||
2. Check out the source code with `git clone git@github.com:YOUR_GITHUB_USERNAME/youtube-dl.git`
|
||||
3. Start a new git branch with `cd youtube-dl; git checkout -b yourextractor`
|
||||
4. Start with this simple template and save it to `youtube_dl/extractor/yourextractor.py`:
|
||||
```python
|
||||
# coding: utf-8
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .common import InfoExtractor
|
||||
|
||||
|
||||
class YourExtractorIE(InfoExtractor):
|
||||
_VALID_URL = r'https?://(?:www\.)?yourextractor\.com/watch/(?P<id>[0-9]+)'
|
||||
_TEST = {
|
||||
'url': 'http://yourextractor.com/watch/42',
|
||||
'md5': 'TODO: md5 sum of the first 10241 bytes of the video file (use --test)',
|
||||
'info_dict': {
|
||||
'id': '42',
|
||||
'ext': 'mp4',
|
||||
'title': 'Video title goes here',
|
||||
'thumbnail': 're:^https?://.*\.jpg$',
|
||||
# TODO more properties, either as:
|
||||
# * A value
|
||||
# * MD5 checksum; start the string with md5:
|
||||
# * A regular expression; start the string with re:
|
||||
# * Any Python type (for example int or float)
|
||||
}
|
||||
}
|
||||
|
||||
def _real_extract(self, url):
|
||||
video_id = self._match_id(url)
|
||||
webpage = self._download_webpage(url, video_id)
|
||||
|
||||
# TODO more code goes here, for example ...
|
||||
title = self._html_search_regex(r'<h1>(.+?)</h1>', webpage, 'title')
|
||||
|
||||
return {
|
||||
'id': video_id,
|
||||
'title': title,
|
||||
'description': self._og_search_description(webpage),
|
||||
'uploader': self._search_regex(r'<div[^>]+id="uploader"[^>]*>([^<]+)<', webpage, 'uploader', fatal=False),
|
||||
# TODO more properties (see youtube_dl/extractor/common.py)
|
||||
}
|
||||
```
|
||||
5. Add an import in [`youtube_dl/extractor/__init__.py`](https://github.com/rg3/youtube-dl/blob/master/youtube_dl/extractor/__init__.py).
|
||||
6. Run `python test/test_download.py TestDownload.test_YourExtractor`. This *should fail* at first, but you can continually re-run it until you're done. If you decide to add more than one test, then rename ``_TEST`` to ``_TESTS`` and make it into a list of dictionaries. The tests will then be named `TestDownload.test_YourExtractor`, `TestDownload.test_YourExtractor_1`, `TestDownload.test_YourExtractor_2`, etc.
|
||||
7. Have a look at [`youtube_dl/extractor/common.py`](https://github.com/rg3/youtube-dl/blob/master/youtube_dl/extractor/common.py) for possible helper methods and a [detailed description of what your extractor should and may return](https://github.com/rg3/youtube-dl/blob/master/youtube_dl/extractor/common.py#L62-L200). Add tests and code for as many as you want.
|
||||
8. If you can, check the code with [flake8](https://pypi.python.org/pypi/flake8).
|
||||
9. When the tests pass, [add](http://git-scm.com/docs/git-add) the new files and [commit](http://git-scm.com/docs/git-commit) them and [push](http://git-scm.com/docs/git-push) the result, like this:
|
||||
|
||||
$ git add youtube_dl/extractor/__init__.py
|
||||
$ git add youtube_dl/extractor/yourextractor.py
|
||||
$ git commit -m '[yourextractor] Add new extractor'
|
||||
$ git push origin yourextractor
|
||||
|
||||
10. Finally, [create a pull request](https://help.github.com/articles/creating-a-pull-request). We'll then review and merge it.
|
||||
|
||||
In any case, thank you very much for your contributions!
|
||||
|
||||
# EMBEDDING YOUTUBE-DL
|
||||
|
||||
youtube-dl makes the best effort to be a good command-line program, and thus should be callable from any programming language. If you encounter any problems parsing its output, feel free to [create a report](https://github.com/rg3/youtube-dl/issues/new).
|
||||
|
||||
From a Python program, you can embed youtube-dl in a more powerful fashion, like this:
|
||||
|
||||
```python
|
||||
from __future__ import unicode_literals
|
||||
import youtube_dl
|
||||
|
||||
ydl_opts = {}
|
||||
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
|
||||
ydl.download(['http://www.youtube.com/watch?v=BaW_jenozKc'])
|
||||
```
|
||||
|
||||
Most likely, you'll want to use various options. For a list of what can be done, have a look at [youtube_dl/YoutubeDL.py](https://github.com/rg3/youtube-dl/blob/master/youtube_dl/YoutubeDL.py#L117-L265). For a start, if you want to intercept youtube-dl's output, set a `logger` object.
|
||||
|
||||
Here's a more complete example of a program that outputs only errors (and a short message after the download is finished), and downloads/converts the video to an mp3 file:
|
||||
|
||||
```python
|
||||
from __future__ import unicode_literals
|
||||
import youtube_dl
|
||||
|
||||
|
||||
class MyLogger(object):
|
||||
def debug(self, msg):
|
||||
pass
|
||||
|
||||
def warning(self, msg):
|
||||
pass
|
||||
|
||||
def error(self, msg):
|
||||
print(msg)
|
||||
|
||||
|
||||
def my_hook(d):
|
||||
if d['status'] == 'finished':
|
||||
print('Done downloading, now converting ...')
|
||||
|
||||
|
||||
ydl_opts = {
|
||||
'format': 'bestaudio/best',
|
||||
'postprocessors': [{
|
||||
'key': 'FFmpegExtractAudio',
|
||||
'preferredcodec': 'mp3',
|
||||
'preferredquality': '192',
|
||||
}],
|
||||
'logger': MyLogger(),
|
||||
'progress_hooks': [my_hook],
|
||||
}
|
||||
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
|
||||
ydl.download(['http://www.youtube.com/watch?v=BaW_jenozKc'])
|
||||
```
|
||||
|
||||
# BUGS
|
||||
|
||||
Bugs and suggestions should be reported at: <https://github.com/rg3/youtube-dl/issues> . Unless you were prompted so or there is another pertinent reason (e.g. GitHub fails to accept the bug report), please do not send bug reports via personal email. For discussions, join us in the irc channel #youtube-dl on freenode.
|
||||
|
||||
**Please include the full output of youtube-dl when run with `-v`**, i.e. add `-v` flag to your command line, copy the **whole** output and post it in the issue body wrapped in \`\`\` for better formatting. It should look similar to this:
|
||||
```
|
||||
$ youtube-dl -v http://www.youtube.com/watch?v=BaW_jenozKcj
|
||||
[debug] System config: []
|
||||
[debug] User config: []
|
||||
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
|
||||
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
|
||||
[debug] youtube-dl version 2015.12.06
|
||||
[debug] Git HEAD: 135392e
|
||||
[debug] Python version 2.6.6 - Windows-2003Server-5.2.3790-SP2
|
||||
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
||||
[debug] Proxy map: {}
|
||||
...
|
||||
```
|
||||
**Do not post screenshots of verbose log only plain text is acceptable.**
|
||||
|
||||
The output (including the first lines) contains important debugging information. Issues without the full output are often not reproducible and therefore do not get solved in short order, if ever.
|
||||
|
||||
Please re-read your issue once again to avoid a couple of common mistakes (you can and should use this as a checklist):
|
||||
|
||||
### Is the description of the issue itself sufficient?
|
||||
|
||||
We often get issue reports that we cannot really decipher. While in most cases we eventually get the required information after asking back multiple times, this poses an unnecessary drain on our resources. Many contributors, including myself, are also not native speakers, so we may misread some parts.
|
||||
|
||||
So please elaborate on what feature you are requesting, or what bug you want to be fixed. Make sure that it's obvious
|
||||
|
||||
- What the problem is
|
||||
- How it could be fixed
|
||||
- How your proposed solution would look like
|
||||
|
||||
If your report is shorter than two lines, it is almost certainly missing some of these, which makes it hard for us to respond to it. We're often too polite to close the issue outright, but the missing info makes misinterpretation likely. As a commiter myself, I often get frustrated by these issues, since the only possible way for me to move forward on them is to ask for clarification over and over.
|
||||
|
||||
For bug reports, this means that your report should contain the *complete* output of youtube-dl when called with the `-v` flag. The error message you get for (most) bugs even says so, but you would not believe how many of our bug reports do not contain this information.
|
||||
|
||||
If your server has multiple IPs or you suspect censorship, adding `--call-home` may be a good idea to get more diagnostics. If the error is `ERROR: Unable to extract ...` and you cannot reproduce it from multiple countries, add `--dump-pages` (warning: this will yield a rather large output, redirect it to the file `log.txt` by adding `>log.txt 2>&1` to your command-line) or upload the `.dump` files you get when you add `--write-pages` [somewhere](https://gist.github.com/).
|
||||
|
||||
**Site support requests must contain an example URL**. An example URL is a URL you might want to download, like http://www.youtube.com/watch?v=BaW_jenozKc . There should be an obvious video present. Except under very special circumstances, the main page of a video service (e.g. http://www.youtube.com/ ) is *not* an example URL.
|
||||
|
||||
### Are you using the latest version?
|
||||
|
||||
Before reporting any issue, type `youtube-dl -U`. This should report that you're up-to-date. About 20% of the reports we receive are already fixed, but people are using outdated versions. This goes for feature requests as well.
|
||||
|
||||
### Is the issue already documented?
|
||||
|
||||
Make sure that someone has not already opened the issue you're trying to open. Search at the top of the window or at https://github.com/rg3/youtube-dl/search?type=Issues . If there is an issue, feel free to write something along the lines of "This affects me as well, with version 2015.01.01. Here is some more information on the issue: ...". While some issues may be old, a new post into them often spurs rapid activity.
|
||||
|
||||
### Why are existing options not enough?
|
||||
|
||||
Before requesting a new feature, please have a quick peek at [the list of supported options](https://github.com/rg3/youtube-dl/blob/master/README.md#synopsis). Many feature requests are for features that actually exist already! Please, absolutely do show off your work in the issue report and detail how the existing similar options do *not* solve your problem.
|
||||
|
||||
### Is there enough context in your bug report?
|
||||
|
||||
People want to solve problems, and often think they do us a favor by breaking down their larger problems (e.g. wanting to skip already downloaded files) to a specific request (e.g. requesting us to look whether the file exists before downloading the info page). However, what often happens is that they break down the problem into two steps: One simple, and one impossible (or extremely complicated one).
|
||||
|
||||
We are then presented with a very complicated request when the original problem could be solved far easier, e.g. by recording the downloaded video IDs in a separate file. To avoid this, you must include the greater context where it is non-obvious. In particular, every feature request that does not consist of adding support for a new site should contain a use case scenario that explains in what situation the missing feature would be useful.
|
||||
|
||||
### Does the issue involve one problem, and one problem only?
|
||||
|
||||
Some of our users seem to think there is a limit of issues they can or should open. There is no limit of issues they can or should open. While it may seem appealing to be able to dump all your issues into one ticket, that means that someone who solves one of your issues cannot mark the issue as closed. Typically, reporting a bunch of issues leads to the ticket lingering since nobody wants to attack that behemoth, until someone mercifully splits the issue into multiple ones.
|
||||
|
||||
In particular, every site support request issue should only pertain to services at one site (generally under a common domain, but always using the same backend technology). Do not request support for vimeo user videos, Whitehouse podcasts, and Google Plus pages in the same issue. Also, make sure that you don't post bug reports alongside feature requests. As a rule of thumb, a feature request does not include outputs of youtube-dl that are not immediately related to the feature at hand. Do not post reports of a network error alongside the request for a new video service.
|
||||
|
||||
### Is anyone going to need the feature?
|
||||
|
||||
Only post features that you (or an incapacitated friend you can personally talk to) require. Do not post features because they seem like a good idea. If they are really useful, they will be requested by someone who requires them.
|
||||
|
||||
### Is your question about youtube-dl?
|
||||
|
||||
It may sound strange, but some bug reports we receive are completely unrelated to youtube-dl and relate to a different or even the reporter's own application. Please make sure that you are actually using youtube-dl. If you are using a UI for youtube-dl, report the bug to the maintainer of the actual application providing the UI. On the other hand, if your UI for youtube-dl fails in some way you believe is related to youtube-dl, by all means, go ahead and report the bug.
|
||||
|
||||
# COPYRIGHT
|
||||
|
||||
youtube-dl is released into the public domain by the copyright holders.
|
||||
|
||||
This README file was originally written by Daniel Bolton (<https://github.com/dbbolton>) and is likewise released into the public domain.
|
||||
|
||||
## BUGS
|
||||
|
||||
Bugs and suggestions should be reported at: <https://github.com/rg3/youtube-dl/issues>
|
||||
|
||||
Please include:
|
||||
|
||||
* Your exact command line, like `youtube-dl -t "http://www.youtube.com/watch?v=uHlDtZ6Oc3s&feature=channel_video_title"`. A common mistake is not to escape the `&`. Putting URLs in quotes should solve this problem.
|
||||
* The output of `youtube-dl --version`
|
||||
* The output of `python --version`
|
||||
* The name and version of your Operating System ("Ubuntu 11.04 x64" or "Windows 7 x64" is usually enough).
|
||||
|
||||
6
bin/youtube-dl
Executable file
6
bin/youtube-dl
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import youtube_dl
|
||||
|
||||
if __name__ == '__main__':
|
||||
youtube_dl.main()
|
||||
BIN
devscripts/SizeOfImage.patch
Normal file
BIN
devscripts/SizeOfImage.patch
Normal file
Binary file not shown.
BIN
devscripts/SizeOfImage_w.patch
Normal file
BIN
devscripts/SizeOfImage_w.patch
Normal file
Binary file not shown.
29
devscripts/bash-completion.in
Normal file
29
devscripts/bash-completion.in
Normal file
@@ -0,0 +1,29 @@
|
||||
__youtube_dl()
|
||||
{
|
||||
local cur prev opts fileopts diropts keywords
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
opts="{{flags}}"
|
||||
keywords=":ytfavorites :ytrecommended :ytsubscriptions :ytwatchlater :ythistory"
|
||||
fileopts="-a|--batch-file|--download-archive|--cookies|--load-info"
|
||||
diropts="--cache-dir"
|
||||
|
||||
if [[ ${prev} =~ ${fileopts} ]]; then
|
||||
COMPREPLY=( $(compgen -f -- ${cur}) )
|
||||
return 0
|
||||
elif [[ ${prev} =~ ${diropts} ]]; then
|
||||
COMPREPLY=( $(compgen -d -- ${cur}) )
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ ${cur} =~ : ]]; then
|
||||
COMPREPLY=( $(compgen -W "${keywords}" -- ${cur}) )
|
||||
return 0
|
||||
elif [[ ${cur} == * ]] ; then
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
complete -F __youtube_dl youtube-dl
|
||||
29
devscripts/bash-completion.py
Executable file
29
devscripts/bash-completion.py
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
from os.path import dirname as dirn
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, dirn(dirn((os.path.abspath(__file__)))))
|
||||
import youtube_dl
|
||||
|
||||
BASH_COMPLETION_FILE = "youtube-dl.bash-completion"
|
||||
BASH_COMPLETION_TEMPLATE = "devscripts/bash-completion.in"
|
||||
|
||||
|
||||
def build_completion(opt_parser):
|
||||
opts_flag = []
|
||||
for group in opt_parser.option_groups:
|
||||
for option in group.option_list:
|
||||
# for every long flag
|
||||
opts_flag.append(option.get_opt_string())
|
||||
with open(BASH_COMPLETION_TEMPLATE) as f:
|
||||
template = f.read()
|
||||
with open(BASH_COMPLETION_FILE, "w") as f:
|
||||
# just using the special char
|
||||
filled_template = template.replace("{{flags}}", " ".join(opts_flag))
|
||||
f.write(filled_template)
|
||||
|
||||
parser = youtube_dl.parseOpts()[0]
|
||||
build_completion(parser)
|
||||
406
devscripts/buildserver.py
Normal file
406
devscripts/buildserver.py
Normal file
@@ -0,0 +1,406 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||
from socketserver import ThreadingMixIn
|
||||
import argparse
|
||||
import ctypes
|
||||
import functools
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
import os.path
|
||||
|
||||
|
||||
class BuildHTTPServer(ThreadingMixIn, HTTPServer):
|
||||
allow_reuse_address = True
|
||||
|
||||
|
||||
advapi32 = ctypes.windll.advapi32
|
||||
|
||||
SC_MANAGER_ALL_ACCESS = 0xf003f
|
||||
SC_MANAGER_CREATE_SERVICE = 0x02
|
||||
SERVICE_WIN32_OWN_PROCESS = 0x10
|
||||
SERVICE_AUTO_START = 0x2
|
||||
SERVICE_ERROR_NORMAL = 0x1
|
||||
DELETE = 0x00010000
|
||||
SERVICE_STATUS_START_PENDING = 0x00000002
|
||||
SERVICE_STATUS_RUNNING = 0x00000004
|
||||
SERVICE_ACCEPT_STOP = 0x1
|
||||
|
||||
SVCNAME = 'youtubedl_builder'
|
||||
|
||||
LPTSTR = ctypes.c_wchar_p
|
||||
START_CALLBACK = ctypes.WINFUNCTYPE(None, ctypes.c_int, ctypes.POINTER(LPTSTR))
|
||||
|
||||
|
||||
class SERVICE_TABLE_ENTRY(ctypes.Structure):
|
||||
_fields_ = [
|
||||
('lpServiceName', LPTSTR),
|
||||
('lpServiceProc', START_CALLBACK)
|
||||
]
|
||||
|
||||
|
||||
HandlerEx = ctypes.WINFUNCTYPE(
|
||||
ctypes.c_int, # return
|
||||
ctypes.c_int, # dwControl
|
||||
ctypes.c_int, # dwEventType
|
||||
ctypes.c_void_p, # lpEventData,
|
||||
ctypes.c_void_p, # lpContext,
|
||||
)
|
||||
|
||||
|
||||
def _ctypes_array(c_type, py_array):
|
||||
ar = (c_type * len(py_array))()
|
||||
ar[:] = py_array
|
||||
return ar
|
||||
|
||||
|
||||
def win_OpenSCManager():
|
||||
res = advapi32.OpenSCManagerW(None, None, SC_MANAGER_ALL_ACCESS)
|
||||
if not res:
|
||||
raise Exception('Opening service manager failed - '
|
||||
'are you running this as administrator?')
|
||||
return res
|
||||
|
||||
|
||||
def win_install_service(service_name, cmdline):
|
||||
manager = win_OpenSCManager()
|
||||
try:
|
||||
h = advapi32.CreateServiceW(
|
||||
manager, service_name, None,
|
||||
SC_MANAGER_CREATE_SERVICE, SERVICE_WIN32_OWN_PROCESS,
|
||||
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
|
||||
cmdline, None, None, None, None, None)
|
||||
if not h:
|
||||
raise OSError('Service creation failed: %s' % ctypes.FormatError())
|
||||
|
||||
advapi32.CloseServiceHandle(h)
|
||||
finally:
|
||||
advapi32.CloseServiceHandle(manager)
|
||||
|
||||
|
||||
def win_uninstall_service(service_name):
|
||||
manager = win_OpenSCManager()
|
||||
try:
|
||||
h = advapi32.OpenServiceW(manager, service_name, DELETE)
|
||||
if not h:
|
||||
raise OSError('Could not find service %s: %s' % (
|
||||
service_name, ctypes.FormatError()))
|
||||
|
||||
try:
|
||||
if not advapi32.DeleteService(h):
|
||||
raise OSError('Deletion failed: %s' % ctypes.FormatError())
|
||||
finally:
|
||||
advapi32.CloseServiceHandle(h)
|
||||
finally:
|
||||
advapi32.CloseServiceHandle(manager)
|
||||
|
||||
|
||||
def win_service_report_event(service_name, msg, is_error=True):
|
||||
with open('C:/sshkeys/log', 'a', encoding='utf-8') as f:
|
||||
f.write(msg + '\n')
|
||||
|
||||
event_log = advapi32.RegisterEventSourceW(None, service_name)
|
||||
if not event_log:
|
||||
raise OSError('Could not report event: %s' % ctypes.FormatError())
|
||||
|
||||
try:
|
||||
type_id = 0x0001 if is_error else 0x0004
|
||||
event_id = 0xc0000000 if is_error else 0x40000000
|
||||
lines = _ctypes_array(LPTSTR, [msg])
|
||||
|
||||
if not advapi32.ReportEventW(
|
||||
event_log, type_id, 0, event_id, None, len(lines), 0,
|
||||
lines, None):
|
||||
raise OSError('Event reporting failed: %s' % ctypes.FormatError())
|
||||
finally:
|
||||
advapi32.DeregisterEventSource(event_log)
|
||||
|
||||
|
||||
def win_service_handler(stop_event, *args):
|
||||
try:
|
||||
raise ValueError('Handler called with args ' + repr(args))
|
||||
TODO
|
||||
except Exception as e:
|
||||
tb = traceback.format_exc()
|
||||
msg = str(e) + '\n' + tb
|
||||
win_service_report_event(service_name, msg, is_error=True)
|
||||
raise
|
||||
|
||||
|
||||
def win_service_set_status(handle, status_code):
|
||||
svcStatus = SERVICE_STATUS()
|
||||
svcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS
|
||||
svcStatus.dwCurrentState = status_code
|
||||
svcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP
|
||||
|
||||
svcStatus.dwServiceSpecificExitCode = 0
|
||||
|
||||
if not advapi32.SetServiceStatus(handle, ctypes.byref(svcStatus)):
|
||||
raise OSError('SetServiceStatus failed: %r' % ctypes.FormatError())
|
||||
|
||||
|
||||
def win_service_main(service_name, real_main, argc, argv_raw):
|
||||
try:
|
||||
# args = [argv_raw[i].value for i in range(argc)]
|
||||
stop_event = threading.Event()
|
||||
handler = HandlerEx(functools.partial(stop_event, win_service_handler))
|
||||
h = advapi32.RegisterServiceCtrlHandlerExW(service_name, handler, None)
|
||||
if not h:
|
||||
raise OSError('Handler registration failed: %s' %
|
||||
ctypes.FormatError())
|
||||
|
||||
TODO
|
||||
except Exception as e:
|
||||
tb = traceback.format_exc()
|
||||
msg = str(e) + '\n' + tb
|
||||
win_service_report_event(service_name, msg, is_error=True)
|
||||
raise
|
||||
|
||||
|
||||
def win_service_start(service_name, real_main):
|
||||
try:
|
||||
cb = START_CALLBACK(
|
||||
functools.partial(win_service_main, service_name, real_main))
|
||||
dispatch_table = _ctypes_array(SERVICE_TABLE_ENTRY, [
|
||||
SERVICE_TABLE_ENTRY(
|
||||
service_name,
|
||||
cb
|
||||
),
|
||||
SERVICE_TABLE_ENTRY(None, ctypes.cast(None, START_CALLBACK))
|
||||
])
|
||||
|
||||
if not advapi32.StartServiceCtrlDispatcherW(dispatch_table):
|
||||
raise OSError('ctypes start failed: %s' % ctypes.FormatError())
|
||||
except Exception as e:
|
||||
tb = traceback.format_exc()
|
||||
msg = str(e) + '\n' + tb
|
||||
win_service_report_event(service_name, msg, is_error=True)
|
||||
raise
|
||||
|
||||
|
||||
def main(args=None):
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-i', '--install',
|
||||
action='store_const', dest='action', const='install',
|
||||
help='Launch at Windows startup')
|
||||
parser.add_argument('-u', '--uninstall',
|
||||
action='store_const', dest='action', const='uninstall',
|
||||
help='Remove Windows service')
|
||||
parser.add_argument('-s', '--service',
|
||||
action='store_const', dest='action', const='service',
|
||||
help='Run as a Windows service')
|
||||
parser.add_argument('-b', '--bind', metavar='<host:port>',
|
||||
action='store', default='localhost:8142',
|
||||
help='Bind to host:port (default %default)')
|
||||
options = parser.parse_args(args=args)
|
||||
|
||||
if options.action == 'install':
|
||||
fn = os.path.abspath(__file__).replace('v:', '\\\\vboxsrv\\vbox')
|
||||
cmdline = '%s %s -s -b %s' % (sys.executable, fn, options.bind)
|
||||
win_install_service(SVCNAME, cmdline)
|
||||
return
|
||||
|
||||
if options.action == 'uninstall':
|
||||
win_uninstall_service(SVCNAME)
|
||||
return
|
||||
|
||||
if options.action == 'service':
|
||||
win_service_start(SVCNAME, main)
|
||||
return
|
||||
|
||||
host, port_str = options.bind.split(':')
|
||||
port = int(port_str)
|
||||
|
||||
print('Listening on %s:%d' % (host, port))
|
||||
srv = BuildHTTPServer((host, port), BuildHTTPRequestHandler)
|
||||
thr = threading.Thread(target=srv.serve_forever)
|
||||
thr.start()
|
||||
input('Press ENTER to shut down')
|
||||
srv.shutdown()
|
||||
thr.join()
|
||||
|
||||
|
||||
def rmtree(path):
|
||||
for name in os.listdir(path):
|
||||
fname = os.path.join(path, name)
|
||||
if os.path.isdir(fname):
|
||||
rmtree(fname)
|
||||
else:
|
||||
os.chmod(fname, 0o666)
|
||||
os.remove(fname)
|
||||
os.rmdir(path)
|
||||
|
||||
#==============================================================================
|
||||
|
||||
|
||||
class BuildError(Exception):
|
||||
def __init__(self, output, code=500):
|
||||
self.output = output
|
||||
self.code = code
|
||||
|
||||
def __str__(self):
|
||||
return self.output
|
||||
|
||||
|
||||
class HTTPError(BuildError):
|
||||
pass
|
||||
|
||||
|
||||
class PythonBuilder(object):
|
||||
def __init__(self, **kwargs):
|
||||
pythonVersion = kwargs.pop('python', '2.7')
|
||||
try:
|
||||
key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\Python\PythonCore\%s\InstallPath' % pythonVersion)
|
||||
try:
|
||||
self.pythonPath, _ = _winreg.QueryValueEx(key, '')
|
||||
finally:
|
||||
_winreg.CloseKey(key)
|
||||
except Exception:
|
||||
raise BuildError('No such Python version: %s' % pythonVersion)
|
||||
|
||||
super(PythonBuilder, self).__init__(**kwargs)
|
||||
|
||||
|
||||
class GITInfoBuilder(object):
|
||||
def __init__(self, **kwargs):
|
||||
try:
|
||||
self.user, self.repoName = kwargs['path'][:2]
|
||||
self.rev = kwargs.pop('rev')
|
||||
except ValueError:
|
||||
raise BuildError('Invalid path')
|
||||
except KeyError as e:
|
||||
raise BuildError('Missing mandatory parameter "%s"' % e.args[0])
|
||||
|
||||
path = os.path.join(os.environ['APPDATA'], 'Build archive', self.repoName, self.user)
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
self.basePath = tempfile.mkdtemp(dir=path)
|
||||
self.buildPath = os.path.join(self.basePath, 'build')
|
||||
|
||||
super(GITInfoBuilder, self).__init__(**kwargs)
|
||||
|
||||
|
||||
class GITBuilder(GITInfoBuilder):
|
||||
def build(self):
|
||||
try:
|
||||
subprocess.check_output(['git', 'clone', 'git://github.com/%s/%s.git' % (self.user, self.repoName), self.buildPath])
|
||||
subprocess.check_output(['git', 'checkout', self.rev], cwd=self.buildPath)
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise BuildError(e.output)
|
||||
|
||||
super(GITBuilder, self).build()
|
||||
|
||||
|
||||
class YoutubeDLBuilder(object):
|
||||
authorizedUsers = ['fraca7', 'phihag', 'rg3', 'FiloSottile']
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
if self.repoName != 'youtube-dl':
|
||||
raise BuildError('Invalid repository "%s"' % self.repoName)
|
||||
if self.user not in self.authorizedUsers:
|
||||
raise HTTPError('Unauthorized user "%s"' % self.user, 401)
|
||||
|
||||
super(YoutubeDLBuilder, self).__init__(**kwargs)
|
||||
|
||||
def build(self):
|
||||
try:
|
||||
subprocess.check_output([os.path.join(self.pythonPath, 'python.exe'), 'setup.py', 'py2exe'],
|
||||
cwd=self.buildPath)
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise BuildError(e.output)
|
||||
|
||||
super(YoutubeDLBuilder, self).build()
|
||||
|
||||
|
||||
class DownloadBuilder(object):
|
||||
def __init__(self, **kwargs):
|
||||
self.handler = kwargs.pop('handler')
|
||||
self.srcPath = os.path.join(self.buildPath, *tuple(kwargs['path'][2:]))
|
||||
self.srcPath = os.path.abspath(os.path.normpath(self.srcPath))
|
||||
if not self.srcPath.startswith(self.buildPath):
|
||||
raise HTTPError(self.srcPath, 401)
|
||||
|
||||
super(DownloadBuilder, self).__init__(**kwargs)
|
||||
|
||||
def build(self):
|
||||
if not os.path.exists(self.srcPath):
|
||||
raise HTTPError('No such file', 404)
|
||||
if os.path.isdir(self.srcPath):
|
||||
raise HTTPError('Is a directory: %s' % self.srcPath, 401)
|
||||
|
||||
self.handler.send_response(200)
|
||||
self.handler.send_header('Content-Type', 'application/octet-stream')
|
||||
self.handler.send_header('Content-Disposition', 'attachment; filename=%s' % os.path.split(self.srcPath)[-1])
|
||||
self.handler.send_header('Content-Length', str(os.stat(self.srcPath).st_size))
|
||||
self.handler.end_headers()
|
||||
|
||||
with open(self.srcPath, 'rb') as src:
|
||||
shutil.copyfileobj(src, self.handler.wfile)
|
||||
|
||||
super(DownloadBuilder, self).build()
|
||||
|
||||
|
||||
class CleanupTempDir(object):
|
||||
def build(self):
|
||||
try:
|
||||
rmtree(self.basePath)
|
||||
except Exception as e:
|
||||
print('WARNING deleting "%s": %s' % (self.basePath, e))
|
||||
|
||||
super(CleanupTempDir, self).build()
|
||||
|
||||
|
||||
class Null(object):
|
||||
def __init__(self, **kwargs):
|
||||
pass
|
||||
|
||||
def start(self):
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
def build(self):
|
||||
pass
|
||||
|
||||
|
||||
class Builder(PythonBuilder, GITBuilder, YoutubeDLBuilder, DownloadBuilder, CleanupTempDir, Null):
|
||||
pass
|
||||
|
||||
|
||||
class BuildHTTPRequestHandler(BaseHTTPRequestHandler):
|
||||
actionDict = {'build': Builder, 'download': Builder} # They're the same, no more caching.
|
||||
|
||||
def do_GET(self):
|
||||
path = urlparse.urlparse(self.path)
|
||||
paramDict = dict([(key, value[0]) for key, value in urlparse.parse_qs(path.query).items()])
|
||||
action, _, path = path.path.strip('/').partition('/')
|
||||
if path:
|
||||
path = path.split('/')
|
||||
if action in self.actionDict:
|
||||
try:
|
||||
builder = self.actionDict[action](path=path, handler=self, **paramDict)
|
||||
builder.start()
|
||||
try:
|
||||
builder.build()
|
||||
finally:
|
||||
builder.close()
|
||||
except BuildError as e:
|
||||
self.send_response(e.code)
|
||||
msg = unicode(e).encode('UTF-8')
|
||||
self.send_header('Content-Type', 'text/plain; charset=UTF-8')
|
||||
self.send_header('Content-Length', len(msg))
|
||||
self.end_headers()
|
||||
self.wfile.write(msg)
|
||||
except HTTPError as e:
|
||||
self.send_response(e.code, str(e))
|
||||
else:
|
||||
self.send_response(500, 'Unknown build method "%s"' % action)
|
||||
else:
|
||||
self.send_response(500, 'Malformed URL')
|
||||
|
||||
#==============================================================================
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
60
devscripts/check-porn.py
Normal file
60
devscripts/check-porn.py
Normal file
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import unicode_literals
|
||||
|
||||
"""
|
||||
This script employs a VERY basic heuristic ('porn' in webpage.lower()) to check
|
||||
if we are not 'age_limit' tagging some porn site
|
||||
|
||||
A second approach implemented relies on a list of porn domains, to activate it
|
||||
pass the list filename as the only argument
|
||||
"""
|
||||
|
||||
# Allow direct execution
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from test.helper import get_testcases
|
||||
from youtube_dl.utils import compat_urllib_parse_urlparse
|
||||
from youtube_dl.utils import compat_urllib_request
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
METHOD = 'LIST'
|
||||
LIST = open(sys.argv[1]).read().decode('utf8').strip()
|
||||
else:
|
||||
METHOD = 'EURISTIC'
|
||||
|
||||
for test in get_testcases():
|
||||
if METHOD == 'EURISTIC':
|
||||
try:
|
||||
webpage = compat_urllib_request.urlopen(test['url'], timeout=10).read()
|
||||
except Exception:
|
||||
print('\nFail: {0}'.format(test['name']))
|
||||
continue
|
||||
|
||||
webpage = webpage.decode('utf8', 'replace')
|
||||
|
||||
RESULT = 'porn' in webpage.lower()
|
||||
|
||||
elif METHOD == 'LIST':
|
||||
domain = compat_urllib_parse_urlparse(test['url']).netloc
|
||||
if not domain:
|
||||
print('\nFail: {0}'.format(test['name']))
|
||||
continue
|
||||
domain = '.'.join(domain.split('.')[-2:])
|
||||
|
||||
RESULT = ('.' + domain + '\n' in LIST or '\n' + domain + '\n' in LIST)
|
||||
|
||||
if RESULT and ('info_dict' not in test or 'age_limit' not in test['info_dict'] or
|
||||
test['info_dict']['age_limit'] != 18):
|
||||
print('\nPotential missing age_limit check: {0}'.format(test['name']))
|
||||
|
||||
elif not RESULT and ('info_dict' in test and 'age_limit' in test['info_dict'] and
|
||||
test['info_dict']['age_limit'] == 18):
|
||||
print('\nPotential false negative: {0}'.format(test['name']))
|
||||
|
||||
else:
|
||||
sys.stdout.write('.')
|
||||
sys.stdout.flush()
|
||||
|
||||
print()
|
||||
5
devscripts/fish-completion.in
Normal file
5
devscripts/fish-completion.in
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
{{commands}}
|
||||
|
||||
|
||||
complete --command youtube-dl --arguments ":ytfavorites :ytrecommended :ytsubscriptions :ytwatchlater :ythistory"
|
||||
48
devscripts/fish-completion.py
Executable file
48
devscripts/fish-completion.py
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import optparse
|
||||
import os
|
||||
from os.path import dirname as dirn
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, dirn(dirn((os.path.abspath(__file__)))))
|
||||
import youtube_dl
|
||||
from youtube_dl.utils import shell_quote
|
||||
|
||||
FISH_COMPLETION_FILE = 'youtube-dl.fish'
|
||||
FISH_COMPLETION_TEMPLATE = 'devscripts/fish-completion.in'
|
||||
|
||||
EXTRA_ARGS = {
|
||||
'recode-video': ['--arguments', 'mp4 flv ogg webm mkv', '--exclusive'],
|
||||
|
||||
# Options that need a file parameter
|
||||
'download-archive': ['--require-parameter'],
|
||||
'cookies': ['--require-parameter'],
|
||||
'load-info': ['--require-parameter'],
|
||||
'batch-file': ['--require-parameter'],
|
||||
}
|
||||
|
||||
|
||||
def build_completion(opt_parser):
|
||||
commands = []
|
||||
|
||||
for group in opt_parser.option_groups:
|
||||
for option in group.option_list:
|
||||
long_option = option.get_opt_string().strip('-')
|
||||
complete_cmd = ['complete', '--command', 'youtube-dl', '--long-option', long_option]
|
||||
if option._short_opts:
|
||||
complete_cmd += ['--short-option', option._short_opts[0].strip('-')]
|
||||
if option.help != optparse.SUPPRESS_HELP:
|
||||
complete_cmd += ['--description', option.help]
|
||||
complete_cmd.extend(EXTRA_ARGS.get(long_option, []))
|
||||
commands.append(shell_quote(complete_cmd))
|
||||
|
||||
with open(FISH_COMPLETION_TEMPLATE) as f:
|
||||
template = f.read()
|
||||
filled_template = template.replace('{{commands}}', '\n'.join(commands))
|
||||
with open(FISH_COMPLETION_FILE, 'w') as f:
|
||||
f.write(filled_template)
|
||||
|
||||
parser = youtube_dl.parseOpts()[0]
|
||||
build_completion(parser)
|
||||
42
devscripts/generate_aes_testdata.py
Normal file
42
devscripts/generate_aes_testdata.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import codecs
|
||||
import subprocess
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from youtube_dl.utils import intlist_to_bytes
|
||||
from youtube_dl.aes import aes_encrypt, key_expansion
|
||||
|
||||
secret_msg = b'Secret message goes here'
|
||||
|
||||
|
||||
def hex_str(int_list):
|
||||
return codecs.encode(intlist_to_bytes(int_list), 'hex')
|
||||
|
||||
|
||||
def openssl_encode(algo, key, iv):
|
||||
cmd = ['openssl', 'enc', '-e', '-' + algo, '-K', hex_str(key), '-iv', hex_str(iv)]
|
||||
prog = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||
out, _ = prog.communicate(secret_msg)
|
||||
return out
|
||||
|
||||
iv = key = [0x20, 0x15] + 14 * [0]
|
||||
|
||||
r = openssl_encode('aes-128-cbc', key, iv)
|
||||
print('aes_cbc_decrypt')
|
||||
print(repr(r))
|
||||
|
||||
password = key
|
||||
new_key = aes_encrypt(password, key_expansion(password))
|
||||
r = openssl_encode('aes-128-ctr', new_key, iv)
|
||||
print('aes_decrypt_text 16')
|
||||
print(repr(r))
|
||||
|
||||
password = key + 16 * [0]
|
||||
new_key = aes_encrypt(password, key_expansion(password)) * (32 // 16)
|
||||
r = openssl_encode('aes-256-ctr', new_key, iv)
|
||||
print('aes_decrypt_text 32')
|
||||
print(repr(r))
|
||||
43
devscripts/gh-pages/add-version.py
Executable file
43
devscripts/gh-pages/add-version.py
Executable file
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import json
|
||||
import sys
|
||||
import hashlib
|
||||
import os.path
|
||||
|
||||
|
||||
if len(sys.argv) <= 1:
|
||||
print('Specify the version number as parameter')
|
||||
sys.exit()
|
||||
version = sys.argv[1]
|
||||
|
||||
with open('update/LATEST_VERSION', 'w') as f:
|
||||
f.write(version)
|
||||
|
||||
versions_info = json.load(open('update/versions.json'))
|
||||
if 'signature' in versions_info:
|
||||
del versions_info['signature']
|
||||
|
||||
new_version = {}
|
||||
|
||||
filenames = {
|
||||
'bin': 'youtube-dl',
|
||||
'exe': 'youtube-dl.exe',
|
||||
'tar': 'youtube-dl-%s.tar.gz' % version}
|
||||
build_dir = os.path.join('..', '..', 'build', version)
|
||||
for key, filename in filenames.items():
|
||||
url = 'https://yt-dl.org/downloads/%s/%s' % (version, filename)
|
||||
fn = os.path.join(build_dir, filename)
|
||||
with open(fn, 'rb') as f:
|
||||
data = f.read()
|
||||
if not data:
|
||||
raise ValueError('File %s is empty!' % fn)
|
||||
sha256sum = hashlib.sha256(data).hexdigest()
|
||||
new_version[key] = (url, sha256sum)
|
||||
|
||||
versions_info['versions'][version] = new_version
|
||||
versions_info['latest'] = version
|
||||
|
||||
with open('update/versions.json', 'w') as jsonf:
|
||||
json.dump(versions_info, jsonf, indent=4, sort_keys=True)
|
||||
31
devscripts/gh-pages/generate-download.py
Executable file
31
devscripts/gh-pages/generate-download.py
Executable file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import hashlib
|
||||
import urllib.request
|
||||
import json
|
||||
|
||||
versions_info = json.load(open('update/versions.json'))
|
||||
version = versions_info['latest']
|
||||
URL = versions_info['versions'][version]['bin'][0]
|
||||
|
||||
data = urllib.request.urlopen(URL).read()
|
||||
|
||||
# Read template page
|
||||
with open('download.html.in', 'r', encoding='utf-8') as tmplf:
|
||||
template = tmplf.read()
|
||||
|
||||
md5sum = hashlib.md5(data).hexdigest()
|
||||
sha1sum = hashlib.sha1(data).hexdigest()
|
||||
sha256sum = hashlib.sha256(data).hexdigest()
|
||||
template = template.replace('@PROGRAM_VERSION@', version)
|
||||
template = template.replace('@PROGRAM_URL@', URL)
|
||||
template = template.replace('@PROGRAM_MD5SUM@', md5sum)
|
||||
template = template.replace('@PROGRAM_SHA1SUM@', sha1sum)
|
||||
template = template.replace('@PROGRAM_SHA256SUM@', sha256sum)
|
||||
template = template.replace('@EXE_URL@', versions_info['versions'][version]['exe'][0])
|
||||
template = template.replace('@EXE_SHA256SUM@', versions_info['versions'][version]['exe'][1])
|
||||
template = template.replace('@TAR_URL@', versions_info['versions'][version]['tar'][0])
|
||||
template = template.replace('@TAR_SHA256SUM@', versions_info['versions'][version]['tar'][1])
|
||||
with open('download.html', 'w', encoding='utf-8') as dlf:
|
||||
dlf.write(template)
|
||||
34
devscripts/gh-pages/sign-versions.py
Executable file
34
devscripts/gh-pages/sign-versions.py
Executable file
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import unicode_literals, with_statement
|
||||
|
||||
import rsa
|
||||
import json
|
||||
from binascii import hexlify
|
||||
|
||||
try:
|
||||
input = raw_input
|
||||
except NameError:
|
||||
pass
|
||||
|
||||
versions_info = json.load(open('update/versions.json'))
|
||||
if 'signature' in versions_info:
|
||||
del versions_info['signature']
|
||||
|
||||
print('Enter the PKCS1 private key, followed by a blank line:')
|
||||
privkey = b''
|
||||
while True:
|
||||
try:
|
||||
line = input()
|
||||
except EOFError:
|
||||
break
|
||||
if line == '':
|
||||
break
|
||||
privkey += line.encode('ascii') + b'\n'
|
||||
privkey = rsa.PrivateKey.load_pkcs1(privkey)
|
||||
|
||||
signature = hexlify(rsa.pkcs1.sign(json.dumps(versions_info, sort_keys=True).encode('utf-8'), privkey, 'SHA-256')).decode()
|
||||
print('signature: ' + signature)
|
||||
|
||||
versions_info['signature'] = signature
|
||||
with open('update/versions.json', 'w') as versionsf:
|
||||
json.dump(versions_info, versionsf, indent=4, sort_keys=True)
|
||||
21
devscripts/gh-pages/update-copyright.py
Executable file
21
devscripts/gh-pages/update-copyright.py
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
from __future__ import with_statement, unicode_literals
|
||||
|
||||
import datetime
|
||||
import glob
|
||||
import io # For Python 2 compatibilty
|
||||
import os
|
||||
import re
|
||||
|
||||
year = str(datetime.datetime.now().year)
|
||||
for fn in glob.glob('*.html*'):
|
||||
with io.open(fn, encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
newc = re.sub(r'(?P<copyright>Copyright © 2006-)(?P<year>[0-9]{4})', 'Copyright © 2006-' + year, content)
|
||||
if content != newc:
|
||||
tmpFn = fn + '.part'
|
||||
with io.open(tmpFn, 'wt', encoding='utf-8') as outf:
|
||||
outf.write(newc)
|
||||
os.rename(tmpFn, fn)
|
||||
76
devscripts/gh-pages/update-feed.py
Executable file
76
devscripts/gh-pages/update-feed.py
Executable file
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
import io
|
||||
import json
|
||||
import textwrap
|
||||
|
||||
|
||||
atom_template = textwrap.dedent("""\
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<link rel="self" href="http://rg3.github.io/youtube-dl/update/releases.atom" />
|
||||
<title>youtube-dl releases</title>
|
||||
<id>https://yt-dl.org/feed/youtube-dl-updates-feed</id>
|
||||
<updated>@TIMESTAMP@</updated>
|
||||
@ENTRIES@
|
||||
</feed>""")
|
||||
|
||||
entry_template = textwrap.dedent("""
|
||||
<entry>
|
||||
<id>https://yt-dl.org/feed/youtube-dl-updates-feed/youtube-dl-@VERSION@</id>
|
||||
<title>New version @VERSION@</title>
|
||||
<link href="http://rg3.github.io/youtube-dl" />
|
||||
<content type="xhtml">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">
|
||||
Downloads available at <a href="https://yt-dl.org/downloads/@VERSION@/">https://yt-dl.org/downloads/@VERSION@/</a>
|
||||
</div>
|
||||
</content>
|
||||
<author>
|
||||
<name>The youtube-dl maintainers</name>
|
||||
</author>
|
||||
<updated>@TIMESTAMP@</updated>
|
||||
</entry>
|
||||
""")
|
||||
|
||||
now = datetime.datetime.now()
|
||||
now_iso = now.isoformat() + 'Z'
|
||||
|
||||
atom_template = atom_template.replace('@TIMESTAMP@', now_iso)
|
||||
|
||||
versions_info = json.load(open('update/versions.json'))
|
||||
versions = list(versions_info['versions'].keys())
|
||||
versions.sort()
|
||||
|
||||
entries = []
|
||||
for v in versions:
|
||||
fields = v.split('.')
|
||||
year, month, day = map(int, fields[:3])
|
||||
faked = 0
|
||||
patchlevel = 0
|
||||
while True:
|
||||
try:
|
||||
datetime.date(year, month, day)
|
||||
except ValueError:
|
||||
day -= 1
|
||||
faked += 1
|
||||
assert day > 0
|
||||
continue
|
||||
break
|
||||
if len(fields) >= 4:
|
||||
try:
|
||||
patchlevel = int(fields[3])
|
||||
except ValueError:
|
||||
patchlevel = 1
|
||||
timestamp = '%04d-%02d-%02dT00:%02d:%02dZ' % (year, month, day, faked, patchlevel)
|
||||
|
||||
entry = entry_template.replace('@TIMESTAMP@', timestamp)
|
||||
entry = entry.replace('@VERSION@', v)
|
||||
entries.append(entry)
|
||||
|
||||
entries_str = textwrap.indent(''.join(entries), '\t')
|
||||
atom_template = atom_template.replace('@ENTRIES@', entries_str)
|
||||
|
||||
with io.open('update/releases.atom', 'w', encoding='utf-8') as atom_file:
|
||||
atom_file.write(atom_template)
|
||||
36
devscripts/gh-pages/update-sites.py
Executable file
36
devscripts/gh-pages/update-sites.py
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import sys
|
||||
import os
|
||||
import textwrap
|
||||
|
||||
# We must be able to import youtube_dl
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
||||
|
||||
import youtube_dl
|
||||
|
||||
|
||||
def main():
|
||||
with open('supportedsites.html.in', 'r', encoding='utf-8') as tmplf:
|
||||
template = tmplf.read()
|
||||
|
||||
ie_htmls = []
|
||||
for ie in youtube_dl.list_extractors(age_limit=None):
|
||||
ie_html = '<b>{}</b>'.format(ie.IE_NAME)
|
||||
ie_desc = getattr(ie, 'IE_DESC', None)
|
||||
if ie_desc is False:
|
||||
continue
|
||||
elif ie_desc is not None:
|
||||
ie_html += ': {}'.format(ie.IE_DESC)
|
||||
if not ie.working():
|
||||
ie_html += ' (Currently broken)'
|
||||
ie_htmls.append('<li>{}</li>'.format(ie_html))
|
||||
|
||||
template = template.replace('@SITES@', textwrap.indent('\n'.join(ie_htmls), '\t'))
|
||||
|
||||
with open('supportedsites.html', 'w', encoding='utf-8') as sitesf:
|
||||
sitesf.write(template)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
32
devscripts/make_contributing.py
Executable file
32
devscripts/make_contributing.py
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import io
|
||||
import optparse
|
||||
import re
|
||||
|
||||
|
||||
def main():
|
||||
parser = optparse.OptionParser(usage='%prog INFILE OUTFILE')
|
||||
options, args = parser.parse_args()
|
||||
if len(args) != 2:
|
||||
parser.error('Expected an input and an output filename')
|
||||
|
||||
infile, outfile = args
|
||||
|
||||
with io.open(infile, encoding='utf-8') as inf:
|
||||
readme = inf.read()
|
||||
|
||||
bug_text = re.search(
|
||||
r'(?s)#\s*BUGS\s*[^\n]*\s*(.*?)#\s*COPYRIGHT', readme).group(1)
|
||||
dev_text = re.search(
|
||||
r'(?s)(#\s*DEVELOPER INSTRUCTIONS.*?)#\s*EMBEDDING YOUTUBE-DL',
|
||||
readme).group(1)
|
||||
|
||||
out = bug_text + dev_text
|
||||
|
||||
with io.open(outfile, 'w', encoding='utf-8') as outf:
|
||||
outf.write(out)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
26
devscripts/make_readme.py
Executable file
26
devscripts/make_readme.py
Executable file
@@ -0,0 +1,26 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import io
|
||||
import sys
|
||||
import re
|
||||
|
||||
README_FILE = 'README.md'
|
||||
helptext = sys.stdin.read()
|
||||
|
||||
if isinstance(helptext, bytes):
|
||||
helptext = helptext.decode('utf-8')
|
||||
|
||||
with io.open(README_FILE, encoding='utf-8') as f:
|
||||
oldreadme = f.read()
|
||||
|
||||
header = oldreadme[:oldreadme.index('# OPTIONS')]
|
||||
footer = oldreadme[oldreadme.index('# CONFIGURATION'):]
|
||||
|
||||
options = helptext[helptext.index(' General Options:') + 19:]
|
||||
options = re.sub(r'(?m)^ (\w.+)$', r'## \1', options)
|
||||
options = '# OPTIONS\n' + options + '\n'
|
||||
|
||||
with io.open(README_FILE, 'w', encoding='utf-8') as f:
|
||||
f.write(header)
|
||||
f.write(options)
|
||||
f.write(footer)
|
||||
45
devscripts/make_supportedsites.py
Normal file
45
devscripts/make_supportedsites.py
Normal file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import io
|
||||
import optparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
# Import youtube_dl
|
||||
ROOT_DIR = os.path.join(os.path.dirname(__file__), '..')
|
||||
sys.path.insert(0, ROOT_DIR)
|
||||
import youtube_dl
|
||||
|
||||
|
||||
def main():
|
||||
parser = optparse.OptionParser(usage='%prog OUTFILE.md')
|
||||
options, args = parser.parse_args()
|
||||
if len(args) != 1:
|
||||
parser.error('Expected an output filename')
|
||||
|
||||
outfile, = args
|
||||
|
||||
def gen_ies_md(ies):
|
||||
for ie in ies:
|
||||
ie_md = '**{0}**'.format(ie.IE_NAME)
|
||||
ie_desc = getattr(ie, 'IE_DESC', None)
|
||||
if ie_desc is False:
|
||||
continue
|
||||
if ie_desc is not None:
|
||||
ie_md += ': {0}'.format(ie.IE_DESC)
|
||||
if not ie.working():
|
||||
ie_md += ' (Currently broken)'
|
||||
yield ie_md
|
||||
|
||||
ies = sorted(youtube_dl.gen_extractors(), key=lambda i: i.IE_NAME.lower())
|
||||
out = '# Supported sites\n' + ''.join(
|
||||
' - ' + md + '\n'
|
||||
for md in gen_ies_md(ies))
|
||||
|
||||
with io.open(outfile, 'w', encoding='utf-8') as outf:
|
||||
outf.write(out)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
0
devscripts/posix-locale.sh
Normal file → Executable file
0
devscripts/posix-locale.sh
Normal file → Executable file
63
devscripts/prepare_manpage.py
Normal file
63
devscripts/prepare_manpage.py
Normal file
@@ -0,0 +1,63 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import io
|
||||
import os.path
|
||||
import sys
|
||||
import re
|
||||
|
||||
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
README_FILE = os.path.join(ROOT_DIR, 'README.md')
|
||||
|
||||
|
||||
def filter_options(readme):
|
||||
ret = ''
|
||||
in_options = False
|
||||
for line in readme.split('\n'):
|
||||
if line.startswith('# '):
|
||||
if line[2:].startswith('OPTIONS'):
|
||||
in_options = True
|
||||
else:
|
||||
in_options = False
|
||||
|
||||
if in_options:
|
||||
if line.lstrip().startswith('-'):
|
||||
option, description = re.split(r'\s{2,}', line.lstrip())
|
||||
split_option = option.split(' ')
|
||||
|
||||
if not split_option[-1].startswith('-'): # metavar
|
||||
option = ' '.join(split_option[:-1] + ['*%s*' % split_option[-1]])
|
||||
|
||||
# Pandoc's definition_lists. See http://pandoc.org/README.html
|
||||
# for more information.
|
||||
ret += '\n%s\n: %s\n' % (option, description)
|
||||
else:
|
||||
ret += line.lstrip() + '\n'
|
||||
else:
|
||||
ret += line + '\n'
|
||||
|
||||
return ret
|
||||
|
||||
with io.open(README_FILE, encoding='utf-8') as f:
|
||||
readme = f.read()
|
||||
|
||||
PREFIX = '''%YOUTUBE-DL(1)
|
||||
|
||||
# NAME
|
||||
|
||||
youtube\-dl \- download videos from youtube.com or other video platforms
|
||||
|
||||
# SYNOPSIS
|
||||
|
||||
**youtube-dl** \[OPTIONS\] URL [URL...]
|
||||
|
||||
'''
|
||||
readme = re.sub(r'(?s)^.*?(?=# DESCRIPTION)', '', readme)
|
||||
readme = re.sub(r'\s+youtube-dl \[OPTIONS\] URL \[URL\.\.\.\]', '', readme)
|
||||
readme = PREFIX + readme
|
||||
|
||||
readme = filter_options(readme)
|
||||
|
||||
if sys.version_info < (3, 0):
|
||||
print(readme.encode('utf-8'))
|
||||
else:
|
||||
print(readme)
|
||||
108
devscripts/release.sh
Executable file
108
devscripts/release.sh
Executable file
@@ -0,0 +1,108 @@
|
||||
#!/bin/bash
|
||||
|
||||
# IMPORTANT: the following assumptions are made
|
||||
# * the GH repo is on the origin remote
|
||||
# * the gh-pages branch is named so locally
|
||||
# * the git config user.signingkey is properly set
|
||||
|
||||
# You will need
|
||||
# pip install coverage nose rsa
|
||||
|
||||
# TODO
|
||||
# release notes
|
||||
# make hash on local files
|
||||
|
||||
set -e
|
||||
|
||||
skip_tests=true
|
||||
if [ "$1" = '--run-tests' ]; then
|
||||
skip_tests=false
|
||||
shift
|
||||
fi
|
||||
|
||||
if [ -z "$1" ]; then echo "ERROR: specify version number like this: $0 1994.09.06"; exit 1; fi
|
||||
version="$1"
|
||||
major_version=$(echo "$version" | sed -n 's#^\([0-9]*\.[0-9]*\.[0-9]*\).*#\1#p')
|
||||
if test "$major_version" '!=' "$(date '+%Y.%m.%d')"; then
|
||||
echo "$version does not start with today's date!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -z "`git tag | grep "$version"`" ]; then echo 'ERROR: version already present'; exit 1; fi
|
||||
if [ ! -z "`git status --porcelain | grep -v CHANGELOG`" ]; then echo 'ERROR: the working directory is not clean; commit or stash changes'; exit 1; fi
|
||||
useless_files=$(find youtube_dl -type f -not -name '*.py')
|
||||
if [ ! -z "$useless_files" ]; then echo "ERROR: Non-.py files in youtube_dl: $useless_files"; exit 1; fi
|
||||
if [ ! -f "updates_key.pem" ]; then echo 'ERROR: updates_key.pem missing'; exit 1; fi
|
||||
|
||||
/bin/echo -e "\n### First of all, testing..."
|
||||
make clean
|
||||
if $skip_tests ; then
|
||||
echo 'SKIPPING TESTS'
|
||||
else
|
||||
nosetests --verbose --with-coverage --cover-package=youtube_dl --cover-html test --stop || exit 1
|
||||
fi
|
||||
|
||||
/bin/echo -e "\n### Changing version in version.py..."
|
||||
sed -i "s/__version__ = '.*'/__version__ = '$version'/" youtube_dl/version.py
|
||||
|
||||
/bin/echo -e "\n### Committing documentation and youtube_dl/version.py..."
|
||||
make README.md CONTRIBUTING.md supportedsites
|
||||
git add README.md CONTRIBUTING.md docs/supportedsites.md youtube_dl/version.py
|
||||
git commit -m "release $version"
|
||||
|
||||
/bin/echo -e "\n### Now tagging, signing and pushing..."
|
||||
git tag -s -m "Release $version" "$version"
|
||||
git show "$version"
|
||||
read -p "Is it good, can I push? (y/n) " -n 1
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit 1; fi
|
||||
echo
|
||||
MASTER=$(git rev-parse --abbrev-ref HEAD)
|
||||
git push origin $MASTER:master
|
||||
git push origin "$version"
|
||||
|
||||
/bin/echo -e "\n### OK, now it is time to build the binaries..."
|
||||
REV=$(git rev-parse HEAD)
|
||||
make youtube-dl youtube-dl.tar.gz
|
||||
read -p "VM running? (y/n) " -n 1
|
||||
wget "http://localhost:8142/build/rg3/youtube-dl/youtube-dl.exe?rev=$REV" -O youtube-dl.exe
|
||||
mkdir -p "build/$version"
|
||||
mv youtube-dl youtube-dl.exe "build/$version"
|
||||
mv youtube-dl.tar.gz "build/$version/youtube-dl-$version.tar.gz"
|
||||
RELEASE_FILES="youtube-dl youtube-dl.exe youtube-dl-$version.tar.gz"
|
||||
(cd build/$version/ && md5sum $RELEASE_FILES > MD5SUMS)
|
||||
(cd build/$version/ && sha1sum $RELEASE_FILES > SHA1SUMS)
|
||||
(cd build/$version/ && sha256sum $RELEASE_FILES > SHA2-256SUMS)
|
||||
(cd build/$version/ && sha512sum $RELEASE_FILES > SHA2-512SUMS)
|
||||
|
||||
/bin/echo -e "\n### Signing and uploading the new binaries to yt-dl.org ..."
|
||||
for f in $RELEASE_FILES; do gpg --passphrase-repeat 5 --detach-sig "build/$version/$f"; done
|
||||
scp -r "build/$version" ytdl@yt-dl.org:html/tmp/
|
||||
ssh ytdl@yt-dl.org "mv html/tmp/$version html/downloads/"
|
||||
ssh ytdl@yt-dl.org "sh html/update_latest.sh $version"
|
||||
|
||||
/bin/echo -e "\n### Now switching to gh-pages..."
|
||||
git clone --branch gh-pages --single-branch . build/gh-pages
|
||||
ROOT=$(pwd)
|
||||
(
|
||||
set -e
|
||||
ORIGIN_URL=$(git config --get remote.origin.url)
|
||||
cd build/gh-pages
|
||||
"$ROOT/devscripts/gh-pages/add-version.py" $version
|
||||
"$ROOT/devscripts/gh-pages/update-feed.py"
|
||||
"$ROOT/devscripts/gh-pages/sign-versions.py" < "$ROOT/updates_key.pem"
|
||||
"$ROOT/devscripts/gh-pages/generate-download.py"
|
||||
"$ROOT/devscripts/gh-pages/update-copyright.py"
|
||||
"$ROOT/devscripts/gh-pages/update-sites.py"
|
||||
git add *.html *.html.in update
|
||||
git commit -m "release $version"
|
||||
git push "$ROOT" gh-pages
|
||||
git push "$ORIGIN_URL" gh-pages
|
||||
)
|
||||
rm -rf build
|
||||
|
||||
make pypi-files
|
||||
echo "Uploading to PyPi ..."
|
||||
python setup.py sdist bdist_wheel upload
|
||||
make clean
|
||||
|
||||
/bin/echo -e "\n### DONE!"
|
||||
56
devscripts/wine-py2exe.sh
Executable file
56
devscripts/wine-py2exe.sh
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Run with as parameter a setup.py that works in the current directory
|
||||
# e.g. no os.chdir()
|
||||
# It will run twice, the first time will crash
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "$0" )" && pwd )"
|
||||
|
||||
if [ ! -d wine-py2exe ]; then
|
||||
|
||||
sudo apt-get install wine1.3 axel bsdiff
|
||||
|
||||
mkdir wine-py2exe
|
||||
cd wine-py2exe
|
||||
export WINEPREFIX=`pwd`
|
||||
|
||||
axel -a "http://www.python.org/ftp/python/2.7/python-2.7.msi"
|
||||
axel -a "http://downloads.sourceforge.net/project/py2exe/py2exe/0.6.9/py2exe-0.6.9.win32-py2.7.exe"
|
||||
#axel -a "http://winetricks.org/winetricks"
|
||||
|
||||
# http://appdb.winehq.org/objectManager.php?sClass=version&iId=21957
|
||||
echo "Follow python setup on screen"
|
||||
wine msiexec /i python-2.7.msi
|
||||
|
||||
echo "Follow py2exe setup on screen"
|
||||
wine py2exe-0.6.9.win32-py2.7.exe
|
||||
|
||||
#echo "Follow Microsoft Visual C++ 2008 Redistributable Package setup on screen"
|
||||
#bash winetricks vcrun2008
|
||||
|
||||
rm py2exe-0.6.9.win32-py2.7.exe
|
||||
rm python-2.7.msi
|
||||
#rm winetricks
|
||||
|
||||
# http://bugs.winehq.org/show_bug.cgi?id=3591
|
||||
|
||||
mv drive_c/Python27/Lib/site-packages/py2exe/run.exe drive_c/Python27/Lib/site-packages/py2exe/run.exe.backup
|
||||
bspatch drive_c/Python27/Lib/site-packages/py2exe/run.exe.backup drive_c/Python27/Lib/site-packages/py2exe/run.exe "$SCRIPT_DIR/SizeOfImage.patch"
|
||||
mv drive_c/Python27/Lib/site-packages/py2exe/run_w.exe drive_c/Python27/Lib/site-packages/py2exe/run_w.exe.backup
|
||||
bspatch drive_c/Python27/Lib/site-packages/py2exe/run_w.exe.backup drive_c/Python27/Lib/site-packages/py2exe/run_w.exe "$SCRIPT_DIR/SizeOfImage_w.patch"
|
||||
|
||||
cd -
|
||||
|
||||
else
|
||||
|
||||
export WINEPREFIX="$( cd wine-py2exe && pwd )"
|
||||
|
||||
fi
|
||||
|
||||
wine "C:\\Python27\\python.exe" "$1" py2exe > "py2exe.log" 2>&1 || true
|
||||
echo '# Copying python27.dll' >> "py2exe.log"
|
||||
cp "$WINEPREFIX/drive_c/windows/system32/python27.dll" build/bdist.win32/winexe/bundle-2.7/
|
||||
wine "C:\\Python27\\python.exe" "$1" py2exe >> "py2exe.log" 2>&1
|
||||
|
||||
28
devscripts/zsh-completion.in
Normal file
28
devscripts/zsh-completion.in
Normal file
@@ -0,0 +1,28 @@
|
||||
#compdef youtube-dl
|
||||
|
||||
__youtube_dl() {
|
||||
local curcontext="$curcontext" fileopts diropts cur prev
|
||||
typeset -A opt_args
|
||||
fileopts="{{fileopts}}"
|
||||
diropts="{{diropts}}"
|
||||
cur=$words[CURRENT]
|
||||
case $cur in
|
||||
:)
|
||||
_arguments '*: :(::ytfavorites ::ytrecommended ::ytsubscriptions ::ytwatchlater ::ythistory)'
|
||||
;;
|
||||
*)
|
||||
prev=$words[CURRENT-1]
|
||||
if [[ ${prev} =~ ${fileopts} ]]; then
|
||||
_path_files
|
||||
elif [[ ${prev} =~ ${diropts} ]]; then
|
||||
_path_files -/
|
||||
elif [[ ${prev} == "--recode-video" ]]; then
|
||||
_arguments '*: :(mp4 flv ogg webm mkv)'
|
||||
else
|
||||
_arguments '*: :({{flags}})'
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
__youtube_dl
|
||||
48
devscripts/zsh-completion.py
Executable file
48
devscripts/zsh-completion.py
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
from os.path import dirname as dirn
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, dirn(dirn((os.path.abspath(__file__)))))
|
||||
import youtube_dl
|
||||
|
||||
ZSH_COMPLETION_FILE = "youtube-dl.zsh"
|
||||
ZSH_COMPLETION_TEMPLATE = "devscripts/zsh-completion.in"
|
||||
|
||||
|
||||
def build_completion(opt_parser):
|
||||
opts = [opt for group in opt_parser.option_groups
|
||||
for opt in group.option_list]
|
||||
opts_file = [opt for opt in opts if opt.metavar == "FILE"]
|
||||
opts_dir = [opt for opt in opts if opt.metavar == "DIR"]
|
||||
|
||||
fileopts = []
|
||||
for opt in opts_file:
|
||||
if opt._short_opts:
|
||||
fileopts.extend(opt._short_opts)
|
||||
if opt._long_opts:
|
||||
fileopts.extend(opt._long_opts)
|
||||
|
||||
diropts = []
|
||||
for opt in opts_dir:
|
||||
if opt._short_opts:
|
||||
diropts.extend(opt._short_opts)
|
||||
if opt._long_opts:
|
||||
diropts.extend(opt._long_opts)
|
||||
|
||||
flags = [opt.get_opt_string() for opt in opts]
|
||||
|
||||
with open(ZSH_COMPLETION_TEMPLATE) as f:
|
||||
template = f.read()
|
||||
|
||||
template = template.replace("{{fileopts}}", "|".join(fileopts))
|
||||
template = template.replace("{{diropts}}", "|".join(diropts))
|
||||
template = template.replace("{{flags}}", " ".join(flags))
|
||||
|
||||
with open(ZSH_COMPLETION_FILE, "w") as f:
|
||||
f.write(template)
|
||||
|
||||
parser = youtube_dl.parseOpts()[0]
|
||||
build_completion(parser)
|
||||
1
docs/.gitignore
vendored
Normal file
1
docs/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
_build/
|
||||
177
docs/Makefile
Normal file
177
docs/Makefile
Normal file
@@ -0,0 +1,177 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
||||
# User-friendly check for sphinx-build
|
||||
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
|
||||
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
|
||||
endif
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " texinfo to make Texinfo files"
|
||||
@echo " info to make Texinfo files and run them through makeinfo"
|
||||
@echo " gettext to make PO message catalogs"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " xml to make Docutils-native XML files"
|
||||
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/youtube-dl.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/youtube-dl.qhc"
|
||||
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/youtube-dl"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/youtube-dl"
|
||||
@echo "# devhelp"
|
||||
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
latexpdfja:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through platex and dvipdfmx..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
texinfo:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
|
||||
xml:
|
||||
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
|
||||
@echo
|
||||
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
|
||||
|
||||
pseudoxml:
|
||||
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
|
||||
@echo
|
||||
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
|
||||
71
docs/conf.py
Normal file
71
docs/conf.py
Normal file
@@ -0,0 +1,71 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# youtube-dl documentation build configuration file, created by
|
||||
# sphinx-quickstart on Fri Mar 14 21:05:43 2014.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys
|
||||
import os
|
||||
# Allows to import youtube_dl
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'youtube-dl'
|
||||
copyright = u'2014, Ricardo Garcia Gonzalez'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
from youtube_dl.version import __version__
|
||||
version = __version__
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = version
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'default'
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'youtube-dldoc'
|
||||
23
docs/index.rst
Normal file
23
docs/index.rst
Normal file
@@ -0,0 +1,23 @@
|
||||
Welcome to youtube-dl's documentation!
|
||||
======================================
|
||||
|
||||
*youtube-dl* is a command-line program to download videos from YouTube.com and more sites.
|
||||
It can also be used in Python code.
|
||||
|
||||
Developer guide
|
||||
---------------
|
||||
|
||||
This section contains information for using *youtube-dl* from Python programs.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
module_guide
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
67
docs/module_guide.rst
Normal file
67
docs/module_guide.rst
Normal file
@@ -0,0 +1,67 @@
|
||||
Using the ``youtube_dl`` module
|
||||
===============================
|
||||
|
||||
When using the ``youtube_dl`` module, you start by creating an instance of :class:`YoutubeDL` and adding all the available extractors:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> from youtube_dl import YoutubeDL
|
||||
>>> ydl = YoutubeDL()
|
||||
>>> ydl.add_default_info_extractors()
|
||||
|
||||
Extracting video information
|
||||
----------------------------
|
||||
|
||||
You use the :meth:`YoutubeDL.extract_info` method for getting the video information, which returns a dictionary:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> info = ydl.extract_info('http://www.youtube.com/watch?v=BaW_jenozKc', download=False)
|
||||
[youtube] Setting language
|
||||
[youtube] BaW_jenozKc: Downloading webpage
|
||||
[youtube] BaW_jenozKc: Downloading video info webpage
|
||||
[youtube] BaW_jenozKc: Extracting video information
|
||||
>>> info['title']
|
||||
'youtube-dl test video "\'/\\ä↭𝕐'
|
||||
>>> info['height'], info['width']
|
||||
(720, 1280)
|
||||
|
||||
If you want to download or play the video you can get its url:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> info['url']
|
||||
'https://...'
|
||||
|
||||
Extracting playlist information
|
||||
-------------------------------
|
||||
|
||||
The playlist information is extracted in a similar way, but the dictionary is a bit different:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> playlist = ydl.extract_info('http://www.ted.com/playlists/13/open_source_open_world', download=False)
|
||||
[TED] open_source_open_world: Downloading playlist webpage
|
||||
...
|
||||
>>> playlist['title']
|
||||
'Open-source, open world'
|
||||
|
||||
|
||||
|
||||
You can access the videos in the playlist with the ``entries`` field:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> for video in playlist['entries']:
|
||||
... print('Video #%d: %s' % (video['playlist_index'], video['title']))
|
||||
|
||||
Video #1: How Arduino is open-sourcing imagination
|
||||
Video #2: The year open data went worldwide
|
||||
Video #3: Massive-scale online collaboration
|
||||
Video #4: The art of asking
|
||||
Video #5: How cognitive surplus will change the world
|
||||
Video #6: The birth of Wikipedia
|
||||
Video #7: Coding a better government
|
||||
Video #8: The era of open innovation
|
||||
Video #9: The currency of the new economy is trust
|
||||
|
||||
726
docs/supportedsites.md
Normal file
726
docs/supportedsites.md
Normal file
File diff suppressed because one or more lines are too long
6
setup.cfg
Normal file
6
setup.cfg
Normal file
@@ -0,0 +1,6 @@
|
||||
[wheel]
|
||||
universal = True
|
||||
|
||||
[flake8]
|
||||
exclude = youtube_dl/extractor/__init__.py,devscripts/buildserver.py,setup.py,build,.git
|
||||
ignore = E402,E501,E731
|
||||
111
setup.py
Normal file
111
setup.py
Normal file
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os.path
|
||||
import warnings
|
||||
import sys
|
||||
|
||||
try:
|
||||
from setuptools import setup
|
||||
setuptools_available = True
|
||||
except ImportError:
|
||||
from distutils.core import setup
|
||||
setuptools_available = False
|
||||
|
||||
try:
|
||||
# This will create an exe that needs Microsoft Visual C++ 2008
|
||||
# Redistributable Package
|
||||
import py2exe
|
||||
except ImportError:
|
||||
if len(sys.argv) >= 2 and sys.argv[1] == 'py2exe':
|
||||
print("Cannot import py2exe", file=sys.stderr)
|
||||
exit(1)
|
||||
|
||||
py2exe_options = {
|
||||
"bundle_files": 1,
|
||||
"compressed": 1,
|
||||
"optimize": 2,
|
||||
"dist_dir": '.',
|
||||
"dll_excludes": ['w9xpopen.exe', 'crypt32.dll'],
|
||||
}
|
||||
|
||||
py2exe_console = [{
|
||||
"script": "./youtube_dl/__main__.py",
|
||||
"dest_base": "youtube-dl",
|
||||
}]
|
||||
|
||||
py2exe_params = {
|
||||
'console': py2exe_console,
|
||||
'options': {"py2exe": py2exe_options},
|
||||
'zipfile': None
|
||||
}
|
||||
|
||||
if len(sys.argv) >= 2 and sys.argv[1] == 'py2exe':
|
||||
params = py2exe_params
|
||||
else:
|
||||
files_spec = [
|
||||
('etc/bash_completion.d', ['youtube-dl.bash-completion']),
|
||||
('etc/fish/completions', ['youtube-dl.fish']),
|
||||
('share/doc/youtube_dl', ['README.txt']),
|
||||
('share/man/man1', ['youtube-dl.1'])
|
||||
]
|
||||
root = os.path.dirname(os.path.abspath(__file__))
|
||||
data_files = []
|
||||
for dirname, files in files_spec:
|
||||
resfiles = []
|
||||
for fn in files:
|
||||
if not os.path.exists(fn):
|
||||
warnings.warn('Skipping file %s since it is not present. Type make to build all automatically generated files.' % fn)
|
||||
else:
|
||||
resfiles.append(fn)
|
||||
data_files.append((dirname, resfiles))
|
||||
|
||||
params = {
|
||||
'data_files': data_files,
|
||||
}
|
||||
if setuptools_available:
|
||||
params['entry_points'] = {'console_scripts': ['youtube-dl = youtube_dl:main']}
|
||||
else:
|
||||
params['scripts'] = ['bin/youtube-dl']
|
||||
|
||||
# Get the version from youtube_dl/version.py without importing the package
|
||||
exec(compile(open('youtube_dl/version.py').read(),
|
||||
'youtube_dl/version.py', 'exec'))
|
||||
|
||||
setup(
|
||||
name='youtube_dl',
|
||||
version=__version__,
|
||||
description='YouTube video downloader',
|
||||
long_description='Small command-line program to download videos from'
|
||||
' YouTube.com and other video sites.',
|
||||
url='https://github.com/rg3/youtube-dl',
|
||||
author='Ricardo Garcia',
|
||||
author_email='ytdl@yt-dl.org',
|
||||
maintainer='Philipp Hagemeister',
|
||||
maintainer_email='phihag@phihag.de',
|
||||
packages=[
|
||||
'youtube_dl',
|
||||
'youtube_dl.extractor', 'youtube_dl.downloader',
|
||||
'youtube_dl.postprocessor'],
|
||||
|
||||
# Provokes warning on most systems (why?!)
|
||||
# test_suite = 'nose.collector',
|
||||
# test_requires = ['nosetest'],
|
||||
|
||||
classifiers=[
|
||||
"Topic :: Multimedia :: Video",
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Environment :: Console",
|
||||
"License :: Public Domain",
|
||||
"Programming Language :: Python :: 2.6",
|
||||
"Programming Language :: Python :: 2.7",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.2",
|
||||
"Programming Language :: Python :: 3.3",
|
||||
"Programming Language :: Python :: 3.4",
|
||||
],
|
||||
|
||||
**params
|
||||
)
|
||||
0
test/__init__.py
Normal file
0
test/__init__.py
Normal file
235
test/helper.py
Normal file
235
test/helper.py
Normal file
@@ -0,0 +1,235 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import errno
|
||||
import io
|
||||
import hashlib
|
||||
import json
|
||||
import os.path
|
||||
import re
|
||||
import types
|
||||
import sys
|
||||
|
||||
import youtube_dl.extractor
|
||||
from youtube_dl import YoutubeDL
|
||||
from youtube_dl.utils import (
|
||||
compat_str,
|
||||
preferredencoding,
|
||||
write_string,
|
||||
)
|
||||
|
||||
|
||||
def get_params(override=None):
|
||||
PARAMETERS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||
"parameters.json")
|
||||
with io.open(PARAMETERS_FILE, encoding='utf-8') as pf:
|
||||
parameters = json.load(pf)
|
||||
if override:
|
||||
parameters.update(override)
|
||||
return parameters
|
||||
|
||||
|
||||
def try_rm(filename):
|
||||
""" Remove a file if it exists """
|
||||
try:
|
||||
os.remove(filename)
|
||||
except OSError as ose:
|
||||
if ose.errno != errno.ENOENT:
|
||||
raise
|
||||
|
||||
|
||||
def report_warning(message):
|
||||
'''
|
||||
Print the message to stderr, it will be prefixed with 'WARNING:'
|
||||
If stderr is a tty file the 'WARNING:' will be colored
|
||||
'''
|
||||
if sys.stderr.isatty() and os.name != 'nt':
|
||||
_msg_header = '\033[0;33mWARNING:\033[0m'
|
||||
else:
|
||||
_msg_header = 'WARNING:'
|
||||
output = '%s %s\n' % (_msg_header, message)
|
||||
if 'b' in getattr(sys.stderr, 'mode', '') or sys.version_info[0] < 3:
|
||||
output = output.encode(preferredencoding())
|
||||
sys.stderr.write(output)
|
||||
|
||||
|
||||
class FakeYDL(YoutubeDL):
|
||||
def __init__(self, override=None):
|
||||
# Different instances of the downloader can't share the same dictionary
|
||||
# some test set the "sublang" parameter, which would break the md5 checks.
|
||||
params = get_params(override=override)
|
||||
super(FakeYDL, self).__init__(params, auto_init=False)
|
||||
self.result = []
|
||||
|
||||
def to_screen(self, s, skip_eol=None):
|
||||
print(s)
|
||||
|
||||
def trouble(self, s, tb=None):
|
||||
raise Exception(s)
|
||||
|
||||
def download(self, x):
|
||||
self.result.append(x)
|
||||
|
||||
def expect_warning(self, regex):
|
||||
# Silence an expected warning matching a regex
|
||||
old_report_warning = self.report_warning
|
||||
|
||||
def report_warning(self, message):
|
||||
if re.match(regex, message):
|
||||
return
|
||||
old_report_warning(message)
|
||||
self.report_warning = types.MethodType(report_warning, self)
|
||||
|
||||
|
||||
def gettestcases(include_onlymatching=False):
|
||||
for ie in youtube_dl.extractor.gen_extractors():
|
||||
for tc in ie.get_testcases(include_onlymatching):
|
||||
yield tc
|
||||
|
||||
|
||||
md5 = lambda s: hashlib.md5(s.encode('utf-8')).hexdigest()
|
||||
|
||||
|
||||
def expect_value(self, got, expected, field):
|
||||
if isinstance(expected, compat_str) and expected.startswith('re:'):
|
||||
match_str = expected[len('re:'):]
|
||||
match_rex = re.compile(match_str)
|
||||
|
||||
self.assertTrue(
|
||||
isinstance(got, compat_str),
|
||||
'Expected a %s object, but got %s for field %s' % (
|
||||
compat_str.__name__, type(got).__name__, field))
|
||||
self.assertTrue(
|
||||
match_rex.match(got),
|
||||
'field %s (value: %r) should match %r' % (field, got, match_str))
|
||||
elif isinstance(expected, compat_str) and expected.startswith('startswith:'):
|
||||
start_str = expected[len('startswith:'):]
|
||||
self.assertTrue(
|
||||
isinstance(got, compat_str),
|
||||
'Expected a %s object, but got %s for field %s' % (
|
||||
compat_str.__name__, type(got).__name__, field))
|
||||
self.assertTrue(
|
||||
got.startswith(start_str),
|
||||
'field %s (value: %r) should start with %r' % (field, got, start_str))
|
||||
elif isinstance(expected, compat_str) and expected.startswith('contains:'):
|
||||
contains_str = expected[len('contains:'):]
|
||||
self.assertTrue(
|
||||
isinstance(got, compat_str),
|
||||
'Expected a %s object, but got %s for field %s' % (
|
||||
compat_str.__name__, type(got).__name__, field))
|
||||
self.assertTrue(
|
||||
contains_str in got,
|
||||
'field %s (value: %r) should contain %r' % (field, got, contains_str))
|
||||
elif isinstance(expected, type):
|
||||
self.assertTrue(
|
||||
isinstance(got, expected),
|
||||
'Expected type %r for field %s, but got value %r of type %r' % (expected, field, got, type(got)))
|
||||
elif isinstance(expected, dict) and isinstance(got, dict):
|
||||
expect_dict(self, got, expected)
|
||||
elif isinstance(expected, list) and isinstance(got, list):
|
||||
self.assertEqual(
|
||||
len(expected), len(got),
|
||||
'Expect a list of length %d, but got a list of length %d for field %s' % (
|
||||
len(expected), len(got), field))
|
||||
for index, (item_got, item_expected) in enumerate(zip(got, expected)):
|
||||
type_got = type(item_got)
|
||||
type_expected = type(item_expected)
|
||||
self.assertEqual(
|
||||
type_expected, type_got,
|
||||
'Type mismatch for list item at index %d for field %s, expected %r, got %r' % (
|
||||
index, field, type_expected, type_got))
|
||||
expect_value(self, item_got, item_expected, field)
|
||||
else:
|
||||
if isinstance(expected, compat_str) and expected.startswith('md5:'):
|
||||
got = 'md5:' + md5(got)
|
||||
elif isinstance(expected, compat_str) and expected.startswith('mincount:'):
|
||||
self.assertTrue(
|
||||
isinstance(got, (list, dict)),
|
||||
'Expected field %s to be a list or a dict, but it is of type %s' % (
|
||||
field, type(got).__name__))
|
||||
expected_num = int(expected.partition(':')[2])
|
||||
assertGreaterEqual(
|
||||
self, len(got), expected_num,
|
||||
'Expected %d items in field %s, but only got %d' % (expected_num, field, len(got)))
|
||||
return
|
||||
self.assertEqual(
|
||||
expected, got,
|
||||
'Invalid value for field %s, expected %r, got %r' % (field, expected, got))
|
||||
|
||||
|
||||
def expect_dict(self, got_dict, expected_dict):
|
||||
for info_field, expected in expected_dict.items():
|
||||
got = got_dict.get(info_field)
|
||||
expect_value(self, got, expected, info_field)
|
||||
|
||||
|
||||
def expect_info_dict(self, got_dict, expected_dict):
|
||||
expect_dict(self, got_dict, expected_dict)
|
||||
# Check for the presence of mandatory fields
|
||||
if got_dict.get('_type') not in ('playlist', 'multi_video'):
|
||||
for key in ('id', 'url', 'title', 'ext'):
|
||||
self.assertTrue(got_dict.get(key), 'Missing mandatory field %s' % key)
|
||||
# Check for mandatory fields that are automatically set by YoutubeDL
|
||||
for key in ['webpage_url', 'extractor', 'extractor_key']:
|
||||
self.assertTrue(got_dict.get(key), 'Missing field: %s' % key)
|
||||
|
||||
# Are checkable fields missing from the test case definition?
|
||||
test_info_dict = dict((key, value if not isinstance(value, compat_str) or len(value) < 250 else 'md5:' + md5(value))
|
||||
for key, value in got_dict.items()
|
||||
if value and key in ('id', 'title', 'description', 'uploader', 'upload_date', 'timestamp', 'uploader_id', 'location', 'age_limit'))
|
||||
missing_keys = set(test_info_dict.keys()) - set(expected_dict.keys())
|
||||
if missing_keys:
|
||||
def _repr(v):
|
||||
if isinstance(v, compat_str):
|
||||
return "'%s'" % v.replace('\\', '\\\\').replace("'", "\\'").replace('\n', '\\n')
|
||||
else:
|
||||
return repr(v)
|
||||
info_dict_str = ''
|
||||
if len(missing_keys) != len(expected_dict):
|
||||
info_dict_str += ''.join(
|
||||
' %s: %s,\n' % (_repr(k), _repr(v))
|
||||
for k, v in test_info_dict.items() if k not in missing_keys)
|
||||
|
||||
if info_dict_str:
|
||||
info_dict_str += '\n'
|
||||
info_dict_str += ''.join(
|
||||
' %s: %s,\n' % (_repr(k), _repr(test_info_dict[k]))
|
||||
for k in missing_keys)
|
||||
write_string(
|
||||
'\n\'info_dict\': {\n' + info_dict_str + '},\n', out=sys.stderr)
|
||||
self.assertFalse(
|
||||
missing_keys,
|
||||
'Missing keys in test definition: %s' % (
|
||||
', '.join(sorted(missing_keys))))
|
||||
|
||||
|
||||
def assertRegexpMatches(self, text, regexp, msg=None):
|
||||
if hasattr(self, 'assertRegexp'):
|
||||
return self.assertRegexp(text, regexp, msg)
|
||||
else:
|
||||
m = re.match(regexp, text)
|
||||
if not m:
|
||||
note = 'Regexp didn\'t match: %r not found' % (regexp)
|
||||
if len(text) < 1000:
|
||||
note += ' in %r' % text
|
||||
if msg is None:
|
||||
msg = note
|
||||
else:
|
||||
msg = note + ', ' + msg
|
||||
self.assertTrue(m, msg)
|
||||
|
||||
|
||||
def assertGreaterEqual(self, got, expected, msg=None):
|
||||
if not (got >= expected):
|
||||
if msg is None:
|
||||
msg = '%r not greater than or equal to %r' % (got, expected)
|
||||
self.assertTrue(got >= expected, msg)
|
||||
|
||||
|
||||
def expect_warnings(ydl, warnings_re):
|
||||
real_warning = ydl.report_warning
|
||||
|
||||
def _report_warning(w):
|
||||
if not any(re.search(w_re, w) for w_re in warnings_re):
|
||||
real_warning(w)
|
||||
|
||||
ydl.report_warning = _report_warning
|
||||
43
test/parameters.json
Normal file
43
test/parameters.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"consoletitle": false,
|
||||
"continuedl": true,
|
||||
"forcedescription": false,
|
||||
"forcefilename": false,
|
||||
"forceformat": false,
|
||||
"forcethumbnail": false,
|
||||
"forcetitle": false,
|
||||
"forceurl": false,
|
||||
"format": "best",
|
||||
"ignoreerrors": false,
|
||||
"listformats": null,
|
||||
"logtostderr": false,
|
||||
"matchtitle": null,
|
||||
"max_downloads": null,
|
||||
"nooverwrites": false,
|
||||
"nopart": false,
|
||||
"noprogress": false,
|
||||
"outtmpl": "%(id)s.%(ext)s",
|
||||
"password": null,
|
||||
"playlistend": -1,
|
||||
"playliststart": 1,
|
||||
"prefer_free_formats": false,
|
||||
"quiet": false,
|
||||
"ratelimit": null,
|
||||
"rejecttitle": null,
|
||||
"retries": 10,
|
||||
"simulate": false,
|
||||
"subtitleslang": null,
|
||||
"subtitlesformat": "best",
|
||||
"test": true,
|
||||
"updatetime": true,
|
||||
"usenetrc": false,
|
||||
"username": null,
|
||||
"verbose": true,
|
||||
"writedescription": false,
|
||||
"writeinfojson": true,
|
||||
"writesubtitles": false,
|
||||
"allsubtitles": false,
|
||||
"listssubtitles": false,
|
||||
"socket_timeout": 20,
|
||||
"fixup": "never"
|
||||
}
|
||||
1
test/swftests/.gitignore
vendored
Normal file
1
test/swftests/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.swf
|
||||
19
test/swftests/ArrayAccess.as
Normal file
19
test/swftests/ArrayAccess.as
Normal file
@@ -0,0 +1,19 @@
|
||||
// input: [["a", "b", "c", "d"]]
|
||||
// output: ["c", "b", "a", "d"]
|
||||
|
||||
package {
|
||||
public class ArrayAccess {
|
||||
public static function main(ar:Array):Array {
|
||||
var aa:ArrayAccess = new ArrayAccess();
|
||||
return aa.f(ar, 2);
|
||||
}
|
||||
|
||||
private function f(ar:Array, num:Number):Array{
|
||||
var x:String = ar[0];
|
||||
var y:String = ar[num % ar.length];
|
||||
ar[0] = y;
|
||||
ar[num] = x;
|
||||
return ar;
|
||||
}
|
||||
}
|
||||
}
|
||||
17
test/swftests/ClassCall.as
Normal file
17
test/swftests/ClassCall.as
Normal file
@@ -0,0 +1,17 @@
|
||||
// input: []
|
||||
// output: 121
|
||||
|
||||
package {
|
||||
public class ClassCall {
|
||||
public static function main():int{
|
||||
var f:OtherClass = new OtherClass();
|
||||
return f.func(100,20);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class OtherClass {
|
||||
public function func(x: int, y: int):int {
|
||||
return x+y+1;
|
||||
}
|
||||
}
|
||||
15
test/swftests/ClassConstruction.as
Normal file
15
test/swftests/ClassConstruction.as
Normal file
@@ -0,0 +1,15 @@
|
||||
// input: []
|
||||
// output: 0
|
||||
|
||||
package {
|
||||
public class ClassConstruction {
|
||||
public static function main():int{
|
||||
var f:Foo = new Foo();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
|
||||
}
|
||||
18
test/swftests/ConstArrayAccess.as
Normal file
18
test/swftests/ConstArrayAccess.as
Normal file
@@ -0,0 +1,18 @@
|
||||
// input: []
|
||||
// output: 4
|
||||
|
||||
package {
|
||||
public class ConstArrayAccess {
|
||||
private static const x:int = 2;
|
||||
private static const ar:Array = ["42", "3411"];
|
||||
|
||||
public static function main():int{
|
||||
var c:ConstArrayAccess = new ConstArrayAccess();
|
||||
return c.f();
|
||||
}
|
||||
|
||||
public function f(): int {
|
||||
return ar[1].length;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
test/swftests/ConstantInt.as
Normal file
12
test/swftests/ConstantInt.as
Normal file
@@ -0,0 +1,12 @@
|
||||
// input: []
|
||||
// output: 2
|
||||
|
||||
package {
|
||||
public class ConstantInt {
|
||||
private static const x:int = 2;
|
||||
|
||||
public static function main():int{
|
||||
return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
10
test/swftests/DictCall.as
Normal file
10
test/swftests/DictCall.as
Normal file
@@ -0,0 +1,10 @@
|
||||
// input: [{"x": 1, "y": 2}]
|
||||
// output: 3
|
||||
|
||||
package {
|
||||
public class DictCall {
|
||||
public static function main(d:Object):int{
|
||||
return d.x + d.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
10
test/swftests/EqualsOperator.as
Normal file
10
test/swftests/EqualsOperator.as
Normal file
@@ -0,0 +1,10 @@
|
||||
// input: []
|
||||
// output: false
|
||||
|
||||
package {
|
||||
public class EqualsOperator {
|
||||
public static function main():Boolean{
|
||||
return 1 == 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
13
test/swftests/LocalVars.as
Normal file
13
test/swftests/LocalVars.as
Normal file
@@ -0,0 +1,13 @@
|
||||
// input: [1, 2]
|
||||
// output: 3
|
||||
|
||||
package {
|
||||
public class LocalVars {
|
||||
public static function main(a:int, b:int):int{
|
||||
var c:int = a + b + b;
|
||||
var d:int = c - b;
|
||||
var e:int = d;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
22
test/swftests/MemberAssignment.as
Normal file
22
test/swftests/MemberAssignment.as
Normal file
@@ -0,0 +1,22 @@
|
||||
// input: [1]
|
||||
// output: 2
|
||||
|
||||
package {
|
||||
public class MemberAssignment {
|
||||
public var v:int;
|
||||
|
||||
public function g():int {
|
||||
return this.v;
|
||||
}
|
||||
|
||||
public function f(a:int):int{
|
||||
this.v = a;
|
||||
return this.v + this.g();
|
||||
}
|
||||
|
||||
public static function main(a:int): int {
|
||||
var v:MemberAssignment = new MemberAssignment();
|
||||
return v.f(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
24
test/swftests/NeOperator.as
Normal file
24
test/swftests/NeOperator.as
Normal file
@@ -0,0 +1,24 @@
|
||||
// input: []
|
||||
// output: 123
|
||||
|
||||
package {
|
||||
public class NeOperator {
|
||||
public static function main(): int {
|
||||
var res:int = 0;
|
||||
if (1 != 2) {
|
||||
res += 3;
|
||||
} else {
|
||||
res += 4;
|
||||
}
|
||||
if (2 != 2) {
|
||||
res += 10;
|
||||
} else {
|
||||
res += 20;
|
||||
}
|
||||
if (9 == 9) {
|
||||
res += 100;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
21
test/swftests/PrivateCall.as
Normal file
21
test/swftests/PrivateCall.as
Normal file
@@ -0,0 +1,21 @@
|
||||
// input: []
|
||||
// output: 9
|
||||
|
||||
package {
|
||||
public class PrivateCall {
|
||||
public static function main():int{
|
||||
var f:OtherClass = new OtherClass();
|
||||
return f.func();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class OtherClass {
|
||||
private function pf():int {
|
||||
return 9;
|
||||
}
|
||||
|
||||
public function func():int {
|
||||
return this.pf();
|
||||
}
|
||||
}
|
||||
22
test/swftests/PrivateVoidCall.as
Normal file
22
test/swftests/PrivateVoidCall.as
Normal file
@@ -0,0 +1,22 @@
|
||||
// input: []
|
||||
// output: 9
|
||||
|
||||
package {
|
||||
public class PrivateVoidCall {
|
||||
public static function main():int{
|
||||
var f:OtherClass = new OtherClass();
|
||||
f.func();
|
||||
return 9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class OtherClass {
|
||||
private function pf():void {
|
||||
;
|
||||
}
|
||||
|
||||
public function func():void {
|
||||
this.pf();
|
||||
}
|
||||
}
|
||||
13
test/swftests/StaticAssignment.as
Normal file
13
test/swftests/StaticAssignment.as
Normal file
@@ -0,0 +1,13 @@
|
||||
// input: [1]
|
||||
// output: 1
|
||||
|
||||
package {
|
||||
public class StaticAssignment {
|
||||
public static var v:int;
|
||||
|
||||
public static function main(a:int):int{
|
||||
v = a;
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
test/swftests/StaticRetrieval.as
Normal file
16
test/swftests/StaticRetrieval.as
Normal file
@@ -0,0 +1,16 @@
|
||||
// input: []
|
||||
// output: 1
|
||||
|
||||
package {
|
||||
public class StaticRetrieval {
|
||||
public static var v:int;
|
||||
|
||||
public static function main():int{
|
||||
if (v) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
test/swftests/StringBasics.as
Normal file
11
test/swftests/StringBasics.as
Normal file
@@ -0,0 +1,11 @@
|
||||
// input: []
|
||||
// output: 3
|
||||
|
||||
package {
|
||||
public class StringBasics {
|
||||
public static function main():int{
|
||||
var s:String = "abc";
|
||||
return s.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
test/swftests/StringCharCodeAt.as
Normal file
11
test/swftests/StringCharCodeAt.as
Normal file
@@ -0,0 +1,11 @@
|
||||
// input: []
|
||||
// output: 9897
|
||||
|
||||
package {
|
||||
public class StringCharCodeAt {
|
||||
public static function main():int{
|
||||
var s:String = "abc";
|
||||
return s.charCodeAt(1) * 100 + s.charCodeAt();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
test/swftests/StringConversion.as
Normal file
11
test/swftests/StringConversion.as
Normal file
@@ -0,0 +1,11 @@
|
||||
// input: []
|
||||
// output: 2
|
||||
|
||||
package {
|
||||
public class StringConversion {
|
||||
public static function main():int{
|
||||
var s:String = String(99);
|
||||
return s.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
70
test/test_InfoExtractor.py
Normal file
70
test/test_InfoExtractor.py
Normal file
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Allow direct execution
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from test.helper import FakeYDL
|
||||
from youtube_dl.extractor.common import InfoExtractor
|
||||
from youtube_dl.extractor import YoutubeIE, get_info_extractor
|
||||
|
||||
|
||||
class TestIE(InfoExtractor):
|
||||
pass
|
||||
|
||||
|
||||
class TestInfoExtractor(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.ie = TestIE(FakeYDL())
|
||||
|
||||
def test_ie_key(self):
|
||||
self.assertEqual(get_info_extractor(YoutubeIE.ie_key()), YoutubeIE)
|
||||
|
||||
def test_html_search_regex(self):
|
||||
html = '<p id="foo">Watch this <a href="http://www.youtube.com/watch?v=BaW_jenozKc">video</a></p>'
|
||||
search = lambda re, *args: self.ie._html_search_regex(re, html, *args)
|
||||
self.assertEqual(search(r'<p id="foo">(.+?)</p>', 'foo'), 'Watch this video')
|
||||
|
||||
def test_opengraph(self):
|
||||
ie = self.ie
|
||||
html = '''
|
||||
<meta name="og:title" content='Foo'/>
|
||||
<meta content="Some video's description " name="og:description"/>
|
||||
<meta property='og:image' content='http://domain.com/pic.jpg?key1=val1&key2=val2'/>
|
||||
<meta content='application/x-shockwave-flash' property='og:video:type'>
|
||||
<meta content='Foo' property=og:foobar>
|
||||
<meta name="og:test1" content='foo > < bar'/>
|
||||
<meta name="og:test2" content="foo >//< bar"/>
|
||||
'''
|
||||
self.assertEqual(ie._og_search_title(html), 'Foo')
|
||||
self.assertEqual(ie._og_search_description(html), 'Some video\'s description ')
|
||||
self.assertEqual(ie._og_search_thumbnail(html), 'http://domain.com/pic.jpg?key1=val1&key2=val2')
|
||||
self.assertEqual(ie._og_search_video_url(html, default=None), None)
|
||||
self.assertEqual(ie._og_search_property('foobar', html), 'Foo')
|
||||
self.assertEqual(ie._og_search_property('test1', html), 'foo > < bar')
|
||||
self.assertEqual(ie._og_search_property('test2', html), 'foo >//< bar')
|
||||
|
||||
def test_html_search_meta(self):
|
||||
ie = self.ie
|
||||
html = '''
|
||||
<meta name="a" content="1" />
|
||||
<meta name='b' content='2'>
|
||||
<meta name="c" content='3'>
|
||||
<meta name=d content='4'>
|
||||
<meta property="e" content='5' >
|
||||
<meta content="6" name="f">
|
||||
'''
|
||||
|
||||
self.assertEqual(ie._html_search_meta('a', html), '1')
|
||||
self.assertEqual(ie._html_search_meta('b', html), '2')
|
||||
self.assertEqual(ie._html_search_meta('c', html), '3')
|
||||
self.assertEqual(ie._html_search_meta('d', html), '4')
|
||||
self.assertEqual(ie._html_search_meta('e', html), '5')
|
||||
self.assertEqual(ie._html_search_meta('f', html), '6')
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
636
test/test_YoutubeDL.py
Normal file
636
test/test_YoutubeDL.py
Normal file
@@ -0,0 +1,636 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Allow direct execution
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
import copy
|
||||
|
||||
from test.helper import FakeYDL, assertRegexpMatches
|
||||
from youtube_dl import YoutubeDL
|
||||
from youtube_dl.compat import compat_str
|
||||
from youtube_dl.extractor import YoutubeIE
|
||||
from youtube_dl.postprocessor.common import PostProcessor
|
||||
from youtube_dl.utils import ExtractorError, match_filter_func
|
||||
|
||||
TEST_URL = 'http://localhost/sample.mp4'
|
||||
|
||||
|
||||
class YDL(FakeYDL):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(YDL, self).__init__(*args, **kwargs)
|
||||
self.downloaded_info_dicts = []
|
||||
self.msgs = []
|
||||
|
||||
def process_info(self, info_dict):
|
||||
self.downloaded_info_dicts.append(info_dict)
|
||||
|
||||
def to_screen(self, msg):
|
||||
self.msgs.append(msg)
|
||||
|
||||
|
||||
def _make_result(formats, **kwargs):
|
||||
res = {
|
||||
'formats': formats,
|
||||
'id': 'testid',
|
||||
'title': 'testttitle',
|
||||
'extractor': 'testex',
|
||||
}
|
||||
res.update(**kwargs)
|
||||
return res
|
||||
|
||||
|
||||
class TestFormatSelection(unittest.TestCase):
|
||||
def test_prefer_free_formats(self):
|
||||
# Same resolution => download webm
|
||||
ydl = YDL()
|
||||
ydl.params['prefer_free_formats'] = True
|
||||
formats = [
|
||||
{'ext': 'webm', 'height': 460, 'url': TEST_URL},
|
||||
{'ext': 'mp4', 'height': 460, 'url': TEST_URL},
|
||||
]
|
||||
info_dict = _make_result(formats)
|
||||
yie = YoutubeIE(ydl)
|
||||
yie._sort_formats(info_dict['formats'])
|
||||
ydl.process_ie_result(info_dict)
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['ext'], 'webm')
|
||||
|
||||
# Different resolution => download best quality (mp4)
|
||||
ydl = YDL()
|
||||
ydl.params['prefer_free_formats'] = True
|
||||
formats = [
|
||||
{'ext': 'webm', 'height': 720, 'url': TEST_URL},
|
||||
{'ext': 'mp4', 'height': 1080, 'url': TEST_URL},
|
||||
]
|
||||
info_dict['formats'] = formats
|
||||
yie = YoutubeIE(ydl)
|
||||
yie._sort_formats(info_dict['formats'])
|
||||
ydl.process_ie_result(info_dict)
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['ext'], 'mp4')
|
||||
|
||||
# No prefer_free_formats => prefer mp4 and flv for greater compatibility
|
||||
ydl = YDL()
|
||||
ydl.params['prefer_free_formats'] = False
|
||||
formats = [
|
||||
{'ext': 'webm', 'height': 720, 'url': TEST_URL},
|
||||
{'ext': 'mp4', 'height': 720, 'url': TEST_URL},
|
||||
{'ext': 'flv', 'height': 720, 'url': TEST_URL},
|
||||
]
|
||||
info_dict['formats'] = formats
|
||||
yie = YoutubeIE(ydl)
|
||||
yie._sort_formats(info_dict['formats'])
|
||||
ydl.process_ie_result(info_dict)
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['ext'], 'mp4')
|
||||
|
||||
ydl = YDL()
|
||||
ydl.params['prefer_free_formats'] = False
|
||||
formats = [
|
||||
{'ext': 'flv', 'height': 720, 'url': TEST_URL},
|
||||
{'ext': 'webm', 'height': 720, 'url': TEST_URL},
|
||||
]
|
||||
info_dict['formats'] = formats
|
||||
yie = YoutubeIE(ydl)
|
||||
yie._sort_formats(info_dict['formats'])
|
||||
ydl.process_ie_result(info_dict)
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['ext'], 'flv')
|
||||
|
||||
def test_format_selection(self):
|
||||
formats = [
|
||||
{'format_id': '35', 'ext': 'mp4', 'preference': 1, 'url': TEST_URL},
|
||||
{'format_id': 'example-with-dashes', 'ext': 'webm', 'preference': 1, 'url': TEST_URL},
|
||||
{'format_id': '45', 'ext': 'webm', 'preference': 2, 'url': TEST_URL},
|
||||
{'format_id': '47', 'ext': 'webm', 'preference': 3, 'url': TEST_URL},
|
||||
{'format_id': '2', 'ext': 'flv', 'preference': 4, 'url': TEST_URL},
|
||||
]
|
||||
info_dict = _make_result(formats)
|
||||
|
||||
ydl = YDL({'format': '20/47'})
|
||||
ydl.process_ie_result(info_dict.copy())
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], '47')
|
||||
|
||||
ydl = YDL({'format': '20/71/worst'})
|
||||
ydl.process_ie_result(info_dict.copy())
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], '35')
|
||||
|
||||
ydl = YDL()
|
||||
ydl.process_ie_result(info_dict.copy())
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], '2')
|
||||
|
||||
ydl = YDL({'format': 'webm/mp4'})
|
||||
ydl.process_ie_result(info_dict.copy())
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], '47')
|
||||
|
||||
ydl = YDL({'format': '3gp/40/mp4'})
|
||||
ydl.process_ie_result(info_dict.copy())
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], '35')
|
||||
|
||||
ydl = YDL({'format': 'example-with-dashes'})
|
||||
ydl.process_ie_result(info_dict.copy())
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], 'example-with-dashes')
|
||||
|
||||
def test_format_selection_audio(self):
|
||||
formats = [
|
||||
{'format_id': 'audio-low', 'ext': 'webm', 'preference': 1, 'vcodec': 'none', 'url': TEST_URL},
|
||||
{'format_id': 'audio-mid', 'ext': 'webm', 'preference': 2, 'vcodec': 'none', 'url': TEST_URL},
|
||||
{'format_id': 'audio-high', 'ext': 'flv', 'preference': 3, 'vcodec': 'none', 'url': TEST_URL},
|
||||
{'format_id': 'vid', 'ext': 'mp4', 'preference': 4, 'url': TEST_URL},
|
||||
]
|
||||
info_dict = _make_result(formats)
|
||||
|
||||
ydl = YDL({'format': 'bestaudio'})
|
||||
ydl.process_ie_result(info_dict.copy())
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], 'audio-high')
|
||||
|
||||
ydl = YDL({'format': 'worstaudio'})
|
||||
ydl.process_ie_result(info_dict.copy())
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], 'audio-low')
|
||||
|
||||
formats = [
|
||||
{'format_id': 'vid-low', 'ext': 'mp4', 'preference': 1, 'url': TEST_URL},
|
||||
{'format_id': 'vid-high', 'ext': 'mp4', 'preference': 2, 'url': TEST_URL},
|
||||
]
|
||||
info_dict = _make_result(formats)
|
||||
|
||||
ydl = YDL({'format': 'bestaudio/worstaudio/best'})
|
||||
ydl.process_ie_result(info_dict.copy())
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], 'vid-high')
|
||||
|
||||
def test_format_selection_audio_exts(self):
|
||||
formats = [
|
||||
{'format_id': 'mp3-64', 'ext': 'mp3', 'abr': 64, 'url': 'http://_', 'vcodec': 'none'},
|
||||
{'format_id': 'ogg-64', 'ext': 'ogg', 'abr': 64, 'url': 'http://_', 'vcodec': 'none'},
|
||||
{'format_id': 'aac-64', 'ext': 'aac', 'abr': 64, 'url': 'http://_', 'vcodec': 'none'},
|
||||
{'format_id': 'mp3-32', 'ext': 'mp3', 'abr': 32, 'url': 'http://_', 'vcodec': 'none'},
|
||||
{'format_id': 'aac-32', 'ext': 'aac', 'abr': 32, 'url': 'http://_', 'vcodec': 'none'},
|
||||
]
|
||||
|
||||
info_dict = _make_result(formats)
|
||||
ydl = YDL({'format': 'best'})
|
||||
ie = YoutubeIE(ydl)
|
||||
ie._sort_formats(info_dict['formats'])
|
||||
ydl.process_ie_result(copy.deepcopy(info_dict))
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], 'aac-64')
|
||||
|
||||
ydl = YDL({'format': 'mp3'})
|
||||
ie = YoutubeIE(ydl)
|
||||
ie._sort_formats(info_dict['formats'])
|
||||
ydl.process_ie_result(copy.deepcopy(info_dict))
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], 'mp3-64')
|
||||
|
||||
ydl = YDL({'prefer_free_formats': True})
|
||||
ie = YoutubeIE(ydl)
|
||||
ie._sort_formats(info_dict['formats'])
|
||||
ydl.process_ie_result(copy.deepcopy(info_dict))
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], 'ogg-64')
|
||||
|
||||
def test_format_selection_video(self):
|
||||
formats = [
|
||||
{'format_id': 'dash-video-low', 'ext': 'mp4', 'preference': 1, 'acodec': 'none', 'url': TEST_URL},
|
||||
{'format_id': 'dash-video-high', 'ext': 'mp4', 'preference': 2, 'acodec': 'none', 'url': TEST_URL},
|
||||
{'format_id': 'vid', 'ext': 'mp4', 'preference': 3, 'url': TEST_URL},
|
||||
]
|
||||
info_dict = _make_result(formats)
|
||||
|
||||
ydl = YDL({'format': 'bestvideo'})
|
||||
ydl.process_ie_result(info_dict.copy())
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], 'dash-video-high')
|
||||
|
||||
ydl = YDL({'format': 'worstvideo'})
|
||||
ydl.process_ie_result(info_dict.copy())
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], 'dash-video-low')
|
||||
|
||||
def test_youtube_format_selection(self):
|
||||
order = [
|
||||
'38', '37', '46', '22', '45', '35', '44', '18', '34', '43', '6', '5', '36', '17', '13',
|
||||
# Apple HTTP Live Streaming
|
||||
'96', '95', '94', '93', '92', '132', '151',
|
||||
# 3D
|
||||
'85', '84', '102', '83', '101', '82', '100',
|
||||
# Dash video
|
||||
'137', '248', '136', '247', '135', '246',
|
||||
'245', '244', '134', '243', '133', '242', '160',
|
||||
# Dash audio
|
||||
'141', '172', '140', '171', '139',
|
||||
]
|
||||
|
||||
def format_info(f_id):
|
||||
info = YoutubeIE._formats[f_id].copy()
|
||||
info['format_id'] = f_id
|
||||
info['url'] = 'url:' + f_id
|
||||
return info
|
||||
formats_order = [format_info(f_id) for f_id in order]
|
||||
|
||||
info_dict = _make_result(list(formats_order), extractor='youtube')
|
||||
ydl = YDL({'format': 'bestvideo+bestaudio'})
|
||||
yie = YoutubeIE(ydl)
|
||||
yie._sort_formats(info_dict['formats'])
|
||||
ydl.process_ie_result(info_dict)
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], '137+141')
|
||||
self.assertEqual(downloaded['ext'], 'mp4')
|
||||
|
||||
info_dict = _make_result(list(formats_order), extractor='youtube')
|
||||
ydl = YDL({'format': 'bestvideo[height>=999999]+bestaudio/best'})
|
||||
yie = YoutubeIE(ydl)
|
||||
yie._sort_formats(info_dict['formats'])
|
||||
ydl.process_ie_result(info_dict)
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], '38')
|
||||
|
||||
info_dict = _make_result(list(formats_order), extractor='youtube')
|
||||
ydl = YDL({'format': 'bestvideo/best,bestaudio'})
|
||||
yie = YoutubeIE(ydl)
|
||||
yie._sort_formats(info_dict['formats'])
|
||||
ydl.process_ie_result(info_dict)
|
||||
downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
|
||||
self.assertEqual(downloaded_ids, ['137', '141'])
|
||||
|
||||
info_dict = _make_result(list(formats_order), extractor='youtube')
|
||||
ydl = YDL({'format': '(bestvideo[ext=mp4],bestvideo[ext=webm])+bestaudio'})
|
||||
yie = YoutubeIE(ydl)
|
||||
yie._sort_formats(info_dict['formats'])
|
||||
ydl.process_ie_result(info_dict)
|
||||
downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
|
||||
self.assertEqual(downloaded_ids, ['137+141', '248+141'])
|
||||
|
||||
info_dict = _make_result(list(formats_order), extractor='youtube')
|
||||
ydl = YDL({'format': '(bestvideo[ext=mp4],bestvideo[ext=webm])[height<=720]+bestaudio'})
|
||||
yie = YoutubeIE(ydl)
|
||||
yie._sort_formats(info_dict['formats'])
|
||||
ydl.process_ie_result(info_dict)
|
||||
downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
|
||||
self.assertEqual(downloaded_ids, ['136+141', '247+141'])
|
||||
|
||||
info_dict = _make_result(list(formats_order), extractor='youtube')
|
||||
ydl = YDL({'format': '(bestvideo[ext=none]/bestvideo[ext=webm])+bestaudio'})
|
||||
yie = YoutubeIE(ydl)
|
||||
yie._sort_formats(info_dict['formats'])
|
||||
ydl.process_ie_result(info_dict)
|
||||
downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
|
||||
self.assertEqual(downloaded_ids, ['248+141'])
|
||||
|
||||
for f1, f2 in zip(formats_order, formats_order[1:]):
|
||||
info_dict = _make_result([f1, f2], extractor='youtube')
|
||||
ydl = YDL({'format': 'best/bestvideo'})
|
||||
yie = YoutubeIE(ydl)
|
||||
yie._sort_formats(info_dict['formats'])
|
||||
ydl.process_ie_result(info_dict)
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], f1['format_id'])
|
||||
|
||||
info_dict = _make_result([f2, f1], extractor='youtube')
|
||||
ydl = YDL({'format': 'best/bestvideo'})
|
||||
yie = YoutubeIE(ydl)
|
||||
yie._sort_formats(info_dict['formats'])
|
||||
ydl.process_ie_result(info_dict)
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], f1['format_id'])
|
||||
|
||||
def test_invalid_format_specs(self):
|
||||
def assert_syntax_error(format_spec):
|
||||
ydl = YDL({'format': format_spec})
|
||||
info_dict = _make_result([{'format_id': 'foo', 'url': TEST_URL}])
|
||||
self.assertRaises(SyntaxError, ydl.process_ie_result, info_dict)
|
||||
|
||||
assert_syntax_error('bestvideo,,best')
|
||||
assert_syntax_error('+bestaudio')
|
||||
assert_syntax_error('bestvideo+')
|
||||
assert_syntax_error('/')
|
||||
|
||||
def test_format_filtering(self):
|
||||
formats = [
|
||||
{'format_id': 'A', 'filesize': 500, 'width': 1000},
|
||||
{'format_id': 'B', 'filesize': 1000, 'width': 500},
|
||||
{'format_id': 'C', 'filesize': 1000, 'width': 400},
|
||||
{'format_id': 'D', 'filesize': 2000, 'width': 600},
|
||||
{'format_id': 'E', 'filesize': 3000},
|
||||
{'format_id': 'F'},
|
||||
{'format_id': 'G', 'filesize': 1000000},
|
||||
]
|
||||
for f in formats:
|
||||
f['url'] = 'http://_/'
|
||||
f['ext'] = 'unknown'
|
||||
info_dict = _make_result(formats)
|
||||
|
||||
ydl = YDL({'format': 'best[filesize<3000]'})
|
||||
ydl.process_ie_result(info_dict)
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], 'D')
|
||||
|
||||
ydl = YDL({'format': 'best[filesize<=3000]'})
|
||||
ydl.process_ie_result(info_dict)
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], 'E')
|
||||
|
||||
ydl = YDL({'format': 'best[filesize <= ? 3000]'})
|
||||
ydl.process_ie_result(info_dict)
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], 'F')
|
||||
|
||||
ydl = YDL({'format': 'best [filesize = 1000] [width>450]'})
|
||||
ydl.process_ie_result(info_dict)
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], 'B')
|
||||
|
||||
ydl = YDL({'format': 'best [filesize = 1000] [width!=450]'})
|
||||
ydl.process_ie_result(info_dict)
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], 'C')
|
||||
|
||||
ydl = YDL({'format': '[filesize>?1]'})
|
||||
ydl.process_ie_result(info_dict)
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], 'G')
|
||||
|
||||
ydl = YDL({'format': '[filesize<1M]'})
|
||||
ydl.process_ie_result(info_dict)
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], 'E')
|
||||
|
||||
ydl = YDL({'format': '[filesize<1MiB]'})
|
||||
ydl.process_ie_result(info_dict)
|
||||
downloaded = ydl.downloaded_info_dicts[0]
|
||||
self.assertEqual(downloaded['format_id'], 'G')
|
||||
|
||||
ydl = YDL({'format': 'all[width>=400][width<=600]'})
|
||||
ydl.process_ie_result(info_dict)
|
||||
downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
|
||||
self.assertEqual(downloaded_ids, ['B', 'C', 'D'])
|
||||
|
||||
ydl = YDL({'format': 'best[height<40]'})
|
||||
try:
|
||||
ydl.process_ie_result(info_dict)
|
||||
except ExtractorError:
|
||||
pass
|
||||
self.assertEqual(ydl.downloaded_info_dicts, [])
|
||||
|
||||
|
||||
class TestYoutubeDL(unittest.TestCase):
|
||||
def test_subtitles(self):
|
||||
def s_formats(lang, autocaption=False):
|
||||
return [{
|
||||
'ext': ext,
|
||||
'url': 'http://localhost/video.%s.%s' % (lang, ext),
|
||||
'_auto': autocaption,
|
||||
} for ext in ['vtt', 'srt', 'ass']]
|
||||
subtitles = dict((l, s_formats(l)) for l in ['en', 'fr', 'es'])
|
||||
auto_captions = dict((l, s_formats(l, True)) for l in ['it', 'pt', 'es'])
|
||||
info_dict = {
|
||||
'id': 'test',
|
||||
'title': 'Test',
|
||||
'url': 'http://localhost/video.mp4',
|
||||
'subtitles': subtitles,
|
||||
'automatic_captions': auto_captions,
|
||||
'extractor': 'TEST',
|
||||
}
|
||||
|
||||
def get_info(params={}):
|
||||
params.setdefault('simulate', True)
|
||||
ydl = YDL(params)
|
||||
ydl.report_warning = lambda *args, **kargs: None
|
||||
return ydl.process_video_result(info_dict, download=False)
|
||||
|
||||
result = get_info()
|
||||
self.assertFalse(result.get('requested_subtitles'))
|
||||
self.assertEqual(result['subtitles'], subtitles)
|
||||
self.assertEqual(result['automatic_captions'], auto_captions)
|
||||
|
||||
result = get_info({'writesubtitles': True})
|
||||
subs = result['requested_subtitles']
|
||||
self.assertTrue(subs)
|
||||
self.assertEqual(set(subs.keys()), set(['en']))
|
||||
self.assertTrue(subs['en'].get('data') is None)
|
||||
self.assertEqual(subs['en']['ext'], 'ass')
|
||||
|
||||
result = get_info({'writesubtitles': True, 'subtitlesformat': 'foo/srt'})
|
||||
subs = result['requested_subtitles']
|
||||
self.assertEqual(subs['en']['ext'], 'srt')
|
||||
|
||||
result = get_info({'writesubtitles': True, 'subtitleslangs': ['es', 'fr', 'it']})
|
||||
subs = result['requested_subtitles']
|
||||
self.assertTrue(subs)
|
||||
self.assertEqual(set(subs.keys()), set(['es', 'fr']))
|
||||
|
||||
result = get_info({'writesubtitles': True, 'writeautomaticsub': True, 'subtitleslangs': ['es', 'pt']})
|
||||
subs = result['requested_subtitles']
|
||||
self.assertTrue(subs)
|
||||
self.assertEqual(set(subs.keys()), set(['es', 'pt']))
|
||||
self.assertFalse(subs['es']['_auto'])
|
||||
self.assertTrue(subs['pt']['_auto'])
|
||||
|
||||
result = get_info({'writeautomaticsub': True, 'subtitleslangs': ['es', 'pt']})
|
||||
subs = result['requested_subtitles']
|
||||
self.assertTrue(subs)
|
||||
self.assertEqual(set(subs.keys()), set(['es', 'pt']))
|
||||
self.assertTrue(subs['es']['_auto'])
|
||||
self.assertTrue(subs['pt']['_auto'])
|
||||
|
||||
def test_add_extra_info(self):
|
||||
test_dict = {
|
||||
'extractor': 'Foo',
|
||||
}
|
||||
extra_info = {
|
||||
'extractor': 'Bar',
|
||||
'playlist': 'funny videos',
|
||||
}
|
||||
YDL.add_extra_info(test_dict, extra_info)
|
||||
self.assertEqual(test_dict['extractor'], 'Foo')
|
||||
self.assertEqual(test_dict['playlist'], 'funny videos')
|
||||
|
||||
def test_prepare_filename(self):
|
||||
info = {
|
||||
'id': '1234',
|
||||
'ext': 'mp4',
|
||||
'width': None,
|
||||
}
|
||||
|
||||
def fname(templ):
|
||||
ydl = YoutubeDL({'outtmpl': templ})
|
||||
return ydl.prepare_filename(info)
|
||||
self.assertEqual(fname('%(id)s.%(ext)s'), '1234.mp4')
|
||||
self.assertEqual(fname('%(id)s-%(width)s.%(ext)s'), '1234-NA.mp4')
|
||||
# Replace missing fields with 'NA'
|
||||
self.assertEqual(fname('%(uploader_date)s-%(id)s.%(ext)s'), 'NA-1234.mp4')
|
||||
|
||||
def test_format_note(self):
|
||||
ydl = YoutubeDL()
|
||||
self.assertEqual(ydl._format_note({}), '')
|
||||
assertRegexpMatches(self, ydl._format_note({
|
||||
'vbr': 10,
|
||||
}), '^\s*10k$')
|
||||
|
||||
def test_postprocessors(self):
|
||||
filename = 'post-processor-testfile.mp4'
|
||||
audiofile = filename + '.mp3'
|
||||
|
||||
class SimplePP(PostProcessor):
|
||||
def run(self, info):
|
||||
with open(audiofile, 'wt') as f:
|
||||
f.write('EXAMPLE')
|
||||
return [info['filepath']], info
|
||||
|
||||
def run_pp(params, PP):
|
||||
with open(filename, 'wt') as f:
|
||||
f.write('EXAMPLE')
|
||||
ydl = YoutubeDL(params)
|
||||
ydl.add_post_processor(PP())
|
||||
ydl.post_process(filename, {'filepath': filename})
|
||||
|
||||
run_pp({'keepvideo': True}, SimplePP)
|
||||
self.assertTrue(os.path.exists(filename), '%s doesn\'t exist' % filename)
|
||||
self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile)
|
||||
os.unlink(filename)
|
||||
os.unlink(audiofile)
|
||||
|
||||
run_pp({'keepvideo': False}, SimplePP)
|
||||
self.assertFalse(os.path.exists(filename), '%s exists' % filename)
|
||||
self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile)
|
||||
os.unlink(audiofile)
|
||||
|
||||
class ModifierPP(PostProcessor):
|
||||
def run(self, info):
|
||||
with open(info['filepath'], 'wt') as f:
|
||||
f.write('MODIFIED')
|
||||
return [], info
|
||||
|
||||
run_pp({'keepvideo': False}, ModifierPP)
|
||||
self.assertTrue(os.path.exists(filename), '%s doesn\'t exist' % filename)
|
||||
os.unlink(filename)
|
||||
|
||||
def test_match_filter(self):
|
||||
class FilterYDL(YDL):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(FilterYDL, self).__init__(*args, **kwargs)
|
||||
self.params['simulate'] = True
|
||||
|
||||
def process_info(self, info_dict):
|
||||
super(YDL, self).process_info(info_dict)
|
||||
|
||||
def _match_entry(self, info_dict, incomplete):
|
||||
res = super(FilterYDL, self)._match_entry(info_dict, incomplete)
|
||||
if res is None:
|
||||
self.downloaded_info_dicts.append(info_dict)
|
||||
return res
|
||||
|
||||
first = {
|
||||
'id': '1',
|
||||
'url': TEST_URL,
|
||||
'title': 'one',
|
||||
'extractor': 'TEST',
|
||||
'duration': 30,
|
||||
'filesize': 10 * 1024,
|
||||
}
|
||||
second = {
|
||||
'id': '2',
|
||||
'url': TEST_URL,
|
||||
'title': 'two',
|
||||
'extractor': 'TEST',
|
||||
'duration': 10,
|
||||
'description': 'foo',
|
||||
'filesize': 5 * 1024,
|
||||
}
|
||||
videos = [first, second]
|
||||
|
||||
def get_videos(filter_=None):
|
||||
ydl = FilterYDL({'match_filter': filter_})
|
||||
for v in videos:
|
||||
ydl.process_ie_result(v, download=True)
|
||||
return [v['id'] for v in ydl.downloaded_info_dicts]
|
||||
|
||||
res = get_videos()
|
||||
self.assertEqual(res, ['1', '2'])
|
||||
|
||||
def f(v):
|
||||
if v['id'] == '1':
|
||||
return None
|
||||
else:
|
||||
return 'Video id is not 1'
|
||||
res = get_videos(f)
|
||||
self.assertEqual(res, ['1'])
|
||||
|
||||
f = match_filter_func('duration < 30')
|
||||
res = get_videos(f)
|
||||
self.assertEqual(res, ['2'])
|
||||
|
||||
f = match_filter_func('description = foo')
|
||||
res = get_videos(f)
|
||||
self.assertEqual(res, ['2'])
|
||||
|
||||
f = match_filter_func('description =? foo')
|
||||
res = get_videos(f)
|
||||
self.assertEqual(res, ['1', '2'])
|
||||
|
||||
f = match_filter_func('filesize > 5KiB')
|
||||
res = get_videos(f)
|
||||
self.assertEqual(res, ['1'])
|
||||
|
||||
def test_playlist_items_selection(self):
|
||||
entries = [{
|
||||
'id': compat_str(i),
|
||||
'title': compat_str(i),
|
||||
'url': TEST_URL,
|
||||
} for i in range(1, 5)]
|
||||
playlist = {
|
||||
'_type': 'playlist',
|
||||
'id': 'test',
|
||||
'entries': entries,
|
||||
'extractor': 'test:playlist',
|
||||
'extractor_key': 'test:playlist',
|
||||
'webpage_url': 'http://example.com',
|
||||
}
|
||||
|
||||
def get_ids(params):
|
||||
ydl = YDL(params)
|
||||
# make a copy because the dictionary can be modified
|
||||
ydl.process_ie_result(playlist.copy())
|
||||
return [int(v['id']) for v in ydl.downloaded_info_dicts]
|
||||
|
||||
result = get_ids({})
|
||||
self.assertEqual(result, [1, 2, 3, 4])
|
||||
|
||||
result = get_ids({'playlistend': 10})
|
||||
self.assertEqual(result, [1, 2, 3, 4])
|
||||
|
||||
result = get_ids({'playlistend': 2})
|
||||
self.assertEqual(result, [1, 2])
|
||||
|
||||
result = get_ids({'playliststart': 10})
|
||||
self.assertEqual(result, [])
|
||||
|
||||
result = get_ids({'playliststart': 2})
|
||||
self.assertEqual(result, [2, 3, 4])
|
||||
|
||||
result = get_ids({'playlist_items': '2-4'})
|
||||
self.assertEqual(result, [2, 3, 4])
|
||||
|
||||
result = get_ids({'playlist_items': '2,4'})
|
||||
self.assertEqual(result, [2, 4])
|
||||
|
||||
result = get_ids({'playlist_items': '10'})
|
||||
self.assertEqual(result, [])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
55
test/test_aes.py
Normal file
55
test/test_aes.py
Normal file
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Allow direct execution
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from youtube_dl.aes import aes_decrypt, aes_encrypt, aes_cbc_decrypt, aes_decrypt_text
|
||||
from youtube_dl.utils import bytes_to_intlist, intlist_to_bytes
|
||||
import base64
|
||||
|
||||
# the encrypted data can be generate with 'devscripts/generate_aes_testdata.py'
|
||||
|
||||
|
||||
class TestAES(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.key = self.iv = [0x20, 0x15] + 14 * [0]
|
||||
self.secret_msg = b'Secret message goes here'
|
||||
|
||||
def test_encrypt(self):
|
||||
msg = b'message'
|
||||
key = list(range(16))
|
||||
encrypted = aes_encrypt(bytes_to_intlist(msg), key)
|
||||
decrypted = intlist_to_bytes(aes_decrypt(encrypted, key))
|
||||
self.assertEqual(decrypted, msg)
|
||||
|
||||
def test_cbc_decrypt(self):
|
||||
data = bytes_to_intlist(
|
||||
b"\x97\x92+\xe5\x0b\xc3\x18\x91ky9m&\xb3\xb5@\xe6'\xc2\x96.\xc8u\x88\xab9-[\x9e|\xf1\xcd"
|
||||
)
|
||||
decrypted = intlist_to_bytes(aes_cbc_decrypt(data, self.key, self.iv))
|
||||
self.assertEqual(decrypted.rstrip(b'\x08'), self.secret_msg)
|
||||
|
||||
def test_decrypt_text(self):
|
||||
password = intlist_to_bytes(self.key).decode('utf-8')
|
||||
encrypted = base64.b64encode(
|
||||
intlist_to_bytes(self.iv[:8]) +
|
||||
b'\x17\x15\x93\xab\x8d\x80V\xcdV\xe0\t\xcdo\xc2\xa5\xd8ksM\r\xe27N\xae'
|
||||
).decode('utf-8')
|
||||
decrypted = (aes_decrypt_text(encrypted, password, 16))
|
||||
self.assertEqual(decrypted, self.secret_msg)
|
||||
|
||||
password = intlist_to_bytes(self.key).decode('utf-8')
|
||||
encrypted = base64.b64encode(
|
||||
intlist_to_bytes(self.iv[:8]) +
|
||||
b'\x0b\xe6\xa4\xd9z\x0e\xb8\xb9\xd0\xd4i_\x85\x1d\x99\x98_\xe5\x80\xe7.\xbf\xa5\x83'
|
||||
).decode('utf-8')
|
||||
decrypted = (aes_decrypt_text(encrypted, password, 32))
|
||||
self.assertEqual(decrypted, self.secret_msg)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
50
test/test_age_restriction.py
Normal file
50
test/test_age_restriction.py
Normal file
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Allow direct execution
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from test.helper import try_rm
|
||||
|
||||
|
||||
from youtube_dl import YoutubeDL
|
||||
|
||||
|
||||
def _download_restricted(url, filename, age):
|
||||
""" Returns true if the file has been downloaded """
|
||||
|
||||
params = {
|
||||
'age_limit': age,
|
||||
'skip_download': True,
|
||||
'writeinfojson': True,
|
||||
'outtmpl': '%(id)s.%(ext)s',
|
||||
}
|
||||
ydl = YoutubeDL(params)
|
||||
ydl.add_default_info_extractors()
|
||||
json_filename = os.path.splitext(filename)[0] + '.info.json'
|
||||
try_rm(json_filename)
|
||||
ydl.download([url])
|
||||
res = os.path.exists(json_filename)
|
||||
try_rm(json_filename)
|
||||
return res
|
||||
|
||||
|
||||
class TestAgeRestriction(unittest.TestCase):
|
||||
def _assert_restricted(self, url, filename, age, old_age=None):
|
||||
self.assertTrue(_download_restricted(url, filename, old_age))
|
||||
self.assertFalse(_download_restricted(url, filename, age))
|
||||
|
||||
def test_youtube(self):
|
||||
self._assert_restricted('07FYdnEawAQ', '07FYdnEawAQ.mp4', 10)
|
||||
|
||||
def test_youporn(self):
|
||||
self._assert_restricted(
|
||||
'http://www.youporn.com/watch/505835/sex-ed-is-it-safe-to-masturbate-daily/',
|
||||
'505835.mp4', 2, old_age=25)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
135
test/test_all_urls.py
Normal file
135
test/test_all_urls.py
Normal file
@@ -0,0 +1,135 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Allow direct execution
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
|
||||
from test.helper import gettestcases
|
||||
|
||||
from youtube_dl.extractor import (
|
||||
FacebookIE,
|
||||
gen_extractors,
|
||||
YoutubeIE,
|
||||
)
|
||||
|
||||
|
||||
class TestAllURLsMatching(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.ies = gen_extractors()
|
||||
|
||||
def matching_ies(self, url):
|
||||
return [ie.IE_NAME for ie in self.ies if ie.suitable(url) and ie.IE_NAME != 'generic']
|
||||
|
||||
def assertMatch(self, url, ie_list):
|
||||
self.assertEqual(self.matching_ies(url), ie_list)
|
||||
|
||||
def test_youtube_playlist_matching(self):
|
||||
assertPlaylist = lambda url: self.assertMatch(url, ['youtube:playlist'])
|
||||
assertPlaylist('ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8')
|
||||
assertPlaylist('UUBABnxM4Ar9ten8Mdjj1j0Q') # 585
|
||||
assertPlaylist('PL63F0C78739B09958')
|
||||
assertPlaylist('https://www.youtube.com/playlist?list=UUBABnxM4Ar9ten8Mdjj1j0Q')
|
||||
assertPlaylist('https://www.youtube.com/course?list=ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8')
|
||||
assertPlaylist('https://www.youtube.com/playlist?list=PLwP_SiAcdui0KVebT0mU9Apz359a4ubsC')
|
||||
assertPlaylist('https://www.youtube.com/watch?v=AV6J6_AeFEQ&playnext=1&list=PL4023E734DA416012') # 668
|
||||
self.assertFalse('youtube:playlist' in self.matching_ies('PLtS2H6bU1M'))
|
||||
# Top tracks
|
||||
assertPlaylist('https://www.youtube.com/playlist?list=MCUS.20142101')
|
||||
|
||||
def test_youtube_matching(self):
|
||||
self.assertTrue(YoutubeIE.suitable('PLtS2H6bU1M'))
|
||||
self.assertFalse(YoutubeIE.suitable('https://www.youtube.com/watch?v=AV6J6_AeFEQ&playnext=1&list=PL4023E734DA416012')) # 668
|
||||
self.assertMatch('http://youtu.be/BaW_jenozKc', ['youtube'])
|
||||
self.assertMatch('http://www.youtube.com/v/BaW_jenozKc', ['youtube'])
|
||||
self.assertMatch('https://youtube.googleapis.com/v/BaW_jenozKc', ['youtube'])
|
||||
self.assertMatch('http://www.cleanvideosearch.com/media/action/yt/watch?videoId=8v_4O44sfjM', ['youtube'])
|
||||
|
||||
def test_youtube_channel_matching(self):
|
||||
assertChannel = lambda url: self.assertMatch(url, ['youtube:channel'])
|
||||
assertChannel('https://www.youtube.com/channel/HCtnHdj3df7iM')
|
||||
assertChannel('https://www.youtube.com/channel/HCtnHdj3df7iM?feature=gb_ch_rec')
|
||||
assertChannel('https://www.youtube.com/channel/HCtnHdj3df7iM/videos')
|
||||
|
||||
def test_youtube_user_matching(self):
|
||||
self.assertMatch('www.youtube.com/NASAgovVideo/videos', ['youtube:user'])
|
||||
|
||||
def test_youtube_feeds(self):
|
||||
self.assertMatch('https://www.youtube.com/feed/watch_later', ['youtube:watchlater'])
|
||||
self.assertMatch('https://www.youtube.com/feed/subscriptions', ['youtube:subscriptions'])
|
||||
self.assertMatch('https://www.youtube.com/feed/recommended', ['youtube:recommended'])
|
||||
self.assertMatch('https://www.youtube.com/my_favorites', ['youtube:favorites'])
|
||||
|
||||
def test_youtube_show_matching(self):
|
||||
self.assertMatch('http://www.youtube.com/show/airdisasters', ['youtube:show'])
|
||||
|
||||
def test_youtube_search_matching(self):
|
||||
self.assertMatch('http://www.youtube.com/results?search_query=making+mustard', ['youtube:search_url'])
|
||||
self.assertMatch('https://www.youtube.com/results?baz=bar&search_query=youtube-dl+test+video&filters=video&lclk=video', ['youtube:search_url'])
|
||||
|
||||
def test_youtube_extract(self):
|
||||
assertExtractId = lambda url, id: self.assertEqual(YoutubeIE.extract_id(url), id)
|
||||
assertExtractId('http://www.youtube.com/watch?&v=BaW_jenozKc', 'BaW_jenozKc')
|
||||
assertExtractId('https://www.youtube.com/watch?&v=BaW_jenozKc', 'BaW_jenozKc')
|
||||
assertExtractId('https://www.youtube.com/watch?feature=player_embedded&v=BaW_jenozKc', 'BaW_jenozKc')
|
||||
assertExtractId('https://www.youtube.com/watch_popup?v=BaW_jenozKc', 'BaW_jenozKc')
|
||||
assertExtractId('http://www.youtube.com/watch?v=BaW_jenozKcsharePLED17F32AD9753930', 'BaW_jenozKc')
|
||||
assertExtractId('BaW_jenozKc', 'BaW_jenozKc')
|
||||
|
||||
def test_facebook_matching(self):
|
||||
self.assertTrue(FacebookIE.suitable('https://www.facebook.com/Shiniknoh#!/photo.php?v=10153317450565268'))
|
||||
self.assertTrue(FacebookIE.suitable('https://www.facebook.com/cindyweather?fref=ts#!/photo.php?v=10152183998945793'))
|
||||
|
||||
def test_no_duplicates(self):
|
||||
ies = gen_extractors()
|
||||
for tc in gettestcases(include_onlymatching=True):
|
||||
url = tc['url']
|
||||
for ie in ies:
|
||||
if type(ie).__name__ in ('GenericIE', tc['name'] + 'IE'):
|
||||
self.assertTrue(ie.suitable(url), '%s should match URL %r' % (type(ie).__name__, url))
|
||||
else:
|
||||
self.assertFalse(
|
||||
ie.suitable(url),
|
||||
'%s should not match URL %r . That URL belongs to %s.' % (type(ie).__name__, url, tc['name']))
|
||||
|
||||
def test_keywords(self):
|
||||
self.assertMatch(':ytsubs', ['youtube:subscriptions'])
|
||||
self.assertMatch(':ytsubscriptions', ['youtube:subscriptions'])
|
||||
self.assertMatch(':ythistory', ['youtube:history'])
|
||||
self.assertMatch(':thedailyshow', ['ComedyCentralShows'])
|
||||
self.assertMatch(':tds', ['ComedyCentralShows'])
|
||||
|
||||
def test_vimeo_matching(self):
|
||||
self.assertMatch('https://vimeo.com/channels/tributes', ['vimeo:channel'])
|
||||
self.assertMatch('https://vimeo.com/channels/31259', ['vimeo:channel'])
|
||||
self.assertMatch('https://vimeo.com/channels/31259/53576664', ['vimeo'])
|
||||
self.assertMatch('https://vimeo.com/user7108434', ['vimeo:user'])
|
||||
self.assertMatch('https://vimeo.com/user7108434/videos', ['vimeo:user'])
|
||||
self.assertMatch('https://vimeo.com/user21297594/review/75524534/3c257a1b5d', ['vimeo:review'])
|
||||
|
||||
# https://github.com/rg3/youtube-dl/issues/1930
|
||||
def test_soundcloud_not_matching_sets(self):
|
||||
self.assertMatch('http://soundcloud.com/floex/sets/gone-ep', ['soundcloud:set'])
|
||||
|
||||
def test_tumblr(self):
|
||||
self.assertMatch('http://tatianamaslanydaily.tumblr.com/post/54196191430/orphan-black-dvd-extra-behind-the-scenes', ['Tumblr'])
|
||||
self.assertMatch('http://tatianamaslanydaily.tumblr.com/post/54196191430', ['Tumblr'])
|
||||
|
||||
def test_pbs(self):
|
||||
# https://github.com/rg3/youtube-dl/issues/2350
|
||||
self.assertMatch('http://video.pbs.org/viralplayer/2365173446/', ['pbs'])
|
||||
self.assertMatch('http://video.pbs.org/widget/partnerplayer/980042464/', ['pbs'])
|
||||
|
||||
def test_yahoo_https(self):
|
||||
# https://github.com/rg3/youtube-dl/issues/2701
|
||||
self.assertMatch(
|
||||
'https://screen.yahoo.com/smartwatches-latest-wearable-gadgets-163745379-cbs.html',
|
||||
['Yahoo'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
59
test/test_cache.py
Normal file
59
test/test_cache.py
Normal file
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import shutil
|
||||
|
||||
# Allow direct execution
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
|
||||
from test.helper import FakeYDL
|
||||
from youtube_dl.cache import Cache
|
||||
|
||||
|
||||
def _is_empty(d):
|
||||
return not bool(os.listdir(d))
|
||||
|
||||
|
||||
def _mkdir(d):
|
||||
if not os.path.exists(d):
|
||||
os.mkdir(d)
|
||||
|
||||
|
||||
class TestCache(unittest.TestCase):
|
||||
def setUp(self):
|
||||
TEST_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
TESTDATA_DIR = os.path.join(TEST_DIR, 'testdata')
|
||||
_mkdir(TESTDATA_DIR)
|
||||
self.test_dir = os.path.join(TESTDATA_DIR, 'cache_test')
|
||||
self.tearDown()
|
||||
|
||||
def tearDown(self):
|
||||
if os.path.exists(self.test_dir):
|
||||
shutil.rmtree(self.test_dir)
|
||||
|
||||
def test_cache(self):
|
||||
ydl = FakeYDL({
|
||||
'cachedir': self.test_dir,
|
||||
})
|
||||
c = Cache(ydl)
|
||||
obj = {'x': 1, 'y': ['ä', '\\a', True]}
|
||||
self.assertEqual(c.load('test_cache', 'k.'), None)
|
||||
c.store('test_cache', 'k.', obj)
|
||||
self.assertEqual(c.load('test_cache', 'k2'), None)
|
||||
self.assertFalse(_is_empty(self.test_dir))
|
||||
self.assertEqual(c.load('test_cache', 'k.'), obj)
|
||||
self.assertEqual(c.load('test_cache', 'y'), None)
|
||||
self.assertEqual(c.load('test_cache2', 'k.'), None)
|
||||
c.remove()
|
||||
self.assertFalse(os.path.exists(self.test_dir))
|
||||
self.assertEqual(c.load('test_cache', 'k.'), None)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
92
test/test_compat.py
Normal file
92
test/test_compat.py
Normal file
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Allow direct execution
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
|
||||
from youtube_dl.utils import get_filesystem_encoding
|
||||
from youtube_dl.compat import (
|
||||
compat_getenv,
|
||||
compat_etree_fromstring,
|
||||
compat_expanduser,
|
||||
compat_shlex_split,
|
||||
compat_str,
|
||||
compat_urllib_parse_unquote,
|
||||
compat_urllib_parse_unquote_plus,
|
||||
)
|
||||
|
||||
|
||||
class TestCompat(unittest.TestCase):
|
||||
def test_compat_getenv(self):
|
||||
test_str = 'тест'
|
||||
os.environ['YOUTUBE-DL-TEST'] = (
|
||||
test_str if sys.version_info >= (3, 0)
|
||||
else test_str.encode(get_filesystem_encoding()))
|
||||
self.assertEqual(compat_getenv('YOUTUBE-DL-TEST'), test_str)
|
||||
|
||||
def test_compat_expanduser(self):
|
||||
old_home = os.environ.get('HOME')
|
||||
test_str = 'C:\Documents and Settings\тест\Application Data'
|
||||
os.environ['HOME'] = (
|
||||
test_str if sys.version_info >= (3, 0)
|
||||
else test_str.encode(get_filesystem_encoding()))
|
||||
self.assertEqual(compat_expanduser('~'), test_str)
|
||||
os.environ['HOME'] = old_home
|
||||
|
||||
def test_all_present(self):
|
||||
import youtube_dl.compat
|
||||
all_names = youtube_dl.compat.__all__
|
||||
present_names = set(filter(
|
||||
lambda c: '_' in c and not c.startswith('_'),
|
||||
dir(youtube_dl.compat))) - set(['unicode_literals'])
|
||||
self.assertEqual(all_names, sorted(present_names))
|
||||
|
||||
def test_compat_urllib_parse_unquote(self):
|
||||
self.assertEqual(compat_urllib_parse_unquote('abc%20def'), 'abc def')
|
||||
self.assertEqual(compat_urllib_parse_unquote('%7e/abc+def'), '~/abc+def')
|
||||
self.assertEqual(compat_urllib_parse_unquote(''), '')
|
||||
self.assertEqual(compat_urllib_parse_unquote('%'), '%')
|
||||
self.assertEqual(compat_urllib_parse_unquote('%%'), '%%')
|
||||
self.assertEqual(compat_urllib_parse_unquote('%%%'), '%%%')
|
||||
self.assertEqual(compat_urllib_parse_unquote('%2F'), '/')
|
||||
self.assertEqual(compat_urllib_parse_unquote('%2f'), '/')
|
||||
self.assertEqual(compat_urllib_parse_unquote('%E6%B4%A5%E6%B3%A2'), '津波')
|
||||
self.assertEqual(
|
||||
compat_urllib_parse_unquote('''<meta property="og:description" content="%E2%96%81%E2%96%82%E2%96%83%E2%96%84%25%E2%96%85%E2%96%86%E2%96%87%E2%96%88" />
|
||||
%<a href="https://ar.wikipedia.org/wiki/%D8%AA%D8%B3%D9%88%D9%86%D8%A7%D9%85%D9%8A">%a'''),
|
||||
'''<meta property="og:description" content="▁▂▃▄%▅▆▇█" />
|
||||
%<a href="https://ar.wikipedia.org/wiki/تسونامي">%a''')
|
||||
self.assertEqual(
|
||||
compat_urllib_parse_unquote('''%28%5E%E2%97%A3_%E2%97%A2%5E%29%E3%81%A3%EF%B8%BB%E3%83%87%E2%95%90%E4%B8%80 %E2%87%80 %E2%87%80 %E2%87%80 %E2%87%80 %E2%87%80 %E2%86%B6%I%Break%25Things%'''),
|
||||
'''(^◣_◢^)っ︻デ═一 ⇀ ⇀ ⇀ ⇀ ⇀ ↶%I%Break%Things%''')
|
||||
|
||||
def test_compat_urllib_parse_unquote_plus(self):
|
||||
self.assertEqual(compat_urllib_parse_unquote_plus('abc%20def'), 'abc def')
|
||||
self.assertEqual(compat_urllib_parse_unquote_plus('%7e/abc+def'), '~/abc def')
|
||||
|
||||
def test_compat_shlex_split(self):
|
||||
self.assertEqual(compat_shlex_split('-option "one two"'), ['-option', 'one two'])
|
||||
|
||||
def test_compat_etree_fromstring(self):
|
||||
xml = '''
|
||||
<root foo="bar" spam="中文">
|
||||
<normal>foo</normal>
|
||||
<chinese>中文</chinese>
|
||||
<foo><bar>spam</bar></foo>
|
||||
</root>
|
||||
'''
|
||||
doc = compat_etree_fromstring(xml.encode('utf-8'))
|
||||
self.assertTrue(isinstance(doc.attrib['foo'], compat_str))
|
||||
self.assertTrue(isinstance(doc.attrib['spam'], compat_str))
|
||||
self.assertTrue(isinstance(doc.find('normal').text, compat_str))
|
||||
self.assertTrue(isinstance(doc.find('chinese').text, compat_str))
|
||||
self.assertTrue(isinstance(doc.find('foo/bar').text, compat_str))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,29 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Various small unit tests
|
||||
|
||||
import os,sys
|
||||
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
|
||||
|
||||
import youtube_dl
|
||||
|
||||
def test_simplify_title():
|
||||
assert youtube_dl._simplify_title(u'abc') == u'abc'
|
||||
assert youtube_dl._simplify_title(u'abc_d-e') == u'abc_d-e'
|
||||
|
||||
assert youtube_dl._simplify_title(u'123') == u'123'
|
||||
|
||||
assert u'/' not in youtube_dl._simplify_title(u'abc/de')
|
||||
assert u'abc' in youtube_dl._simplify_title(u'abc/de')
|
||||
assert u'de' in youtube_dl._simplify_title(u'abc/de')
|
||||
assert u'/' not in youtube_dl._simplify_title(u'abc/de///')
|
||||
|
||||
assert u'\\' not in youtube_dl._simplify_title(u'abc\\de')
|
||||
assert u'abc' in youtube_dl._simplify_title(u'abc\\de')
|
||||
assert u'de' in youtube_dl._simplify_title(u'abc\\de')
|
||||
|
||||
assert youtube_dl._simplify_title(u'ä') == u'ä'
|
||||
assert youtube_dl._simplify_title(u'кириллица') == u'кириллица'
|
||||
|
||||
# Strip underlines
|
||||
assert youtube_dl._simplify_title(u'\'a_') == u'a'
|
||||
234
test/test_download.py
Normal file
234
test/test_download.py
Normal file
@@ -0,0 +1,234 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Allow direct execution
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from test.helper import (
|
||||
assertGreaterEqual,
|
||||
expect_warnings,
|
||||
get_params,
|
||||
gettestcases,
|
||||
expect_info_dict,
|
||||
try_rm,
|
||||
report_warning,
|
||||
)
|
||||
|
||||
|
||||
import hashlib
|
||||
import io
|
||||
import json
|
||||
import socket
|
||||
|
||||
import youtube_dl.YoutubeDL
|
||||
from youtube_dl.compat import (
|
||||
compat_http_client,
|
||||
compat_urllib_error,
|
||||
compat_HTTPError,
|
||||
)
|
||||
from youtube_dl.utils import (
|
||||
DownloadError,
|
||||
ExtractorError,
|
||||
format_bytes,
|
||||
UnavailableVideoError,
|
||||
)
|
||||
from youtube_dl.extractor import get_info_extractor
|
||||
|
||||
RETRIES = 3
|
||||
|
||||
|
||||
class YoutubeDL(youtube_dl.YoutubeDL):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.to_stderr = self.to_screen
|
||||
self.processed_info_dicts = []
|
||||
super(YoutubeDL, self).__init__(*args, **kwargs)
|
||||
|
||||
def report_warning(self, message):
|
||||
# Don't accept warnings during tests
|
||||
raise ExtractorError(message)
|
||||
|
||||
def process_info(self, info_dict):
|
||||
self.processed_info_dicts.append(info_dict)
|
||||
return super(YoutubeDL, self).process_info(info_dict)
|
||||
|
||||
|
||||
def _file_md5(fn):
|
||||
with open(fn, 'rb') as f:
|
||||
return hashlib.md5(f.read()).hexdigest()
|
||||
|
||||
defs = gettestcases()
|
||||
|
||||
|
||||
class TestDownload(unittest.TestCase):
|
||||
maxDiff = None
|
||||
|
||||
def setUp(self):
|
||||
self.defs = defs
|
||||
|
||||
# Dynamically generate tests
|
||||
|
||||
|
||||
def generator(test_case):
|
||||
|
||||
def test_template(self):
|
||||
ie = youtube_dl.extractor.get_info_extractor(test_case['name'])
|
||||
other_ies = [get_info_extractor(ie_key) for ie_key in test_case.get('add_ie', [])]
|
||||
is_playlist = any(k.startswith('playlist') for k in test_case)
|
||||
test_cases = test_case.get(
|
||||
'playlist', [] if is_playlist else [test_case])
|
||||
|
||||
def print_skipping(reason):
|
||||
print('Skipping %s: %s' % (test_case['name'], reason))
|
||||
if not ie.working():
|
||||
print_skipping('IE marked as not _WORKING')
|
||||
return
|
||||
|
||||
for tc in test_cases:
|
||||
info_dict = tc.get('info_dict', {})
|
||||
if not (info_dict.get('id') and info_dict.get('ext')):
|
||||
raise Exception('Test definition incorrect. The output file cannot be known. Are both \'id\' and \'ext\' keys present?')
|
||||
|
||||
if 'skip' in test_case:
|
||||
print_skipping(test_case['skip'])
|
||||
return
|
||||
for other_ie in other_ies:
|
||||
if not other_ie.working():
|
||||
print_skipping('test depends on %sIE, marked as not WORKING' % other_ie.ie_key())
|
||||
return
|
||||
|
||||
params = get_params(test_case.get('params', {}))
|
||||
if is_playlist and 'playlist' not in test_case:
|
||||
params.setdefault('extract_flat', 'in_playlist')
|
||||
params.setdefault('skip_download', True)
|
||||
|
||||
ydl = YoutubeDL(params, auto_init=False)
|
||||
ydl.add_default_info_extractors()
|
||||
finished_hook_called = set()
|
||||
|
||||
def _hook(status):
|
||||
if status['status'] == 'finished':
|
||||
finished_hook_called.add(status['filename'])
|
||||
ydl.add_progress_hook(_hook)
|
||||
expect_warnings(ydl, test_case.get('expected_warnings', []))
|
||||
|
||||
def get_tc_filename(tc):
|
||||
return ydl.prepare_filename(tc.get('info_dict', {}))
|
||||
|
||||
res_dict = None
|
||||
|
||||
def try_rm_tcs_files(tcs=None):
|
||||
if tcs is None:
|
||||
tcs = test_cases
|
||||
for tc in tcs:
|
||||
tc_filename = get_tc_filename(tc)
|
||||
try_rm(tc_filename)
|
||||
try_rm(tc_filename + '.part')
|
||||
try_rm(os.path.splitext(tc_filename)[0] + '.info.json')
|
||||
try_rm_tcs_files()
|
||||
try:
|
||||
try_num = 1
|
||||
while True:
|
||||
try:
|
||||
# We're not using .download here sine that is just a shim
|
||||
# for outside error handling, and returns the exit code
|
||||
# instead of the result dict.
|
||||
res_dict = ydl.extract_info(
|
||||
test_case['url'],
|
||||
force_generic_extractor=params.get('force_generic_extractor', False))
|
||||
except (DownloadError, ExtractorError) as err:
|
||||
# Check if the exception is not a network related one
|
||||
if not err.exc_info[0] in (compat_urllib_error.URLError, socket.timeout, UnavailableVideoError, compat_http_client.BadStatusLine) or (err.exc_info[0] == compat_HTTPError and err.exc_info[1].code == 503):
|
||||
raise
|
||||
|
||||
if try_num == RETRIES:
|
||||
report_warning('Failed due to network errors, skipping...')
|
||||
return
|
||||
|
||||
print('Retrying: {0} failed tries\n\n##########\n\n'.format(try_num))
|
||||
|
||||
try_num += 1
|
||||
else:
|
||||
break
|
||||
|
||||
if is_playlist:
|
||||
self.assertTrue(res_dict['_type'] in ['playlist', 'multi_video'])
|
||||
self.assertTrue('entries' in res_dict)
|
||||
expect_info_dict(self, res_dict, test_case.get('info_dict', {}))
|
||||
|
||||
if 'playlist_mincount' in test_case:
|
||||
assertGreaterEqual(
|
||||
self,
|
||||
len(res_dict['entries']),
|
||||
test_case['playlist_mincount'],
|
||||
'Expected at least %d in playlist %s, but got only %d' % (
|
||||
test_case['playlist_mincount'], test_case['url'],
|
||||
len(res_dict['entries'])))
|
||||
if 'playlist_count' in test_case:
|
||||
self.assertEqual(
|
||||
len(res_dict['entries']),
|
||||
test_case['playlist_count'],
|
||||
'Expected %d entries in playlist %s, but got %d.' % (
|
||||
test_case['playlist_count'],
|
||||
test_case['url'],
|
||||
len(res_dict['entries']),
|
||||
))
|
||||
if 'playlist_duration_sum' in test_case:
|
||||
got_duration = sum(e['duration'] for e in res_dict['entries'])
|
||||
self.assertEqual(
|
||||
test_case['playlist_duration_sum'], got_duration)
|
||||
|
||||
for tc in test_cases:
|
||||
tc_filename = get_tc_filename(tc)
|
||||
if not test_case.get('params', {}).get('skip_download', False):
|
||||
self.assertTrue(os.path.exists(tc_filename), msg='Missing file ' + tc_filename)
|
||||
self.assertTrue(tc_filename in finished_hook_called)
|
||||
expected_minsize = tc.get('file_minsize', 10000)
|
||||
if expected_minsize is not None:
|
||||
if params.get('test'):
|
||||
expected_minsize = max(expected_minsize, 10000)
|
||||
got_fsize = os.path.getsize(tc_filename)
|
||||
assertGreaterEqual(
|
||||
self, got_fsize, expected_minsize,
|
||||
'Expected %s to be at least %s, but it\'s only %s ' %
|
||||
(tc_filename, format_bytes(expected_minsize),
|
||||
format_bytes(got_fsize)))
|
||||
if 'md5' in tc:
|
||||
md5_for_file = _file_md5(tc_filename)
|
||||
self.assertEqual(md5_for_file, tc['md5'])
|
||||
info_json_fn = os.path.splitext(tc_filename)[0] + '.info.json'
|
||||
self.assertTrue(
|
||||
os.path.exists(info_json_fn),
|
||||
'Missing info file %s' % info_json_fn)
|
||||
with io.open(info_json_fn, encoding='utf-8') as infof:
|
||||
info_dict = json.load(infof)
|
||||
|
||||
expect_info_dict(self, info_dict, tc.get('info_dict', {}))
|
||||
finally:
|
||||
try_rm_tcs_files()
|
||||
if is_playlist and res_dict is not None and res_dict.get('entries'):
|
||||
# Remove all other files that may have been extracted if the
|
||||
# extractor returns full results even with extract_flat
|
||||
res_tcs = [{'info_dict': e} for e in res_dict['entries']]
|
||||
try_rm_tcs_files(res_tcs)
|
||||
|
||||
return test_template
|
||||
|
||||
# And add them to TestDownload
|
||||
for n, test_case in enumerate(defs):
|
||||
test_method = generator(test_case)
|
||||
tname = 'test_' + str(test_case['name'])
|
||||
i = 1
|
||||
while hasattr(TestDownload, tname):
|
||||
tname = 'test_%s_%d' % (test_case['name'], i)
|
||||
i += 1
|
||||
test_method.__name__ = str(tname)
|
||||
setattr(TestDownload, test_method.__name__, test_method)
|
||||
del test_method
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
43
test/test_execution.py
Normal file
43
test/test_execution.py
Normal file
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from youtube_dl.utils import encodeArgument
|
||||
|
||||
rootDir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
|
||||
try:
|
||||
_DEV_NULL = subprocess.DEVNULL
|
||||
except AttributeError:
|
||||
_DEV_NULL = open(os.devnull, 'wb')
|
||||
|
||||
|
||||
class TestExecution(unittest.TestCase):
|
||||
def test_import(self):
|
||||
subprocess.check_call([sys.executable, '-c', 'import youtube_dl'], cwd=rootDir)
|
||||
|
||||
def test_module_exec(self):
|
||||
if sys.version_info >= (2, 7): # Python 2.6 doesn't support package execution
|
||||
subprocess.check_call([sys.executable, '-m', 'youtube_dl', '--version'], cwd=rootDir, stdout=_DEV_NULL)
|
||||
|
||||
def test_main_exec(self):
|
||||
subprocess.check_call([sys.executable, 'youtube_dl/__main__.py', '--version'], cwd=rootDir, stdout=_DEV_NULL)
|
||||
|
||||
def test_cmdline_umlauts(self):
|
||||
p = subprocess.Popen(
|
||||
[sys.executable, 'youtube_dl/__main__.py', encodeArgument('ä'), '--version'],
|
||||
cwd=rootDir, stdout=_DEV_NULL, stderr=subprocess.PIPE)
|
||||
_, stderr = p.communicate()
|
||||
self.assertFalse(stderr)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
119
test/test_http.py
Normal file
119
test/test_http.py
Normal file
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Allow direct execution
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from youtube_dl import YoutubeDL
|
||||
from youtube_dl.compat import compat_http_server, compat_urllib_request
|
||||
import ssl
|
||||
import threading
|
||||
|
||||
TEST_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
class HTTPTestRequestHandler(compat_http_server.BaseHTTPRequestHandler):
|
||||
def log_message(self, format, *args):
|
||||
pass
|
||||
|
||||
def do_GET(self):
|
||||
if self.path == '/video.html':
|
||||
self.send_response(200)
|
||||
self.send_header('Content-Type', 'text/html; charset=utf-8')
|
||||
self.end_headers()
|
||||
self.wfile.write(b'<html><video src="/vid.mp4" /></html>')
|
||||
elif self.path == '/vid.mp4':
|
||||
self.send_response(200)
|
||||
self.send_header('Content-Type', 'video/mp4')
|
||||
self.end_headers()
|
||||
self.wfile.write(b'\x00\x00\x00\x00\x20\x66\x74[video]')
|
||||
else:
|
||||
assert False
|
||||
|
||||
|
||||
class FakeLogger(object):
|
||||
def debug(self, msg):
|
||||
pass
|
||||
|
||||
def warning(self, msg):
|
||||
pass
|
||||
|
||||
def error(self, msg):
|
||||
pass
|
||||
|
||||
|
||||
class TestHTTP(unittest.TestCase):
|
||||
def setUp(self):
|
||||
certfn = os.path.join(TEST_DIR, 'testcert.pem')
|
||||
self.httpd = compat_http_server.HTTPServer(
|
||||
('localhost', 0), HTTPTestRequestHandler)
|
||||
self.httpd.socket = ssl.wrap_socket(
|
||||
self.httpd.socket, certfile=certfn, server_side=True)
|
||||
self.port = self.httpd.socket.getsockname()[1]
|
||||
self.server_thread = threading.Thread(target=self.httpd.serve_forever)
|
||||
self.server_thread.daemon = True
|
||||
self.server_thread.start()
|
||||
|
||||
def test_nocheckcertificate(self):
|
||||
if sys.version_info >= (2, 7, 9): # No certificate checking anyways
|
||||
ydl = YoutubeDL({'logger': FakeLogger()})
|
||||
self.assertRaises(
|
||||
Exception,
|
||||
ydl.extract_info, 'https://localhost:%d/video.html' % self.port)
|
||||
|
||||
ydl = YoutubeDL({'logger': FakeLogger(), 'nocheckcertificate': True})
|
||||
r = ydl.extract_info('https://localhost:%d/video.html' % self.port)
|
||||
self.assertEqual(r['url'], 'https://localhost:%d/vid.mp4' % self.port)
|
||||
|
||||
|
||||
def _build_proxy_handler(name):
|
||||
class HTTPTestRequestHandler(compat_http_server.BaseHTTPRequestHandler):
|
||||
proxy_name = name
|
||||
|
||||
def log_message(self, format, *args):
|
||||
pass
|
||||
|
||||
def do_GET(self):
|
||||
self.send_response(200)
|
||||
self.send_header('Content-Type', 'text/plain; charset=utf-8')
|
||||
self.end_headers()
|
||||
self.wfile.write('{self.proxy_name}: {self.path}'.format(self=self).encode('utf-8'))
|
||||
return HTTPTestRequestHandler
|
||||
|
||||
|
||||
class TestProxy(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.proxy = compat_http_server.HTTPServer(
|
||||
('localhost', 0), _build_proxy_handler('normal'))
|
||||
self.port = self.proxy.socket.getsockname()[1]
|
||||
self.proxy_thread = threading.Thread(target=self.proxy.serve_forever)
|
||||
self.proxy_thread.daemon = True
|
||||
self.proxy_thread.start()
|
||||
|
||||
self.cn_proxy = compat_http_server.HTTPServer(
|
||||
('localhost', 0), _build_proxy_handler('cn'))
|
||||
self.cn_port = self.cn_proxy.socket.getsockname()[1]
|
||||
self.cn_proxy_thread = threading.Thread(target=self.cn_proxy.serve_forever)
|
||||
self.cn_proxy_thread.daemon = True
|
||||
self.cn_proxy_thread.start()
|
||||
|
||||
def test_proxy(self):
|
||||
cn_proxy = 'localhost:{0}'.format(self.cn_port)
|
||||
ydl = YoutubeDL({
|
||||
'proxy': 'localhost:{0}'.format(self.port),
|
||||
'cn_verification_proxy': cn_proxy,
|
||||
})
|
||||
url = 'http://foo.com/bar'
|
||||
response = ydl.urlopen(url).read().decode('utf-8')
|
||||
self.assertEqual(response, 'normal: {0}'.format(url))
|
||||
|
||||
req = compat_urllib_request.Request(url)
|
||||
req.add_header('Ytdl-request-proxy', cn_proxy)
|
||||
response = ydl.urlopen(req).read().decode('utf-8')
|
||||
self.assertEqual(response, 'cn: {0}'.format(url))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
109
test/test_jsinterp.py
Normal file
109
test/test_jsinterp.py
Normal file
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Allow direct execution
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from youtube_dl.jsinterp import JSInterpreter
|
||||
|
||||
|
||||
class TestJSInterpreter(unittest.TestCase):
|
||||
def test_basic(self):
|
||||
jsi = JSInterpreter('function x(){;}')
|
||||
self.assertEqual(jsi.call_function('x'), None)
|
||||
|
||||
jsi = JSInterpreter('function x3(){return 42;}')
|
||||
self.assertEqual(jsi.call_function('x3'), 42)
|
||||
|
||||
jsi = JSInterpreter('var x5 = function(){return 42;}')
|
||||
self.assertEqual(jsi.call_function('x5'), 42)
|
||||
|
||||
def test_calc(self):
|
||||
jsi = JSInterpreter('function x4(a){return 2*a+1;}')
|
||||
self.assertEqual(jsi.call_function('x4', 3), 7)
|
||||
|
||||
def test_empty_return(self):
|
||||
jsi = JSInterpreter('function f(){return; y()}')
|
||||
self.assertEqual(jsi.call_function('f'), None)
|
||||
|
||||
def test_morespace(self):
|
||||
jsi = JSInterpreter('function x (a) { return 2 * a + 1 ; }')
|
||||
self.assertEqual(jsi.call_function('x', 3), 7)
|
||||
|
||||
jsi = JSInterpreter('function f () { x = 2 ; return x; }')
|
||||
self.assertEqual(jsi.call_function('f'), 2)
|
||||
|
||||
def test_strange_chars(self):
|
||||
jsi = JSInterpreter('function $_xY1 ($_axY1) { var $_axY2 = $_axY1 + 1; return $_axY2; }')
|
||||
self.assertEqual(jsi.call_function('$_xY1', 20), 21)
|
||||
|
||||
def test_operators(self):
|
||||
jsi = JSInterpreter('function f(){return 1 << 5;}')
|
||||
self.assertEqual(jsi.call_function('f'), 32)
|
||||
|
||||
jsi = JSInterpreter('function f(){return 19 & 21;}')
|
||||
self.assertEqual(jsi.call_function('f'), 17)
|
||||
|
||||
jsi = JSInterpreter('function f(){return 11 >> 2;}')
|
||||
self.assertEqual(jsi.call_function('f'), 2)
|
||||
|
||||
def test_array_access(self):
|
||||
jsi = JSInterpreter('function f(){var x = [1,2,3]; x[0] = 4; x[0] = 5; x[2] = 7; return x;}')
|
||||
self.assertEqual(jsi.call_function('f'), [5, 2, 7])
|
||||
|
||||
def test_parens(self):
|
||||
jsi = JSInterpreter('function f(){return (1) + (2) * ((( (( (((((3)))))) )) ));}')
|
||||
self.assertEqual(jsi.call_function('f'), 7)
|
||||
|
||||
jsi = JSInterpreter('function f(){return (1 + 2) * 3;}')
|
||||
self.assertEqual(jsi.call_function('f'), 9)
|
||||
|
||||
def test_assignments(self):
|
||||
jsi = JSInterpreter('function f(){var x = 20; x = 30 + 1; return x;}')
|
||||
self.assertEqual(jsi.call_function('f'), 31)
|
||||
|
||||
jsi = JSInterpreter('function f(){var x = 20; x += 30 + 1; return x;}')
|
||||
self.assertEqual(jsi.call_function('f'), 51)
|
||||
|
||||
jsi = JSInterpreter('function f(){var x = 20; x -= 30 + 1; return x;}')
|
||||
self.assertEqual(jsi.call_function('f'), -11)
|
||||
|
||||
def test_comments(self):
|
||||
'Skipping: Not yet fully implemented'
|
||||
return
|
||||
jsi = JSInterpreter('''
|
||||
function x() {
|
||||
var x = /* 1 + */ 2;
|
||||
var y = /* 30
|
||||
* 40 */ 50;
|
||||
return x + y;
|
||||
}
|
||||
''')
|
||||
self.assertEqual(jsi.call_function('x'), 52)
|
||||
|
||||
jsi = JSInterpreter('''
|
||||
function f() {
|
||||
var x = "/*";
|
||||
var y = 1 /* comment */ + 2;
|
||||
return y;
|
||||
}
|
||||
''')
|
||||
self.assertEqual(jsi.call_function('f'), 3)
|
||||
|
||||
def test_precedence(self):
|
||||
jsi = JSInterpreter('''
|
||||
function x() {
|
||||
var a = [10, 20, 30, 40, 50];
|
||||
var b = 6;
|
||||
a[0]=a[b%a.length];
|
||||
return a;
|
||||
}''')
|
||||
self.assertEqual(jsi.call_function('x'), [20, 20, 30, 40, 50])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
26
test/test_netrc.py
Normal file
26
test/test_netrc.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# coding: utf-8
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
|
||||
from youtube_dl.extractor import (
|
||||
gen_extractors,
|
||||
)
|
||||
|
||||
|
||||
class TestNetRc(unittest.TestCase):
|
||||
def test_netrc_present(self):
|
||||
for ie in gen_extractors():
|
||||
if not hasattr(ie, '_login'):
|
||||
continue
|
||||
self.assertTrue(
|
||||
hasattr(ie, '_NETRC_MACHINE'),
|
||||
'Extractor %s supports login, but is missing a _NETRC_MACHINE property' % ie.IE_NAME)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
17
test/test_postprocessors.py
Normal file
17
test/test_postprocessors.py
Normal file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Allow direct execution
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from youtube_dl.postprocessor import MetadataFromTitlePP
|
||||
|
||||
|
||||
class TestMetadataFromTitle(unittest.TestCase):
|
||||
def test_format_to_regex(self):
|
||||
pp = MetadataFromTitlePP(None, '%(title)s - %(artist)s')
|
||||
self.assertEqual(pp._titleregex, '(?P<title>.+)\ \-\ (?P<artist>.+)')
|
||||
371
test/test_subtitles.py
Normal file
371
test/test_subtitles.py
Normal file
@@ -0,0 +1,371 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Allow direct execution
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from test.helper import FakeYDL, md5
|
||||
|
||||
|
||||
from youtube_dl.extractor import (
|
||||
BlipTVIE,
|
||||
YoutubeIE,
|
||||
DailymotionIE,
|
||||
TEDIE,
|
||||
VimeoIE,
|
||||
WallaIE,
|
||||
CeskaTelevizeIE,
|
||||
LyndaIE,
|
||||
NPOIE,
|
||||
ComedyCentralIE,
|
||||
NRKTVIE,
|
||||
RaiIE,
|
||||
VikiIE,
|
||||
ThePlatformIE,
|
||||
ThePlatformFeedIE,
|
||||
RTVEALaCartaIE,
|
||||
FunnyOrDieIE,
|
||||
DemocracynowIE,
|
||||
)
|
||||
|
||||
|
||||
class BaseTestSubtitles(unittest.TestCase):
|
||||
url = None
|
||||
IE = None
|
||||
|
||||
def setUp(self):
|
||||
self.DL = FakeYDL()
|
||||
self.ie = self.IE()
|
||||
self.DL.add_info_extractor(self.ie)
|
||||
|
||||
def getInfoDict(self):
|
||||
info_dict = self.DL.extract_info(self.url, download=False)
|
||||
return info_dict
|
||||
|
||||
def getSubtitles(self):
|
||||
info_dict = self.getInfoDict()
|
||||
subtitles = info_dict['requested_subtitles']
|
||||
if not subtitles:
|
||||
return subtitles
|
||||
for sub_info in subtitles.values():
|
||||
if sub_info.get('data') is None:
|
||||
uf = self.DL.urlopen(sub_info['url'])
|
||||
sub_info['data'] = uf.read().decode('utf-8')
|
||||
return dict((l, sub_info['data']) for l, sub_info in subtitles.items())
|
||||
|
||||
|
||||
class TestYoutubeSubtitles(BaseTestSubtitles):
|
||||
url = 'QRS8MkLhQmM'
|
||||
IE = YoutubeIE
|
||||
|
||||
def test_youtube_allsubtitles(self):
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertEqual(len(subtitles.keys()), 13)
|
||||
self.assertEqual(md5(subtitles['en']), '4cd9278a35ba2305f47354ee13472260')
|
||||
self.assertEqual(md5(subtitles['it']), '164a51f16f260476a05b50fe4c2f161d')
|
||||
for lang in ['it', 'fr', 'de']:
|
||||
self.assertTrue(subtitles.get(lang) is not None, 'Subtitles for \'%s\' not extracted' % lang)
|
||||
|
||||
def test_youtube_subtitles_sbv_format(self):
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['subtitlesformat'] = 'sbv'
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertEqual(md5(subtitles['en']), '13aeaa0c245a8bed9a451cb643e3ad8b')
|
||||
|
||||
def test_youtube_subtitles_vtt_format(self):
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['subtitlesformat'] = 'vtt'
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertEqual(md5(subtitles['en']), '3cb210999d3e021bd6c7f0ea751eab06')
|
||||
|
||||
def test_youtube_automatic_captions(self):
|
||||
self.url = '8YoUxe5ncPo'
|
||||
self.DL.params['writeautomaticsub'] = True
|
||||
self.DL.params['subtitleslangs'] = ['it']
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertTrue(subtitles['it'] is not None)
|
||||
|
||||
def test_youtube_translated_subtitles(self):
|
||||
# This video has a subtitles track, which can be translated
|
||||
self.url = 'Ky9eprVWzlI'
|
||||
self.DL.params['writeautomaticsub'] = True
|
||||
self.DL.params['subtitleslangs'] = ['it']
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertTrue(subtitles['it'] is not None)
|
||||
|
||||
def test_youtube_nosubtitles(self):
|
||||
self.DL.expect_warning('video doesn\'t have subtitles')
|
||||
self.url = 'n5BB19UTcdA'
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertFalse(subtitles)
|
||||
|
||||
|
||||
class TestDailymotionSubtitles(BaseTestSubtitles):
|
||||
url = 'http://www.dailymotion.com/video/xczg00'
|
||||
IE = DailymotionIE
|
||||
|
||||
def test_allsubtitles(self):
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertTrue(len(subtitles.keys()) >= 6)
|
||||
self.assertEqual(md5(subtitles['en']), '976553874490cba125086bbfea3ff76f')
|
||||
self.assertEqual(md5(subtitles['fr']), '594564ec7d588942e384e920e5341792')
|
||||
for lang in ['es', 'fr', 'de']:
|
||||
self.assertTrue(subtitles.get(lang) is not None, 'Subtitles for \'%s\' not extracted' % lang)
|
||||
|
||||
def test_nosubtitles(self):
|
||||
self.DL.expect_warning('video doesn\'t have subtitles')
|
||||
self.url = 'http://www.dailymotion.com/video/x12u166_le-zapping-tele-star-du-08-aout-2013_tv'
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertFalse(subtitles)
|
||||
|
||||
|
||||
class TestTedSubtitles(BaseTestSubtitles):
|
||||
url = 'http://www.ted.com/talks/dan_dennett_on_our_consciousness.html'
|
||||
IE = TEDIE
|
||||
|
||||
def test_allsubtitles(self):
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertTrue(len(subtitles.keys()) >= 28)
|
||||
self.assertEqual(md5(subtitles['en']), '4262c1665ff928a2dada178f62cb8d14')
|
||||
self.assertEqual(md5(subtitles['fr']), '66a63f7f42c97a50f8c0e90bc7797bb5')
|
||||
for lang in ['es', 'fr', 'de']:
|
||||
self.assertTrue(subtitles.get(lang) is not None, 'Subtitles for \'%s\' not extracted' % lang)
|
||||
|
||||
|
||||
class TestBlipTVSubtitles(BaseTestSubtitles):
|
||||
url = 'http://blip.tv/a/a-6603250'
|
||||
IE = BlipTVIE
|
||||
|
||||
def test_allsubtitles(self):
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertEqual(set(subtitles.keys()), set(['en']))
|
||||
self.assertEqual(md5(subtitles['en']), '5b75c300af65fe4476dff79478bb93e4')
|
||||
|
||||
|
||||
class TestVimeoSubtitles(BaseTestSubtitles):
|
||||
url = 'http://vimeo.com/76979871'
|
||||
IE = VimeoIE
|
||||
|
||||
def test_allsubtitles(self):
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertEqual(set(subtitles.keys()), set(['de', 'en', 'es', 'fr']))
|
||||
self.assertEqual(md5(subtitles['en']), '8062383cf4dec168fc40a088aa6d5888')
|
||||
self.assertEqual(md5(subtitles['fr']), 'b6191146a6c5d3a452244d853fde6dc8')
|
||||
|
||||
def test_nosubtitles(self):
|
||||
self.DL.expect_warning('video doesn\'t have subtitles')
|
||||
self.url = 'http://vimeo.com/56015672'
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertFalse(subtitles)
|
||||
|
||||
|
||||
class TestWallaSubtitles(BaseTestSubtitles):
|
||||
url = 'http://vod.walla.co.il/movie/2705958/the-yes-men'
|
||||
IE = WallaIE
|
||||
|
||||
def test_allsubtitles(self):
|
||||
self.DL.expect_warning('Automatic Captions not supported by this server')
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertEqual(set(subtitles.keys()), set(['heb']))
|
||||
self.assertEqual(md5(subtitles['heb']), 'e758c5d7cb982f6bef14f377ec7a3920')
|
||||
|
||||
def test_nosubtitles(self):
|
||||
self.DL.expect_warning('video doesn\'t have subtitles')
|
||||
self.url = 'http://vod.walla.co.il/movie/2642630/one-direction-all-for-one'
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertFalse(subtitles)
|
||||
|
||||
|
||||
class TestCeskaTelevizeSubtitles(BaseTestSubtitles):
|
||||
url = 'http://www.ceskatelevize.cz/ivysilani/10600540290-u6-uzasny-svet-techniky'
|
||||
IE = CeskaTelevizeIE
|
||||
|
||||
def test_allsubtitles(self):
|
||||
self.DL.expect_warning('Automatic Captions not supported by this server')
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertEqual(set(subtitles.keys()), set(['cs']))
|
||||
self.assertTrue(len(subtitles['cs']) > 20000)
|
||||
|
||||
def test_nosubtitles(self):
|
||||
self.DL.expect_warning('video doesn\'t have subtitles')
|
||||
self.url = 'http://www.ceskatelevize.cz/ivysilani/ivysilani/10441294653-hyde-park-civilizace/214411058091220'
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertFalse(subtitles)
|
||||
|
||||
|
||||
class TestLyndaSubtitles(BaseTestSubtitles):
|
||||
url = 'http://www.lynda.com/Bootstrap-tutorials/Using-exercise-files/110885/114408-4.html'
|
||||
IE = LyndaIE
|
||||
|
||||
def test_allsubtitles(self):
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertEqual(set(subtitles.keys()), set(['en']))
|
||||
self.assertEqual(md5(subtitles['en']), '09bbe67222259bed60deaa26997d73a7')
|
||||
|
||||
|
||||
class TestNPOSubtitles(BaseTestSubtitles):
|
||||
url = 'http://www.npo.nl/nos-journaal/28-08-2014/POW_00722860'
|
||||
IE = NPOIE
|
||||
|
||||
def test_allsubtitles(self):
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertEqual(set(subtitles.keys()), set(['nl']))
|
||||
self.assertEqual(md5(subtitles['nl']), 'fc6435027572b63fb4ab143abd5ad3f4')
|
||||
|
||||
|
||||
class TestMTVSubtitles(BaseTestSubtitles):
|
||||
url = 'http://www.cc.com/video-clips/kllhuv/stand-up-greg-fitzsimmons--uncensored---too-good-of-a-mother'
|
||||
IE = ComedyCentralIE
|
||||
|
||||
def getInfoDict(self):
|
||||
return super(TestMTVSubtitles, self).getInfoDict()['entries'][0]
|
||||
|
||||
def test_allsubtitles(self):
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertEqual(set(subtitles.keys()), set(['en']))
|
||||
self.assertEqual(md5(subtitles['en']), 'b9f6ca22a6acf597ec76f61749765e65')
|
||||
|
||||
|
||||
class TestNRKSubtitles(BaseTestSubtitles):
|
||||
url = 'http://tv.nrk.no/serie/ikke-gjoer-dette-hjemme/DMPV73000411/sesong-2/episode-1'
|
||||
IE = NRKTVIE
|
||||
|
||||
def test_allsubtitles(self):
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertEqual(set(subtitles.keys()), set(['no']))
|
||||
self.assertEqual(md5(subtitles['no']), '544fa917d3197fcbee64634559221cc2')
|
||||
|
||||
|
||||
class TestRaiSubtitles(BaseTestSubtitles):
|
||||
url = 'http://www.rai.tv/dl/RaiTV/programmi/media/ContentItem-cb27157f-9dd0-4aee-b788-b1f67643a391.html'
|
||||
IE = RaiIE
|
||||
|
||||
def test_allsubtitles(self):
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertEqual(set(subtitles.keys()), set(['it']))
|
||||
self.assertEqual(md5(subtitles['it']), 'b1d90a98755126b61e667567a1f6680a')
|
||||
|
||||
|
||||
class TestVikiSubtitles(BaseTestSubtitles):
|
||||
url = 'http://www.viki.com/videos/1060846v-punch-episode-18'
|
||||
IE = VikiIE
|
||||
|
||||
def test_allsubtitles(self):
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertEqual(set(subtitles.keys()), set(['en']))
|
||||
self.assertEqual(md5(subtitles['en']), '53cb083a5914b2d84ef1ab67b880d18a')
|
||||
|
||||
|
||||
class TestThePlatformSubtitles(BaseTestSubtitles):
|
||||
# from http://www.3playmedia.com/services-features/tools/integrations/theplatform/
|
||||
# (see http://theplatform.com/about/partners/type/subtitles-closed-captioning/)
|
||||
url = 'theplatform:JFUjUE1_ehvq'
|
||||
IE = ThePlatformIE
|
||||
|
||||
def test_allsubtitles(self):
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertEqual(set(subtitles.keys()), set(['en']))
|
||||
self.assertEqual(md5(subtitles['en']), '97e7670cbae3c4d26ae8bcc7fdd78d4b')
|
||||
|
||||
|
||||
class TestThePlatformFeedSubtitles(BaseTestSubtitles):
|
||||
url = 'http://feed.theplatform.com/f/7wvmTC/msnbc_video-p-test?form=json&pretty=true&range=-40&byGuid=n_hardball_5biden_140207'
|
||||
IE = ThePlatformFeedIE
|
||||
|
||||
def test_allsubtitles(self):
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertEqual(set(subtitles.keys()), set(['en']))
|
||||
self.assertEqual(md5(subtitles['en']), '48649a22e82b2da21c9a67a395eedade')
|
||||
|
||||
|
||||
class TestRtveSubtitles(BaseTestSubtitles):
|
||||
url = 'http://www.rtve.es/alacarta/videos/los-misterios-de-laura/misterios-laura-capitulo-32-misterio-del-numero-17-2-parte/2428621/'
|
||||
IE = RTVEALaCartaIE
|
||||
|
||||
def test_allsubtitles(self):
|
||||
print('Skipping, only available from Spain')
|
||||
return
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertEqual(set(subtitles.keys()), set(['es']))
|
||||
self.assertEqual(md5(subtitles['es']), '69e70cae2d40574fb7316f31d6eb7fca')
|
||||
|
||||
|
||||
class TestFunnyOrDieSubtitles(BaseTestSubtitles):
|
||||
url = 'http://www.funnyordie.com/videos/224829ff6d/judd-apatow-will-direct-your-vine'
|
||||
IE = FunnyOrDieIE
|
||||
|
||||
def test_allsubtitles(self):
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertEqual(set(subtitles.keys()), set(['en']))
|
||||
self.assertEqual(md5(subtitles['en']), 'c5593c193eacd353596c11c2d4f9ecc4')
|
||||
|
||||
|
||||
class TestDemocracynowSubtitles(BaseTestSubtitles):
|
||||
url = 'http://www.democracynow.org/shows/2015/7/3'
|
||||
IE = DemocracynowIE
|
||||
|
||||
def test_allsubtitles(self):
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertEqual(set(subtitles.keys()), set(['en']))
|
||||
self.assertEqual(md5(subtitles['en']), 'acaca989e24a9e45a6719c9b3d60815c')
|
||||
|
||||
def test_subtitles_in_page(self):
|
||||
self.url = 'http://www.democracynow.org/2015/7/3/this_flag_comes_down_today_bree'
|
||||
self.DL.params['writesubtitles'] = True
|
||||
self.DL.params['allsubtitles'] = True
|
||||
subtitles = self.getSubtitles()
|
||||
self.assertEqual(set(subtitles.keys()), set(['en']))
|
||||
self.assertEqual(md5(subtitles['en']), 'acaca989e24a9e45a6719c9b3d60815c')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
80
test/test_swfinterp.py
Normal file
80
test/test_swfinterp.py
Normal file
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Allow direct execution
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
|
||||
import errno
|
||||
import io
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
from youtube_dl.swfinterp import SWFInterpreter
|
||||
|
||||
|
||||
TEST_DIR = os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)), 'swftests')
|
||||
|
||||
|
||||
class TestSWFInterpreter(unittest.TestCase):
|
||||
pass
|
||||
|
||||
|
||||
def _make_testfunc(testfile):
|
||||
m = re.match(r'^(.*)\.(as)$', testfile)
|
||||
if not m:
|
||||
return
|
||||
test_id = m.group(1)
|
||||
|
||||
def test_func(self):
|
||||
as_file = os.path.join(TEST_DIR, testfile)
|
||||
swf_file = os.path.join(TEST_DIR, test_id + '.swf')
|
||||
if ((not os.path.exists(swf_file)) or
|
||||
os.path.getmtime(swf_file) < os.path.getmtime(as_file)):
|
||||
# Recompile
|
||||
try:
|
||||
subprocess.check_call([
|
||||
'mxmlc', '-output', swf_file,
|
||||
'-static-link-runtime-shared-libraries', as_file])
|
||||
except OSError as ose:
|
||||
if ose.errno == errno.ENOENT:
|
||||
print('mxmlc not found! Skipping test.')
|
||||
return
|
||||
raise
|
||||
|
||||
with open(swf_file, 'rb') as swf_f:
|
||||
swf_content = swf_f.read()
|
||||
swfi = SWFInterpreter(swf_content)
|
||||
|
||||
with io.open(as_file, 'r', encoding='utf-8') as as_f:
|
||||
as_content = as_f.read()
|
||||
|
||||
def _find_spec(key):
|
||||
m = re.search(
|
||||
r'(?m)^//\s*%s:\s*(.*?)\n' % re.escape(key), as_content)
|
||||
if not m:
|
||||
raise ValueError('Cannot find %s in %s' % (key, testfile))
|
||||
return json.loads(m.group(1))
|
||||
|
||||
input_args = _find_spec('input')
|
||||
output = _find_spec('output')
|
||||
|
||||
swf_class = swfi.extract_class(test_id)
|
||||
func = swfi.extract_function(swf_class, 'main')
|
||||
res = func(input_args)
|
||||
self.assertEqual(res, output)
|
||||
|
||||
test_func.__name__ = str('test_swf_' + test_id)
|
||||
setattr(TestSWFInterpreter, test_func.__name__, test_func)
|
||||
|
||||
|
||||
for testfile in os.listdir(TEST_DIR):
|
||||
_make_testfunc(testfile)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
63
test/test_unicode_literals.py
Normal file
63
test/test_unicode_literals.py
Normal file
@@ -0,0 +1,63 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Allow direct execution
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
import io
|
||||
import re
|
||||
|
||||
rootDir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
IGNORED_FILES = [
|
||||
'setup.py', # http://bugs.python.org/issue13943
|
||||
'conf.py',
|
||||
'buildserver.py',
|
||||
]
|
||||
|
||||
IGNORED_DIRS = [
|
||||
'.git',
|
||||
'.tox',
|
||||
]
|
||||
|
||||
from test.helper import assertRegexpMatches
|
||||
|
||||
|
||||
class TestUnicodeLiterals(unittest.TestCase):
|
||||
def test_all_files(self):
|
||||
for dirpath, dirnames, filenames in os.walk(rootDir):
|
||||
for ignore_dir in IGNORED_DIRS:
|
||||
if ignore_dir in dirnames:
|
||||
# If we remove the directory from dirnames os.walk won't
|
||||
# recurse into it
|
||||
dirnames.remove(ignore_dir)
|
||||
for basename in filenames:
|
||||
if not basename.endswith('.py'):
|
||||
continue
|
||||
if basename in IGNORED_FILES:
|
||||
continue
|
||||
|
||||
fn = os.path.join(dirpath, basename)
|
||||
with io.open(fn, encoding='utf-8') as inf:
|
||||
code = inf.read()
|
||||
|
||||
if "'" not in code and '"' not in code:
|
||||
continue
|
||||
assertRegexpMatches(
|
||||
self,
|
||||
code,
|
||||
r'(?:(?:#.*?|\s*)\n)*from __future__ import (?:[a-z_]+,\s*)*unicode_literals',
|
||||
'unicode_literals import missing in %s' % fn)
|
||||
|
||||
m = re.search(r'(?<=\s)u[\'"](?!\)|,|$)', code)
|
||||
if m is not None:
|
||||
self.assertTrue(
|
||||
m is None,
|
||||
'u present in %s, around %s' % (
|
||||
fn, code[m.start() - 10:m.end() + 10]))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
751
test/test_utils.py
Normal file
751
test/test_utils.py
Normal file
@@ -0,0 +1,751 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Allow direct execution
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
|
||||
# Various small unit tests
|
||||
import io
|
||||
import json
|
||||
import xml.etree.ElementTree
|
||||
|
||||
from youtube_dl.utils import (
|
||||
age_restricted,
|
||||
args_to_str,
|
||||
clean_html,
|
||||
DateRange,
|
||||
detect_exe_version,
|
||||
determine_ext,
|
||||
encodeFilename,
|
||||
escape_rfc3986,
|
||||
escape_url,
|
||||
ExtractorError,
|
||||
find_xpath_attr,
|
||||
fix_xml_ampersands,
|
||||
InAdvancePagedList,
|
||||
intlist_to_bytes,
|
||||
is_html,
|
||||
js_to_json,
|
||||
limit_length,
|
||||
OnDemandPagedList,
|
||||
orderedSet,
|
||||
parse_duration,
|
||||
parse_filesize,
|
||||
parse_iso8601,
|
||||
read_batch_urls,
|
||||
sanitize_filename,
|
||||
sanitize_path,
|
||||
prepend_extension,
|
||||
replace_extension,
|
||||
shell_quote,
|
||||
smuggle_url,
|
||||
str_to_int,
|
||||
strip_jsonp,
|
||||
struct_unpack,
|
||||
timeconvert,
|
||||
unescapeHTML,
|
||||
unified_strdate,
|
||||
unsmuggle_url,
|
||||
uppercase_escape,
|
||||
lowercase_escape,
|
||||
url_basename,
|
||||
urlencode_postdata,
|
||||
version_tuple,
|
||||
xpath_with_ns,
|
||||
xpath_element,
|
||||
xpath_text,
|
||||
xpath_attr,
|
||||
render_table,
|
||||
match_str,
|
||||
parse_dfxp_time_expr,
|
||||
dfxp2srt,
|
||||
cli_option,
|
||||
cli_valueless_option,
|
||||
cli_bool_option,
|
||||
)
|
||||
from youtube_dl.compat import (
|
||||
compat_etree_fromstring,
|
||||
)
|
||||
|
||||
|
||||
class TestUtil(unittest.TestCase):
|
||||
def test_timeconvert(self):
|
||||
self.assertTrue(timeconvert('') is None)
|
||||
self.assertTrue(timeconvert('bougrg') is None)
|
||||
|
||||
def test_sanitize_filename(self):
|
||||
self.assertEqual(sanitize_filename('abc'), 'abc')
|
||||
self.assertEqual(sanitize_filename('abc_d-e'), 'abc_d-e')
|
||||
|
||||
self.assertEqual(sanitize_filename('123'), '123')
|
||||
|
||||
self.assertEqual('abc_de', sanitize_filename('abc/de'))
|
||||
self.assertFalse('/' in sanitize_filename('abc/de///'))
|
||||
|
||||
self.assertEqual('abc_de', sanitize_filename('abc/<>\\*|de'))
|
||||
self.assertEqual('xxx', sanitize_filename('xxx/<>\\*|'))
|
||||
self.assertEqual('yes no', sanitize_filename('yes? no'))
|
||||
self.assertEqual('this - that', sanitize_filename('this: that'))
|
||||
|
||||
self.assertEqual(sanitize_filename('AT&T'), 'AT&T')
|
||||
aumlaut = 'ä'
|
||||
self.assertEqual(sanitize_filename(aumlaut), aumlaut)
|
||||
tests = '\u043a\u0438\u0440\u0438\u043b\u043b\u0438\u0446\u0430'
|
||||
self.assertEqual(sanitize_filename(tests), tests)
|
||||
|
||||
self.assertEqual(
|
||||
sanitize_filename('New World record at 0:12:34'),
|
||||
'New World record at 0_12_34')
|
||||
|
||||
self.assertEqual(sanitize_filename('--gasdgf'), '_-gasdgf')
|
||||
self.assertEqual(sanitize_filename('--gasdgf', is_id=True), '--gasdgf')
|
||||
self.assertEqual(sanitize_filename('.gasdgf'), 'gasdgf')
|
||||
self.assertEqual(sanitize_filename('.gasdgf', is_id=True), '.gasdgf')
|
||||
|
||||
forbidden = '"\0\\/'
|
||||
for fc in forbidden:
|
||||
for fbc in forbidden:
|
||||
self.assertTrue(fbc not in sanitize_filename(fc))
|
||||
|
||||
def test_sanitize_filename_restricted(self):
|
||||
self.assertEqual(sanitize_filename('abc', restricted=True), 'abc')
|
||||
self.assertEqual(sanitize_filename('abc_d-e', restricted=True), 'abc_d-e')
|
||||
|
||||
self.assertEqual(sanitize_filename('123', restricted=True), '123')
|
||||
|
||||
self.assertEqual('abc_de', sanitize_filename('abc/de', restricted=True))
|
||||
self.assertFalse('/' in sanitize_filename('abc/de///', restricted=True))
|
||||
|
||||
self.assertEqual('abc_de', sanitize_filename('abc/<>\\*|de', restricted=True))
|
||||
self.assertEqual('xxx', sanitize_filename('xxx/<>\\*|', restricted=True))
|
||||
self.assertEqual('yes_no', sanitize_filename('yes? no', restricted=True))
|
||||
self.assertEqual('this_-_that', sanitize_filename('this: that', restricted=True))
|
||||
|
||||
tests = 'a\xe4b\u4e2d\u56fd\u7684c'
|
||||
self.assertEqual(sanitize_filename(tests, restricted=True), 'a_b_c')
|
||||
self.assertTrue(sanitize_filename('\xf6', restricted=True) != '') # No empty filename
|
||||
|
||||
forbidden = '"\0\\/&!: \'\t\n()[]{}$;`^,#'
|
||||
for fc in forbidden:
|
||||
for fbc in forbidden:
|
||||
self.assertTrue(fbc not in sanitize_filename(fc, restricted=True))
|
||||
|
||||
# Handle a common case more neatly
|
||||
self.assertEqual(sanitize_filename('\u5927\u58f0\u5e26 - Song', restricted=True), 'Song')
|
||||
self.assertEqual(sanitize_filename('\u603b\u7edf: Speech', restricted=True), 'Speech')
|
||||
# .. but make sure the file name is never empty
|
||||
self.assertTrue(sanitize_filename('-', restricted=True) != '')
|
||||
self.assertTrue(sanitize_filename(':', restricted=True) != '')
|
||||
|
||||
def test_sanitize_ids(self):
|
||||
self.assertEqual(sanitize_filename('_n_cd26wFpw', is_id=True), '_n_cd26wFpw')
|
||||
self.assertEqual(sanitize_filename('_BD_eEpuzXw', is_id=True), '_BD_eEpuzXw')
|
||||
self.assertEqual(sanitize_filename('N0Y__7-UOdI', is_id=True), 'N0Y__7-UOdI')
|
||||
|
||||
def test_sanitize_path(self):
|
||||
if sys.platform != 'win32':
|
||||
return
|
||||
|
||||
self.assertEqual(sanitize_path('abc'), 'abc')
|
||||
self.assertEqual(sanitize_path('abc/def'), 'abc\\def')
|
||||
self.assertEqual(sanitize_path('abc\\def'), 'abc\\def')
|
||||
self.assertEqual(sanitize_path('abc|def'), 'abc#def')
|
||||
self.assertEqual(sanitize_path('<>:"|?*'), '#######')
|
||||
self.assertEqual(sanitize_path('C:/abc/def'), 'C:\\abc\\def')
|
||||
self.assertEqual(sanitize_path('C?:/abc/def'), 'C##\\abc\\def')
|
||||
|
||||
self.assertEqual(sanitize_path('\\\\?\\UNC\\ComputerName\\abc'), '\\\\?\\UNC\\ComputerName\\abc')
|
||||
self.assertEqual(sanitize_path('\\\\?\\UNC/ComputerName/abc'), '\\\\?\\UNC\\ComputerName\\abc')
|
||||
|
||||
self.assertEqual(sanitize_path('\\\\?\\C:\\abc'), '\\\\?\\C:\\abc')
|
||||
self.assertEqual(sanitize_path('\\\\?\\C:/abc'), '\\\\?\\C:\\abc')
|
||||
self.assertEqual(sanitize_path('\\\\?\\C:\\ab?c\\de:f'), '\\\\?\\C:\\ab#c\\de#f')
|
||||
self.assertEqual(sanitize_path('\\\\?\\C:\\abc'), '\\\\?\\C:\\abc')
|
||||
|
||||
self.assertEqual(
|
||||
sanitize_path('youtube/%(uploader)s/%(autonumber)s-%(title)s-%(upload_date)s.%(ext)s'),
|
||||
'youtube\\%(uploader)s\\%(autonumber)s-%(title)s-%(upload_date)s.%(ext)s')
|
||||
|
||||
self.assertEqual(
|
||||
sanitize_path('youtube/TheWreckingYard ./00001-Not bad, Especially for Free! (1987 Yamaha 700)-20141116.mp4.part'),
|
||||
'youtube\\TheWreckingYard #\\00001-Not bad, Especially for Free! (1987 Yamaha 700)-20141116.mp4.part')
|
||||
self.assertEqual(sanitize_path('abc/def...'), 'abc\\def..#')
|
||||
self.assertEqual(sanitize_path('abc.../def'), 'abc..#\\def')
|
||||
self.assertEqual(sanitize_path('abc.../def...'), 'abc..#\\def..#')
|
||||
|
||||
self.assertEqual(sanitize_path('../abc'), '..\\abc')
|
||||
self.assertEqual(sanitize_path('../../abc'), '..\\..\\abc')
|
||||
self.assertEqual(sanitize_path('./abc'), 'abc')
|
||||
self.assertEqual(sanitize_path('./../abc'), '..\\abc')
|
||||
|
||||
def test_prepend_extension(self):
|
||||
self.assertEqual(prepend_extension('abc.ext', 'temp'), 'abc.temp.ext')
|
||||
self.assertEqual(prepend_extension('abc.ext', 'temp', 'ext'), 'abc.temp.ext')
|
||||
self.assertEqual(prepend_extension('abc.unexpected_ext', 'temp', 'ext'), 'abc.unexpected_ext.temp')
|
||||
self.assertEqual(prepend_extension('abc', 'temp'), 'abc.temp')
|
||||
self.assertEqual(prepend_extension('.abc', 'temp'), '.abc.temp')
|
||||
self.assertEqual(prepend_extension('.abc.ext', 'temp'), '.abc.temp.ext')
|
||||
|
||||
def test_replace_extension(self):
|
||||
self.assertEqual(replace_extension('abc.ext', 'temp'), 'abc.temp')
|
||||
self.assertEqual(replace_extension('abc.ext', 'temp', 'ext'), 'abc.temp')
|
||||
self.assertEqual(replace_extension('abc.unexpected_ext', 'temp', 'ext'), 'abc.unexpected_ext.temp')
|
||||
self.assertEqual(replace_extension('abc', 'temp'), 'abc.temp')
|
||||
self.assertEqual(replace_extension('.abc', 'temp'), '.abc.temp')
|
||||
self.assertEqual(replace_extension('.abc.ext', 'temp'), '.abc.temp')
|
||||
|
||||
def test_ordered_set(self):
|
||||
self.assertEqual(orderedSet([1, 1, 2, 3, 4, 4, 5, 6, 7, 3, 5]), [1, 2, 3, 4, 5, 6, 7])
|
||||
self.assertEqual(orderedSet([]), [])
|
||||
self.assertEqual(orderedSet([1]), [1])
|
||||
# keep the list ordered
|
||||
self.assertEqual(orderedSet([135, 1, 1, 1]), [135, 1])
|
||||
|
||||
def test_unescape_html(self):
|
||||
self.assertEqual(unescapeHTML('%20;'), '%20;')
|
||||
self.assertEqual(unescapeHTML('/'), '/')
|
||||
self.assertEqual(unescapeHTML('/'), '/')
|
||||
self.assertEqual(unescapeHTML('é'), 'é')
|
||||
self.assertEqual(unescapeHTML('�'), '�')
|
||||
|
||||
def test_daterange(self):
|
||||
_20century = DateRange("19000101", "20000101")
|
||||
self.assertFalse("17890714" in _20century)
|
||||
_ac = DateRange("00010101")
|
||||
self.assertTrue("19690721" in _ac)
|
||||
_firstmilenium = DateRange(end="10000101")
|
||||
self.assertTrue("07110427" in _firstmilenium)
|
||||
|
||||
def test_unified_dates(self):
|
||||
self.assertEqual(unified_strdate('December 21, 2010'), '20101221')
|
||||
self.assertEqual(unified_strdate('8/7/2009'), '20090708')
|
||||
self.assertEqual(unified_strdate('Dec 14, 2012'), '20121214')
|
||||
self.assertEqual(unified_strdate('2012/10/11 01:56:38 +0000'), '20121011')
|
||||
self.assertEqual(unified_strdate('1968 12 10'), '19681210')
|
||||
self.assertEqual(unified_strdate('1968-12-10'), '19681210')
|
||||
self.assertEqual(unified_strdate('28/01/2014 21:00:00 +0100'), '20140128')
|
||||
self.assertEqual(
|
||||
unified_strdate('11/26/2014 11:30:00 AM PST', day_first=False),
|
||||
'20141126')
|
||||
self.assertEqual(
|
||||
unified_strdate('2/2/2015 6:47:40 PM', day_first=False),
|
||||
'20150202')
|
||||
self.assertEqual(unified_strdate('25-09-2014'), '20140925')
|
||||
self.assertEqual(unified_strdate('UNKNOWN DATE FORMAT'), None)
|
||||
|
||||
def test_determine_ext(self):
|
||||
self.assertEqual(determine_ext('http://example.com/foo/bar.mp4/?download'), 'mp4')
|
||||
self.assertEqual(determine_ext('http://example.com/foo/bar/?download', None), None)
|
||||
self.assertEqual(determine_ext('http://example.com/foo/bar.nonext/?download', None), None)
|
||||
self.assertEqual(determine_ext('http://example.com/foo/bar/mp4?download', None), None)
|
||||
self.assertEqual(determine_ext('http://example.com/foo/bar.m3u8//?download'), 'm3u8')
|
||||
|
||||
def test_find_xpath_attr(self):
|
||||
testxml = '''<root>
|
||||
<node/>
|
||||
<node x="a"/>
|
||||
<node x="a" y="c" />
|
||||
<node x="b" y="d" />
|
||||
<node x="" />
|
||||
</root>'''
|
||||
doc = compat_etree_fromstring(testxml)
|
||||
|
||||
self.assertEqual(find_xpath_attr(doc, './/fourohfour', 'n'), None)
|
||||
self.assertEqual(find_xpath_attr(doc, './/fourohfour', 'n', 'v'), None)
|
||||
self.assertEqual(find_xpath_attr(doc, './/node', 'n'), None)
|
||||
self.assertEqual(find_xpath_attr(doc, './/node', 'n', 'v'), None)
|
||||
self.assertEqual(find_xpath_attr(doc, './/node', 'x'), doc[1])
|
||||
self.assertEqual(find_xpath_attr(doc, './/node', 'x', 'a'), doc[1])
|
||||
self.assertEqual(find_xpath_attr(doc, './/node', 'x', 'b'), doc[3])
|
||||
self.assertEqual(find_xpath_attr(doc, './/node', 'y'), doc[2])
|
||||
self.assertEqual(find_xpath_attr(doc, './/node', 'y', 'c'), doc[2])
|
||||
self.assertEqual(find_xpath_attr(doc, './/node', 'y', 'd'), doc[3])
|
||||
self.assertEqual(find_xpath_attr(doc, './/node', 'x', ''), doc[4])
|
||||
|
||||
def test_xpath_with_ns(self):
|
||||
testxml = '''<root xmlns:media="http://example.com/">
|
||||
<media:song>
|
||||
<media:author>The Author</media:author>
|
||||
<url>http://server.com/download.mp3</url>
|
||||
</media:song>
|
||||
</root>'''
|
||||
doc = compat_etree_fromstring(testxml)
|
||||
find = lambda p: doc.find(xpath_with_ns(p, {'media': 'http://example.com/'}))
|
||||
self.assertTrue(find('media:song') is not None)
|
||||
self.assertEqual(find('media:song/media:author').text, 'The Author')
|
||||
self.assertEqual(find('media:song/url').text, 'http://server.com/download.mp3')
|
||||
|
||||
def test_xpath_element(self):
|
||||
doc = xml.etree.ElementTree.Element('root')
|
||||
div = xml.etree.ElementTree.SubElement(doc, 'div')
|
||||
p = xml.etree.ElementTree.SubElement(div, 'p')
|
||||
p.text = 'Foo'
|
||||
self.assertEqual(xpath_element(doc, 'div/p'), p)
|
||||
self.assertEqual(xpath_element(doc, ['div/p']), p)
|
||||
self.assertEqual(xpath_element(doc, ['div/bar', 'div/p']), p)
|
||||
self.assertEqual(xpath_element(doc, 'div/bar', default='default'), 'default')
|
||||
self.assertEqual(xpath_element(doc, ['div/bar'], default='default'), 'default')
|
||||
self.assertTrue(xpath_element(doc, 'div/bar') is None)
|
||||
self.assertTrue(xpath_element(doc, ['div/bar']) is None)
|
||||
self.assertTrue(xpath_element(doc, ['div/bar'], 'div/baz') is None)
|
||||
self.assertRaises(ExtractorError, xpath_element, doc, 'div/bar', fatal=True)
|
||||
self.assertRaises(ExtractorError, xpath_element, doc, ['div/bar'], fatal=True)
|
||||
self.assertRaises(ExtractorError, xpath_element, doc, ['div/bar', 'div/baz'], fatal=True)
|
||||
|
||||
def test_xpath_text(self):
|
||||
testxml = '''<root>
|
||||
<div>
|
||||
<p>Foo</p>
|
||||
</div>
|
||||
</root>'''
|
||||
doc = compat_etree_fromstring(testxml)
|
||||
self.assertEqual(xpath_text(doc, 'div/p'), 'Foo')
|
||||
self.assertEqual(xpath_text(doc, 'div/bar', default='default'), 'default')
|
||||
self.assertTrue(xpath_text(doc, 'div/bar') is None)
|
||||
self.assertRaises(ExtractorError, xpath_text, doc, 'div/bar', fatal=True)
|
||||
|
||||
def test_xpath_attr(self):
|
||||
testxml = '''<root>
|
||||
<div>
|
||||
<p x="a">Foo</p>
|
||||
</div>
|
||||
</root>'''
|
||||
doc = compat_etree_fromstring(testxml)
|
||||
self.assertEqual(xpath_attr(doc, 'div/p', 'x'), 'a')
|
||||
self.assertEqual(xpath_attr(doc, 'div/bar', 'x'), None)
|
||||
self.assertEqual(xpath_attr(doc, 'div/p', 'y'), None)
|
||||
self.assertEqual(xpath_attr(doc, 'div/bar', 'x', default='default'), 'default')
|
||||
self.assertEqual(xpath_attr(doc, 'div/p', 'y', default='default'), 'default')
|
||||
self.assertRaises(ExtractorError, xpath_attr, doc, 'div/bar', 'x', fatal=True)
|
||||
self.assertRaises(ExtractorError, xpath_attr, doc, 'div/p', 'y', fatal=True)
|
||||
|
||||
def test_smuggle_url(self):
|
||||
data = {"ö": "ö", "abc": [3]}
|
||||
url = 'https://foo.bar/baz?x=y#a'
|
||||
smug_url = smuggle_url(url, data)
|
||||
unsmug_url, unsmug_data = unsmuggle_url(smug_url)
|
||||
self.assertEqual(url, unsmug_url)
|
||||
self.assertEqual(data, unsmug_data)
|
||||
|
||||
res_url, res_data = unsmuggle_url(url)
|
||||
self.assertEqual(res_url, url)
|
||||
self.assertEqual(res_data, None)
|
||||
|
||||
def test_shell_quote(self):
|
||||
args = ['ffmpeg', '-i', encodeFilename('ñ€ß\'.mp4')]
|
||||
self.assertEqual(shell_quote(args), """ffmpeg -i 'ñ€ß'"'"'.mp4'""")
|
||||
|
||||
def test_str_to_int(self):
|
||||
self.assertEqual(str_to_int('123,456'), 123456)
|
||||
self.assertEqual(str_to_int('123.456'), 123456)
|
||||
|
||||
def test_url_basename(self):
|
||||
self.assertEqual(url_basename('http://foo.de/'), '')
|
||||
self.assertEqual(url_basename('http://foo.de/bar/baz'), 'baz')
|
||||
self.assertEqual(url_basename('http://foo.de/bar/baz?x=y'), 'baz')
|
||||
self.assertEqual(url_basename('http://foo.de/bar/baz#x=y'), 'baz')
|
||||
self.assertEqual(url_basename('http://foo.de/bar/baz/'), 'baz')
|
||||
self.assertEqual(
|
||||
url_basename('http://media.w3.org/2010/05/sintel/trailer.mp4'),
|
||||
'trailer.mp4')
|
||||
|
||||
def test_parse_duration(self):
|
||||
self.assertEqual(parse_duration(None), None)
|
||||
self.assertEqual(parse_duration(False), None)
|
||||
self.assertEqual(parse_duration('invalid'), None)
|
||||
self.assertEqual(parse_duration('1'), 1)
|
||||
self.assertEqual(parse_duration('1337:12'), 80232)
|
||||
self.assertEqual(parse_duration('9:12:43'), 33163)
|
||||
self.assertEqual(parse_duration('12:00'), 720)
|
||||
self.assertEqual(parse_duration('00:01:01'), 61)
|
||||
self.assertEqual(parse_duration('x:y'), None)
|
||||
self.assertEqual(parse_duration('3h11m53s'), 11513)
|
||||
self.assertEqual(parse_duration('3h 11m 53s'), 11513)
|
||||
self.assertEqual(parse_duration('3 hours 11 minutes 53 seconds'), 11513)
|
||||
self.assertEqual(parse_duration('3 hours 11 mins 53 secs'), 11513)
|
||||
self.assertEqual(parse_duration('62m45s'), 3765)
|
||||
self.assertEqual(parse_duration('6m59s'), 419)
|
||||
self.assertEqual(parse_duration('49s'), 49)
|
||||
self.assertEqual(parse_duration('0h0m0s'), 0)
|
||||
self.assertEqual(parse_duration('0m0s'), 0)
|
||||
self.assertEqual(parse_duration('0s'), 0)
|
||||
self.assertEqual(parse_duration('01:02:03.05'), 3723.05)
|
||||
self.assertEqual(parse_duration('T30M38S'), 1838)
|
||||
self.assertEqual(parse_duration('5 s'), 5)
|
||||
self.assertEqual(parse_duration('3 min'), 180)
|
||||
self.assertEqual(parse_duration('2.5 hours'), 9000)
|
||||
self.assertEqual(parse_duration('02:03:04'), 7384)
|
||||
self.assertEqual(parse_duration('01:02:03:04'), 93784)
|
||||
self.assertEqual(parse_duration('1 hour 3 minutes'), 3780)
|
||||
self.assertEqual(parse_duration('87 Min.'), 5220)
|
||||
|
||||
def test_fix_xml_ampersands(self):
|
||||
self.assertEqual(
|
||||
fix_xml_ampersands('"&x=y&z=a'), '"&x=y&z=a')
|
||||
self.assertEqual(
|
||||
fix_xml_ampersands('"&x=y&wrong;&z=a'),
|
||||
'"&x=y&wrong;&z=a')
|
||||
self.assertEqual(
|
||||
fix_xml_ampersands('&'><"'),
|
||||
'&'><"')
|
||||
self.assertEqual(
|
||||
fix_xml_ampersands('Ӓ᪼'), 'Ӓ᪼')
|
||||
self.assertEqual(fix_xml_ampersands('&#&#'), '&#&#')
|
||||
|
||||
def test_paged_list(self):
|
||||
def testPL(size, pagesize, sliceargs, expected):
|
||||
def get_page(pagenum):
|
||||
firstid = pagenum * pagesize
|
||||
upto = min(size, pagenum * pagesize + pagesize)
|
||||
for i in range(firstid, upto):
|
||||
yield i
|
||||
|
||||
pl = OnDemandPagedList(get_page, pagesize)
|
||||
got = pl.getslice(*sliceargs)
|
||||
self.assertEqual(got, expected)
|
||||
|
||||
iapl = InAdvancePagedList(get_page, size // pagesize + 1, pagesize)
|
||||
got = iapl.getslice(*sliceargs)
|
||||
self.assertEqual(got, expected)
|
||||
|
||||
testPL(5, 2, (), [0, 1, 2, 3, 4])
|
||||
testPL(5, 2, (1,), [1, 2, 3, 4])
|
||||
testPL(5, 2, (2,), [2, 3, 4])
|
||||
testPL(5, 2, (4,), [4])
|
||||
testPL(5, 2, (0, 3), [0, 1, 2])
|
||||
testPL(5, 2, (1, 4), [1, 2, 3])
|
||||
testPL(5, 2, (2, 99), [2, 3, 4])
|
||||
testPL(5, 2, (20, 99), [])
|
||||
|
||||
def test_struct_unpack(self):
|
||||
self.assertEqual(struct_unpack('!B', b'\x00'), (0,))
|
||||
|
||||
def test_read_batch_urls(self):
|
||||
f = io.StringIO('''\xef\xbb\xbf foo
|
||||
bar\r
|
||||
baz
|
||||
# More after this line\r
|
||||
; or after this
|
||||
bam''')
|
||||
self.assertEqual(read_batch_urls(f), ['foo', 'bar', 'baz', 'bam'])
|
||||
|
||||
def test_urlencode_postdata(self):
|
||||
data = urlencode_postdata({'username': 'foo@bar.com', 'password': '1234'})
|
||||
self.assertTrue(isinstance(data, bytes))
|
||||
|
||||
def test_parse_iso8601(self):
|
||||
self.assertEqual(parse_iso8601('2014-03-23T23:04:26+0100'), 1395612266)
|
||||
self.assertEqual(parse_iso8601('2014-03-23T22:04:26+0000'), 1395612266)
|
||||
self.assertEqual(parse_iso8601('2014-03-23T22:04:26Z'), 1395612266)
|
||||
self.assertEqual(parse_iso8601('2014-03-23T22:04:26.1234Z'), 1395612266)
|
||||
self.assertEqual(parse_iso8601('2015-09-29T08:27:31.727'), 1443515251)
|
||||
self.assertEqual(parse_iso8601('2015-09-29T08-27-31.727'), None)
|
||||
|
||||
def test_strip_jsonp(self):
|
||||
stripped = strip_jsonp('cb ([ {"id":"532cb",\n\n\n"x":\n3}\n]\n);')
|
||||
d = json.loads(stripped)
|
||||
self.assertEqual(d, [{"id": "532cb", "x": 3}])
|
||||
|
||||
stripped = strip_jsonp('parseMetadata({"STATUS":"OK"})\n\n\n//epc')
|
||||
d = json.loads(stripped)
|
||||
self.assertEqual(d, {'STATUS': 'OK'})
|
||||
|
||||
def test_uppercase_escape(self):
|
||||
self.assertEqual(uppercase_escape('aä'), 'aä')
|
||||
self.assertEqual(uppercase_escape('\\U0001d550'), '𝕐')
|
||||
|
||||
def test_lowercase_escape(self):
|
||||
self.assertEqual(lowercase_escape('aä'), 'aä')
|
||||
self.assertEqual(lowercase_escape('\\u0026'), '&')
|
||||
|
||||
def test_limit_length(self):
|
||||
self.assertEqual(limit_length(None, 12), None)
|
||||
self.assertEqual(limit_length('foo', 12), 'foo')
|
||||
self.assertTrue(
|
||||
limit_length('foo bar baz asd', 12).startswith('foo bar'))
|
||||
self.assertTrue('...' in limit_length('foo bar baz asd', 12))
|
||||
|
||||
def test_escape_rfc3986(self):
|
||||
reserved = "!*'();:@&=+$,/?#[]"
|
||||
unreserved = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~'
|
||||
self.assertEqual(escape_rfc3986(reserved), reserved)
|
||||
self.assertEqual(escape_rfc3986(unreserved), unreserved)
|
||||
self.assertEqual(escape_rfc3986('тест'), '%D1%82%D0%B5%D1%81%D1%82')
|
||||
self.assertEqual(escape_rfc3986('%D1%82%D0%B5%D1%81%D1%82'), '%D1%82%D0%B5%D1%81%D1%82')
|
||||
self.assertEqual(escape_rfc3986('foo bar'), 'foo%20bar')
|
||||
self.assertEqual(escape_rfc3986('foo%20bar'), 'foo%20bar')
|
||||
|
||||
def test_escape_url(self):
|
||||
self.assertEqual(
|
||||
escape_url('http://wowza.imust.org/srv/vod/telemb/new/UPLOAD/UPLOAD/20224_IncendieHavré_FD.mp4'),
|
||||
'http://wowza.imust.org/srv/vod/telemb/new/UPLOAD/UPLOAD/20224_IncendieHavre%CC%81_FD.mp4'
|
||||
)
|
||||
self.assertEqual(
|
||||
escape_url('http://www.ardmediathek.de/tv/Sturm-der-Liebe/Folge-2036-Zu-Mann-und-Frau-erklärt/Das-Erste/Video?documentId=22673108&bcastId=5290'),
|
||||
'http://www.ardmediathek.de/tv/Sturm-der-Liebe/Folge-2036-Zu-Mann-und-Frau-erkl%C3%A4rt/Das-Erste/Video?documentId=22673108&bcastId=5290'
|
||||
)
|
||||
self.assertEqual(
|
||||
escape_url('http://тест.рф/фрагмент'),
|
||||
'http://тест.рф/%D1%84%D1%80%D0%B0%D0%B3%D0%BC%D0%B5%D0%BD%D1%82'
|
||||
)
|
||||
self.assertEqual(
|
||||
escape_url('http://тест.рф/абв?абв=абв#абв'),
|
||||
'http://тест.рф/%D0%B0%D0%B1%D0%B2?%D0%B0%D0%B1%D0%B2=%D0%B0%D0%B1%D0%B2#%D0%B0%D0%B1%D0%B2'
|
||||
)
|
||||
self.assertEqual(escape_url('http://vimeo.com/56015672#at=0'), 'http://vimeo.com/56015672#at=0')
|
||||
|
||||
def test_js_to_json_realworld(self):
|
||||
inp = '''{
|
||||
'clip':{'provider':'pseudo'}
|
||||
}'''
|
||||
self.assertEqual(js_to_json(inp), '''{
|
||||
"clip":{"provider":"pseudo"}
|
||||
}''')
|
||||
json.loads(js_to_json(inp))
|
||||
|
||||
inp = '''{
|
||||
'playlist':[{'controls':{'all':null}}]
|
||||
}'''
|
||||
self.assertEqual(js_to_json(inp), '''{
|
||||
"playlist":[{"controls":{"all":null}}]
|
||||
}''')
|
||||
|
||||
inp = '''"The CW\\'s \\'Crazy Ex-Girlfriend\\'"'''
|
||||
self.assertEqual(js_to_json(inp), '''"The CW's 'Crazy Ex-Girlfriend'"''')
|
||||
|
||||
inp = '"SAND Number: SAND 2013-7800P\\nPresenter: Tom Russo\\nHabanero Software Training - Xyce Software\\nXyce, Sandia\\u0027s"'
|
||||
json_code = js_to_json(inp)
|
||||
self.assertEqual(json.loads(json_code), json.loads(inp))
|
||||
|
||||
def test_js_to_json_edgecases(self):
|
||||
on = js_to_json("{abc_def:'1\\'\\\\2\\\\\\'3\"4'}")
|
||||
self.assertEqual(json.loads(on), {"abc_def": "1'\\2\\'3\"4"})
|
||||
|
||||
on = js_to_json('{"abc": true}')
|
||||
self.assertEqual(json.loads(on), {'abc': True})
|
||||
|
||||
# Ignore JavaScript code as well
|
||||
on = js_to_json('''{
|
||||
"x": 1,
|
||||
y: "a",
|
||||
z: some.code
|
||||
}''')
|
||||
d = json.loads(on)
|
||||
self.assertEqual(d['x'], 1)
|
||||
self.assertEqual(d['y'], 'a')
|
||||
|
||||
on = js_to_json('["abc", "def",]')
|
||||
self.assertEqual(json.loads(on), ['abc', 'def'])
|
||||
|
||||
on = js_to_json('{"abc": "def",}')
|
||||
self.assertEqual(json.loads(on), {'abc': 'def'})
|
||||
|
||||
def test_clean_html(self):
|
||||
self.assertEqual(clean_html('a:\nb'), 'a: b')
|
||||
self.assertEqual(clean_html('a:\n "b"'), 'a: "b"')
|
||||
|
||||
def test_intlist_to_bytes(self):
|
||||
self.assertEqual(
|
||||
intlist_to_bytes([0, 1, 127, 128, 255]),
|
||||
b'\x00\x01\x7f\x80\xff')
|
||||
|
||||
def test_args_to_str(self):
|
||||
self.assertEqual(
|
||||
args_to_str(['foo', 'ba/r', '-baz', '2 be', '']),
|
||||
'foo ba/r -baz \'2 be\' \'\''
|
||||
)
|
||||
|
||||
def test_parse_filesize(self):
|
||||
self.assertEqual(parse_filesize(None), None)
|
||||
self.assertEqual(parse_filesize(''), None)
|
||||
self.assertEqual(parse_filesize('91 B'), 91)
|
||||
self.assertEqual(parse_filesize('foobar'), None)
|
||||
self.assertEqual(parse_filesize('2 MiB'), 2097152)
|
||||
self.assertEqual(parse_filesize('5 GB'), 5000000000)
|
||||
self.assertEqual(parse_filesize('1.2Tb'), 1200000000000)
|
||||
self.assertEqual(parse_filesize('1,24 KB'), 1240)
|
||||
|
||||
def test_version_tuple(self):
|
||||
self.assertEqual(version_tuple('1'), (1,))
|
||||
self.assertEqual(version_tuple('10.23.344'), (10, 23, 344))
|
||||
self.assertEqual(version_tuple('10.1-6'), (10, 1, 6)) # avconv style
|
||||
|
||||
def test_detect_exe_version(self):
|
||||
self.assertEqual(detect_exe_version('''ffmpeg version 1.2.1
|
||||
built on May 27 2013 08:37:26 with gcc 4.7 (Debian 4.7.3-4)
|
||||
configuration: --prefix=/usr --extra-'''), '1.2.1')
|
||||
self.assertEqual(detect_exe_version('''ffmpeg version N-63176-g1fb4685
|
||||
built on May 15 2014 22:09:06 with gcc 4.8.2 (GCC)'''), 'N-63176-g1fb4685')
|
||||
self.assertEqual(detect_exe_version('''X server found. dri2 connection failed!
|
||||
Trying to open render node...
|
||||
Success at /dev/dri/renderD128.
|
||||
ffmpeg version 2.4.4 Copyright (c) 2000-2014 the FFmpeg ...'''), '2.4.4')
|
||||
|
||||
def test_age_restricted(self):
|
||||
self.assertFalse(age_restricted(None, 10)) # unrestricted content
|
||||
self.assertFalse(age_restricted(1, None)) # unrestricted policy
|
||||
self.assertFalse(age_restricted(8, 10))
|
||||
self.assertTrue(age_restricted(18, 14))
|
||||
self.assertFalse(age_restricted(18, 18))
|
||||
|
||||
def test_is_html(self):
|
||||
self.assertFalse(is_html(b'\x49\x44\x43<html'))
|
||||
self.assertTrue(is_html(b'<!DOCTYPE foo>\xaaa'))
|
||||
self.assertTrue(is_html( # UTF-8 with BOM
|
||||
b'\xef\xbb\xbf<!DOCTYPE foo>\xaaa'))
|
||||
self.assertTrue(is_html( # UTF-16-LE
|
||||
b'\xff\xfe<\x00h\x00t\x00m\x00l\x00>\x00\xe4\x00'
|
||||
))
|
||||
self.assertTrue(is_html( # UTF-16-BE
|
||||
b'\xfe\xff\x00<\x00h\x00t\x00m\x00l\x00>\x00\xe4'
|
||||
))
|
||||
self.assertTrue(is_html( # UTF-32-BE
|
||||
b'\x00\x00\xFE\xFF\x00\x00\x00<\x00\x00\x00h\x00\x00\x00t\x00\x00\x00m\x00\x00\x00l\x00\x00\x00>\x00\x00\x00\xe4'))
|
||||
self.assertTrue(is_html( # UTF-32-LE
|
||||
b'\xFF\xFE\x00\x00<\x00\x00\x00h\x00\x00\x00t\x00\x00\x00m\x00\x00\x00l\x00\x00\x00>\x00\x00\x00\xe4\x00\x00\x00'))
|
||||
|
||||
def test_render_table(self):
|
||||
self.assertEqual(
|
||||
render_table(
|
||||
['a', 'bcd'],
|
||||
[[123, 4], [9999, 51]]),
|
||||
'a bcd\n'
|
||||
'123 4\n'
|
||||
'9999 51')
|
||||
|
||||
def test_match_str(self):
|
||||
self.assertRaises(ValueError, match_str, 'xy>foobar', {})
|
||||
self.assertFalse(match_str('xy', {'x': 1200}))
|
||||
self.assertTrue(match_str('!xy', {'x': 1200}))
|
||||
self.assertTrue(match_str('x', {'x': 1200}))
|
||||
self.assertFalse(match_str('!x', {'x': 1200}))
|
||||
self.assertTrue(match_str('x', {'x': 0}))
|
||||
self.assertFalse(match_str('x>0', {'x': 0}))
|
||||
self.assertFalse(match_str('x>0', {}))
|
||||
self.assertTrue(match_str('x>?0', {}))
|
||||
self.assertTrue(match_str('x>1K', {'x': 1200}))
|
||||
self.assertFalse(match_str('x>2K', {'x': 1200}))
|
||||
self.assertTrue(match_str('x>=1200 & x < 1300', {'x': 1200}))
|
||||
self.assertFalse(match_str('x>=1100 & x < 1200', {'x': 1200}))
|
||||
self.assertFalse(match_str('y=a212', {'y': 'foobar42'}))
|
||||
self.assertTrue(match_str('y=foobar42', {'y': 'foobar42'}))
|
||||
self.assertFalse(match_str('y!=foobar42', {'y': 'foobar42'}))
|
||||
self.assertTrue(match_str('y!=foobar2', {'y': 'foobar42'}))
|
||||
self.assertFalse(match_str(
|
||||
'like_count > 100 & dislike_count <? 50 & description',
|
||||
{'like_count': 90, 'description': 'foo'}))
|
||||
self.assertTrue(match_str(
|
||||
'like_count > 100 & dislike_count <? 50 & description',
|
||||
{'like_count': 190, 'description': 'foo'}))
|
||||
self.assertFalse(match_str(
|
||||
'like_count > 100 & dislike_count <? 50 & description',
|
||||
{'like_count': 190, 'dislike_count': 60, 'description': 'foo'}))
|
||||
self.assertFalse(match_str(
|
||||
'like_count > 100 & dislike_count <? 50 & description',
|
||||
{'like_count': 190, 'dislike_count': 10}))
|
||||
|
||||
def test_parse_dfxp_time_expr(self):
|
||||
self.assertEqual(parse_dfxp_time_expr(None), 0.0)
|
||||
self.assertEqual(parse_dfxp_time_expr(''), 0.0)
|
||||
self.assertEqual(parse_dfxp_time_expr('0.1'), 0.1)
|
||||
self.assertEqual(parse_dfxp_time_expr('0.1s'), 0.1)
|
||||
self.assertEqual(parse_dfxp_time_expr('00:00:01'), 1.0)
|
||||
self.assertEqual(parse_dfxp_time_expr('00:00:01.100'), 1.1)
|
||||
|
||||
def test_dfxp2srt(self):
|
||||
dfxp_data = '''<?xml version="1.0" encoding="UTF-8"?>
|
||||
<tt xmlns="http://www.w3.org/ns/ttml" xml:lang="en" xmlns:tts="http://www.w3.org/ns/ttml#parameter">
|
||||
<body>
|
||||
<div xml:lang="en">
|
||||
<p begin="0" end="1">The following line contains Chinese characters and special symbols</p>
|
||||
<p begin="1" end="2">第二行<br/>♪♪</p>
|
||||
<p begin="2" dur="1"><span>Third<br/>Line</span></p>
|
||||
</div>
|
||||
</body>
|
||||
</tt>'''
|
||||
srt_data = '''1
|
||||
00:00:00,000 --> 00:00:01,000
|
||||
The following line contains Chinese characters and special symbols
|
||||
|
||||
2
|
||||
00:00:01,000 --> 00:00:02,000
|
||||
第二行
|
||||
♪♪
|
||||
|
||||
3
|
||||
00:00:02,000 --> 00:00:03,000
|
||||
Third
|
||||
Line
|
||||
|
||||
'''
|
||||
self.assertEqual(dfxp2srt(dfxp_data), srt_data)
|
||||
|
||||
dfxp_data_no_default_namespace = '''<?xml version="1.0" encoding="UTF-8"?>
|
||||
<tt xml:lang="en" xmlns:tts="http://www.w3.org/ns/ttml#parameter">
|
||||
<body>
|
||||
<div xml:lang="en">
|
||||
<p begin="0" end="1">The first line</p>
|
||||
</div>
|
||||
</body>
|
||||
</tt>'''
|
||||
srt_data = '''1
|
||||
00:00:00,000 --> 00:00:01,000
|
||||
The first line
|
||||
|
||||
'''
|
||||
self.assertEqual(dfxp2srt(dfxp_data_no_default_namespace), srt_data)
|
||||
|
||||
def test_cli_option(self):
|
||||
self.assertEqual(cli_option({'proxy': '127.0.0.1:3128'}, '--proxy', 'proxy'), ['--proxy', '127.0.0.1:3128'])
|
||||
self.assertEqual(cli_option({'proxy': None}, '--proxy', 'proxy'), [])
|
||||
self.assertEqual(cli_option({}, '--proxy', 'proxy'), [])
|
||||
|
||||
def test_cli_valueless_option(self):
|
||||
self.assertEqual(cli_valueless_option(
|
||||
{'downloader': 'external'}, '--external-downloader', 'downloader', 'external'), ['--external-downloader'])
|
||||
self.assertEqual(cli_valueless_option(
|
||||
{'downloader': 'internal'}, '--external-downloader', 'downloader', 'external'), [])
|
||||
self.assertEqual(cli_valueless_option(
|
||||
{'nocheckcertificate': True}, '--no-check-certificate', 'nocheckcertificate'), ['--no-check-certificate'])
|
||||
self.assertEqual(cli_valueless_option(
|
||||
{'nocheckcertificate': False}, '--no-check-certificate', 'nocheckcertificate'), [])
|
||||
self.assertEqual(cli_valueless_option(
|
||||
{'checkcertificate': True}, '--no-check-certificate', 'checkcertificate', False), [])
|
||||
self.assertEqual(cli_valueless_option(
|
||||
{'checkcertificate': False}, '--no-check-certificate', 'checkcertificate', False), ['--no-check-certificate'])
|
||||
|
||||
def test_cli_bool_option(self):
|
||||
self.assertEqual(
|
||||
cli_bool_option(
|
||||
{'nocheckcertificate': True}, '--no-check-certificate', 'nocheckcertificate'),
|
||||
['--no-check-certificate', 'true'])
|
||||
self.assertEqual(
|
||||
cli_bool_option(
|
||||
{'nocheckcertificate': True}, '--no-check-certificate', 'nocheckcertificate', separator='='),
|
||||
['--no-check-certificate=true'])
|
||||
self.assertEqual(
|
||||
cli_bool_option(
|
||||
{'nocheckcertificate': True}, '--check-certificate', 'nocheckcertificate', 'false', 'true'),
|
||||
['--check-certificate', 'false'])
|
||||
self.assertEqual(
|
||||
cli_bool_option(
|
||||
{'nocheckcertificate': True}, '--check-certificate', 'nocheckcertificate', 'false', 'true', '='),
|
||||
['--check-certificate=false'])
|
||||
self.assertEqual(
|
||||
cli_bool_option(
|
||||
{'nocheckcertificate': False}, '--check-certificate', 'nocheckcertificate', 'false', 'true'),
|
||||
['--check-certificate', 'true'])
|
||||
self.assertEqual(
|
||||
cli_bool_option(
|
||||
{'nocheckcertificate': False}, '--check-certificate', 'nocheckcertificate', 'false', 'true', '='),
|
||||
['--check-certificate=true'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
78
test/test_write_annotations.py
Normal file
78
test/test_write_annotations.py
Normal file
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Allow direct execution
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from test.helper import get_params, try_rm
|
||||
|
||||
|
||||
import io
|
||||
|
||||
import xml.etree.ElementTree
|
||||
|
||||
import youtube_dl.YoutubeDL
|
||||
import youtube_dl.extractor
|
||||
|
||||
|
||||
class YoutubeDL(youtube_dl.YoutubeDL):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(YoutubeDL, self).__init__(*args, **kwargs)
|
||||
self.to_stderr = self.to_screen
|
||||
|
||||
params = get_params({
|
||||
'writeannotations': True,
|
||||
'skip_download': True,
|
||||
'writeinfojson': False,
|
||||
'format': 'flv',
|
||||
})
|
||||
|
||||
|
||||
TEST_ID = 'gr51aVj-mLg'
|
||||
ANNOTATIONS_FILE = TEST_ID + '.annotations.xml'
|
||||
EXPECTED_ANNOTATIONS = ['Speech bubble', 'Note', 'Title', 'Spotlight', 'Label']
|
||||
|
||||
|
||||
class TestAnnotations(unittest.TestCase):
|
||||
def setUp(self):
|
||||
# Clear old files
|
||||
self.tearDown()
|
||||
|
||||
def test_info_json(self):
|
||||
expected = list(EXPECTED_ANNOTATIONS) # Two annotations could have the same text.
|
||||
ie = youtube_dl.extractor.YoutubeIE()
|
||||
ydl = YoutubeDL(params)
|
||||
ydl.add_info_extractor(ie)
|
||||
ydl.download([TEST_ID])
|
||||
self.assertTrue(os.path.exists(ANNOTATIONS_FILE))
|
||||
annoxml = None
|
||||
with io.open(ANNOTATIONS_FILE, 'r', encoding='utf-8') as annof:
|
||||
annoxml = xml.etree.ElementTree.parse(annof)
|
||||
self.assertTrue(annoxml is not None, 'Failed to parse annotations XML')
|
||||
root = annoxml.getroot()
|
||||
self.assertEqual(root.tag, 'document')
|
||||
annotationsTag = root.find('annotations')
|
||||
self.assertEqual(annotationsTag.tag, 'annotations')
|
||||
annotations = annotationsTag.findall('annotation')
|
||||
|
||||
# Not all the annotations have TEXT children and the annotations are returned unsorted.
|
||||
for a in annotations:
|
||||
self.assertEqual(a.tag, 'annotation')
|
||||
if a.get('type') == 'text':
|
||||
textTag = a.find('TEXT')
|
||||
text = textTag.text
|
||||
self.assertTrue(text in expected) # assertIn only added in python 2.7
|
||||
# remove the first occurance, there could be more than one annotation with the same text
|
||||
expected.remove(text)
|
||||
# We should have seen (and removed) all the expected annotation texts.
|
||||
self.assertEqual(len(expected), 0, 'Not all expected annotations were found.')
|
||||
|
||||
def tearDown(self):
|
||||
try_rm(ANNOTATIONS_FILE)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
70
test/test_youtube_lists.py
Normal file
70
test/test_youtube_lists.py
Normal file
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Allow direct execution
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from test.helper import FakeYDL
|
||||
|
||||
|
||||
from youtube_dl.extractor import (
|
||||
YoutubePlaylistIE,
|
||||
YoutubeIE,
|
||||
)
|
||||
|
||||
|
||||
class TestYoutubeLists(unittest.TestCase):
|
||||
def assertIsPlaylist(self, info):
|
||||
"""Make sure the info has '_type' set to 'playlist'"""
|
||||
self.assertEqual(info['_type'], 'playlist')
|
||||
|
||||
def test_youtube_playlist_noplaylist(self):
|
||||
dl = FakeYDL()
|
||||
dl.params['noplaylist'] = True
|
||||
ie = YoutubePlaylistIE(dl)
|
||||
result = ie.extract('https://www.youtube.com/watch?v=FXxLjLQi3Fg&list=PLwiyx1dc3P2JR9N8gQaQN_BCvlSlap7re')
|
||||
self.assertEqual(result['_type'], 'url')
|
||||
self.assertEqual(YoutubeIE().extract_id(result['url']), 'FXxLjLQi3Fg')
|
||||
|
||||
def test_youtube_course(self):
|
||||
dl = FakeYDL()
|
||||
ie = YoutubePlaylistIE(dl)
|
||||
# TODO find a > 100 (paginating?) videos course
|
||||
result = ie.extract('https://www.youtube.com/course?list=ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8')
|
||||
entries = result['entries']
|
||||
self.assertEqual(YoutubeIE().extract_id(entries[0]['url']), 'j9WZyLZCBzs')
|
||||
self.assertEqual(len(entries), 25)
|
||||
self.assertEqual(YoutubeIE().extract_id(entries[-1]['url']), 'rYefUsYuEp0')
|
||||
|
||||
def test_youtube_mix(self):
|
||||
dl = FakeYDL()
|
||||
ie = YoutubePlaylistIE(dl)
|
||||
result = ie.extract('https://www.youtube.com/watch?v=W01L70IGBgE&index=2&list=RDOQpdSVF_k_w')
|
||||
entries = result['entries']
|
||||
self.assertTrue(len(entries) >= 20)
|
||||
original_video = entries[0]
|
||||
self.assertEqual(original_video['id'], 'OQpdSVF_k_w')
|
||||
|
||||
def test_youtube_toptracks(self):
|
||||
print('Skipping: The playlist page gives error 500')
|
||||
return
|
||||
dl = FakeYDL()
|
||||
ie = YoutubePlaylistIE(dl)
|
||||
result = ie.extract('https://www.youtube.com/playlist?list=MCUS')
|
||||
entries = result['entries']
|
||||
self.assertEqual(len(entries), 100)
|
||||
|
||||
def test_youtube_flat_playlist_titles(self):
|
||||
dl = FakeYDL()
|
||||
dl.params['extract_flat'] = True
|
||||
ie = YoutubePlaylistIE(dl)
|
||||
result = ie.extract('https://www.youtube.com/playlist?list=PLwiyx1dc3P2JR9N8gQaQN_BCvlSlap7re')
|
||||
self.assertIsPlaylist(result)
|
||||
for entry in result['entries']:
|
||||
self.assertTrue(entry.get('title'))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
122
test/test_youtube_signature.py
Normal file
122
test/test_youtube_signature.py
Normal file
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Allow direct execution
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
import io
|
||||
import re
|
||||
import string
|
||||
|
||||
from test.helper import FakeYDL
|
||||
from youtube_dl.extractor import YoutubeIE
|
||||
from youtube_dl.compat import compat_str, compat_urlretrieve
|
||||
|
||||
_TESTS = [
|
||||
(
|
||||
'https://s.ytimg.com/yts/jsbin/html5player-vflHOr_nV.js',
|
||||
'js',
|
||||
86,
|
||||
'>=<;:/.-[+*)(\'&%$#"!ZYX0VUTSRQPONMLKJIHGFEDCBA\\yxwvutsrqponmlkjihgfedcba987654321',
|
||||
),
|
||||
(
|
||||
'https://s.ytimg.com/yts/jsbin/html5player-vfldJ8xgI.js',
|
||||
'js',
|
||||
85,
|
||||
'3456789a0cdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRS[UVWXYZ!"#$%&\'()*+,-./:;<=>?@',
|
||||
),
|
||||
(
|
||||
'https://s.ytimg.com/yts/jsbin/html5player-vfle-mVwz.js',
|
||||
'js',
|
||||
90,
|
||||
']\\[@?>=<;:/.-,+*)(\'&%$#"hZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjiagfedcb39876',
|
||||
),
|
||||
(
|
||||
'https://s.ytimg.com/yts/jsbin/html5player-en_US-vfl0Cbn9e.js',
|
||||
'js',
|
||||
84,
|
||||
'O1I3456789abcde0ghijklmnopqrstuvwxyzABCDEFGHfJKLMN2PQRSTUVW@YZ!"#$%&\'()*+,-./:;<=',
|
||||
),
|
||||
(
|
||||
'https://s.ytimg.com/yts/jsbin/html5player-en_US-vflXGBaUN.js',
|
||||
'js',
|
||||
'2ACFC7A61CA478CD21425E5A57EBD73DDC78E22A.2094302436B2D377D14A3BBA23022D023B8BC25AA',
|
||||
'A52CB8B320D22032ABB3A41D773D2B6342034902.A22E87CDD37DBE75A5E52412DC874AC16A7CFCA2',
|
||||
),
|
||||
(
|
||||
'https://s.ytimg.com/yts/jsbin/html5player-en_US-vflBb0OQx.js',
|
||||
'js',
|
||||
84,
|
||||
'123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQ0STUVWXYZ!"#$%&\'()*+,@./:;<=>'
|
||||
),
|
||||
(
|
||||
'https://s.ytimg.com/yts/jsbin/html5player-en_US-vfl9FYC6l.js',
|
||||
'js',
|
||||
83,
|
||||
'123456789abcdefghijklmnopqr0tuvwxyzABCDETGHIJKLMNOPQRS>UVWXYZ!"#$%&\'()*+,-./:;<=F'
|
||||
),
|
||||
(
|
||||
'https://s.ytimg.com/yts/jsbin/html5player-en_US-vflCGk6yw/html5player.js',
|
||||
'js',
|
||||
'4646B5181C6C3020DF1D9C7FCFEA.AD80ABF70C39BD369CCCAE780AFBB98FA6B6CB42766249D9488C288',
|
||||
'82C8849D94266724DC6B6AF89BBFA087EACCD963.B93C07FBA084ACAEFCF7C9D1FD0203C6C1815B6B'
|
||||
),
|
||||
(
|
||||
'https://s.ytimg.com/yts/jsbin/html5player-en_US-vflKjOTVq/html5player.js',
|
||||
'js',
|
||||
'312AA52209E3623129A412D56A40F11CB0AF14AE.3EE09501CB14E3BCDC3B2AE808BF3F1D14E7FBF12',
|
||||
'112AA5220913623229A412D56A40F11CB0AF14AE.3EE0950FCB14EEBCDC3B2AE808BF331D14E7FBF3',
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
class TestSignature(unittest.TestCase):
|
||||
def setUp(self):
|
||||
TEST_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
self.TESTDATA_DIR = os.path.join(TEST_DIR, 'testdata')
|
||||
if not os.path.exists(self.TESTDATA_DIR):
|
||||
os.mkdir(self.TESTDATA_DIR)
|
||||
|
||||
|
||||
def make_tfunc(url, stype, sig_input, expected_sig):
|
||||
m = re.match(r'.*-([a-zA-Z0-9_-]+)(?:/watch_as3|/html5player)?\.[a-z]+$', url)
|
||||
assert m, '%r should follow URL format' % url
|
||||
test_id = m.group(1)
|
||||
|
||||
def test_func(self):
|
||||
basename = 'player-%s.%s' % (test_id, stype)
|
||||
fn = os.path.join(self.TESTDATA_DIR, basename)
|
||||
|
||||
if not os.path.exists(fn):
|
||||
compat_urlretrieve(url, fn)
|
||||
|
||||
ydl = FakeYDL()
|
||||
ie = YoutubeIE(ydl)
|
||||
if stype == 'js':
|
||||
with io.open(fn, encoding='utf-8') as testf:
|
||||
jscode = testf.read()
|
||||
func = ie._parse_sig_js(jscode)
|
||||
else:
|
||||
assert stype == 'swf'
|
||||
with open(fn, 'rb') as testf:
|
||||
swfcode = testf.read()
|
||||
func = ie._parse_sig_swf(swfcode)
|
||||
src_sig = (
|
||||
compat_str(string.printable[:sig_input])
|
||||
if isinstance(sig_input, int) else sig_input)
|
||||
got_sig = func(src_sig)
|
||||
self.assertEqual(got_sig, expected_sig)
|
||||
|
||||
test_func.__name__ = str('test_signature_' + stype + '_' + test_id)
|
||||
setattr(TestSignature, test_func.__name__, test_func)
|
||||
|
||||
for test_spec in _TESTS:
|
||||
make_tfunc(*test_spec)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
52
test/testcert.pem
Normal file
52
test/testcert.pem
Normal file
@@ -0,0 +1,52 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDMF0bAzaHAdIyB
|
||||
HRmnIp4vv40lGqEePmWqicCl0QZ0wsb5dNysSxSa7330M2QeQopGfdaUYF1uTcNp
|
||||
Qx6ECgBSfg+RrOBI7r/u4F+sKX8MUXVaf/5QoBUrGNGSn/pp7HMGOuQqO6BVg4+h
|
||||
A1ySSwUG8mZItLRry1ISyErmW8b9xlqfd97uLME/5tX+sMelRFjUbAx8A4CK58Ev
|
||||
mMguHVTlXzx5RMdYcf1VScYcjlV/qA45uzP8zwI5aigfcmUD+tbGuQRhKxUhmw0J
|
||||
aobtOR6+JSOAULW5gYa/egE4dWLwbyM6b6eFbdnjlQzEA1EW7ChMPAW/Mo83KyiP
|
||||
tKMCSQulAgMBAAECggEALCfBDAexPjU5DNoh6bIorUXxIJzxTNzNHCdvgbCGiA54
|
||||
BBKPh8s6qwazpnjT6WQWDIg/O5zZufqjE4wM9x4+0Zoqfib742ucJO9wY4way6x4
|
||||
Clt0xzbLPabB+MoZ4H7ip+9n2+dImhe7pGdYyOHoNYeOL57BBi1YFW42Hj6u/8pd
|
||||
63YCXisto3Rz1YvRQVjwsrS+cRKZlzAFQRviL30jav7Wh1aWEfcXxjj4zhm8pJdk
|
||||
ITGtq6howz57M0NtX6hZnfe8ywzTnDFIGKIMA2cYHuYJcBh9bc4tCGubTvTKK9UE
|
||||
8fM+f6UbfGqfpKCq1mcgs0XMoFDSzKS9+mSJn0+5JQKBgQD+OCKaeH3Yzw5zGnlw
|
||||
XuQfMJGNcgNr+ImjmvzUAC2fAZUJLAcQueE5kzMv5Fmd+EFE2CEX1Vit3tg0SXvA
|
||||
G+bq609doILHMA03JHnV1npO/YNIhG3AAtJlKYGxQNfWH9mflYj9mEui8ZFxG52o
|
||||
zWhHYuifOjjZszUR+/eio6NPzwKBgQDNhUBTrT8LIX4SE/EFUiTlYmWIvOMgXYvN
|
||||
8Cm3IRNQ/yyphZaXEU0eJzfX5uCDfSVOgd6YM/2pRah+t+1Hvey4H8e0GVTu5wMP
|
||||
gkkqwKPGIR1YOmlw6ippqwvoJD7LuYrm6Q4D6e1PvkjwCq6lEndrOPmPrrXNd0JJ
|
||||
XO60y3U2SwKBgQDLkyZarryQXxcCI6Q10Tc6pskYDMIit095PUbTeiUOXNT9GE28
|
||||
Hi32ziLCakk9kCysNasii81MxtQ54tJ/f5iGbNMMddnkKl2a19Hc5LjjAm4cJzg/
|
||||
98KGEhvyVqvAo5bBDZ06/rcrD+lZOzUglQS5jcIcqCIYa0LHWQ/wJLxFzwKBgFcZ
|
||||
1SRhdSmDfUmuF+S4ZpistflYjC3IV5rk4NkS9HvMWaJS0nqdw4A3AMzItXgkjq4S
|
||||
DkOVLTkTI5Do5HAWRv/VwC5M2hkR4NMu1VGAKSisGiKtRsirBWSZMEenLNHshbjN
|
||||
Jrpz5rZ4H7NT46ZkCCZyFBpX4gb9NyOedjA7Via3AoGARF8RxbYjnEGGFuhnbrJB
|
||||
FTPR0vaL4faY3lOgRZ8jOG9V2c9Hzi/y8a8TU4C11jnJSDqYCXBTd5XN28npYxtD
|
||||
pjRsCwy6ze+yvYXPO7C978eMG3YRyj366NXUxnXN59ibwe/lxi2OD9z8J1LEdF6z
|
||||
VJua1Wn8HKxnXMI61DhTCSo=
|
||||
-----END PRIVATE KEY-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEEzCCAvugAwIBAgIJAK1haYi6gmSKMA0GCSqGSIb3DQEBCwUAMIGeMQswCQYD
|
||||
VQQGEwJERTEMMAoGA1UECAwDTlJXMRQwEgYDVQQHDAtEdWVzc2VsZG9yZjEbMBkG
|
||||
A1UECgwSeW91dHViZS1kbCBwcm9qZWN0MRkwFwYDVQQLDBB5b3V0dWJlLWRsIHRl
|
||||
c3RzMRIwEAYDVQQDDAlsb2NhbGhvc3QxHzAdBgkqhkiG9w0BCQEWEHBoaWhhZ0Bw
|
||||
aGloYWcuZGUwIBcNMTUwMTMwMDExNTA4WhgPMjExNTAxMDYwMTE1MDhaMIGeMQsw
|
||||
CQYDVQQGEwJERTEMMAoGA1UECAwDTlJXMRQwEgYDVQQHDAtEdWVzc2VsZG9yZjEb
|
||||
MBkGA1UECgwSeW91dHViZS1kbCBwcm9qZWN0MRkwFwYDVQQLDBB5b3V0dWJlLWRs
|
||||
IHRlc3RzMRIwEAYDVQQDDAlsb2NhbGhvc3QxHzAdBgkqhkiG9w0BCQEWEHBoaWhh
|
||||
Z0BwaGloYWcuZGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDMF0bA
|
||||
zaHAdIyBHRmnIp4vv40lGqEePmWqicCl0QZ0wsb5dNysSxSa7330M2QeQopGfdaU
|
||||
YF1uTcNpQx6ECgBSfg+RrOBI7r/u4F+sKX8MUXVaf/5QoBUrGNGSn/pp7HMGOuQq
|
||||
O6BVg4+hA1ySSwUG8mZItLRry1ISyErmW8b9xlqfd97uLME/5tX+sMelRFjUbAx8
|
||||
A4CK58EvmMguHVTlXzx5RMdYcf1VScYcjlV/qA45uzP8zwI5aigfcmUD+tbGuQRh
|
||||
KxUhmw0JaobtOR6+JSOAULW5gYa/egE4dWLwbyM6b6eFbdnjlQzEA1EW7ChMPAW/
|
||||
Mo83KyiPtKMCSQulAgMBAAGjUDBOMB0GA1UdDgQWBBTBUZoqhQkzHQ6xNgZfFxOd
|
||||
ZEVt8TAfBgNVHSMEGDAWgBTBUZoqhQkzHQ6xNgZfFxOdZEVt8TAMBgNVHRMEBTAD
|
||||
AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCUOCl3T/J9B08Z+ijfOJAtkbUaEHuVZb4x
|
||||
5EpZSy2ZbkLvtsftMFieHVNXn9dDswQc5qjYStCC4o60LKw4M6Y63FRsAZ/DNaqb
|
||||
PY3jyCyuugZ8/sNf50vHYkAcF7SQYqOQFQX4TQsNUk2xMJIt7H0ErQFmkf/u3dg6
|
||||
cy89zkT462IwxzSG7NNhIlRkL9o5qg+Y1mF9eZA1B0rcL6hO24PPTHOd90HDChBu
|
||||
SZ6XMi/LzYQSTf0Vg2R+uMIVlzSlkdcZ6sqVnnqeLL8dFyIa4e9sj/D4ZCYP8Mqe
|
||||
Z73H5/NNhmwCHRqVUTgm307xblQaWGhwAiDkaRvRW2aJQ0qGEdZK
|
||||
-----END CERTIFICATE-----
|
||||
13
tox.ini
Normal file
13
tox.ini
Normal file
@@ -0,0 +1,13 @@
|
||||
[tox]
|
||||
envlist = py26,py27,py33,py34,py35
|
||||
[testenv]
|
||||
deps =
|
||||
nose
|
||||
coverage
|
||||
# We need a valid $HOME for test_compat_expanduser
|
||||
passenv = HOME
|
||||
defaultargs = test --exclude test_download.py --exclude test_age_restriction.py
|
||||
--exclude test_subtitles.py --exclude test_write_annotations.py
|
||||
--exclude test_youtube_lists.py
|
||||
commands = nosetests --verbose {posargs:{[testenv]defaultargs}} # --with-coverage --cover-package=youtube_dl --cover-html
|
||||
# test.test_download:TestDownload.test_NowVideo
|
||||
4627
youtube-dl
4627
youtube-dl
File diff suppressed because it is too large
Load Diff
@@ -1,6 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import youtube_dl
|
||||
|
||||
youtube_dl.main()
|
||||
24
youtube-dl.plugin.zsh
Normal file
24
youtube-dl.plugin.zsh
Normal file
@@ -0,0 +1,24 @@
|
||||
# This allows the youtube-dl command to be installed in ZSH using antigen.
|
||||
# Antigen is a bundle manager. It allows you to enhance the functionality of
|
||||
# your zsh session by installing bundles and themes easily.
|
||||
|
||||
# Antigen documentation:
|
||||
# http://antigen.sharats.me/
|
||||
# https://github.com/zsh-users/antigen
|
||||
|
||||
# Install youtube-dl:
|
||||
# antigen bundle rg3/youtube-dl
|
||||
# Bundles installed by antigen are available for use immediately.
|
||||
|
||||
# Update youtube-dl (and all other antigen bundles):
|
||||
# antigen update
|
||||
|
||||
# The antigen command will download the git repository to a folder and then
|
||||
# execute an enabling script (this file). The complete process for loading the
|
||||
# code is documented here:
|
||||
# https://github.com/zsh-users/antigen#notes-on-writing-plugins
|
||||
|
||||
# This specific script just aliases youtube-dl to the python script that this
|
||||
# library provides. This requires updating the PYTHONPATH to ensure that the
|
||||
# full set of code can be located.
|
||||
alias youtube-dl="PYTHONPATH=$(dirname $0) $(dirname $0)/bin/youtube-dl"
|
||||
2042
youtube_dl/YoutubeDL.py
Executable file
2042
youtube_dl/YoutubeDL.py
Executable file
File diff suppressed because it is too large
Load Diff
5025
youtube_dl/__init__.py
Executable file → Normal file
5025
youtube_dl/__init__.py
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
19
youtube_dl/__main__.py
Executable file
19
youtube_dl/__main__.py
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Execute with
|
||||
# $ python youtube_dl/__main__.py (2.6+)
|
||||
# $ python -m youtube_dl (2.7+)
|
||||
|
||||
import sys
|
||||
|
||||
if __package__ is None and not hasattr(sys, "frozen"):
|
||||
# direct call of __main__.py
|
||||
import os.path
|
||||
path = os.path.realpath(os.path.abspath(__file__))
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(path)))
|
||||
|
||||
import youtube_dl
|
||||
|
||||
if __name__ == '__main__':
|
||||
youtube_dl.main()
|
||||
331
youtube_dl/aes.py
Normal file
331
youtube_dl/aes.py
Normal file
@@ -0,0 +1,331 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import base64
|
||||
from math import ceil
|
||||
|
||||
from .utils import bytes_to_intlist, intlist_to_bytes
|
||||
|
||||
BLOCK_SIZE_BYTES = 16
|
||||
|
||||
|
||||
def aes_ctr_decrypt(data, key, counter):
|
||||
"""
|
||||
Decrypt with aes in counter mode
|
||||
|
||||
@param {int[]} data cipher
|
||||
@param {int[]} key 16/24/32-Byte cipher key
|
||||
@param {instance} counter Instance whose next_value function (@returns {int[]} 16-Byte block)
|
||||
returns the next counter block
|
||||
@returns {int[]} decrypted data
|
||||
"""
|
||||
expanded_key = key_expansion(key)
|
||||
block_count = int(ceil(float(len(data)) / BLOCK_SIZE_BYTES))
|
||||
|
||||
decrypted_data = []
|
||||
for i in range(block_count):
|
||||
counter_block = counter.next_value()
|
||||
block = data[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES]
|
||||
block += [0] * (BLOCK_SIZE_BYTES - len(block))
|
||||
|
||||
cipher_counter_block = aes_encrypt(counter_block, expanded_key)
|
||||
decrypted_data += xor(block, cipher_counter_block)
|
||||
decrypted_data = decrypted_data[:len(data)]
|
||||
|
||||
return decrypted_data
|
||||
|
||||
|
||||
def aes_cbc_decrypt(data, key, iv):
|
||||
"""
|
||||
Decrypt with aes in CBC mode
|
||||
|
||||
@param {int[]} data cipher
|
||||
@param {int[]} key 16/24/32-Byte cipher key
|
||||
@param {int[]} iv 16-Byte IV
|
||||
@returns {int[]} decrypted data
|
||||
"""
|
||||
expanded_key = key_expansion(key)
|
||||
block_count = int(ceil(float(len(data)) / BLOCK_SIZE_BYTES))
|
||||
|
||||
decrypted_data = []
|
||||
previous_cipher_block = iv
|
||||
for i in range(block_count):
|
||||
block = data[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES]
|
||||
block += [0] * (BLOCK_SIZE_BYTES - len(block))
|
||||
|
||||
decrypted_block = aes_decrypt(block, expanded_key)
|
||||
decrypted_data += xor(decrypted_block, previous_cipher_block)
|
||||
previous_cipher_block = block
|
||||
decrypted_data = decrypted_data[:len(data)]
|
||||
|
||||
return decrypted_data
|
||||
|
||||
|
||||
def key_expansion(data):
|
||||
"""
|
||||
Generate key schedule
|
||||
|
||||
@param {int[]} data 16/24/32-Byte cipher key
|
||||
@returns {int[]} 176/208/240-Byte expanded key
|
||||
"""
|
||||
data = data[:] # copy
|
||||
rcon_iteration = 1
|
||||
key_size_bytes = len(data)
|
||||
expanded_key_size_bytes = (key_size_bytes // 4 + 7) * BLOCK_SIZE_BYTES
|
||||
|
||||
while len(data) < expanded_key_size_bytes:
|
||||
temp = data[-4:]
|
||||
temp = key_schedule_core(temp, rcon_iteration)
|
||||
rcon_iteration += 1
|
||||
data += xor(temp, data[-key_size_bytes: 4 - key_size_bytes])
|
||||
|
||||
for _ in range(3):
|
||||
temp = data[-4:]
|
||||
data += xor(temp, data[-key_size_bytes: 4 - key_size_bytes])
|
||||
|
||||
if key_size_bytes == 32:
|
||||
temp = data[-4:]
|
||||
temp = sub_bytes(temp)
|
||||
data += xor(temp, data[-key_size_bytes: 4 - key_size_bytes])
|
||||
|
||||
for _ in range(3 if key_size_bytes == 32 else 2 if key_size_bytes == 24 else 0):
|
||||
temp = data[-4:]
|
||||
data += xor(temp, data[-key_size_bytes: 4 - key_size_bytes])
|
||||
data = data[:expanded_key_size_bytes]
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def aes_encrypt(data, expanded_key):
|
||||
"""
|
||||
Encrypt one block with aes
|
||||
|
||||
@param {int[]} data 16-Byte state
|
||||
@param {int[]} expanded_key 176/208/240-Byte expanded key
|
||||
@returns {int[]} 16-Byte cipher
|
||||
"""
|
||||
rounds = len(expanded_key) // BLOCK_SIZE_BYTES - 1
|
||||
|
||||
data = xor(data, expanded_key[:BLOCK_SIZE_BYTES])
|
||||
for i in range(1, rounds + 1):
|
||||
data = sub_bytes(data)
|
||||
data = shift_rows(data)
|
||||
if i != rounds:
|
||||
data = mix_columns(data)
|
||||
data = xor(data, expanded_key[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES])
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def aes_decrypt(data, expanded_key):
|
||||
"""
|
||||
Decrypt one block with aes
|
||||
|
||||
@param {int[]} data 16-Byte cipher
|
||||
@param {int[]} expanded_key 176/208/240-Byte expanded key
|
||||
@returns {int[]} 16-Byte state
|
||||
"""
|
||||
rounds = len(expanded_key) // BLOCK_SIZE_BYTES - 1
|
||||
|
||||
for i in range(rounds, 0, -1):
|
||||
data = xor(data, expanded_key[i * BLOCK_SIZE_BYTES: (i + 1) * BLOCK_SIZE_BYTES])
|
||||
if i != rounds:
|
||||
data = mix_columns_inv(data)
|
||||
data = shift_rows_inv(data)
|
||||
data = sub_bytes_inv(data)
|
||||
data = xor(data, expanded_key[:BLOCK_SIZE_BYTES])
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def aes_decrypt_text(data, password, key_size_bytes):
|
||||
"""
|
||||
Decrypt text
|
||||
- The first 8 Bytes of decoded 'data' are the 8 high Bytes of the counter
|
||||
- The cipher key is retrieved by encrypting the first 16 Byte of 'password'
|
||||
with the first 'key_size_bytes' Bytes from 'password' (if necessary filled with 0's)
|
||||
- Mode of operation is 'counter'
|
||||
|
||||
@param {str} data Base64 encoded string
|
||||
@param {str,unicode} password Password (will be encoded with utf-8)
|
||||
@param {int} key_size_bytes Possible values: 16 for 128-Bit, 24 for 192-Bit or 32 for 256-Bit
|
||||
@returns {str} Decrypted data
|
||||
"""
|
||||
NONCE_LENGTH_BYTES = 8
|
||||
|
||||
data = bytes_to_intlist(base64.b64decode(data.encode('utf-8')))
|
||||
password = bytes_to_intlist(password.encode('utf-8'))
|
||||
|
||||
key = password[:key_size_bytes] + [0] * (key_size_bytes - len(password))
|
||||
key = aes_encrypt(key[:BLOCK_SIZE_BYTES], key_expansion(key)) * (key_size_bytes // BLOCK_SIZE_BYTES)
|
||||
|
||||
nonce = data[:NONCE_LENGTH_BYTES]
|
||||
cipher = data[NONCE_LENGTH_BYTES:]
|
||||
|
||||
class Counter:
|
||||
__value = nonce + [0] * (BLOCK_SIZE_BYTES - NONCE_LENGTH_BYTES)
|
||||
|
||||
def next_value(self):
|
||||
temp = self.__value
|
||||
self.__value = inc(self.__value)
|
||||
return temp
|
||||
|
||||
decrypted_data = aes_ctr_decrypt(cipher, key, Counter())
|
||||
plaintext = intlist_to_bytes(decrypted_data)
|
||||
|
||||
return plaintext
|
||||
|
||||
RCON = (0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36)
|
||||
SBOX = (0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
|
||||
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
|
||||
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
|
||||
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
|
||||
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
|
||||
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
|
||||
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
|
||||
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
|
||||
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
|
||||
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
|
||||
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
|
||||
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
|
||||
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
|
||||
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
|
||||
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16)
|
||||
SBOX_INV = (0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d)
|
||||
MIX_COLUMN_MATRIX = ((0x2, 0x3, 0x1, 0x1),
|
||||
(0x1, 0x2, 0x3, 0x1),
|
||||
(0x1, 0x1, 0x2, 0x3),
|
||||
(0x3, 0x1, 0x1, 0x2))
|
||||
MIX_COLUMN_MATRIX_INV = ((0xE, 0xB, 0xD, 0x9),
|
||||
(0x9, 0xE, 0xB, 0xD),
|
||||
(0xD, 0x9, 0xE, 0xB),
|
||||
(0xB, 0xD, 0x9, 0xE))
|
||||
RIJNDAEL_EXP_TABLE = (0x01, 0x03, 0x05, 0x0F, 0x11, 0x33, 0x55, 0xFF, 0x1A, 0x2E, 0x72, 0x96, 0xA1, 0xF8, 0x13, 0x35,
|
||||
0x5F, 0xE1, 0x38, 0x48, 0xD8, 0x73, 0x95, 0xA4, 0xF7, 0x02, 0x06, 0x0A, 0x1E, 0x22, 0x66, 0xAA,
|
||||
0xE5, 0x34, 0x5C, 0xE4, 0x37, 0x59, 0xEB, 0x26, 0x6A, 0xBE, 0xD9, 0x70, 0x90, 0xAB, 0xE6, 0x31,
|
||||
0x53, 0xF5, 0x04, 0x0C, 0x14, 0x3C, 0x44, 0xCC, 0x4F, 0xD1, 0x68, 0xB8, 0xD3, 0x6E, 0xB2, 0xCD,
|
||||
0x4C, 0xD4, 0x67, 0xA9, 0xE0, 0x3B, 0x4D, 0xD7, 0x62, 0xA6, 0xF1, 0x08, 0x18, 0x28, 0x78, 0x88,
|
||||
0x83, 0x9E, 0xB9, 0xD0, 0x6B, 0xBD, 0xDC, 0x7F, 0x81, 0x98, 0xB3, 0xCE, 0x49, 0xDB, 0x76, 0x9A,
|
||||
0xB5, 0xC4, 0x57, 0xF9, 0x10, 0x30, 0x50, 0xF0, 0x0B, 0x1D, 0x27, 0x69, 0xBB, 0xD6, 0x61, 0xA3,
|
||||
0xFE, 0x19, 0x2B, 0x7D, 0x87, 0x92, 0xAD, 0xEC, 0x2F, 0x71, 0x93, 0xAE, 0xE9, 0x20, 0x60, 0xA0,
|
||||
0xFB, 0x16, 0x3A, 0x4E, 0xD2, 0x6D, 0xB7, 0xC2, 0x5D, 0xE7, 0x32, 0x56, 0xFA, 0x15, 0x3F, 0x41,
|
||||
0xC3, 0x5E, 0xE2, 0x3D, 0x47, 0xC9, 0x40, 0xC0, 0x5B, 0xED, 0x2C, 0x74, 0x9C, 0xBF, 0xDA, 0x75,
|
||||
0x9F, 0xBA, 0xD5, 0x64, 0xAC, 0xEF, 0x2A, 0x7E, 0x82, 0x9D, 0xBC, 0xDF, 0x7A, 0x8E, 0x89, 0x80,
|
||||
0x9B, 0xB6, 0xC1, 0x58, 0xE8, 0x23, 0x65, 0xAF, 0xEA, 0x25, 0x6F, 0xB1, 0xC8, 0x43, 0xC5, 0x54,
|
||||
0xFC, 0x1F, 0x21, 0x63, 0xA5, 0xF4, 0x07, 0x09, 0x1B, 0x2D, 0x77, 0x99, 0xB0, 0xCB, 0x46, 0xCA,
|
||||
0x45, 0xCF, 0x4A, 0xDE, 0x79, 0x8B, 0x86, 0x91, 0xA8, 0xE3, 0x3E, 0x42, 0xC6, 0x51, 0xF3, 0x0E,
|
||||
0x12, 0x36, 0x5A, 0xEE, 0x29, 0x7B, 0x8D, 0x8C, 0x8F, 0x8A, 0x85, 0x94, 0xA7, 0xF2, 0x0D, 0x17,
|
||||
0x39, 0x4B, 0xDD, 0x7C, 0x84, 0x97, 0xA2, 0xFD, 0x1C, 0x24, 0x6C, 0xB4, 0xC7, 0x52, 0xF6, 0x01)
|
||||
RIJNDAEL_LOG_TABLE = (0x00, 0x00, 0x19, 0x01, 0x32, 0x02, 0x1a, 0xc6, 0x4b, 0xc7, 0x1b, 0x68, 0x33, 0xee, 0xdf, 0x03,
|
||||
0x64, 0x04, 0xe0, 0x0e, 0x34, 0x8d, 0x81, 0xef, 0x4c, 0x71, 0x08, 0xc8, 0xf8, 0x69, 0x1c, 0xc1,
|
||||
0x7d, 0xc2, 0x1d, 0xb5, 0xf9, 0xb9, 0x27, 0x6a, 0x4d, 0xe4, 0xa6, 0x72, 0x9a, 0xc9, 0x09, 0x78,
|
||||
0x65, 0x2f, 0x8a, 0x05, 0x21, 0x0f, 0xe1, 0x24, 0x12, 0xf0, 0x82, 0x45, 0x35, 0x93, 0xda, 0x8e,
|
||||
0x96, 0x8f, 0xdb, 0xbd, 0x36, 0xd0, 0xce, 0x94, 0x13, 0x5c, 0xd2, 0xf1, 0x40, 0x46, 0x83, 0x38,
|
||||
0x66, 0xdd, 0xfd, 0x30, 0xbf, 0x06, 0x8b, 0x62, 0xb3, 0x25, 0xe2, 0x98, 0x22, 0x88, 0x91, 0x10,
|
||||
0x7e, 0x6e, 0x48, 0xc3, 0xa3, 0xb6, 0x1e, 0x42, 0x3a, 0x6b, 0x28, 0x54, 0xfa, 0x85, 0x3d, 0xba,
|
||||
0x2b, 0x79, 0x0a, 0x15, 0x9b, 0x9f, 0x5e, 0xca, 0x4e, 0xd4, 0xac, 0xe5, 0xf3, 0x73, 0xa7, 0x57,
|
||||
0xaf, 0x58, 0xa8, 0x50, 0xf4, 0xea, 0xd6, 0x74, 0x4f, 0xae, 0xe9, 0xd5, 0xe7, 0xe6, 0xad, 0xe8,
|
||||
0x2c, 0xd7, 0x75, 0x7a, 0xeb, 0x16, 0x0b, 0xf5, 0x59, 0xcb, 0x5f, 0xb0, 0x9c, 0xa9, 0x51, 0xa0,
|
||||
0x7f, 0x0c, 0xf6, 0x6f, 0x17, 0xc4, 0x49, 0xec, 0xd8, 0x43, 0x1f, 0x2d, 0xa4, 0x76, 0x7b, 0xb7,
|
||||
0xcc, 0xbb, 0x3e, 0x5a, 0xfb, 0x60, 0xb1, 0x86, 0x3b, 0x52, 0xa1, 0x6c, 0xaa, 0x55, 0x29, 0x9d,
|
||||
0x97, 0xb2, 0x87, 0x90, 0x61, 0xbe, 0xdc, 0xfc, 0xbc, 0x95, 0xcf, 0xcd, 0x37, 0x3f, 0x5b, 0xd1,
|
||||
0x53, 0x39, 0x84, 0x3c, 0x41, 0xa2, 0x6d, 0x47, 0x14, 0x2a, 0x9e, 0x5d, 0x56, 0xf2, 0xd3, 0xab,
|
||||
0x44, 0x11, 0x92, 0xd9, 0x23, 0x20, 0x2e, 0x89, 0xb4, 0x7c, 0xb8, 0x26, 0x77, 0x99, 0xe3, 0xa5,
|
||||
0x67, 0x4a, 0xed, 0xde, 0xc5, 0x31, 0xfe, 0x18, 0x0d, 0x63, 0x8c, 0x80, 0xc0, 0xf7, 0x70, 0x07)
|
||||
|
||||
|
||||
def sub_bytes(data):
|
||||
return [SBOX[x] for x in data]
|
||||
|
||||
|
||||
def sub_bytes_inv(data):
|
||||
return [SBOX_INV[x] for x in data]
|
||||
|
||||
|
||||
def rotate(data):
|
||||
return data[1:] + [data[0]]
|
||||
|
||||
|
||||
def key_schedule_core(data, rcon_iteration):
|
||||
data = rotate(data)
|
||||
data = sub_bytes(data)
|
||||
data[0] = data[0] ^ RCON[rcon_iteration]
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def xor(data1, data2):
|
||||
return [x ^ y for x, y in zip(data1, data2)]
|
||||
|
||||
|
||||
def rijndael_mul(a, b):
|
||||
if(a == 0 or b == 0):
|
||||
return 0
|
||||
return RIJNDAEL_EXP_TABLE[(RIJNDAEL_LOG_TABLE[a] + RIJNDAEL_LOG_TABLE[b]) % 0xFF]
|
||||
|
||||
|
||||
def mix_column(data, matrix):
|
||||
data_mixed = []
|
||||
for row in range(4):
|
||||
mixed = 0
|
||||
for column in range(4):
|
||||
# xor is (+) and (-)
|
||||
mixed ^= rijndael_mul(data[column], matrix[row][column])
|
||||
data_mixed.append(mixed)
|
||||
return data_mixed
|
||||
|
||||
|
||||
def mix_columns(data, matrix=MIX_COLUMN_MATRIX):
|
||||
data_mixed = []
|
||||
for i in range(4):
|
||||
column = data[i * 4: (i + 1) * 4]
|
||||
data_mixed += mix_column(column, matrix)
|
||||
return data_mixed
|
||||
|
||||
|
||||
def mix_columns_inv(data):
|
||||
return mix_columns(data, MIX_COLUMN_MATRIX_INV)
|
||||
|
||||
|
||||
def shift_rows(data):
|
||||
data_shifted = []
|
||||
for column in range(4):
|
||||
for row in range(4):
|
||||
data_shifted.append(data[((column + row) & 0b11) * 4 + row])
|
||||
return data_shifted
|
||||
|
||||
|
||||
def shift_rows_inv(data):
|
||||
data_shifted = []
|
||||
for column in range(4):
|
||||
for row in range(4):
|
||||
data_shifted.append(data[((column - row) & 0b11) * 4 + row])
|
||||
return data_shifted
|
||||
|
||||
|
||||
def inc(data):
|
||||
data = data[:] # copy
|
||||
for i in range(len(data) - 1, -1, -1):
|
||||
if data[i] == 255:
|
||||
data[i] = 0
|
||||
else:
|
||||
data[i] = data[i] + 1
|
||||
break
|
||||
return data
|
||||
|
||||
__all__ = ['aes_encrypt', 'key_expansion', 'aes_ctr_decrypt', 'aes_cbc_decrypt', 'aes_decrypt_text']
|
||||
93
youtube_dl/cache.py
Normal file
93
youtube_dl/cache.py
Normal file
@@ -0,0 +1,93 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import errno
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import traceback
|
||||
|
||||
from .compat import compat_expanduser, compat_getenv
|
||||
from .utils import write_json_file
|
||||
|
||||
|
||||
class Cache(object):
|
||||
def __init__(self, ydl):
|
||||
self._ydl = ydl
|
||||
|
||||
def _get_root_dir(self):
|
||||
res = self._ydl.params.get('cachedir')
|
||||
if res is None:
|
||||
cache_root = compat_getenv('XDG_CACHE_HOME', '~/.cache')
|
||||
res = os.path.join(cache_root, 'youtube-dl')
|
||||
return compat_expanduser(res)
|
||||
|
||||
def _get_cache_fn(self, section, key, dtype):
|
||||
assert re.match(r'^[a-zA-Z0-9_.-]+$', section), \
|
||||
'invalid section %r' % section
|
||||
assert re.match(r'^[a-zA-Z0-9_.-]+$', key), 'invalid key %r' % key
|
||||
return os.path.join(
|
||||
self._get_root_dir(), section, '%s.%s' % (key, dtype))
|
||||
|
||||
@property
|
||||
def enabled(self):
|
||||
return self._ydl.params.get('cachedir') is not False
|
||||
|
||||
def store(self, section, key, data, dtype='json'):
|
||||
assert dtype in ('json',)
|
||||
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
fn = self._get_cache_fn(section, key, dtype)
|
||||
try:
|
||||
try:
|
||||
os.makedirs(os.path.dirname(fn))
|
||||
except OSError as ose:
|
||||
if ose.errno != errno.EEXIST:
|
||||
raise
|
||||
write_json_file(data, fn)
|
||||
except Exception:
|
||||
tb = traceback.format_exc()
|
||||
self._ydl.report_warning(
|
||||
'Writing cache to %r failed: %s' % (fn, tb))
|
||||
|
||||
def load(self, section, key, dtype='json', default=None):
|
||||
assert dtype in ('json',)
|
||||
|
||||
if not self.enabled:
|
||||
return default
|
||||
|
||||
cache_fn = self._get_cache_fn(section, key, dtype)
|
||||
try:
|
||||
try:
|
||||
with io.open(cache_fn, 'r', encoding='utf-8') as cachef:
|
||||
return json.load(cachef)
|
||||
except ValueError:
|
||||
try:
|
||||
file_size = os.path.getsize(cache_fn)
|
||||
except (OSError, IOError) as oe:
|
||||
file_size = str(oe)
|
||||
self._ydl.report_warning(
|
||||
'Cache retrieval from %s failed (%s)' % (cache_fn, file_size))
|
||||
except IOError:
|
||||
pass # No cache available
|
||||
|
||||
return default
|
||||
|
||||
def remove(self):
|
||||
if not self.enabled:
|
||||
self._ydl.to_screen('Cache is disabled (Did you combine --no-cache-dir and --rm-cache-dir?)')
|
||||
return
|
||||
|
||||
cachedir = self._get_root_dir()
|
||||
if not any((term in cachedir) for term in ('cache', 'tmp')):
|
||||
raise Exception('Not removing directory %s - this does not look like a cache dir' % cachedir)
|
||||
|
||||
self._ydl.to_screen(
|
||||
'Removing cache dir %s .' % cachedir, skip_eol=True)
|
||||
if os.path.exists(cachedir):
|
||||
self._ydl.to_screen('.', skip_eol=True)
|
||||
shutil.rmtree(cachedir)
|
||||
self._ydl.to_screen('.')
|
||||
581
youtube_dl/compat.py
Normal file
581
youtube_dl/compat.py
Normal file
@@ -0,0 +1,581 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import binascii
|
||||
import collections
|
||||
import email
|
||||
import getpass
|
||||
import io
|
||||
import optparse
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import shutil
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
import itertools
|
||||
import xml.etree.ElementTree
|
||||
|
||||
|
||||
try:
|
||||
import urllib.request as compat_urllib_request
|
||||
except ImportError: # Python 2
|
||||
import urllib2 as compat_urllib_request
|
||||
|
||||
try:
|
||||
import urllib.error as compat_urllib_error
|
||||
except ImportError: # Python 2
|
||||
import urllib2 as compat_urllib_error
|
||||
|
||||
try:
|
||||
import urllib.parse as compat_urllib_parse
|
||||
except ImportError: # Python 2
|
||||
import urllib as compat_urllib_parse
|
||||
|
||||
try:
|
||||
from urllib.parse import urlparse as compat_urllib_parse_urlparse
|
||||
except ImportError: # Python 2
|
||||
from urlparse import urlparse as compat_urllib_parse_urlparse
|
||||
|
||||
try:
|
||||
import urllib.parse as compat_urlparse
|
||||
except ImportError: # Python 2
|
||||
import urlparse as compat_urlparse
|
||||
|
||||
try:
|
||||
import urllib.response as compat_urllib_response
|
||||
except ImportError: # Python 2
|
||||
import urllib as compat_urllib_response
|
||||
|
||||
try:
|
||||
import http.cookiejar as compat_cookiejar
|
||||
except ImportError: # Python 2
|
||||
import cookielib as compat_cookiejar
|
||||
|
||||
try:
|
||||
import http.cookies as compat_cookies
|
||||
except ImportError: # Python 2
|
||||
import Cookie as compat_cookies
|
||||
|
||||
try:
|
||||
import html.entities as compat_html_entities
|
||||
except ImportError: # Python 2
|
||||
import htmlentitydefs as compat_html_entities
|
||||
|
||||
try:
|
||||
import http.client as compat_http_client
|
||||
except ImportError: # Python 2
|
||||
import httplib as compat_http_client
|
||||
|
||||
try:
|
||||
from urllib.error import HTTPError as compat_HTTPError
|
||||
except ImportError: # Python 2
|
||||
from urllib2 import HTTPError as compat_HTTPError
|
||||
|
||||
try:
|
||||
from urllib.request import urlretrieve as compat_urlretrieve
|
||||
except ImportError: # Python 2
|
||||
from urllib import urlretrieve as compat_urlretrieve
|
||||
|
||||
|
||||
try:
|
||||
from subprocess import DEVNULL
|
||||
compat_subprocess_get_DEVNULL = lambda: DEVNULL
|
||||
except ImportError:
|
||||
compat_subprocess_get_DEVNULL = lambda: open(os.path.devnull, 'w')
|
||||
|
||||
try:
|
||||
import http.server as compat_http_server
|
||||
except ImportError:
|
||||
import BaseHTTPServer as compat_http_server
|
||||
|
||||
try:
|
||||
compat_str = unicode # Python 2
|
||||
except NameError:
|
||||
compat_str = str
|
||||
|
||||
try:
|
||||
from urllib.parse import unquote_to_bytes as compat_urllib_parse_unquote_to_bytes
|
||||
from urllib.parse import unquote as compat_urllib_parse_unquote
|
||||
from urllib.parse import unquote_plus as compat_urllib_parse_unquote_plus
|
||||
except ImportError: # Python 2
|
||||
_asciire = (compat_urllib_parse._asciire if hasattr(compat_urllib_parse, '_asciire')
|
||||
else re.compile('([\x00-\x7f]+)'))
|
||||
|
||||
# HACK: The following are the correct unquote_to_bytes, unquote and unquote_plus
|
||||
# implementations from cpython 3.4.3's stdlib. Python 2's version
|
||||
# is apparently broken (see https://github.com/rg3/youtube-dl/pull/6244)
|
||||
|
||||
def compat_urllib_parse_unquote_to_bytes(string):
|
||||
"""unquote_to_bytes('abc%20def') -> b'abc def'."""
|
||||
# Note: strings are encoded as UTF-8. This is only an issue if it contains
|
||||
# unescaped non-ASCII characters, which URIs should not.
|
||||
if not string:
|
||||
# Is it a string-like object?
|
||||
string.split
|
||||
return b''
|
||||
if isinstance(string, compat_str):
|
||||
string = string.encode('utf-8')
|
||||
bits = string.split(b'%')
|
||||
if len(bits) == 1:
|
||||
return string
|
||||
res = [bits[0]]
|
||||
append = res.append
|
||||
for item in bits[1:]:
|
||||
try:
|
||||
append(compat_urllib_parse._hextochr[item[:2]])
|
||||
append(item[2:])
|
||||
except KeyError:
|
||||
append(b'%')
|
||||
append(item)
|
||||
return b''.join(res)
|
||||
|
||||
def compat_urllib_parse_unquote(string, encoding='utf-8', errors='replace'):
|
||||
"""Replace %xx escapes by their single-character equivalent. The optional
|
||||
encoding and errors parameters specify how to decode percent-encoded
|
||||
sequences into Unicode characters, as accepted by the bytes.decode()
|
||||
method.
|
||||
By default, percent-encoded sequences are decoded with UTF-8, and invalid
|
||||
sequences are replaced by a placeholder character.
|
||||
|
||||
unquote('abc%20def') -> 'abc def'.
|
||||
"""
|
||||
if '%' not in string:
|
||||
string.split
|
||||
return string
|
||||
if encoding is None:
|
||||
encoding = 'utf-8'
|
||||
if errors is None:
|
||||
errors = 'replace'
|
||||
bits = _asciire.split(string)
|
||||
res = [bits[0]]
|
||||
append = res.append
|
||||
for i in range(1, len(bits), 2):
|
||||
append(compat_urllib_parse_unquote_to_bytes(bits[i]).decode(encoding, errors))
|
||||
append(bits[i + 1])
|
||||
return ''.join(res)
|
||||
|
||||
def compat_urllib_parse_unquote_plus(string, encoding='utf-8', errors='replace'):
|
||||
"""Like unquote(), but also replace plus signs by spaces, as required for
|
||||
unquoting HTML form values.
|
||||
|
||||
unquote_plus('%7e/abc+def') -> '~/abc def'
|
||||
"""
|
||||
string = string.replace('+', ' ')
|
||||
return compat_urllib_parse_unquote(string, encoding, errors)
|
||||
|
||||
try:
|
||||
from urllib.request import DataHandler as compat_urllib_request_DataHandler
|
||||
except ImportError: # Python < 3.4
|
||||
# Ported from CPython 98774:1733b3bd46db, Lib/urllib/request.py
|
||||
class compat_urllib_request_DataHandler(compat_urllib_request.BaseHandler):
|
||||
def data_open(self, req):
|
||||
# data URLs as specified in RFC 2397.
|
||||
#
|
||||
# ignores POSTed data
|
||||
#
|
||||
# syntax:
|
||||
# dataurl := "data:" [ mediatype ] [ ";base64" ] "," data
|
||||
# mediatype := [ type "/" subtype ] *( ";" parameter )
|
||||
# data := *urlchar
|
||||
# parameter := attribute "=" value
|
||||
url = req.get_full_url()
|
||||
|
||||
scheme, data = url.split(":", 1)
|
||||
mediatype, data = data.split(",", 1)
|
||||
|
||||
# even base64 encoded data URLs might be quoted so unquote in any case:
|
||||
data = compat_urllib_parse_unquote_to_bytes(data)
|
||||
if mediatype.endswith(";base64"):
|
||||
data = binascii.a2b_base64(data)
|
||||
mediatype = mediatype[:-7]
|
||||
|
||||
if not mediatype:
|
||||
mediatype = "text/plain;charset=US-ASCII"
|
||||
|
||||
headers = email.message_from_string(
|
||||
"Content-type: %s\nContent-length: %d\n" % (mediatype, len(data)))
|
||||
|
||||
return compat_urllib_response.addinfourl(io.BytesIO(data), headers, url)
|
||||
|
||||
try:
|
||||
compat_basestring = basestring # Python 2
|
||||
except NameError:
|
||||
compat_basestring = str
|
||||
|
||||
try:
|
||||
compat_chr = unichr # Python 2
|
||||
except NameError:
|
||||
compat_chr = chr
|
||||
|
||||
try:
|
||||
from xml.etree.ElementTree import ParseError as compat_xml_parse_error
|
||||
except ImportError: # Python 2.6
|
||||
from xml.parsers.expat import ExpatError as compat_xml_parse_error
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
compat_etree_fromstring = xml.etree.ElementTree.fromstring
|
||||
else:
|
||||
# python 2.x tries to encode unicode strings with ascii (see the
|
||||
# XMLParser._fixtext method)
|
||||
etree = xml.etree.ElementTree
|
||||
|
||||
try:
|
||||
_etree_iter = etree.Element.iter
|
||||
except AttributeError: # Python <=2.6
|
||||
def _etree_iter(root):
|
||||
for el in root.findall('*'):
|
||||
yield el
|
||||
for sub in _etree_iter(el):
|
||||
yield sub
|
||||
|
||||
# on 2.6 XML doesn't have a parser argument, function copied from CPython
|
||||
# 2.7 source
|
||||
def _XML(text, parser=None):
|
||||
if not parser:
|
||||
parser = etree.XMLParser(target=etree.TreeBuilder())
|
||||
parser.feed(text)
|
||||
return parser.close()
|
||||
|
||||
def _element_factory(*args, **kwargs):
|
||||
el = etree.Element(*args, **kwargs)
|
||||
for k, v in el.items():
|
||||
if isinstance(v, bytes):
|
||||
el.set(k, v.decode('utf-8'))
|
||||
return el
|
||||
|
||||
def compat_etree_fromstring(text):
|
||||
doc = _XML(text, parser=etree.XMLParser(target=etree.TreeBuilder(element_factory=_element_factory)))
|
||||
for el in _etree_iter(doc):
|
||||
if el.text is not None and isinstance(el.text, bytes):
|
||||
el.text = el.text.decode('utf-8')
|
||||
return doc
|
||||
|
||||
try:
|
||||
from urllib.parse import parse_qs as compat_parse_qs
|
||||
except ImportError: # Python 2
|
||||
# HACK: The following is the correct parse_qs implementation from cpython 3's stdlib.
|
||||
# Python 2's version is apparently totally broken
|
||||
|
||||
def _parse_qsl(qs, keep_blank_values=False, strict_parsing=False,
|
||||
encoding='utf-8', errors='replace'):
|
||||
qs, _coerce_result = qs, compat_str
|
||||
pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')]
|
||||
r = []
|
||||
for name_value in pairs:
|
||||
if not name_value and not strict_parsing:
|
||||
continue
|
||||
nv = name_value.split('=', 1)
|
||||
if len(nv) != 2:
|
||||
if strict_parsing:
|
||||
raise ValueError("bad query field: %r" % (name_value,))
|
||||
# Handle case of a control-name with no equal sign
|
||||
if keep_blank_values:
|
||||
nv.append('')
|
||||
else:
|
||||
continue
|
||||
if len(nv[1]) or keep_blank_values:
|
||||
name = nv[0].replace('+', ' ')
|
||||
name = compat_urllib_parse_unquote(
|
||||
name, encoding=encoding, errors=errors)
|
||||
name = _coerce_result(name)
|
||||
value = nv[1].replace('+', ' ')
|
||||
value = compat_urllib_parse_unquote(
|
||||
value, encoding=encoding, errors=errors)
|
||||
value = _coerce_result(value)
|
||||
r.append((name, value))
|
||||
return r
|
||||
|
||||
def compat_parse_qs(qs, keep_blank_values=False, strict_parsing=False,
|
||||
encoding='utf-8', errors='replace'):
|
||||
parsed_result = {}
|
||||
pairs = _parse_qsl(qs, keep_blank_values, strict_parsing,
|
||||
encoding=encoding, errors=errors)
|
||||
for name, value in pairs:
|
||||
if name in parsed_result:
|
||||
parsed_result[name].append(value)
|
||||
else:
|
||||
parsed_result[name] = [value]
|
||||
return parsed_result
|
||||
|
||||
try:
|
||||
from shlex import quote as shlex_quote
|
||||
except ImportError: # Python < 3.3
|
||||
def shlex_quote(s):
|
||||
if re.match(r'^[-_\w./]+$', s):
|
||||
return s
|
||||
else:
|
||||
return "'" + s.replace("'", "'\"'\"'") + "'"
|
||||
|
||||
|
||||
if sys.version_info >= (2, 7, 3):
|
||||
compat_shlex_split = shlex.split
|
||||
else:
|
||||
# Working around shlex issue with unicode strings on some python 2
|
||||
# versions (see http://bugs.python.org/issue1548891)
|
||||
def compat_shlex_split(s, comments=False, posix=True):
|
||||
if isinstance(s, compat_str):
|
||||
s = s.encode('utf-8')
|
||||
return shlex.split(s, comments, posix)
|
||||
|
||||
|
||||
def compat_ord(c):
|
||||
if type(c) is int:
|
||||
return c
|
||||
else:
|
||||
return ord(c)
|
||||
|
||||
|
||||
if sys.version_info >= (3, 0):
|
||||
compat_getenv = os.getenv
|
||||
compat_expanduser = os.path.expanduser
|
||||
else:
|
||||
# Environment variables should be decoded with filesystem encoding.
|
||||
# Otherwise it will fail if any non-ASCII characters present (see #3854 #3217 #2918)
|
||||
|
||||
def compat_getenv(key, default=None):
|
||||
from .utils import get_filesystem_encoding
|
||||
env = os.getenv(key, default)
|
||||
if env:
|
||||
env = env.decode(get_filesystem_encoding())
|
||||
return env
|
||||
|
||||
# HACK: The default implementations of os.path.expanduser from cpython do not decode
|
||||
# environment variables with filesystem encoding. We will work around this by
|
||||
# providing adjusted implementations.
|
||||
# The following are os.path.expanduser implementations from cpython 2.7.8 stdlib
|
||||
# for different platforms with correct environment variables decoding.
|
||||
|
||||
if os.name == 'posix':
|
||||
def compat_expanduser(path):
|
||||
"""Expand ~ and ~user constructions. If user or $HOME is unknown,
|
||||
do nothing."""
|
||||
if not path.startswith('~'):
|
||||
return path
|
||||
i = path.find('/', 1)
|
||||
if i < 0:
|
||||
i = len(path)
|
||||
if i == 1:
|
||||
if 'HOME' not in os.environ:
|
||||
import pwd
|
||||
userhome = pwd.getpwuid(os.getuid()).pw_dir
|
||||
else:
|
||||
userhome = compat_getenv('HOME')
|
||||
else:
|
||||
import pwd
|
||||
try:
|
||||
pwent = pwd.getpwnam(path[1:i])
|
||||
except KeyError:
|
||||
return path
|
||||
userhome = pwent.pw_dir
|
||||
userhome = userhome.rstrip('/')
|
||||
return (userhome + path[i:]) or '/'
|
||||
elif os.name == 'nt' or os.name == 'ce':
|
||||
def compat_expanduser(path):
|
||||
"""Expand ~ and ~user constructs.
|
||||
|
||||
If user or $HOME is unknown, do nothing."""
|
||||
if path[:1] != '~':
|
||||
return path
|
||||
i, n = 1, len(path)
|
||||
while i < n and path[i] not in '/\\':
|
||||
i = i + 1
|
||||
|
||||
if 'HOME' in os.environ:
|
||||
userhome = compat_getenv('HOME')
|
||||
elif 'USERPROFILE' in os.environ:
|
||||
userhome = compat_getenv('USERPROFILE')
|
||||
elif 'HOMEPATH' not in os.environ:
|
||||
return path
|
||||
else:
|
||||
try:
|
||||
drive = compat_getenv('HOMEDRIVE')
|
||||
except KeyError:
|
||||
drive = ''
|
||||
userhome = os.path.join(drive, compat_getenv('HOMEPATH'))
|
||||
|
||||
if i != 1: # ~user
|
||||
userhome = os.path.join(os.path.dirname(userhome), path[1:i])
|
||||
|
||||
return userhome + path[i:]
|
||||
else:
|
||||
compat_expanduser = os.path.expanduser
|
||||
|
||||
|
||||
if sys.version_info < (3, 0):
|
||||
def compat_print(s):
|
||||
from .utils import preferredencoding
|
||||
print(s.encode(preferredencoding(), 'xmlcharrefreplace'))
|
||||
else:
|
||||
def compat_print(s):
|
||||
assert isinstance(s, compat_str)
|
||||
print(s)
|
||||
|
||||
|
||||
try:
|
||||
subprocess_check_output = subprocess.check_output
|
||||
except AttributeError:
|
||||
def subprocess_check_output(*args, **kwargs):
|
||||
assert 'input' not in kwargs
|
||||
p = subprocess.Popen(*args, stdout=subprocess.PIPE, **kwargs)
|
||||
output, _ = p.communicate()
|
||||
ret = p.poll()
|
||||
if ret:
|
||||
raise subprocess.CalledProcessError(ret, p.args, output=output)
|
||||
return output
|
||||
|
||||
if sys.version_info < (3, 0) and sys.platform == 'win32':
|
||||
def compat_getpass(prompt, *args, **kwargs):
|
||||
if isinstance(prompt, compat_str):
|
||||
from .utils import preferredencoding
|
||||
prompt = prompt.encode(preferredencoding())
|
||||
return getpass.getpass(prompt, *args, **kwargs)
|
||||
else:
|
||||
compat_getpass = getpass.getpass
|
||||
|
||||
# Old 2.6 and 2.7 releases require kwargs to be bytes
|
||||
try:
|
||||
def _testfunc(x):
|
||||
pass
|
||||
_testfunc(**{'x': 0})
|
||||
except TypeError:
|
||||
def compat_kwargs(kwargs):
|
||||
return dict((bytes(k), v) for k, v in kwargs.items())
|
||||
else:
|
||||
compat_kwargs = lambda kwargs: kwargs
|
||||
|
||||
|
||||
if sys.version_info < (2, 7):
|
||||
def compat_socket_create_connection(address, timeout, source_address=None):
|
||||
host, port = address
|
||||
err = None
|
||||
for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
|
||||
af, socktype, proto, canonname, sa = res
|
||||
sock = None
|
||||
try:
|
||||
sock = socket.socket(af, socktype, proto)
|
||||
sock.settimeout(timeout)
|
||||
if source_address:
|
||||
sock.bind(source_address)
|
||||
sock.connect(sa)
|
||||
return sock
|
||||
except socket.error as _:
|
||||
err = _
|
||||
if sock is not None:
|
||||
sock.close()
|
||||
if err is not None:
|
||||
raise err
|
||||
else:
|
||||
raise socket.error("getaddrinfo returns an empty list")
|
||||
else:
|
||||
compat_socket_create_connection = socket.create_connection
|
||||
|
||||
|
||||
# Fix https://github.com/rg3/youtube-dl/issues/4223
|
||||
# See http://bugs.python.org/issue9161 for what is broken
|
||||
def workaround_optparse_bug9161():
|
||||
op = optparse.OptionParser()
|
||||
og = optparse.OptionGroup(op, 'foo')
|
||||
try:
|
||||
og.add_option('-t')
|
||||
except TypeError:
|
||||
real_add_option = optparse.OptionGroup.add_option
|
||||
|
||||
def _compat_add_option(self, *args, **kwargs):
|
||||
enc = lambda v: (
|
||||
v.encode('ascii', 'replace') if isinstance(v, compat_str)
|
||||
else v)
|
||||
bargs = [enc(a) for a in args]
|
||||
bkwargs = dict(
|
||||
(k, enc(v)) for k, v in kwargs.items())
|
||||
return real_add_option(self, *bargs, **bkwargs)
|
||||
optparse.OptionGroup.add_option = _compat_add_option
|
||||
|
||||
if hasattr(shutil, 'get_terminal_size'): # Python >= 3.3
|
||||
compat_get_terminal_size = shutil.get_terminal_size
|
||||
else:
|
||||
_terminal_size = collections.namedtuple('terminal_size', ['columns', 'lines'])
|
||||
|
||||
def compat_get_terminal_size(fallback=(80, 24)):
|
||||
columns = compat_getenv('COLUMNS')
|
||||
if columns:
|
||||
columns = int(columns)
|
||||
else:
|
||||
columns = None
|
||||
lines = compat_getenv('LINES')
|
||||
if lines:
|
||||
lines = int(lines)
|
||||
else:
|
||||
lines = None
|
||||
|
||||
if columns is None or lines is None or columns <= 0 or lines <= 0:
|
||||
try:
|
||||
sp = subprocess.Popen(
|
||||
['stty', 'size'],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
out, err = sp.communicate()
|
||||
_lines, _columns = map(int, out.split())
|
||||
except Exception:
|
||||
_columns, _lines = _terminal_size(*fallback)
|
||||
|
||||
if columns is None or columns <= 0:
|
||||
columns = _columns
|
||||
if lines is None or lines <= 0:
|
||||
lines = _lines
|
||||
return _terminal_size(columns, lines)
|
||||
|
||||
try:
|
||||
itertools.count(start=0, step=1)
|
||||
compat_itertools_count = itertools.count
|
||||
except TypeError: # Python 2.6
|
||||
def compat_itertools_count(start=0, step=1):
|
||||
n = start
|
||||
while True:
|
||||
yield n
|
||||
n += step
|
||||
|
||||
if sys.version_info >= (3, 0):
|
||||
from tokenize import tokenize as compat_tokenize_tokenize
|
||||
else:
|
||||
from tokenize import generate_tokens as compat_tokenize_tokenize
|
||||
|
||||
__all__ = [
|
||||
'compat_HTTPError',
|
||||
'compat_basestring',
|
||||
'compat_chr',
|
||||
'compat_cookiejar',
|
||||
'compat_cookies',
|
||||
'compat_etree_fromstring',
|
||||
'compat_expanduser',
|
||||
'compat_get_terminal_size',
|
||||
'compat_getenv',
|
||||
'compat_getpass',
|
||||
'compat_html_entities',
|
||||
'compat_http_client',
|
||||
'compat_http_server',
|
||||
'compat_itertools_count',
|
||||
'compat_kwargs',
|
||||
'compat_ord',
|
||||
'compat_parse_qs',
|
||||
'compat_print',
|
||||
'compat_shlex_split',
|
||||
'compat_socket_create_connection',
|
||||
'compat_str',
|
||||
'compat_subprocess_get_DEVNULL',
|
||||
'compat_tokenize_tokenize',
|
||||
'compat_urllib_error',
|
||||
'compat_urllib_parse',
|
||||
'compat_urllib_parse_unquote',
|
||||
'compat_urllib_parse_unquote_plus',
|
||||
'compat_urllib_parse_unquote_to_bytes',
|
||||
'compat_urllib_parse_urlparse',
|
||||
'compat_urllib_request',
|
||||
'compat_urllib_request_DataHandler',
|
||||
'compat_urllib_response',
|
||||
'compat_urlparse',
|
||||
'compat_urlretrieve',
|
||||
'compat_xml_parse_error',
|
||||
'shlex_quote',
|
||||
'subprocess_check_output',
|
||||
'workaround_optparse_bug9161',
|
||||
]
|
||||
48
youtube_dl/downloader/__init__.py
Normal file
48
youtube_dl/downloader/__init__.py
Normal file
@@ -0,0 +1,48 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .common import FileDownloader
|
||||
from .external import get_external_downloader
|
||||
from .f4m import F4mFD
|
||||
from .hls import HlsFD
|
||||
from .hls import NativeHlsFD
|
||||
from .http import HttpFD
|
||||
from .rtsp import RtspFD
|
||||
from .rtmp import RtmpFD
|
||||
from .dash import DashSegmentsFD
|
||||
|
||||
from ..utils import (
|
||||
determine_protocol,
|
||||
)
|
||||
|
||||
PROTOCOL_MAP = {
|
||||
'rtmp': RtmpFD,
|
||||
'm3u8_native': NativeHlsFD,
|
||||
'm3u8': HlsFD,
|
||||
'mms': RtspFD,
|
||||
'rtsp': RtspFD,
|
||||
'f4m': F4mFD,
|
||||
'http_dash_segments': DashSegmentsFD,
|
||||
}
|
||||
|
||||
|
||||
def get_suitable_downloader(info_dict, params={}):
|
||||
"""Get the downloader class that can handle the info dict."""
|
||||
protocol = determine_protocol(info_dict)
|
||||
info_dict['protocol'] = protocol
|
||||
|
||||
external_downloader = params.get('external_downloader')
|
||||
if external_downloader is not None:
|
||||
ed = get_external_downloader(external_downloader)
|
||||
if ed.supports(info_dict):
|
||||
return ed
|
||||
|
||||
if protocol == 'm3u8' and params.get('hls_prefer_native'):
|
||||
return NativeHlsFD
|
||||
|
||||
return PROTOCOL_MAP.get(protocol, HttpFD)
|
||||
|
||||
|
||||
__all__ = [
|
||||
'get_suitable_downloader',
|
||||
'FileDownloader',
|
||||
]
|
||||
372
youtube_dl/downloader/common.py
Normal file
372
youtube_dl/downloader/common.py
Normal file
@@ -0,0 +1,372 @@
|
||||
from __future__ import division, unicode_literals
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
|
||||
from ..compat import compat_str
|
||||
from ..utils import (
|
||||
encodeFilename,
|
||||
decodeArgument,
|
||||
format_bytes,
|
||||
timeconvert,
|
||||
)
|
||||
|
||||
|
||||
class FileDownloader(object):
|
||||
"""File Downloader class.
|
||||
|
||||
File downloader objects are the ones responsible of downloading the
|
||||
actual video file and writing it to disk.
|
||||
|
||||
File downloaders accept a lot of parameters. In order not to saturate
|
||||
the object constructor with arguments, it receives a dictionary of
|
||||
options instead.
|
||||
|
||||
Available options:
|
||||
|
||||
verbose: Print additional info to stdout.
|
||||
quiet: Do not print messages to stdout.
|
||||
ratelimit: Download speed limit, in bytes/sec.
|
||||
retries: Number of times to retry for HTTP error 5xx
|
||||
buffersize: Size of download buffer in bytes.
|
||||
noresizebuffer: Do not automatically resize the download buffer.
|
||||
continuedl: Try to continue downloads if possible.
|
||||
noprogress: Do not print the progress bar.
|
||||
logtostderr: Log messages to stderr instead of stdout.
|
||||
consoletitle: Display progress in console window's titlebar.
|
||||
nopart: Do not use temporary .part files.
|
||||
updatetime: Use the Last-modified header to set output file timestamps.
|
||||
test: Download only first bytes to test the downloader.
|
||||
min_filesize: Skip files smaller than this size
|
||||
max_filesize: Skip files larger than this size
|
||||
xattr_set_filesize: Set ytdl.filesize user xattribute with expected size.
|
||||
(experimental)
|
||||
external_downloader_args: A list of additional command-line arguments for the
|
||||
external downloader.
|
||||
|
||||
Subclasses of this one must re-define the real_download method.
|
||||
"""
|
||||
|
||||
_TEST_FILE_SIZE = 10241
|
||||
params = None
|
||||
|
||||
def __init__(self, ydl, params):
|
||||
"""Create a FileDownloader object with the given options."""
|
||||
self.ydl = ydl
|
||||
self._progress_hooks = []
|
||||
self.params = params
|
||||
self.add_progress_hook(self.report_progress)
|
||||
|
||||
@staticmethod
|
||||
def format_seconds(seconds):
|
||||
(mins, secs) = divmod(seconds, 60)
|
||||
(hours, mins) = divmod(mins, 60)
|
||||
if hours > 99:
|
||||
return '--:--:--'
|
||||
if hours == 0:
|
||||
return '%02d:%02d' % (mins, secs)
|
||||
else:
|
||||
return '%02d:%02d:%02d' % (hours, mins, secs)
|
||||
|
||||
@staticmethod
|
||||
def calc_percent(byte_counter, data_len):
|
||||
if data_len is None:
|
||||
return None
|
||||
return float(byte_counter) / float(data_len) * 100.0
|
||||
|
||||
@staticmethod
|
||||
def format_percent(percent):
|
||||
if percent is None:
|
||||
return '---.-%'
|
||||
return '%6s' % ('%3.1f%%' % percent)
|
||||
|
||||
@staticmethod
|
||||
def calc_eta(start, now, total, current):
|
||||
if total is None:
|
||||
return None
|
||||
if now is None:
|
||||
now = time.time()
|
||||
dif = now - start
|
||||
if current == 0 or dif < 0.001: # One millisecond
|
||||
return None
|
||||
rate = float(current) / dif
|
||||
return int((float(total) - float(current)) / rate)
|
||||
|
||||
@staticmethod
|
||||
def format_eta(eta):
|
||||
if eta is None:
|
||||
return '--:--'
|
||||
return FileDownloader.format_seconds(eta)
|
||||
|
||||
@staticmethod
|
||||
def calc_speed(start, now, bytes):
|
||||
dif = now - start
|
||||
if bytes == 0 or dif < 0.001: # One millisecond
|
||||
return None
|
||||
return float(bytes) / dif
|
||||
|
||||
@staticmethod
|
||||
def format_speed(speed):
|
||||
if speed is None:
|
||||
return '%10s' % '---b/s'
|
||||
return '%10s' % ('%s/s' % format_bytes(speed))
|
||||
|
||||
@staticmethod
|
||||
def best_block_size(elapsed_time, bytes):
|
||||
new_min = max(bytes / 2.0, 1.0)
|
||||
new_max = min(max(bytes * 2.0, 1.0), 4194304) # Do not surpass 4 MB
|
||||
if elapsed_time < 0.001:
|
||||
return int(new_max)
|
||||
rate = bytes / elapsed_time
|
||||
if rate > new_max:
|
||||
return int(new_max)
|
||||
if rate < new_min:
|
||||
return int(new_min)
|
||||
return int(rate)
|
||||
|
||||
@staticmethod
|
||||
def parse_bytes(bytestr):
|
||||
"""Parse a string indicating a byte quantity into an integer."""
|
||||
matchobj = re.match(r'(?i)^(\d+(?:\.\d+)?)([kMGTPEZY]?)$', bytestr)
|
||||
if matchobj is None:
|
||||
return None
|
||||
number = float(matchobj.group(1))
|
||||
multiplier = 1024.0 ** 'bkmgtpezy'.index(matchobj.group(2).lower())
|
||||
return int(round(number * multiplier))
|
||||
|
||||
def to_screen(self, *args, **kargs):
|
||||
self.ydl.to_screen(*args, **kargs)
|
||||
|
||||
def to_stderr(self, message):
|
||||
self.ydl.to_screen(message)
|
||||
|
||||
def to_console_title(self, message):
|
||||
self.ydl.to_console_title(message)
|
||||
|
||||
def trouble(self, *args, **kargs):
|
||||
self.ydl.trouble(*args, **kargs)
|
||||
|
||||
def report_warning(self, *args, **kargs):
|
||||
self.ydl.report_warning(*args, **kargs)
|
||||
|
||||
def report_error(self, *args, **kargs):
|
||||
self.ydl.report_error(*args, **kargs)
|
||||
|
||||
def slow_down(self, start_time, now, byte_counter):
|
||||
"""Sleep if the download speed is over the rate limit."""
|
||||
rate_limit = self.params.get('ratelimit', None)
|
||||
if rate_limit is None or byte_counter == 0:
|
||||
return
|
||||
if now is None:
|
||||
now = time.time()
|
||||
elapsed = now - start_time
|
||||
if elapsed <= 0.0:
|
||||
return
|
||||
speed = float(byte_counter) / elapsed
|
||||
if speed > rate_limit:
|
||||
time.sleep(max((byte_counter // rate_limit) - elapsed, 0))
|
||||
|
||||
def temp_name(self, filename):
|
||||
"""Returns a temporary filename for the given filename."""
|
||||
if self.params.get('nopart', False) or filename == '-' or \
|
||||
(os.path.exists(encodeFilename(filename)) and not os.path.isfile(encodeFilename(filename))):
|
||||
return filename
|
||||
return filename + '.part'
|
||||
|
||||
def undo_temp_name(self, filename):
|
||||
if filename.endswith('.part'):
|
||||
return filename[:-len('.part')]
|
||||
return filename
|
||||
|
||||
def try_rename(self, old_filename, new_filename):
|
||||
try:
|
||||
if old_filename == new_filename:
|
||||
return
|
||||
os.rename(encodeFilename(old_filename), encodeFilename(new_filename))
|
||||
except (IOError, OSError) as err:
|
||||
self.report_error('unable to rename file: %s' % compat_str(err))
|
||||
|
||||
def try_utime(self, filename, last_modified_hdr):
|
||||
"""Try to set the last-modified time of the given file."""
|
||||
if last_modified_hdr is None:
|
||||
return
|
||||
if not os.path.isfile(encodeFilename(filename)):
|
||||
return
|
||||
timestr = last_modified_hdr
|
||||
if timestr is None:
|
||||
return
|
||||
filetime = timeconvert(timestr)
|
||||
if filetime is None:
|
||||
return filetime
|
||||
# Ignore obviously invalid dates
|
||||
if filetime == 0:
|
||||
return
|
||||
try:
|
||||
os.utime(filename, (time.time(), filetime))
|
||||
except Exception:
|
||||
pass
|
||||
return filetime
|
||||
|
||||
def report_destination(self, filename):
|
||||
"""Report destination filename."""
|
||||
self.to_screen('[download] Destination: ' + filename)
|
||||
|
||||
def _report_progress_status(self, msg, is_last_line=False):
|
||||
fullmsg = '[download] ' + msg
|
||||
if self.params.get('progress_with_newline', False):
|
||||
self.to_screen(fullmsg)
|
||||
else:
|
||||
if os.name == 'nt':
|
||||
prev_len = getattr(self, '_report_progress_prev_line_length',
|
||||
0)
|
||||
if prev_len > len(fullmsg):
|
||||
fullmsg += ' ' * (prev_len - len(fullmsg))
|
||||
self._report_progress_prev_line_length = len(fullmsg)
|
||||
clear_line = '\r'
|
||||
else:
|
||||
clear_line = ('\r\x1b[K' if sys.stderr.isatty() else '\r')
|
||||
self.to_screen(clear_line + fullmsg, skip_eol=not is_last_line)
|
||||
self.to_console_title('youtube-dl ' + msg)
|
||||
|
||||
def report_progress(self, s):
|
||||
if s['status'] == 'finished':
|
||||
if self.params.get('noprogress', False):
|
||||
self.to_screen('[download] Download completed')
|
||||
else:
|
||||
s['_total_bytes_str'] = format_bytes(s['total_bytes'])
|
||||
if s.get('elapsed') is not None:
|
||||
s['_elapsed_str'] = self.format_seconds(s['elapsed'])
|
||||
msg_template = '100%% of %(_total_bytes_str)s in %(_elapsed_str)s'
|
||||
else:
|
||||
msg_template = '100%% of %(_total_bytes_str)s'
|
||||
self._report_progress_status(
|
||||
msg_template % s, is_last_line=True)
|
||||
|
||||
if self.params.get('noprogress'):
|
||||
return
|
||||
|
||||
if s['status'] != 'downloading':
|
||||
return
|
||||
|
||||
if s.get('eta') is not None:
|
||||
s['_eta_str'] = self.format_eta(s['eta'])
|
||||
else:
|
||||
s['_eta_str'] = 'Unknown ETA'
|
||||
|
||||
if s.get('total_bytes') and s.get('downloaded_bytes') is not None:
|
||||
s['_percent_str'] = self.format_percent(100 * s['downloaded_bytes'] / s['total_bytes'])
|
||||
elif s.get('total_bytes_estimate') and s.get('downloaded_bytes') is not None:
|
||||
s['_percent_str'] = self.format_percent(100 * s['downloaded_bytes'] / s['total_bytes_estimate'])
|
||||
else:
|
||||
if s.get('downloaded_bytes') == 0:
|
||||
s['_percent_str'] = self.format_percent(0)
|
||||
else:
|
||||
s['_percent_str'] = 'Unknown %'
|
||||
|
||||
if s.get('speed') is not None:
|
||||
s['_speed_str'] = self.format_speed(s['speed'])
|
||||
else:
|
||||
s['_speed_str'] = 'Unknown speed'
|
||||
|
||||
if s.get('total_bytes') is not None:
|
||||
s['_total_bytes_str'] = format_bytes(s['total_bytes'])
|
||||
msg_template = '%(_percent_str)s of %(_total_bytes_str)s at %(_speed_str)s ETA %(_eta_str)s'
|
||||
elif s.get('total_bytes_estimate') is not None:
|
||||
s['_total_bytes_estimate_str'] = format_bytes(s['total_bytes_estimate'])
|
||||
msg_template = '%(_percent_str)s of ~%(_total_bytes_estimate_str)s at %(_speed_str)s ETA %(_eta_str)s'
|
||||
else:
|
||||
if s.get('downloaded_bytes') is not None:
|
||||
s['_downloaded_bytes_str'] = format_bytes(s['downloaded_bytes'])
|
||||
if s.get('elapsed'):
|
||||
s['_elapsed_str'] = self.format_seconds(s['elapsed'])
|
||||
msg_template = '%(_downloaded_bytes_str)s at %(_speed_str)s (%(_elapsed_str)s)'
|
||||
else:
|
||||
msg_template = '%(_downloaded_bytes_str)s at %(_speed_str)s'
|
||||
else:
|
||||
msg_template = '%(_percent_str)s % at %(_speed_str)s ETA %(_eta_str)s'
|
||||
|
||||
self._report_progress_status(msg_template % s)
|
||||
|
||||
def report_resuming_byte(self, resume_len):
|
||||
"""Report attempt to resume at given byte."""
|
||||
self.to_screen('[download] Resuming download at byte %s' % resume_len)
|
||||
|
||||
def report_retry(self, count, retries):
|
||||
"""Report retry in case of HTTP error 5xx"""
|
||||
self.to_screen('[download] Got server HTTP error. Retrying (attempt %d of %d)...' % (count, retries))
|
||||
|
||||
def report_file_already_downloaded(self, file_name):
|
||||
"""Report file has already been fully downloaded."""
|
||||
try:
|
||||
self.to_screen('[download] %s has already been downloaded' % file_name)
|
||||
except UnicodeEncodeError:
|
||||
self.to_screen('[download] The file has already been downloaded')
|
||||
|
||||
def report_unable_to_resume(self):
|
||||
"""Report it was impossible to resume download."""
|
||||
self.to_screen('[download] Unable to resume')
|
||||
|
||||
def download(self, filename, info_dict):
|
||||
"""Download to a filename using the info from info_dict
|
||||
Return True on success and False otherwise
|
||||
"""
|
||||
|
||||
nooverwrites_and_exists = (
|
||||
self.params.get('nooverwrites', False) and
|
||||
os.path.exists(encodeFilename(filename))
|
||||
)
|
||||
|
||||
continuedl_and_exists = (
|
||||
self.params.get('continuedl', True) and
|
||||
os.path.isfile(encodeFilename(filename)) and
|
||||
not self.params.get('nopart', False)
|
||||
)
|
||||
|
||||
# Check file already present
|
||||
if filename != '-' and (nooverwrites_and_exists or continuedl_and_exists):
|
||||
self.report_file_already_downloaded(filename)
|
||||
self._hook_progress({
|
||||
'filename': filename,
|
||||
'status': 'finished',
|
||||
'total_bytes': os.path.getsize(encodeFilename(filename)),
|
||||
})
|
||||
return True
|
||||
|
||||
sleep_interval = self.params.get('sleep_interval')
|
||||
if sleep_interval:
|
||||
self.to_screen('[download] Sleeping %s seconds...' % sleep_interval)
|
||||
time.sleep(sleep_interval)
|
||||
|
||||
return self.real_download(filename, info_dict)
|
||||
|
||||
def real_download(self, filename, info_dict):
|
||||
"""Real download process. Redefine in subclasses."""
|
||||
raise NotImplementedError('This method must be implemented by subclasses')
|
||||
|
||||
def _hook_progress(self, status):
|
||||
for ph in self._progress_hooks:
|
||||
ph(status)
|
||||
|
||||
def add_progress_hook(self, ph):
|
||||
# See YoutubeDl.py (search for progress_hooks) for a description of
|
||||
# this interface
|
||||
self._progress_hooks.append(ph)
|
||||
|
||||
def _debug_cmd(self, args, exe=None):
|
||||
if not self.params.get('verbose', False):
|
||||
return
|
||||
|
||||
str_args = [decodeArgument(a) for a in args]
|
||||
|
||||
if exe is None:
|
||||
exe = os.path.basename(str_args[0])
|
||||
|
||||
try:
|
||||
import pipes
|
||||
shell_quote = lambda args: ' '.join(map(pipes.quote, str_args))
|
||||
except ImportError:
|
||||
shell_quote = repr
|
||||
self.to_screen('[debug] %s command line: %s' % (
|
||||
exe, shell_quote(str_args)))
|
||||
66
youtube_dl/downloader/dash.py
Normal file
66
youtube_dl/downloader/dash.py
Normal file
@@ -0,0 +1,66 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import re
|
||||
|
||||
from .common import FileDownloader
|
||||
from ..utils import sanitized_Request
|
||||
|
||||
|
||||
class DashSegmentsFD(FileDownloader):
|
||||
"""
|
||||
Download segments in a DASH manifest
|
||||
"""
|
||||
def real_download(self, filename, info_dict):
|
||||
self.report_destination(filename)
|
||||
tmpfilename = self.temp_name(filename)
|
||||
base_url = info_dict['url']
|
||||
segment_urls = info_dict['segment_urls']
|
||||
|
||||
is_test = self.params.get('test', False)
|
||||
remaining_bytes = self._TEST_FILE_SIZE if is_test else None
|
||||
byte_counter = 0
|
||||
|
||||
def append_url_to_file(outf, target_url, target_name, remaining_bytes=None):
|
||||
self.to_screen('[DashSegments] %s: Downloading %s' % (info_dict['id'], target_name))
|
||||
req = sanitized_Request(target_url)
|
||||
if remaining_bytes is not None:
|
||||
req.add_header('Range', 'bytes=0-%d' % (remaining_bytes - 1))
|
||||
|
||||
data = self.ydl.urlopen(req).read()
|
||||
|
||||
if remaining_bytes is not None:
|
||||
data = data[:remaining_bytes]
|
||||
|
||||
outf.write(data)
|
||||
return len(data)
|
||||
|
||||
def combine_url(base_url, target_url):
|
||||
if re.match(r'^https?://', target_url):
|
||||
return target_url
|
||||
return '%s%s%s' % (base_url, '' if base_url.endswith('/') else '/', target_url)
|
||||
|
||||
with open(tmpfilename, 'wb') as outf:
|
||||
append_url_to_file(
|
||||
outf, combine_url(base_url, info_dict['initialization_url']),
|
||||
'initialization segment')
|
||||
for i, segment_url in enumerate(segment_urls):
|
||||
segment_len = append_url_to_file(
|
||||
outf, combine_url(base_url, segment_url),
|
||||
'segment %d / %d' % (i + 1, len(segment_urls)),
|
||||
remaining_bytes)
|
||||
byte_counter += segment_len
|
||||
if remaining_bytes is not None:
|
||||
remaining_bytes -= segment_len
|
||||
if remaining_bytes <= 0:
|
||||
break
|
||||
|
||||
self.try_rename(tmpfilename, filename)
|
||||
|
||||
self._hook_progress({
|
||||
'downloaded_bytes': byte_counter,
|
||||
'total_bytes': byte_counter,
|
||||
'filename': filename,
|
||||
'status': 'finished',
|
||||
})
|
||||
|
||||
return True
|
||||
155
youtube_dl/downloader/external.py
Normal file
155
youtube_dl/downloader/external.py
Normal file
@@ -0,0 +1,155 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os.path
|
||||
import subprocess
|
||||
|
||||
from .common import FileDownloader
|
||||
from ..utils import (
|
||||
cli_option,
|
||||
cli_valueless_option,
|
||||
cli_bool_option,
|
||||
cli_configuration_args,
|
||||
encodeFilename,
|
||||
encodeArgument,
|
||||
)
|
||||
|
||||
|
||||
class ExternalFD(FileDownloader):
|
||||
def real_download(self, filename, info_dict):
|
||||
self.report_destination(filename)
|
||||
tmpfilename = self.temp_name(filename)
|
||||
|
||||
retval = self._call_downloader(tmpfilename, info_dict)
|
||||
if retval == 0:
|
||||
fsize = os.path.getsize(encodeFilename(tmpfilename))
|
||||
self.to_screen('\r[%s] Downloaded %s bytes' % (self.get_basename(), fsize))
|
||||
self.try_rename(tmpfilename, filename)
|
||||
self._hook_progress({
|
||||
'downloaded_bytes': fsize,
|
||||
'total_bytes': fsize,
|
||||
'filename': filename,
|
||||
'status': 'finished',
|
||||
})
|
||||
return True
|
||||
else:
|
||||
self.to_stderr('\n')
|
||||
self.report_error('%s exited with code %d' % (
|
||||
self.get_basename(), retval))
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def get_basename(cls):
|
||||
return cls.__name__[:-2].lower()
|
||||
|
||||
@property
|
||||
def exe(self):
|
||||
return self.params.get('external_downloader')
|
||||
|
||||
@classmethod
|
||||
def supports(cls, info_dict):
|
||||
return info_dict['protocol'] in ('http', 'https', 'ftp', 'ftps')
|
||||
|
||||
def _option(self, command_option, param):
|
||||
return cli_option(self.params, command_option, param)
|
||||
|
||||
def _bool_option(self, command_option, param, true_value='true', false_value='false', separator=None):
|
||||
return cli_bool_option(self.params, command_option, param, true_value, false_value, separator)
|
||||
|
||||
def _valueless_option(self, command_option, param, expected_value=True):
|
||||
return cli_valueless_option(self.params, command_option, param, expected_value)
|
||||
|
||||
def _configuration_args(self, default=[]):
|
||||
return cli_configuration_args(self.params, 'external_downloader_args', default)
|
||||
|
||||
def _call_downloader(self, tmpfilename, info_dict):
|
||||
""" Either overwrite this or implement _make_cmd """
|
||||
cmd = [encodeArgument(a) for a in self._make_cmd(tmpfilename, info_dict)]
|
||||
|
||||
self._debug_cmd(cmd)
|
||||
|
||||
p = subprocess.Popen(
|
||||
cmd, stderr=subprocess.PIPE)
|
||||
_, stderr = p.communicate()
|
||||
if p.returncode != 0:
|
||||
self.to_stderr(stderr)
|
||||
return p.returncode
|
||||
|
||||
|
||||
class CurlFD(ExternalFD):
|
||||
def _make_cmd(self, tmpfilename, info_dict):
|
||||
cmd = [self.exe, '--location', '-o', tmpfilename]
|
||||
for key, val in info_dict['http_headers'].items():
|
||||
cmd += ['--header', '%s: %s' % (key, val)]
|
||||
cmd += self._option('--interface', 'source_address')
|
||||
cmd += self._option('--proxy', 'proxy')
|
||||
cmd += self._valueless_option('--insecure', 'nocheckcertificate')
|
||||
cmd += self._configuration_args()
|
||||
cmd += ['--', info_dict['url']]
|
||||
return cmd
|
||||
|
||||
|
||||
class AxelFD(ExternalFD):
|
||||
def _make_cmd(self, tmpfilename, info_dict):
|
||||
cmd = [self.exe, '-o', tmpfilename]
|
||||
for key, val in info_dict['http_headers'].items():
|
||||
cmd += ['-H', '%s: %s' % (key, val)]
|
||||
cmd += self._configuration_args()
|
||||
cmd += ['--', info_dict['url']]
|
||||
return cmd
|
||||
|
||||
|
||||
class WgetFD(ExternalFD):
|
||||
def _make_cmd(self, tmpfilename, info_dict):
|
||||
cmd = [self.exe, '-O', tmpfilename, '-nv', '--no-cookies']
|
||||
for key, val in info_dict['http_headers'].items():
|
||||
cmd += ['--header', '%s: %s' % (key, val)]
|
||||
cmd += self._option('--bind-address', 'source_address')
|
||||
cmd += self._option('--proxy', 'proxy')
|
||||
cmd += self._valueless_option('--no-check-certificate', 'nocheckcertificate')
|
||||
cmd += self._configuration_args()
|
||||
cmd += ['--', info_dict['url']]
|
||||
return cmd
|
||||
|
||||
|
||||
class Aria2cFD(ExternalFD):
|
||||
def _make_cmd(self, tmpfilename, info_dict):
|
||||
cmd = [self.exe, '-c']
|
||||
cmd += self._configuration_args([
|
||||
'--min-split-size', '1M', '--max-connection-per-server', '4'])
|
||||
dn = os.path.dirname(tmpfilename)
|
||||
if dn:
|
||||
cmd += ['--dir', dn]
|
||||
cmd += ['--out', os.path.basename(tmpfilename)]
|
||||
for key, val in info_dict['http_headers'].items():
|
||||
cmd += ['--header', '%s: %s' % (key, val)]
|
||||
cmd += self._option('--interface', 'source_address')
|
||||
cmd += self._option('--all-proxy', 'proxy')
|
||||
cmd += self._bool_option('--check-certificate', 'nocheckcertificate', 'false', 'true', '=')
|
||||
cmd += ['--', info_dict['url']]
|
||||
return cmd
|
||||
|
||||
|
||||
class HttpieFD(ExternalFD):
|
||||
def _make_cmd(self, tmpfilename, info_dict):
|
||||
cmd = ['http', '--download', '--output', tmpfilename, info_dict['url']]
|
||||
for key, val in info_dict['http_headers'].items():
|
||||
cmd += ['%s:%s' % (key, val)]
|
||||
return cmd
|
||||
|
||||
_BY_NAME = dict(
|
||||
(klass.get_basename(), klass)
|
||||
for name, klass in globals().items()
|
||||
if name.endswith('FD') and name != 'ExternalFD'
|
||||
)
|
||||
|
||||
|
||||
def list_external_downloaders():
|
||||
return sorted(_BY_NAME.keys())
|
||||
|
||||
|
||||
def get_external_downloader(external_downloader):
|
||||
""" Given the name of the executable, see whether we support the given
|
||||
downloader . """
|
||||
# Drop .exe extension on Windows
|
||||
bn = os.path.splitext(os.path.basename(external_downloader))[0]
|
||||
return _BY_NAME[bn]
|
||||
391
youtube_dl/downloader/f4m.py
Normal file
391
youtube_dl/downloader/f4m.py
Normal file
@@ -0,0 +1,391 @@
|
||||
from __future__ import division, unicode_literals
|
||||
|
||||
import base64
|
||||
import io
|
||||
import itertools
|
||||
import os
|
||||
import time
|
||||
|
||||
from .fragment import FragmentFD
|
||||
from ..compat import (
|
||||
compat_etree_fromstring,
|
||||
compat_urlparse,
|
||||
compat_urllib_error,
|
||||
compat_urllib_parse_urlparse,
|
||||
)
|
||||
from ..utils import (
|
||||
encodeFilename,
|
||||
sanitize_open,
|
||||
struct_pack,
|
||||
struct_unpack,
|
||||
xpath_text,
|
||||
)
|
||||
|
||||
|
||||
class FlvReader(io.BytesIO):
|
||||
"""
|
||||
Reader for Flv files
|
||||
The file format is documented in https://www.adobe.com/devnet/f4v.html
|
||||
"""
|
||||
|
||||
# Utility functions for reading numbers and strings
|
||||
def read_unsigned_long_long(self):
|
||||
return struct_unpack('!Q', self.read(8))[0]
|
||||
|
||||
def read_unsigned_int(self):
|
||||
return struct_unpack('!I', self.read(4))[0]
|
||||
|
||||
def read_unsigned_char(self):
|
||||
return struct_unpack('!B', self.read(1))[0]
|
||||
|
||||
def read_string(self):
|
||||
res = b''
|
||||
while True:
|
||||
char = self.read(1)
|
||||
if char == b'\x00':
|
||||
break
|
||||
res += char
|
||||
return res
|
||||
|
||||
def read_box_info(self):
|
||||
"""
|
||||
Read a box and return the info as a tuple: (box_size, box_type, box_data)
|
||||
"""
|
||||
real_size = size = self.read_unsigned_int()
|
||||
box_type = self.read(4)
|
||||
header_end = 8
|
||||
if size == 1:
|
||||
real_size = self.read_unsigned_long_long()
|
||||
header_end = 16
|
||||
return real_size, box_type, self.read(real_size - header_end)
|
||||
|
||||
def read_asrt(self):
|
||||
# version
|
||||
self.read_unsigned_char()
|
||||
# flags
|
||||
self.read(3)
|
||||
quality_entry_count = self.read_unsigned_char()
|
||||
# QualityEntryCount
|
||||
for i in range(quality_entry_count):
|
||||
self.read_string()
|
||||
|
||||
segment_run_count = self.read_unsigned_int()
|
||||
segments = []
|
||||
for i in range(segment_run_count):
|
||||
first_segment = self.read_unsigned_int()
|
||||
fragments_per_segment = self.read_unsigned_int()
|
||||
segments.append((first_segment, fragments_per_segment))
|
||||
|
||||
return {
|
||||
'segment_run': segments,
|
||||
}
|
||||
|
||||
def read_afrt(self):
|
||||
# version
|
||||
self.read_unsigned_char()
|
||||
# flags
|
||||
self.read(3)
|
||||
# time scale
|
||||
self.read_unsigned_int()
|
||||
|
||||
quality_entry_count = self.read_unsigned_char()
|
||||
# QualitySegmentUrlModifiers
|
||||
for i in range(quality_entry_count):
|
||||
self.read_string()
|
||||
|
||||
fragments_count = self.read_unsigned_int()
|
||||
fragments = []
|
||||
for i in range(fragments_count):
|
||||
first = self.read_unsigned_int()
|
||||
first_ts = self.read_unsigned_long_long()
|
||||
duration = self.read_unsigned_int()
|
||||
if duration == 0:
|
||||
discontinuity_indicator = self.read_unsigned_char()
|
||||
else:
|
||||
discontinuity_indicator = None
|
||||
fragments.append({
|
||||
'first': first,
|
||||
'ts': first_ts,
|
||||
'duration': duration,
|
||||
'discontinuity_indicator': discontinuity_indicator,
|
||||
})
|
||||
|
||||
return {
|
||||
'fragments': fragments,
|
||||
}
|
||||
|
||||
def read_abst(self):
|
||||
# version
|
||||
self.read_unsigned_char()
|
||||
# flags
|
||||
self.read(3)
|
||||
|
||||
self.read_unsigned_int() # BootstrapinfoVersion
|
||||
# Profile,Live,Update,Reserved
|
||||
flags = self.read_unsigned_char()
|
||||
live = flags & 0x20 != 0
|
||||
# time scale
|
||||
self.read_unsigned_int()
|
||||
# CurrentMediaTime
|
||||
self.read_unsigned_long_long()
|
||||
# SmpteTimeCodeOffset
|
||||
self.read_unsigned_long_long()
|
||||
|
||||
self.read_string() # MovieIdentifier
|
||||
server_count = self.read_unsigned_char()
|
||||
# ServerEntryTable
|
||||
for i in range(server_count):
|
||||
self.read_string()
|
||||
quality_count = self.read_unsigned_char()
|
||||
# QualityEntryTable
|
||||
for i in range(quality_count):
|
||||
self.read_string()
|
||||
# DrmData
|
||||
self.read_string()
|
||||
# MetaData
|
||||
self.read_string()
|
||||
|
||||
segments_count = self.read_unsigned_char()
|
||||
segments = []
|
||||
for i in range(segments_count):
|
||||
box_size, box_type, box_data = self.read_box_info()
|
||||
assert box_type == b'asrt'
|
||||
segment = FlvReader(box_data).read_asrt()
|
||||
segments.append(segment)
|
||||
fragments_run_count = self.read_unsigned_char()
|
||||
fragments = []
|
||||
for i in range(fragments_run_count):
|
||||
box_size, box_type, box_data = self.read_box_info()
|
||||
assert box_type == b'afrt'
|
||||
fragments.append(FlvReader(box_data).read_afrt())
|
||||
|
||||
return {
|
||||
'segments': segments,
|
||||
'fragments': fragments,
|
||||
'live': live,
|
||||
}
|
||||
|
||||
def read_bootstrap_info(self):
|
||||
total_size, box_type, box_data = self.read_box_info()
|
||||
assert box_type == b'abst'
|
||||
return FlvReader(box_data).read_abst()
|
||||
|
||||
|
||||
def read_bootstrap_info(bootstrap_bytes):
|
||||
return FlvReader(bootstrap_bytes).read_bootstrap_info()
|
||||
|
||||
|
||||
def build_fragments_list(boot_info):
|
||||
""" Return a list of (segment, fragment) for each fragment in the video """
|
||||
res = []
|
||||
segment_run_table = boot_info['segments'][0]
|
||||
fragment_run_entry_table = boot_info['fragments'][0]['fragments']
|
||||
first_frag_number = fragment_run_entry_table[0]['first']
|
||||
fragments_counter = itertools.count(first_frag_number)
|
||||
for segment, fragments_count in segment_run_table['segment_run']:
|
||||
for _ in range(fragments_count):
|
||||
res.append((segment, next(fragments_counter)))
|
||||
|
||||
if boot_info['live']:
|
||||
res = res[-2:]
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def write_unsigned_int(stream, val):
|
||||
stream.write(struct_pack('!I', val))
|
||||
|
||||
|
||||
def write_unsigned_int_24(stream, val):
|
||||
stream.write(struct_pack('!I', val)[1:])
|
||||
|
||||
|
||||
def write_flv_header(stream):
|
||||
"""Writes the FLV header to stream"""
|
||||
# FLV header
|
||||
stream.write(b'FLV\x01')
|
||||
stream.write(b'\x05')
|
||||
stream.write(b'\x00\x00\x00\x09')
|
||||
stream.write(b'\x00\x00\x00\x00')
|
||||
|
||||
|
||||
def write_metadata_tag(stream, metadata):
|
||||
"""Writes optional metadata tag to stream"""
|
||||
SCRIPT_TAG = b'\x12'
|
||||
FLV_TAG_HEADER_LEN = 11
|
||||
|
||||
if metadata:
|
||||
stream.write(SCRIPT_TAG)
|
||||
write_unsigned_int_24(stream, len(metadata))
|
||||
stream.write(b'\x00\x00\x00\x00\x00\x00\x00')
|
||||
stream.write(metadata)
|
||||
write_unsigned_int(stream, FLV_TAG_HEADER_LEN + len(metadata))
|
||||
|
||||
|
||||
def _add_ns(prop):
|
||||
return '{http://ns.adobe.com/f4m/1.0}%s' % prop
|
||||
|
||||
|
||||
class F4mFD(FragmentFD):
|
||||
"""
|
||||
A downloader for f4m manifests or AdobeHDS.
|
||||
"""
|
||||
|
||||
FD_NAME = 'f4m'
|
||||
|
||||
def _get_unencrypted_media(self, doc):
|
||||
media = doc.findall(_add_ns('media'))
|
||||
if not media:
|
||||
self.report_error('No media found')
|
||||
for e in (doc.findall(_add_ns('drmAdditionalHeader')) +
|
||||
doc.findall(_add_ns('drmAdditionalHeaderSet'))):
|
||||
# If id attribute is missing it's valid for all media nodes
|
||||
# without drmAdditionalHeaderId or drmAdditionalHeaderSetId attribute
|
||||
if 'id' not in e.attrib:
|
||||
self.report_error('Missing ID in f4m DRM')
|
||||
media = list(filter(lambda e: 'drmAdditionalHeaderId' not in e.attrib and
|
||||
'drmAdditionalHeaderSetId' not in e.attrib,
|
||||
media))
|
||||
if not media:
|
||||
self.report_error('Unsupported DRM')
|
||||
return media
|
||||
|
||||
def _get_bootstrap_from_url(self, bootstrap_url):
|
||||
bootstrap = self.ydl.urlopen(bootstrap_url).read()
|
||||
return read_bootstrap_info(bootstrap)
|
||||
|
||||
def _update_live_fragments(self, bootstrap_url, latest_fragment):
|
||||
fragments_list = []
|
||||
retries = 30
|
||||
while (not fragments_list) and (retries > 0):
|
||||
boot_info = self._get_bootstrap_from_url(bootstrap_url)
|
||||
fragments_list = build_fragments_list(boot_info)
|
||||
fragments_list = [f for f in fragments_list if f[1] > latest_fragment]
|
||||
if not fragments_list:
|
||||
# Retry after a while
|
||||
time.sleep(5.0)
|
||||
retries -= 1
|
||||
|
||||
if not fragments_list:
|
||||
self.report_error('Failed to update fragments')
|
||||
|
||||
return fragments_list
|
||||
|
||||
def _parse_bootstrap_node(self, node, base_url):
|
||||
if node.text is None:
|
||||
bootstrap_url = compat_urlparse.urljoin(
|
||||
base_url, node.attrib['url'])
|
||||
boot_info = self._get_bootstrap_from_url(bootstrap_url)
|
||||
else:
|
||||
bootstrap_url = None
|
||||
bootstrap = base64.b64decode(node.text.encode('ascii'))
|
||||
boot_info = read_bootstrap_info(bootstrap)
|
||||
return (boot_info, bootstrap_url)
|
||||
|
||||
def real_download(self, filename, info_dict):
|
||||
man_url = info_dict['url']
|
||||
requested_bitrate = info_dict.get('tbr')
|
||||
self.to_screen('[%s] Downloading f4m manifest' % self.FD_NAME)
|
||||
urlh = self.ydl.urlopen(man_url)
|
||||
man_url = urlh.geturl()
|
||||
manifest = urlh.read()
|
||||
|
||||
doc = compat_etree_fromstring(manifest)
|
||||
formats = [(int(f.attrib.get('bitrate', -1)), f)
|
||||
for f in self._get_unencrypted_media(doc)]
|
||||
if requested_bitrate is None:
|
||||
# get the best format
|
||||
formats = sorted(formats, key=lambda f: f[0])
|
||||
rate, media = formats[-1]
|
||||
else:
|
||||
rate, media = list(filter(
|
||||
lambda f: int(f[0]) == requested_bitrate, formats))[0]
|
||||
|
||||
base_url = compat_urlparse.urljoin(man_url, media.attrib['url'])
|
||||
bootstrap_node = doc.find(_add_ns('bootstrapInfo'))
|
||||
boot_info, bootstrap_url = self._parse_bootstrap_node(bootstrap_node, base_url)
|
||||
live = boot_info['live']
|
||||
metadata_node = media.find(_add_ns('metadata'))
|
||||
if metadata_node is not None:
|
||||
metadata = base64.b64decode(metadata_node.text.encode('ascii'))
|
||||
else:
|
||||
metadata = None
|
||||
|
||||
fragments_list = build_fragments_list(boot_info)
|
||||
if self.params.get('test', False):
|
||||
# We only download the first fragment
|
||||
fragments_list = fragments_list[:1]
|
||||
total_frags = len(fragments_list)
|
||||
# For some akamai manifests we'll need to add a query to the fragment url
|
||||
akamai_pv = xpath_text(doc, _add_ns('pv-2.0'))
|
||||
|
||||
ctx = {
|
||||
'filename': filename,
|
||||
'total_frags': total_frags,
|
||||
}
|
||||
|
||||
self._prepare_frag_download(ctx)
|
||||
|
||||
dest_stream = ctx['dest_stream']
|
||||
|
||||
write_flv_header(dest_stream)
|
||||
if not live:
|
||||
write_metadata_tag(dest_stream, metadata)
|
||||
|
||||
base_url_parsed = compat_urllib_parse_urlparse(base_url)
|
||||
|
||||
self._start_frag_download(ctx)
|
||||
|
||||
frags_filenames = []
|
||||
while fragments_list:
|
||||
seg_i, frag_i = fragments_list.pop(0)
|
||||
name = 'Seg%d-Frag%d' % (seg_i, frag_i)
|
||||
query = []
|
||||
if base_url_parsed.query:
|
||||
query.append(base_url_parsed.query)
|
||||
if akamai_pv:
|
||||
query.append(akamai_pv.strip(';'))
|
||||
if info_dict.get('extra_param_to_segment_url'):
|
||||
query.append(info_dict['extra_param_to_segment_url'])
|
||||
url_parsed = base_url_parsed._replace(path=base_url_parsed.path + name, query='&'.join(query))
|
||||
frag_filename = '%s-%s' % (ctx['tmpfilename'], name)
|
||||
try:
|
||||
success = ctx['dl'].download(frag_filename, {'url': url_parsed.geturl()})
|
||||
if not success:
|
||||
return False
|
||||
(down, frag_sanitized) = sanitize_open(frag_filename, 'rb')
|
||||
down_data = down.read()
|
||||
down.close()
|
||||
reader = FlvReader(down_data)
|
||||
while True:
|
||||
_, box_type, box_data = reader.read_box_info()
|
||||
if box_type == b'mdat':
|
||||
dest_stream.write(box_data)
|
||||
break
|
||||
if live:
|
||||
os.remove(encodeFilename(frag_sanitized))
|
||||
else:
|
||||
frags_filenames.append(frag_sanitized)
|
||||
except (compat_urllib_error.HTTPError, ) as err:
|
||||
if live and (err.code == 404 or err.code == 410):
|
||||
# We didn't keep up with the live window. Continue
|
||||
# with the next available fragment.
|
||||
msg = 'Fragment %d unavailable' % frag_i
|
||||
self.report_warning(msg)
|
||||
fragments_list = []
|
||||
else:
|
||||
raise
|
||||
|
||||
if not fragments_list and live and bootstrap_url:
|
||||
fragments_list = self._update_live_fragments(bootstrap_url, frag_i)
|
||||
total_frags += len(fragments_list)
|
||||
if fragments_list and (fragments_list[0][1] > frag_i + 1):
|
||||
msg = 'Missed %d fragments' % (fragments_list[0][1] - (frag_i + 1))
|
||||
self.report_warning(msg)
|
||||
|
||||
self._finish_frag_download(ctx)
|
||||
|
||||
for frag_file in frags_filenames:
|
||||
os.remove(encodeFilename(frag_file))
|
||||
|
||||
return True
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user