Compare commits
2720 Commits
Author | SHA1 | Date | |
---|---|---|---|
c3ae3f2895 | |||
8b41956091 | |||
![]() |
264e27ab3f | ||
74f6abc97a | |||
8edbfc5198 | |||
![]() |
8513d1f22b | ||
![]() |
cb75e3dc7e | ||
![]() |
a8926dae57 | ||
![]() |
c5502737f2 | ||
![]() |
206cea8b56 | ||
![]() |
003a8b07e1 | ||
![]() |
c5d69eb231 | ||
![]() |
78864ab380 | ||
ec22a6ec6b | |||
![]() |
b435857e15 | ||
8198419156 | |||
60718dbf72 | |||
![]() |
1fa00a5738 | ||
![]() |
d2b2600e5e | ||
![]() |
d062db3c17 | ||
![]() |
32a8bb7a3e | ||
![]() |
d8417cbf71 | ||
863a05b33d | |||
![]() |
3fc3abe7a5 | ||
96fcaf9385 | |||
0b14981163 | |||
87a56a6fac | |||
![]() |
0fa938e096 | ||
![]() |
b7e3a60fbc | ||
![]() |
653ccaae49 | ||
ca00b34314 | |||
0c5811801f | |||
d9727c901c | |||
63b8e7101f | |||
![]() |
4f5da775d4 | ||
![]() |
3464ad6e5e | ||
![]() |
d28480dd92 | ||
![]() |
4902b4ecba | ||
![]() |
0e0a38460e | ||
![]() |
4266a10ffb | ||
![]() |
31fc55eca7 | ||
![]() |
4d389f75a2 | ||
abe29e044f | |||
c5a6ed3179 | |||
99058ee135 | |||
b2e335fbba | |||
1d3bbfd250 | |||
916e328e10 | |||
fe02145fed | |||
![]() |
ad41b25be5 | ||
![]() |
d2b1103e26 | ||
![]() |
0b05cd761c | ||
![]() |
28ba7880e4 | ||
![]() |
4680fd118b | ||
![]() |
9dcfe98437 | ||
![]() |
55c264916b | ||
![]() |
0ec77f5514 | ||
![]() |
f238d0514f | ||
![]() |
d8613d2285 | ||
![]() |
1e83028702 | ||
![]() |
e974d3bc55 | ||
![]() |
7c96044d18 | ||
d5d70f1b40 | |||
![]() |
34e0b36401 | ||
![]() |
2fbe0e8bb1 | ||
![]() |
33ee8a38ca | ||
5f4562467e | |||
![]() |
56ef4cda82 | ||
![]() |
5975b69b42 | ||
![]() |
d0a3c7256a | ||
d94c14967c | |||
f15828fa95 | |||
f64eacefe3 | |||
c8f2effca8 | |||
![]() |
74f4859e13 | ||
![]() |
8c987fc0d2 | ||
![]() |
efc202d2ee | ||
![]() |
3cbca7c0ac | ||
![]() |
82e4244473 | ||
![]() |
836620c375 | ||
addfff8626 | |||
3836742e7d | |||
74fd171131 | |||
d511bf2cd8 | |||
0cbbedd250 | |||
![]() |
4824cae36c | ||
![]() |
b67359aca6 | ||
99179edae2 | |||
ae6dad6e48 | |||
6902a8392f | |||
4991c5a1ad | |||
![]() |
a3e3001d49 | ||
4fdf1c2411 | |||
ea00c0af50 | |||
e6dbd7ddda | |||
9741d127a9 | |||
8efc7e9369 | |||
da009f8d22 | |||
f8133b7abf | |||
![]() |
2362862f31 | ||
![]() |
f287ed48ed | ||
![]() |
b8a9caeb4c | ||
![]() |
dccd8445e6 | ||
![]() |
c5fb009c83 | ||
![]() |
4d8973b0a5 | ||
![]() |
f57d91ac16 | ||
![]() |
ccc5923ab3 | ||
![]() |
31debe6bbf | ||
![]() |
40d1507237 | ||
ea2be02a29 | |||
c21a6a54f8 | |||
70a2e330ef | |||
d5c70676b0 | |||
202c92a42d | |||
![]() |
3cb4d35cee | ||
![]() |
3d35984cf5 | ||
![]() |
2217d1ab95 | ||
![]() |
75ddc12390 | ||
d48fab9d98 | |||
d30aeb3902 | |||
d479c4ae7d | |||
9c220e08f8 | |||
eee38a626d | |||
f29a45a2c2 | |||
a5b68d4fb0 | |||
8a7d119962 | |||
84a0793a10 | |||
2f4eeda397 | |||
96ed7abdc5 | |||
![]() |
6a91918e6f | ||
![]() |
2c3edc0503 | ||
![]() |
f6bac8a08e | ||
4ce11a174a | |||
d92f5e6508 | |||
513821123e | |||
![]() |
f56c804e86 | ||
![]() |
fb50f7adb4 | ||
![]() |
a99bf60cea | ||
40d981df25 | |||
f5165cfae5 | |||
055bae0450 | |||
74e5ea6e20 | |||
32f3ca0568 | |||
fd3423fe09 | |||
05d299816b | |||
2b80d450fa | |||
![]() |
9a31115eff | ||
4baf3b6913 | |||
5e48331eae | |||
5766db2c09 | |||
c4f6f48eeb | |||
943e2d7fe7 | |||
c4fa8fabb2 | |||
6868047ee4 | |||
80e7ee46fb | |||
61ee957add | |||
![]() |
6e66d377f6 | ||
99e759a5be | |||
eafca84717 | |||
0e2fd0c6f5 | |||
0ccf65fcf8 | |||
af06fded73 | |||
0bfe8ff41d | |||
![]() |
804f0294bb | ||
![]() |
7a4430856d | ||
![]() |
6bd40e253a | ||
![]() |
c2d178efc3 | ||
97da508df5 | |||
![]() |
211128f128 | ||
2f69d16828 | |||
bb2363f68a | |||
![]() |
fc461931bd | ||
724f4f9b37 | |||
6f790d99c9 | |||
efb986ffd9 | |||
bd9ad9982b | |||
![]() |
e5a8a6aba4 | ||
![]() |
da835fbd6b | ||
1538e6ec4e | |||
95e0c37222 | |||
95870df45b | |||
8b2889e317 | |||
0fc452b683 | |||
6e19854e4c | |||
6331cb2374 | |||
983537b0fd | |||
58fd2dddf8 | |||
49b2fbd2b0 | |||
68814e31e7 | |||
429739837b | |||
fef1440865 | |||
afd29715fa | |||
e329742c8d | |||
5695d0e94a | |||
5a964dacbb | |||
fea3bb63c1 | |||
![]() |
580c940d42 | ||
![]() |
7ea8cd4a09 | ||
4f936f958d | |||
![]() |
a6ca962fcb | ||
0b4401e64b | |||
2b50c5aaf4 | |||
da4ea77c2a | |||
af4786ce0e | |||
f9b8f0528d | |||
b9d717b9f9 | |||
cbc9165afd | |||
a9e18620b9 | |||
613dd77d2c | |||
9b6d5daeef | |||
![]() |
b816ecc7e3 | ||
d01aae7860 | |||
50cb427377 | |||
977cdee046 | |||
4db4010abf | |||
ba37839adf | |||
c9196fda03 | |||
b03b4745db | |||
8df2a2d00a | |||
184220f4c5 | |||
5d6d27907d | |||
5e5dc35a1e | |||
24b7b6fabd | |||
c5ab6b9993 | |||
05740f7903 | |||
fc7f995bd2 | |||
d99a39e5d5 | |||
0b897fdc98 | |||
a475a912e6 | |||
8f17b73091 | |||
![]() |
cb56b76ef9 | ||
d198ae9ef1 | |||
![]() |
eff238e85c | ||
![]() |
a436e60fb8 | ||
![]() |
2c570f8d4e | ||
![]() |
6f23bdd331 | ||
![]() |
b797f9e26d | ||
![]() |
2b13973eca | ||
![]() |
9331b229fe | ||
![]() |
ccd0795a4e | ||
![]() |
1f98493dbd | ||
![]() |
f20d906b67 | ||
65757dee1c | |||
b259a3ac3d | |||
ca1f816ad9 | |||
6f509967bf | |||
56574c41be | |||
3cdfc2d33a | |||
1b154551a2 | |||
c419016a12 | |||
f10478ceef | |||
d477773054 | |||
8ed280ebf4 | |||
762e96b8a6 | |||
23c77fbe4b | |||
e99dd72cb6 | |||
b095b7e769 | |||
6b97e1bfaf | |||
3ceb83d40e | |||
d80340f0ae | |||
3acc2fb160 | |||
034db1a282 | |||
b07b9bf0b9 | |||
97460e7d99 | |||
ddc750469c | |||
0448537509 | |||
583463ab42 | |||
b20e298f6e | |||
090d59fcb7 | |||
1d174d6797 | |||
15a47b5612 | |||
4d1ea6e4cd | |||
13ef00cb2e | |||
d2c1641569 | |||
a1873e74e5 | |||
![]() |
8be86fe80c | ||
4dc90ef5da | |||
e130264254 | |||
93039a6813 | |||
07b3c8a7b4 | |||
83fe635438 | |||
3ee96fb663 | |||
6684ba1b1d | |||
466778875d | |||
a71e8fae00 | |||
f58bf3028a | |||
595556c39f | |||
eeaa4fbbb4 | |||
49b11e1f84 | |||
e3133d88d7 | |||
1a50b6243d | |||
076558d4f5 | |||
fb5d0cd760 | |||
7c8ba61f03 | |||
20e463e41b | |||
5d3984e353 | |||
941aea80bb | |||
0533aa7f6f | |||
568e2d5063 | |||
86c7aa8b8a | |||
f61e7a193f | |||
![]() |
567dae8ced | ||
![]() |
02f483a873 | ||
7051e1c5f6 | |||
87295b4bfd | |||
23ca6b4fac | |||
9e3559625c | |||
351d582c8f | |||
5b1ea6187f | |||
211782fae4 | |||
20279d1597 | |||
![]() |
44466aa769 | ||
![]() |
d27d014eb0 | ||
e884ca54ef | |||
336420cf50 | |||
f16e83f21b | |||
0eedc3aa19 | |||
f232775161 | |||
bd57463d42 | |||
2c4910e9e7 | |||
2b14d32bea | |||
![]() |
ee66747def | ||
259c28f8c1 | |||
b6a5360390 | |||
0b7b947786 | |||
147e257cee | |||
ccb8483766 | |||
68ccb3a944 | |||
b317eca5e3 | |||
5ffacccdd7 | |||
a41936af94 | |||
![]() |
0991adc291 | ||
b9aceb895d | |||
8633ef9513 | |||
![]() |
7820cef60a | ||
4666454482 | |||
db42d9ec37 | |||
d7b48a2256 | |||
50ec279917 | |||
e8a8f3c210 | |||
e0fc642fc3 | |||
835ed6d9bb | |||
3781928693 | |||
![]() |
cb39006f6c | ||
![]() |
52447096f2 | ||
2f98d05e7c | |||
74e753934c | |||
9bc54f27cf | |||
d9e6c06b22 | |||
e02d82981a | |||
98da06cd83 | |||
0d62266008 | |||
1ae0c2e312 | |||
61629080b2 | |||
4cf104720c | |||
2c866e205b | |||
ca91ad3188 | |||
33de6beab3 | |||
871f046755 | |||
aef021dcd1 | |||
489f43529c | |||
78203aac9a | |||
3c95f0b66b | |||
3347788712 | |||
0c5b4c05c6 | |||
![]() |
5056706742 | ||
b8949eafe2 | |||
9286d6a7b8 | |||
9fd2f1e6a7 | |||
b98474880d | |||
5347d296dc | |||
666a387d1b | |||
bb66e16b69 | |||
2cddf1405f | |||
8575437626 | |||
c965a3dca0 | |||
c48aca8d5c | |||
4360284355 | |||
f44eeaf7dd | |||
a0418bec59 | |||
5eff26e40e | |||
4e78517651 | |||
10d9eb70c8 | |||
![]() |
0ba3aad666 | ||
8bfbe855a1 | |||
3fbf60ee21 | |||
6bfd916fef | |||
a5e4b15349 | |||
94f370e76c | |||
7cc353ab04 | |||
506626d6b1 | |||
26898f38ad | |||
4fdff1bf13 | |||
![]() |
7d4a6e74d2 | ||
![]() |
b33a01cf26 | ||
0689b03603 | |||
ee8cd29da9 | |||
c4a3159b33 | |||
![]() |
a4511ca2ab | ||
17b4ab6151 | |||
d2a7af2884 | |||
d05f1ca2c8 | |||
832d66bfb9 | |||
c8a46dac5d | |||
7005376061 | |||
ab213f45e2 | |||
fa504ae8a3 | |||
d305eb6a9c | |||
f8bc6f8612 | |||
9099937119 | |||
b827468e2f | |||
587795552e | |||
![]() |
0a1ff9b6bd | ||
b01cf32321 | |||
9ba6c293ed | |||
99681e1d1e | |||
![]() |
96775acf5a | ||
![]() |
ba992067ad | ||
2552d99308 | |||
e99e25b3b9 | |||
70820d7be6 | |||
38fda46d44 | |||
9d383d6aef | |||
ba0408a741 | |||
07c21c3bfd | |||
5ffefd2a19 | |||
e3e15850bb | |||
54b367b153 | |||
b61127270e | |||
1d41c2fd19 | |||
7c7e131dc0 | |||
85fbbf8980 | |||
612fab1b2a | |||
fbd8c69eea | |||
8fcac04aad | |||
7d902cca1e | |||
![]() |
ddc1d7c6bc | ||
![]() |
5bb90c6185 | ||
9452547204 | |||
34c09583b4 | |||
38b0927d01 | |||
715bde5ecf | |||
6c2eb317fe | |||
05516f3260 | |||
![]() |
264df83943 | ||
3a546612d9 | |||
3cac01ff27 | |||
![]() |
e01521618f | ||
ee63f3b86d | |||
a900511d5e | |||
3fe092d788 | |||
e2fe5004e7 | |||
442af031eb | |||
e22882bd02 | |||
523d39b3bb | |||
65efefb094 | |||
44edf70842 | |||
16a46b3211 | |||
e9cc85141c | |||
cfcafd2ba3 | |||
e67dd15308 | |||
a76f840ff8 | |||
269a36c549 | |||
![]() |
36bf248385 | ||
![]() |
046135f8e3 | ||
![]() |
97e469da7b | ||
01beb015dc | |||
50d5692884 | |||
![]() |
0ea6513e9c | ||
e2b683556b | |||
14587ebb59 | |||
be3cf44608 | |||
1538cd84a9 | |||
![]() |
f5b808b997 | ||
f92d8aed3d | |||
f6c769187e | |||
c70e3727be | |||
a6a0228ef8 | |||
![]() |
d2a5595df2 | ||
![]() |
e9c07a123a | ||
![]() |
1e8e2a197b | ||
39d9d3f5b6 | |||
8bada7f882 | |||
![]() |
a940062255 | ||
![]() |
93efd31a5b | ||
![]() |
2e9fdc6d9f | ||
b9f5f230a2 | |||
0a751a303f | |||
b2da629034 | |||
37a542c009 | |||
0451ee7f08 | |||
d8dd76c6e0 | |||
9cee0ee504 | |||
![]() |
b464ef0ac3 | ||
![]() |
7f09206a47 | ||
![]() |
65573eafac | ||
![]() |
58a545d30c | ||
![]() |
dfb0b7801d | ||
![]() |
aab2c0601d | ||
![]() |
a21175d903 | ||
![]() |
9c7f4cc604 | ||
![]() |
3017e4f51a | ||
![]() |
5355e5bbfd | ||
![]() |
5ed1ec681f | ||
![]() |
0a4031cd7b | ||
![]() |
31ea4a7093 | ||
![]() |
0ca2d33ee1 | ||
![]() |
48bcd3a8c2 | ||
1ab8200c7f | |||
91e61dbd5c | |||
fb4ef57148 | |||
ced0129e03 | |||
![]() |
740b6501cd | ||
![]() |
07e18c07ac | ||
67f16b0de4 | |||
fd3d92d3b2 | |||
5ba5d537b5 | |||
4efa87d6bf | |||
![]() |
442897ba5b | ||
![]() |
2b79da5c35 | ||
![]() |
cc3a8e5d62 | ||
280a708afe | |||
![]() |
f5a348a863 | ||
![]() |
85a4e9cb5c | ||
4715dbdbd0 | |||
afad77af19 | |||
94d51bd56f | |||
72ed1bc1ac | |||
4a1b83961d | |||
b4a50ed03a | |||
00f9fea98c | |||
501651125f | |||
18e8d35910 | |||
9e4d231285 | |||
2972e79f9e | |||
4d32eaa036 | |||
e4f141b94c | |||
ccf36abd30 | |||
![]() |
d147db3382 | ||
![]() |
9d29dc6b68 | ||
![]() |
6562b33bbc | ||
![]() |
f58f297cdb | ||
![]() |
376b991b63 | ||
![]() |
120d31244e | ||
![]() |
679549cbf2 | ||
![]() |
a623d924fa | ||
![]() |
95fb141ad9 | ||
![]() |
fad6f54794 | ||
![]() |
e1525d98cd | ||
![]() |
3d69d2bf63 | ||
![]() |
cb2dd03e77 | ||
![]() |
3253f82900 | ||
33a00efd82 | |||
8bcbf24713 | |||
![]() |
52ba727664 | ||
![]() |
a1cfacd8da | ||
![]() |
5b6e7ba91d | ||
77a19a0b17 | |||
7ecb90640c | |||
![]() |
691ce6fec7 | ||
![]() |
618f214a4f | ||
![]() |
48df91f796 | ||
![]() |
d27d0bd2e4 | ||
![]() |
39d954d56a | ||
![]() |
78b1922dd7 | ||
![]() |
639253e9bb | ||
![]() |
f8fe2a295f | ||
![]() |
9d2831f520 | ||
![]() |
c2438a7508 | ||
4298958952 | |||
54a80d6bdc | |||
aba655a9c7 | |||
![]() |
b6eef94383 | ||
![]() |
7526db9e6c | ||
![]() |
c853337d41 | ||
![]() |
00dd72e284 | ||
![]() |
05850371a6 | ||
![]() |
c285cb84bd | ||
![]() |
a4a0e1def3 | ||
![]() |
fea7a42ece | ||
![]() |
72f74b7f6e | ||
![]() |
a92456e144 | ||
![]() |
7f7a82802d | ||
![]() |
93097ab630 | ||
![]() |
d3d22a8f4b | ||
![]() |
7a1b082216 | ||
![]() |
0e907c5ad0 | ||
![]() |
59b8dc4f41 | ||
![]() |
299109433c | ||
9823d761d9 | |||
![]() |
db6b8d3b6b | ||
![]() |
c61a18545e | ||
c1181f855a | |||
e2aa2affd7 | |||
![]() |
7f18d25d0d | ||
![]() |
314817242b | ||
![]() |
945a0f30aa | ||
![]() |
a7c8a7201a | ||
![]() |
6be94658a7 | ||
![]() |
490dcc5020 | ||
![]() |
8e6bade42b | ||
![]() |
c145e4267c | ||
![]() |
a4064190dd | ||
![]() |
f97213630c | ||
![]() |
6a21e22bf1 | ||
77f8729257 | |||
39d4e1be72 | |||
ebe55aba61 | |||
![]() |
3c4f1b7814 | ||
![]() |
ce024ff006 | ||
![]() |
e603b120c3 | ||
![]() |
b17af505c2 | ||
![]() |
5d5a3b80e5 | ||
![]() |
c8a73b63fd | ||
![]() |
ce7a46bbed | ||
![]() |
eee67f09e1 | ||
![]() |
ab7246565c | ||
![]() |
096d067d6c | ||
![]() |
9d2709be19 | ||
![]() |
3cce978e26 | ||
![]() |
8f30a74c7d | ||
![]() |
a86a2ba04a | ||
![]() |
f4ffb30153 | ||
![]() |
ecdaa6f2b3 | ||
![]() |
2b8b406f9d | ||
![]() |
212a794c65 | ||
![]() |
0e2dede168 | ||
![]() |
c1f3fa6004 | ||
![]() |
e2be19039f | ||
846f6f2190 | |||
37716f34de | |||
![]() |
f01ccf9797 | ||
![]() |
074baa63f5 | ||
![]() |
763eb08dad | ||
![]() |
1d40a88166 | ||
![]() |
5766b36b33 | ||
![]() |
4cea0b6099 | ||
![]() |
43fd5caf30 | ||
![]() |
5c1a1b13f4 | ||
![]() |
109e1a75bf | ||
![]() |
99f8384129 | ||
![]() |
f3cb399605 | ||
![]() |
c94ce79e68 | ||
![]() |
744930a090 | ||
![]() |
be7aa991d7 | ||
![]() |
c815bc2996 | ||
![]() |
924520955e | ||
![]() |
0bff0a4998 | ||
![]() |
691c003e95 | ||
![]() |
a28dab9bdc | ||
![]() |
c33c0259a7 | ||
![]() |
77d40f8d31 | ||
![]() |
619b766c85 | ||
![]() |
693ffed9be | ||
![]() |
c175d5470f | ||
![]() |
42e6d06559 | ||
![]() |
25da127d02 | ||
![]() |
00b88675ea | ||
![]() |
c552db59e4 | ||
![]() |
763116fb24 | ||
![]() |
f3531f1c2c | ||
![]() |
a2a67d82ab | ||
69cdcc8226 | |||
![]() |
5e11e51f6a | ||
![]() |
a419347eba | ||
![]() |
ab42e47385 | ||
![]() |
50cfd52c23 | ||
![]() |
e0ff0c63c8 | ||
![]() |
a123def967 | ||
![]() |
8360a2f4e7 | ||
![]() |
f13a1b2aed | ||
![]() |
cec5838649 | ||
![]() |
2c0de05e9d | ||
![]() |
f782afef8d | ||
![]() |
a45688867d | ||
![]() |
6104cfa56a | ||
![]() |
6869ed937b | ||
![]() |
945cc55b54 | ||
![]() |
7e7cabfdc2 | ||
![]() |
cbd61e2fce | ||
![]() |
ffdac3ce2c | ||
![]() |
eaa64cb02f | ||
![]() |
b36a418dff | ||
![]() |
46ca3ab51d | ||
![]() |
0deaab7c1a | ||
![]() |
c6d45b22b6 | ||
![]() |
69bcc9d012 | ||
![]() |
182409ce3a | ||
![]() |
c45dc0c838 | ||
![]() |
7d175678ab | ||
![]() |
dd86515d2e | ||
![]() |
b1a4b8bfed | ||
![]() |
ac9bdab78e | ||
![]() |
177b6e2d48 | ||
![]() |
b48014f8e6 | ||
![]() |
f1881352c8 | ||
![]() |
d6572fd027 | ||
![]() |
7e5edc2f6e | ||
![]() |
709c75c517 | ||
![]() |
ebc4d53fa9 | ||
![]() |
dbd95c5c64 | ||
![]() |
42565f19fc | ||
![]() |
8d9909acfb | ||
![]() |
9c7f9a935b | ||
![]() |
c9fc3f11a6 | ||
![]() |
75046d11fb | ||
![]() |
bb39d9ddcf | ||
![]() |
fb629404c6 | ||
![]() |
78691ba344 | ||
![]() |
f41fde8471 | ||
![]() |
319d217dc1 | ||
![]() |
ec80501977 | ||
![]() |
4a0319389b | ||
![]() |
ebcc304642 | ||
![]() |
c695a51883 | ||
![]() |
3cc447c5f2 | ||
![]() |
52742ceeca | ||
![]() |
08d86019e4 | ||
![]() |
582a62d75b | ||
![]() |
8ebadf5236 | ||
![]() |
814f5ca194 | ||
![]() |
3da63182cd | ||
![]() |
029a903d79 | ||
e2588a5379 | |||
0d8bcd5dad | |||
63f22a54e1 | |||
ab18550711 | |||
4092f61898 | |||
ebb6609a2b | |||
![]() |
820345f84d | ||
5a1d52d82c | |||
![]() |
9adb97d300 | ||
![]() |
eae4d704a1 | ||
![]() |
84cc6711b4 | ||
![]() |
5be02b1592 | ||
![]() |
255894e241 | ||
6c8c87b2dd | |||
dba3fee477 | |||
50fba8fc8d | |||
5eab417134 | |||
ff0bfb9f12 | |||
1671e3b126 | |||
fe53501990 | |||
e497859587 | |||
97b05b1dbf | |||
![]() |
588799a2ff | ||
d5a1e0b1c6 | |||
5883b7344e | |||
8522779df1 | |||
![]() |
7976ba1dff | ||
![]() |
e88ca3048c | ||
![]() |
8412bafc5c | ||
2a8adcb89a | |||
829e3f47ff | |||
4e4634496a | |||
d148efd458 | |||
f7656b0401 | |||
6635448bda | |||
baa89c5bbf | |||
![]() |
ab1144865f | ||
![]() |
4348ff2689 | ||
![]() |
33c4b321db | ||
39d9a25e19 | |||
b5dad73f6f | |||
![]() |
99eb49e347 | ||
![]() |
11f111790e | ||
f8e470c7f4 | |||
d8a2e39006 | |||
c6d1c552f8 | |||
e383477b01 | |||
129b16d93d | |||
48f29ff1b8 | |||
e62b76d2cc | |||
d368937bce | |||
4b3ccabb44 | |||
4dcfe3e434 | |||
273d7399a0 | |||
5ce0479268 | |||
de3ce6cdb7 | |||
3e192cc57e | |||
6c5902837c | |||
e522ffad4e | |||
64221fb3fb | |||
c73044b6b4 | |||
ad1b356879 | |||
07caf2e316 | |||
c2137a2a80 | |||
44da37f009 | |||
d0b967388a | |||
41096c7f23 | |||
![]() |
4f6fb6993d | ||
![]() |
fa3e3e0764 | ||
fe2b97c941 | |||
6e52ae307c | |||
6e077ee621 | |||
30e2f73d5f | |||
7469e9c63d | |||
![]() |
296ddbe930 | ||
![]() |
e20f2d0bf6 | ||
![]() |
cc61f4eb61 | ||
![]() |
0a61b8052c | ||
![]() |
cbcbfea6e8 | ||
![]() |
57abfe7653 | ||
e0313814b8 | |||
59df524a91 | |||
b304393bc3 | |||
![]() |
f6304ccd4d | ||
![]() |
9d241cc0d4 | ||
![]() |
a46ca210f5 | ||
![]() |
328857f97f | ||
![]() |
b00fbfa23d | ||
![]() |
3a75f8d7d1 | ||
![]() |
84344b6789 | ||
![]() |
b75d28fd0d | ||
![]() |
a8424e59b0 | ||
![]() |
420bf851b5 | ||
![]() |
83c8233812 | ||
![]() |
52a3860717 | ||
![]() |
531c6c0f4c | ||
![]() |
5699b4515b | ||
6a1b90f8f8 | |||
![]() |
ceedc9c645 | ||
3f40487c99 | |||
a6f7761544 | |||
e1c9cd6cdc | |||
d5cb443925 | |||
![]() |
9333cd56f9 | ||
![]() |
910001e3a1 | ||
121491a3be | |||
152b2152cb | |||
![]() |
0abbe45a6d | ||
![]() |
403d6a322a | ||
![]() |
4ec20ef796 | ||
![]() |
3b7eaa107e | ||
![]() |
8375e9129d | ||
![]() |
53fbece6b5 | ||
![]() |
69d909d3eb | ||
4346c90aa2 | |||
f8c185d09f | |||
558bb2f4f3 | |||
7b07eb89a3 | |||
bec33cad87 | |||
eb6217add9 | |||
7d94f9fb19 | |||
324e9c960d | |||
96575e61f2 | |||
8d57cba762 | |||
e1823ece68 | |||
![]() |
b23414eab1 | ||
38a4f05000 | |||
041c87a2c9 | |||
![]() |
ef06fc758c | ||
![]() |
9f1c95c829 | ||
f14ff31a20 | |||
ddc329e8f1 | |||
8453c34bfc | |||
c6fcdf967c | |||
1427c502c0 | |||
4e84370128 | |||
5314d886be | |||
829af21c49 | |||
![]() |
c9406b8f96 | ||
![]() |
af398632f3 | ||
![]() |
e574b5e61a | ||
![]() |
d946fda859 | ||
![]() |
df3771e791 | ||
df00725077 | |||
26846d592c | |||
21466e017f | |||
b033db969c | |||
d18e4d430c | |||
14ac5ac03e | |||
![]() |
464279ca1c | ||
![]() |
6014de9cd5 | ||
![]() |
e7c3e07626 | ||
![]() |
c4057bb5a0 | ||
![]() |
34f0420753 | ||
![]() |
10bd1343c3 | ||
4979f8dace | |||
b2846de94f | |||
501f2f85d5 | |||
580bb5a6fe | |||
e27df771aa | |||
0f321f1597 | |||
10872f751e | |||
20567ae75e | |||
f06d99480d | |||
c2e39687e6 | |||
6972d9d02b | |||
d8b3d2c508 | |||
1da1dce981 | |||
c4f9485e13 | |||
9cff4d5a42 | |||
6ca4b519bf | |||
3685bf04d0 | |||
fc5e30e6ae | |||
047c668ee1 | |||
e55a1f608a | |||
![]() |
cbbf82a4ae | ||
![]() |
81d9e2f164 | ||
![]() |
8397296286 | ||
![]() |
06d0412558 | ||
![]() |
ffde067c5e | ||
c4a05ec49e | |||
ed92411df2 | |||
7a690b245f | |||
![]() |
7af65f4346 | ||
![]() |
c89e127d8a | ||
![]() |
104bfa8784 | ||
![]() |
3013b56d16 | ||
![]() |
188316132e | ||
![]() |
53c7f7d602 | ||
![]() |
3ccc102412 | ||
![]() |
e99749097a | ||
9d1995125a | |||
![]() |
b18f654e37 | ||
![]() |
a70d9394da | ||
![]() |
6eff7be49a | ||
01efcd3156 | |||
112b88a7f9 | |||
![]() |
c61b73c281 | ||
79a7c14fdf | |||
![]() |
e4513d18b9 | ||
![]() |
7870ededcb | ||
![]() |
195a4e971d | ||
![]() |
aa02358b1b | ||
![]() |
18fe05b9ef | ||
![]() |
5b5b3b203c | ||
![]() |
49cee5bf58 | ||
![]() |
ac1b51c9ac | ||
![]() |
746b91f257 | ||
![]() |
77d970fd5a | ||
![]() |
678c87d0f4 | ||
![]() |
f352a38836 | ||
![]() |
d402f0c93d | ||
![]() |
7093a57a03 | ||
![]() |
6a9432d62e | ||
![]() |
7440e64eb6 | ||
97436e8357 | |||
![]() |
f9ff90eb72 | ||
![]() |
6acece85a2 | ||
2d24f01831 | |||
f2b228561f | |||
ce9cae4ff8 | |||
c3a387d646 | |||
b24085bbe5 | |||
![]() |
41419738c5 | ||
![]() |
dd65f174ef | ||
![]() |
d888d4834d | ||
![]() |
ce8cd91d72 | ||
![]() |
0cefaba925 | ||
565807126c | |||
bed548d5af | |||
fbd230f21e | |||
dc402acd4a | |||
e3dab56e79 | |||
d3578e2a2e | |||
7a6e7baf18 | |||
![]() |
97f23286d3 | ||
11ff89fef2 | |||
764a7f2e13 | |||
1db58dee89 | |||
f13956d380 | |||
522ae4eb41 | |||
3e889d2747 | |||
ed13424913 | |||
bdfca07626 | |||
![]() |
ba3bc9e2ed | ||
![]() |
f164951848 | ||
![]() |
bfaf72a547 | ||
008c79e743 | |||
0d565818d4 | |||
c1a7f90860 | |||
c2e36453b8 | |||
675e8a91a4 | |||
cae94320b5 | |||
bafef846d9 | |||
db42a46c71 | |||
adcd1e8d9a | |||
ca57b71266 | |||
e3da181cea | |||
3da6ccfbbe | |||
444ba47463 | |||
![]() |
377aa9bca1 | ||
![]() |
4ffbfce51e | ||
![]() |
d1ed30e79c | ||
8ca5591933 | |||
7d9db79619 | |||
508533b83e | |||
0a521b7456 | |||
0c348ec17e | |||
df8bab6b72 | |||
f6fb4b4be3 | |||
0f74ccd446 | |||
02bde80725 | |||
e2a39a3eb5 | |||
3a2fe5e860 | |||
fb8244ee1a | |||
045627a583 | |||
e7898b5b8f | |||
080f435708 | |||
f2a3d597dd | |||
74743357d0 | |||
1de88909e9 | |||
f7dc55f087 | |||
![]() |
67da35ab35 | ||
![]() |
136d77a8aa | ||
![]() |
bf0b59b3b3 | ||
![]() |
f19bc6a4b0 | ||
![]() |
79ab065500 | ||
![]() |
9d07bc241c | ||
![]() |
d9ba62aa2c | ||
![]() |
1f407bc34f | ||
1aa6367517 | |||
2436d86000 | |||
17f9280b3f | |||
326b9998fd | |||
3b64ce7408 | |||
7c88180b83 | |||
![]() |
7d0741bd7e | ||
![]() |
65612a1c86 | ||
![]() |
a408a43d96 | ||
![]() |
bc0a38b405 | ||
![]() |
913994f312 | ||
![]() |
0fabbc9039 | ||
![]() |
92c3d33ce5 | ||
d29da5597f | |||
2415091a2f | |||
![]() |
05537ba1b2 | ||
703f28e87d | |||
![]() |
f91f83faef | ||
![]() |
d598396bb2 | ||
fdb1f9dd39 | |||
9e3b49d67f | |||
f6bda355b9 | |||
a34b674f7d | |||
307826c4d3 | |||
9faba9fd30 | |||
87c04bf00b | |||
7bd83f83ed | |||
528ef4dd1a | |||
5ab17da73d | |||
![]() |
0c55af2622 | ||
e331800898 | |||
![]() |
e4257f28c9 | ||
97f402be0b | |||
1e978ea435 | |||
629c7862ca | |||
7006ffb75d | |||
b42993b495 | |||
![]() |
a9935cb609 | ||
![]() |
05be39d286 | ||
![]() |
0c77f7a82d | ||
![]() |
18f113d8e7 | ||
175e464c17 | |||
0cea3e03ae | |||
de2b204646 | |||
e1c3979af7 | |||
46438b7412 | |||
![]() |
6a103a1492 | ||
![]() |
a24937b7fd | ||
d7c1e9724b | |||
![]() |
224405d737 | ||
6c2d4ded1c | |||
ee22244b53 | |||
![]() |
5376858175 | ||
![]() |
910f60031a | ||
3240dacfe8 | |||
76c0f56be8 | |||
d85ae48f4e | |||
e99b2064e7 | |||
57f4ede102 | |||
0c55de7fcc | |||
![]() |
af1a49e5f4 | ||
![]() |
28e3ab9132 | ||
60f35bdd5d | |||
44db814ded | |||
349a01265f | |||
a0a9c23bcd | |||
2b81cee653 | |||
140ffc5c5e | |||
8cd9fb80ba | |||
21ce36db9c | |||
f010b27b14 | |||
b0a682f606 | |||
e2acc9fdd2 | |||
0e8d3d1862 | |||
a0f714097a | |||
15e182809d | |||
![]() |
7673d2ba04 | ||
![]() |
7a765757dd | ||
![]() |
2db086ee32 | ||
![]() |
366d79ddad | ||
![]() |
2bff0d6bcc | ||
![]() |
1aa24a38a4 | ||
f62c3047b5 | |||
0cdff150f5 | |||
75eda7e1b1 | |||
f22ac28e4d | |||
33964fac45 | |||
![]() |
5e5e4f6f2c | ||
![]() |
4a74bd0fe7 | ||
e7bcff5e71 | |||
cadedeb06c | |||
5af6c97bee | |||
cf41068fef | |||
![]() |
81bd0fcbf4 | ||
![]() |
b6f7321497 | ||
538427c269 | |||
f61183d2d8 | |||
48551f0617 | |||
6f682c1e71 | |||
f747febd0a | |||
1f9ab5d880 | |||
f43b0be5b8 | |||
bb46535e71 | |||
2bc70b53c1 | |||
![]() |
786a261a70 | ||
![]() |
a226d25dc6 | ||
ede1b1954c | |||
17f7264863 | |||
d6d8c0d119 | |||
4f6ed70044 | |||
cf5d7d2f08 | |||
d0dca206f7 | |||
![]() |
382dd3405a | ||
![]() |
a655a7848b | ||
![]() |
9ac0a91f17 | ||
![]() |
49d7dace3b | ||
bda3fbbe63 | |||
![]() |
e2e578a66d | ||
ef1447a816 | |||
![]() |
d436c846ac | ||
![]() |
24268c5130 | ||
6ebd1f121a | |||
394943c36f | |||
6ee9b79e45 | |||
da482c373e | |||
![]() |
22900a0d91 | ||
![]() |
e7922c4ded | ||
![]() |
f19ef3e486 | ||
![]() |
5b6a23b13a | ||
![]() |
ce1e055848 | ||
![]() |
f72e16f571 | ||
fc3343270a | |||
e1c9402d3f | |||
![]() |
4148aa54f3 | ||
![]() |
204440b06b | ||
![]() |
6a26c0b621 | ||
![]() |
c955adf7f6 | ||
![]() |
c68d53faf3 | ||
![]() |
ceda7c9ca0 | ||
54f0cae2ff | |||
eeb9ee0852 | |||
87da4b78ab | |||
141ad67650 | |||
a288fc52e0 | |||
7e8de0602b | |||
![]() |
45b0df7a1b | ||
![]() |
8a4bbe157e | ||
![]() |
5d8a718018 | ||
667bd46643 | |||
b29a9f43ce | |||
51c73fa853 | |||
![]() |
849c407712 | ||
b8a1ab0138 | |||
939329a96c | |||
409bc7fd94 | |||
ad8ce95545 | |||
3131e65b66 | |||
![]() |
a314b2acc7 | ||
![]() |
a2217b2b36 | ||
![]() |
a15e4c6c28 | ||
![]() |
e407c046d9 | ||
13731e7b35 | |||
3fbd8b8d14 | |||
3876f74f6c | |||
b47aa34d6a | |||
295242316b | |||
274e37b284 | |||
1997be371c | |||
c957577e72 | |||
cf463100cd | |||
![]() |
c7d473a7eb | ||
ab1ee37077 | |||
85a61e6166 | |||
![]() |
8e275e926f | ||
![]() |
051bc9c468 | ||
![]() |
aaf425be9b | ||
![]() |
01c5a05c86 | ||
![]() |
6a034b9613 | ||
![]() |
3e8b7a7f24 | ||
![]() |
af02a2f7f6 | ||
![]() |
8df576b39d | ||
![]() |
0cdc69bcb3 | ||
![]() |
4e1239ab5e | ||
![]() |
d1a03f500f | ||
![]() |
8a32aad6c3 | ||
![]() |
a3597e45fa | ||
![]() |
7d0d7e0278 | ||
![]() |
8846691c47 | ||
![]() |
0f72dfea0f | ||
![]() |
77bb9f144f | ||
![]() |
ef9fe8d197 | ||
![]() |
56e00199aa | ||
![]() |
3a4447cd08 | ||
![]() |
c7b7f4744c | ||
29c85254e7 | |||
4cea4514a0 | |||
![]() |
2f685d53a7 | ||
b23f0ee5a9 | |||
![]() |
0932f77fac | ||
![]() |
05860a5b5c | ||
![]() |
317aade5e0 | ||
![]() |
4ccb06f289 | ||
45ba9e1bd4 | |||
6107e38e56 | |||
3af2577c11 | |||
d93805eb96 | |||
4bd869f5fa | |||
2c8f426e30 | |||
37bb7ac8ca | |||
c0e0994bb3 | |||
![]() |
8a33ee2078 | ||
![]() |
81d9ed1766 | ||
![]() |
7461d8c1f1 | ||
![]() |
8cbf94f9eb | ||
![]() |
9141aa1d25 | ||
![]() |
8ef9009e48 | ||
![]() |
973dbe6fb2 | ||
![]() |
7c70378396 | ||
![]() |
27e14e7f36 | ||
![]() |
30bdf871aa | ||
![]() |
5a0190ddcc | ||
![]() |
98e7a6d2b3 | ||
![]() |
3af2f29739 | ||
![]() |
f7207689d5 | ||
![]() |
1a01f59d53 | ||
![]() |
7dd03fda8d | ||
![]() |
c62254da1e | ||
![]() |
621f132069 | ||
![]() |
467d21257a | ||
482a63c996 | |||
252f9ccee2 | |||
0f356892ba | |||
fae3492dd2 | |||
![]() |
f6babeecd2 | ||
![]() |
d9f3e9e2e7 | ||
![]() |
ed357b1a3e | ||
![]() |
ee8901cf02 | ||
![]() |
d10825d4a9 | ||
b54c9fd2c1 | |||
65504e8660 | |||
c902d4c219 | |||
![]() |
39953b6925 | ||
![]() |
c81c4cb873 | ||
![]() |
4be3f16805 | ||
![]() |
c9f1f69c16 | ||
b3f3a60ca6 | |||
fc18b44a56 | |||
d3cb42d441 | |||
4120fc6f0b | |||
adba42d114 | |||
![]() |
9a5ea68682 | ||
![]() |
6d0514b451 | ||
![]() |
ac493d7bcb | ||
![]() |
9e446f9ae8 | ||
![]() |
e1b53a63f4 | ||
![]() |
776a8c5a63 | ||
f7dee01609 | |||
6e44710b94 | |||
0d494c50af | |||
00b8e14adf | |||
61290dfbcf | |||
fbca6ac1fd | |||
abe83bc5bd | |||
fb8deb327d | |||
![]() |
e43182b842 | ||
![]() |
12ee1a70b2 | ||
![]() |
c9a453309f | ||
0a4d6c0bd8 | |||
a617dc3e2b | |||
63d2e19769 | |||
97e5bc87ef | |||
0aa9e39ee3 | |||
061f96ad89 | |||
![]() |
d4804c2b70 | ||
![]() |
745e2952ff | ||
![]() |
9a5430beeb | ||
![]() |
1486d83ec5 | ||
221499c1a8 | |||
c3bf470a80 | |||
04544ac9e0 | |||
669bcbd191 | |||
9252d6f9ca | |||
![]() |
3793e2c4ec | ||
![]() |
a092054417 | ||
![]() |
e0b70375a6 | ||
![]() |
77c2173421 | ||
![]() |
17e8cf777f | ||
![]() |
eda2ac510a | ||
256b05531e | |||
b003ee8748 | |||
![]() |
5d46e922ed | ||
![]() |
c31cb0c057 | ||
![]() |
b234ce3f51 | ||
![]() |
0e5fc8eb11 | ||
![]() |
7ee40e58c4 | ||
ba01451038 | |||
5b285db165 | |||
0da70caf7f | |||
a4a1ed4357 | |||
6e5d53dbde | |||
95329803a9 | |||
![]() |
e183966482 | ||
![]() |
9755338f73 | ||
![]() |
dafd722f20 | ||
![]() |
38dba5d19a | ||
![]() |
bafdaebc42 | ||
![]() |
fc292cd29d | ||
![]() |
553201db21 | ||
![]() |
452096b976 | ||
![]() |
1e8c968bd6 | ||
![]() |
b1878d6026 | ||
47876d6131 | |||
6198739f7a | |||
23de1e6db8 | |||
1591ddca2f | |||
![]() |
0a5e08382f | ||
83480e456a | |||
da2cd92884 | |||
0cee758dc3 | |||
fc6f4ecc74 | |||
![]() |
2253ad13cc | ||
9acabfb20f | |||
3d2d60469e | |||
b5d77685b9 | |||
557cb30feb | |||
59ba19b965 | |||
7213ff0c76 | |||
404578515b | |||
![]() |
9e068b3926 | ||
fd6fcda781 | |||
23ca49ea8e | |||
7df881442a | |||
eb2830b8f3 | |||
c54b3a08b8 | |||
7874488a61 | |||
07957409cb | |||
fc07065413 | |||
![]() |
50f270fd76 | ||
ba5be7449b | |||
edf5ef588d | |||
405c24b0e3 | |||
1b85c22ffc | |||
8e20e7a5b5 | |||
3024b3fd3b | |||
51f7f3a378 | |||
4ad6d699e7 | |||
c6e6a9d36e | |||
ad4d73ea0d | |||
352c6ba4ba | |||
ce27d69e39 | |||
![]() |
5fd6698d05 | ||
![]() |
0f62383aec | ||
![]() |
b09071f20f | ||
![]() |
f5b6d56489 | ||
![]() |
527c4b58c1 | ||
![]() |
430ac8323f | ||
![]() |
8c70af56ad | ||
7feaadbd7d | |||
69bbb88407 | |||
59bd51a419 | |||
b34ae8f051 | |||
5a4f2069f0 | |||
f6ca6a5e0d | |||
![]() |
56a67729e3 | ||
![]() |
0c81d519b7 | ||
![]() |
5067499fa1 | ||
![]() |
c155c4b601 | ||
cc16834455 | |||
708e943c44 | |||
43ec87e412 | |||
a14643f710 | |||
a2d6dd2c5b | |||
![]() |
7d6ab5ca41 | ||
![]() |
a9e03504de | ||
![]() |
3b59af11f6 | ||
![]() |
3a2286f874 | ||
![]() |
ab0e8d94a2 | ||
![]() |
be7770e679 | ||
![]() |
60c5f06689 | ||
![]() |
b391ed15ed | ||
88cf742895 | |||
f0eb5663f7 | |||
d8e297dde7 | |||
f956539b4b | |||
![]() |
0ad4789ff2 | ||
![]() |
dd9cae57a8 | ||
![]() |
84e4558d7d | ||
![]() |
2dcc75ad2a | ||
![]() |
6409f07c9b | ||
33b25b5780 | |||
![]() |
b38f6606c1 | ||
![]() |
0a239e1d4a | ||
![]() |
30e298d98b | ||
![]() |
3729aa31fd | ||
![]() |
3f4d154414 | ||
![]() |
4c76a93adb | ||
![]() |
ce0e0b2004 | ||
fa0b7d9acc | |||
c82dbd82b1 | |||
b5f97d0883 | |||
![]() |
b3e162e706 | ||
![]() |
f6d821c932 | ||
![]() |
45fb0ad9f3 | ||
beb6d1f43f | |||
c0662bc111 | |||
327f38b535 | |||
87008f3fe3 | |||
4d1736eaf6 | |||
03e86fcb24 | |||
5346dc1a98 | |||
be7623a462 | |||
f92edb44ba | |||
![]() |
2250ce642a | ||
![]() |
f4b52b7ccd | ||
![]() |
59f80086db | ||
![]() |
8e7bd9280d | ||
![]() |
daca27ea45 | ||
![]() |
7b49493924 | ||
![]() |
848f30955d | ||
![]() |
07162b56c8 | ||
![]() |
d9e4c4d7f4 | ||
ec7ec564be | |||
0fb9096096 | |||
bb7a88ffc9 | |||
5a4becba68 | |||
8fa720539a | |||
2083d8c6a6 | |||
36cb07b0cc | |||
ebad5ad61c | |||
8ea587accb | |||
d976b59732 | |||
41ea29209f | |||
bbcd6243e7 | |||
95eabfaaf8 | |||
fbbab0d819 | |||
56901e5ff7 | |||
04cbcf2759 | |||
99ad70e80a | |||
92b9d0a996 | |||
![]() |
0874b3e461 | ||
![]() |
ac8d65ad78 | ||
![]() |
bd14dc3112 | ||
![]() |
cefe20f11d | ||
78229227d2 | |||
61810b7215 | |||
fb4d85ff8b | |||
937d2c54c8 | |||
![]() |
5b37df5bc9 | ||
![]() |
add3bcedf6 | ||
![]() |
7284af9329 | ||
![]() |
959932b827 | ||
![]() |
f9b2100d75 | ||
![]() |
a2454e8e7d | ||
4322cb3ee5 | |||
![]() |
a7311a5752 | ||
b18e7c7839 | |||
18b8ddc419 | |||
48841481f0 | |||
bf45e31c62 | |||
1488cd0f48 | |||
![]() |
5b05d86ec6 | ||
![]() |
212981dfee | ||
![]() |
7864404a8c | ||
51e4003089 | |||
6da32a1ccb | |||
eb32e2e23e | |||
![]() |
5673a6554b | ||
![]() |
fe5c34ebae | ||
![]() |
6ce5e8bd03 | ||
27f05879b1 | |||
60297f56d7 | |||
c92c664d3d | |||
24c1473b1d | |||
9e88fdeec9 | |||
69e5760b37 | |||
5a715f385a | |||
f9818a2b1d | |||
900defcd42 | |||
15cbb6bb71 | |||
a0c6287d2c | |||
14f61bbbb3 | |||
cd30545c08 | |||
![]() |
00c0171d31 | ||
![]() |
1e5afa8568 | ||
e117e3310c | |||
8448001a17 | |||
032b7d8230 | |||
![]() |
6caa1c3e81 | ||
b47deadc97 | |||
60e25b98b7 | |||
474909ae66 | |||
caada2bfa0 | |||
ec460794eb | |||
![]() |
929d471aa8 | ||
![]() |
6c4dbc545d | ||
![]() |
f8a3afd672 | ||
![]() |
5f81e923ca | ||
![]() |
d9f5a8621d | ||
![]() |
27d9616126 | ||
![]() |
50e3cdba05 | ||
![]() |
6fa01a3b2d | ||
![]() |
fc7d8f72b0 | ||
![]() |
03ff4dc0fd | ||
![]() |
1d842f024a | ||
1c4b0335a5 | |||
50606a6828 | |||
25b0603fde | |||
937ae8ad60 | |||
6d4a9abd35 | |||
533f7620ad | |||
49d88f0060 | |||
1c4d1e9a62 | |||
51f20c2c33 | |||
258effcc84 | |||
3bd641abd0 | |||
be1d95e991 | |||
bd82a0c435 | |||
0f384c86fe | |||
5362e7cf15 | |||
4c2c198c0a | |||
51899e9ea0 | |||
3fc312a66b | |||
e9d0d79809 | |||
69cae1a052 | |||
cc71e3a5ca | |||
c5f98a04fa | |||
489a0ead14 | |||
88e7d60e3e | |||
0d145fc77f | |||
b2e4ab4a30 | |||
c9cccd7581 | |||
![]() |
58f562d1bd | ||
0a76a0db22 | |||
080cc962fb | |||
b3fcdb8e46 | |||
f6cff78528 | |||
5fd20fc77c | |||
9ae07688a5 | |||
9a2a51518a | |||
c0b9fe0340 | |||
d3564dfcb5 | |||
8480788856 | |||
6bcf40b41a | |||
6b811b36b9 | |||
8619fd2c05 | |||
d9dcb1e583 | |||
bf461ee77e | |||
![]() |
2537f48d08 | ||
1339209fa9 | |||
8744c83ff6 | |||
09731ffd3a | |||
6d5678c14e | |||
e4004e6f83 | |||
17773a2de9 | |||
![]() |
97ead4cdd6 | ||
![]() |
18c850c085 | ||
![]() |
6b49c03eb8 | ||
![]() |
95dd34f009 | ||
f630d2dd27 | |||
f69f06b038 | |||
5a934050d4 | |||
df8cd90b85 | |||
![]() |
85d7cfb9e0 | ||
![]() |
f97779bed7 | ||
![]() |
f4f5873692 | ||
f3e2dfacdf | |||
9d0bafb8fa | |||
1119612684 | |||
dc6c568e9f | |||
bef8fe0c8c | |||
3e97958100 | |||
cac1ad35bf | |||
579af7e3ad | |||
e4ee5e3016 | |||
caaa8dacad | |||
ff499844a2 | |||
97fe1baf6a | |||
7aff01ea84 | |||
7f467dbdc8 | |||
0675c4caeb | |||
66f25e845a | |||
fcbee9d9c5 | |||
624badfb5f | |||
![]() |
4677b27e49 | ||
f9c3d58b47 | |||
5b5c39bf45 | |||
37e3e9e2cf | |||
af42b9e9a8 | |||
3fbe8e70e6 | |||
6a234759d5 | |||
85a8b587cd | |||
![]() |
6849427b4f | ||
![]() |
bb1b9d63df | ||
![]() |
5efd19e4e0 | ||
![]() |
c0a63bcd76 | ||
![]() |
6fc0e0fe22 | ||
![]() |
ef3f184233 | ||
20733d3bd2 | |||
530b481ffd | |||
8ecf423dfc | |||
![]() |
67cc3ad5b0 | ||
![]() |
e6dcd3a892 | ||
![]() |
e257cc8b05 | ||
![]() |
26d3646630 | ||
![]() |
668df37d20 | ||
![]() |
9e6885d9b3 | ||
2a57c24e9d | |||
e53290db18 | |||
96d5d75d56 | |||
![]() |
32a4ccc575 | ||
![]() |
1c0554ab6e | ||
![]() |
347c579da5 | ||
![]() |
835db4341f | ||
bf0947ee82 | |||
a3a1110b41 | |||
fc074234af | |||
1e8e067a80 | |||
fd25ead0bd | |||
6892469e0e | |||
8f31713f6a | |||
a9698dd89e | |||
223de5606e | |||
e4b5b97268 | |||
669b26a171 | |||
e3723d7c9f | |||
33d566be36 | |||
e8fe115ffe | |||
d7a5e3ef53 | |||
042da4d921 | |||
05522addba | |||
f4fa5d115a | |||
b7ba422983 | |||
7f1c5b2e1a | |||
157a78857d | |||
ef93532c96 | |||
fe6fd13a6a | |||
05cd98f9b4 | |||
1a2bd800d9 | |||
661604dd4e | |||
1fc6d0ad54 | |||
1a6e9257f3 | |||
1cd0177f87 | |||
c90097eca7 | |||
![]() |
a01c11ca1a | ||
![]() |
a57b57f306 | ||
![]() |
10e412d494 | ||
![]() |
6a798fb7b5 | ||
![]() |
23ad969332 | ||
b475e31f70 | |||
![]() |
fda3ef2cfc | ||
892ef4abe1 | |||
81093d1342 | |||
abd823ab95 | |||
3bc284b522 | |||
5f7c971345 | |||
46a1506c51 | |||
0202faf7f9 | |||
bff518a038 | |||
0b293c517f | |||
afd9c2b2c0 | |||
331da7f4fe | |||
![]() |
25a257b6f1 | ||
82ac0db333 | |||
3dbefa8d01 | |||
e8712a3a11 | |||
104594ed59 | |||
a6ce41fac5 | |||
a97834d2b7 | |||
![]() |
485a3ee11a | ||
![]() |
b835dbcf4c | ||
![]() |
6a13d22556 | ||
![]() |
a296dedebe | ||
![]() |
161e7ca8b2 | ||
90a70eb245 | |||
0898b8ee66 | |||
ab4de7b392 | |||
f39e201067 | |||
![]() |
c884cfe6f6 | ||
![]() |
02219f7376 | ||
834054958c | |||
![]() |
66ba367530 | ||
![]() |
7652c19699 | ||
![]() |
39b741fae1 | ||
![]() |
9493bedb0a | ||
![]() |
1647da0abd | ||
![]() |
921591e61f | ||
![]() |
dec5af96b4 | ||
39ba081384 | |||
![]() |
c270e147c1 | ||
![]() |
98bfadb763 | ||
![]() |
bae011da1d | ||
![]() |
6d621d5eb9 | ||
fa1c18ce2d | |||
![]() |
f779993008 | ||
73c195eb63 | |||
7748147630 | |||
e193d8964f | |||
de71286f3c | |||
0f094da348 | |||
0c3f84c2da | |||
2332ac2a69 | |||
a670100ba3 | |||
979825b07f | |||
![]() |
648ea64b21 | ||
![]() |
4fdb9084a6 | ||
![]() |
9fbc7aef25 | ||
![]() |
3dd79269bc | ||
![]() |
d3999991d0 | ||
![]() |
00b9864dbf | ||
![]() |
c76b098fbb | ||
![]() |
863fb08fa1 | ||
![]() |
f1ae06ab40 | ||
14c305a494 | |||
4c9023f7cb | |||
![]() |
4244b048f8 | ||
![]() |
6a15d8c790 | ||
7afa63ce10 | |||
66391da1f7 | |||
![]() |
a8746e4780 | ||
af81681beb | |||
![]() |
2926b1734c | ||
![]() |
5d43282188 | ||
![]() |
b96ee4efa2 | ||
![]() |
6b0fe83989 | ||
![]() |
1c5a9ed042 | ||
efaafea78e | |||
273e940fa1 | |||
7bac7aaaf3 | |||
9f430bf117 | |||
c7f5178b9c | |||
![]() |
cb3a8b6eac | ||
![]() |
0406b52c9b | ||
![]() |
b62b668d1a | ||
![]() |
40d3aa9d4c | ||
![]() |
b0ce258925 | ||
![]() |
57b30df4eb | ||
![]() |
78a8952f55 | ||
![]() |
c1558b206f | ||
![]() |
f9b9877491 | ||
bbd34be212 | |||
cc7a8028d1 | |||
ce5acb490a | |||
4822e47156 | |||
a2c867c224 | |||
fd1c8c45a8 | |||
![]() |
05a92cd8e6 | ||
![]() |
1fe8dbb00e | ||
![]() |
24fdc4d75e | ||
![]() |
17b19c9724 | ||
![]() |
6e236f753d | ||
![]() |
a45c3336a3 | ||
![]() |
57523f11c1 | ||
![]() |
597fc5504d | ||
3df7ef0366 | |||
6e5c9a3a8e | |||
3d91fac2fd | |||
aec3976896 | |||
8a78de2b8c | |||
a139d915bd | |||
![]() |
450a5e14ab | ||
e6d44a6199 | |||
6630c29071 | |||
![]() |
8ee6503e54 | ||
f186076fb0 | |||
49eeed6ac8 | |||
35e89b76ca | |||
23e262b0b9 | |||
47d2b80aa5 | |||
![]() |
8aaf9a1c5e | ||
![]() |
6760d2a5f4 | ||
![]() |
d71b71f2b1 | ||
![]() |
04785e25b9 | ||
![]() |
2e1692cf09 | ||
![]() |
e92c23c949 | ||
![]() |
f2fe5140e1 | ||
![]() |
2261039a76 | ||
![]() |
2461b9525c | ||
![]() |
7f6c4faeb5 | ||
![]() |
a48ed65b36 | ||
![]() |
03c24ef14e | ||
![]() |
93d3710f51 | ||
![]() |
c7385e5e6a | ||
![]() |
b1d7df8a8c | ||
![]() |
ff601f9ccc | ||
![]() |
2fc0160c40 | ||
![]() |
398d264319 | ||
![]() |
7ce82617dc | ||
![]() |
4e52b9c8d7 | ||
dc04414e9a | |||
a7f8560acf | |||
217cb1f66d | |||
1d17981325 | |||
ba9754ac59 | |||
9a45ba1873 | |||
46481fb733 | |||
87439e19ca | |||
bd06a44706 | |||
c54dd79b3a | |||
e249b22312 | |||
![]() |
667b6b69b6 | ||
![]() |
2fa63f8b30 | ||
![]() |
22cb45ac40 | ||
![]() |
8ddc34da45 | ||
![]() |
667e4345a0 | ||
![]() |
98c44f1bbd | ||
![]() |
b0718f6b55 | ||
![]() |
57afc4cd5d | ||
![]() |
3a8a8c4256 | ||
![]() |
3fe50e1d47 | ||
![]() |
c8395df513 | ||
![]() |
2307fed62c | ||
![]() |
fd2c83f052 | ||
0018ac040a | |||
61831b11dc | |||
540172117f | |||
16640722d6 | |||
e0c8eb7640 | |||
![]() |
435bc826d3 | ||
![]() |
d084d18cfa | ||
![]() |
690f62b3ba | ||
3aa7f19530 | |||
0a83510690 | |||
f3521228e9 | |||
ab38e35bcd | |||
b64eff9bbb | |||
4b989eb092 | |||
8dc1c4fcf4 | |||
8233c4f9e4 | |||
e71d2012ca | |||
![]() |
b062d3b3dd | ||
![]() |
4062782015 | ||
![]() |
0cc490d286 | ||
![]() |
72abe9da13 | ||
1e5fe1f60b | |||
29ef11619a | |||
640782ae00 | |||
3882e49231 | |||
b64cb14456 | |||
d3950bdcf1 | |||
73901f6e2e | |||
70d9415ba2 | |||
d9b37ac6f0 | |||
![]() |
dc2198d3f6 | ||
fdc3af97aa | |||
5030a86311 | |||
3d5beece87 | |||
![]() |
19905e99be | ||
![]() |
f79138b356 | ||
![]() |
a40a2df971 | ||
![]() |
ebf0128185 | ||
7a135b9fa4 | |||
![]() |
331fb2781b | ||
![]() |
0c319aa184 | ||
2c502c5e27 | |||
63958df99b | |||
42fc22eec9 | |||
b39ba06d92 | |||
![]() |
baa92b4ed5 | ||
![]() |
070d3ee653 | ||
6364f142ff | |||
7b974e7e0b | |||
![]() |
454c7f14a0 | ||
3d3352438b | |||
b2263efaf0 | |||
![]() |
5f7983ca17 | ||
f4e64d9df7 | |||
30702e9b23 | |||
1bd71abf66 | |||
d7a4e0357a | |||
cdb6313c33 | |||
b3711e31ad | |||
aff250ff13 | |||
a69267dc87 | |||
![]() |
c9687649a4 | ||
![]() |
9e6f993af5 | ||
b328b47bf4 | |||
bd7e655788 | |||
a928f5ef1f | |||
d73eb16aeb | |||
a6728a33da | |||
20855c9c44 | |||
92ffea2237 | |||
81240a5240 | |||
f8df357134 | |||
5b11418209 | |||
8b05b16c8a | |||
d4bf3403e1 | |||
0c661b373e | |||
c8a9d8ef35 | |||
e768b35848 | |||
5e507c0294 | |||
948de5462f | |||
![]() |
035829f33d | ||
![]() |
115f3e1fb0 | ||
![]() |
6a73dffdab | ||
100f6dac3d | |||
![]() |
c671148025 | ||
![]() |
c243f21bff | ||
![]() |
4892764832 | ||
![]() |
b9dc7ec12e | ||
![]() |
ab58875b13 | ||
c67404e74e | |||
5f6efbf6d0 | |||
![]() |
f674b78edb | ||
bb5f3a92b0 | |||
546b668502 | |||
f6d2ac7fb2 | |||
f22865acb1 | |||
f99f9e41e5 | |||
3849a96ed2 | |||
69701ab506 | |||
![]() |
2654ada226 | ||
![]() |
e728532958 | ||
![]() |
2aee4376cb | ||
010399d865 | |||
![]() |
73aade4fb3 | ||
20c77e1529 | |||
5fd7997661 | |||
363a3e57ff | |||
![]() |
5283b8d127 | ||
![]() |
13545fdd70 | ||
4c988f0767 | |||
![]() |
dc3f540a64 | ||
6d064270fc | |||
d20ac3994d | |||
![]() |
c90ac9ee6c | ||
![]() |
67d608a1fb | ||
ed7fd9783e | |||
994aa72d71 | |||
![]() |
28ed69e575 | ||
b874ff7e87 | |||
![]() |
9c0c73358d | ||
![]() |
2159862d1a | ||
c5e74fefe5 | |||
26c744ca45 | |||
10f3337906 | |||
de094433da | |||
![]() |
0dee248f8a | ||
![]() |
674c202e88 | ||
![]() |
c7b567891c | ||
![]() |
2f5020e29c | ||
![]() |
3f979b159d | ||
![]() |
a9f943154c | ||
![]() |
b3cfe65325 | ||
![]() |
77e1bf61ca | ||
![]() |
746d440ce0 | ||
aeccbc975f | |||
1bf651b88b | |||
![]() |
b25a16f171 | ||
421559c26e | |||
336e50e94a | |||
f7c31950b3 | |||
dc02f9cd88 | |||
![]() |
095f018fbb | ||
![]() |
9c7533bb5d | ||
![]() |
a29fd1e90c | ||
![]() |
7343e0ff00 | ||
![]() |
915755b349 | ||
![]() |
255ccdcbc1 | ||
![]() |
2973b4097d | ||
![]() |
9abf7d6aef | ||
![]() |
2e6912ed43 | ||
![]() |
93d41be5ef | ||
![]() |
f428a372cc | ||
![]() |
d3861b9917 | ||
![]() |
2fc09679ab | ||
![]() |
2679aefb4e | ||
![]() |
453b8a962d | ||
![]() |
ecd629f97d | ||
ee82a6196d | |||
43afe7b1a8 | |||
29ce3c7c8b | |||
1bf86aff0b | |||
![]() |
c502c21798 | ||
![]() |
3a70a5a627 | ||
![]() |
3eafe4c765 | ||
![]() |
9d3acf98ff | ||
![]() |
18ee23960c | ||
![]() |
3d64df57a1 | ||
71804173fc | |||
dcc1861399 | |||
e7f449472c | |||
b37813257a | |||
59e1fbd0d1 | |||
0d212f6478 | |||
3a1cd51bc7 | |||
![]() |
18db940d59 | ||
![]() |
543e0b0d65 | ||
38281ba61f | |||
a98d521006 | |||
b0c2012327 | |||
1061e86fad | |||
164b0e5463 | |||
02bc228d6f | |||
a61f113cd1 | |||
afb6436109 | |||
22dd5b8adc | |||
![]() |
fc353ee0bd | ||
734444e183 | |||
89d32e3bef | |||
ec061eb3e0 | |||
702da0a929 | |||
49bba109ac | |||
ddec4f88fb | |||
3466dc1099 | |||
![]() |
bf8f1508cd | ||
![]() |
0235c5ef40 | ||
![]() |
661325af5a | ||
![]() |
c716071e9c | ||
![]() |
370be48226 | ||
395173613f | |||
046175d866 | |||
![]() |
a731c890c2 | ||
66b19326d5 | |||
![]() |
23c30a99cb | ||
![]() |
f4ce899810 | ||
164f6603fd | |||
![]() |
88b86333f4 | ||
![]() |
2669ae0995 | ||
![]() |
7c4f088b3e | ||
![]() |
a67adba710 | ||
![]() |
73f9b72d63 | ||
![]() |
6e98cf4fe0 | ||
![]() |
085ca76bcc | ||
![]() |
150270b14f | ||
![]() |
9a6888d7f9 | ||
![]() |
6c182ba4bb | ||
![]() |
42cffea077 | ||
3834403c79 | |||
d397eaaa08 | |||
56d8b72b07 | |||
c78719bfe4 | |||
91f2206a4f | |||
6d6799b99e | |||
3f8df84a4a | |||
127aebeadc | |||
![]() |
dbaa659912 | ||
8034dc3ca7 | |||
0a8abad72e | |||
a8378d0411 | |||
7fbb3b12d1 | |||
1ced604354 | |||
8a9882c906 | |||
f87e3b52e3 | |||
c826f7fb48 | |||
59424a899f | |||
a4ec6a5369 | |||
7ba6f5a755 | |||
7fa874f625 | |||
55bfd6aa2d | |||
![]() |
41021e1abb | ||
65656b333a | |||
0bf0715adc | |||
857f0a0448 | |||
79ac955b33 | |||
252f1047e5 | |||
9f433b2e6b | |||
dfbf01dad5 | |||
688634695d | |||
3380ecfa28 | |||
![]() |
48896568ce | ||
![]() |
4ad2cf91d7 | ||
![]() |
15f7981dd2 | ||
![]() |
30a0ddc3fb | ||
![]() |
526c42b246 | ||
0ca035dc44 | |||
3455d3f943 | |||
42acdc314a | |||
4fd1800944 | |||
dccdb99632 | |||
94af227b70 | |||
fdd0d6ceb1 | |||
5402bd0dc2 | |||
9d2816f4a7 | |||
![]() |
2eab528af0 | ||
b41c58341f | |||
90b8aa7811 | |||
56650ebfb4 | |||
44f4e551b7 | |||
9d4cc26890 | |||
f173e88787 | |||
ef40282081 | |||
32d9204e4a | |||
dd4906258d | |||
![]() |
c4b355124a | ||
15165aa9af | |||
c7fcef2096 | |||
2b4f8ed55c | |||
![]() |
681890780c | ||
49b39008c5 | |||
98b14158e6 | |||
476caf3f59 | |||
4f3c15eb04 | |||
c839799023 | |||
b7ff4fe87a | |||
435683c5d1 | |||
1f3f17c8e6 | |||
d4b28058a7 | |||
43044586d1 | |||
6074a02cf5 | |||
57d196edd6 | |||
bf832a407e | |||
5ae41521a0 | |||
d537379798 | |||
4f5e3401f7 | |||
81beb63916 | |||
3a2e9ad5d3 | |||
01b4b227ae | |||
f854ac031d | |||
![]() |
14e7a8eb12 | ||
![]() |
1339049886 | ||
73bd8c8515 | |||
![]() |
e2c7315759 | ||
![]() |
7a9b1297ca | ||
![]() |
7c255d6cb1 | ||
54aff53afe | |||
2f10cca40f | |||
![]() |
ae428394a9 | ||
81dd267e29 | |||
![]() |
4ec4013a44 | ||
![]() |
46c78ca4a4 | ||
![]() |
50bd1c05ac | ||
![]() |
36a6667645 | ||
![]() |
225f6a57bc | ||
1fdeba0745 | |||
f6f748217a | |||
3f39cea89e | |||
bda6d7819c | |||
![]() |
5a64a866da | ||
![]() |
67fd074f04 | ||
![]() |
163e748f9c | ||
![]() |
8f84481d48 | ||
229f0d1cfd | |||
![]() |
c1c21e55b4 | ||
![]() |
dfd36070eb | ||
![]() |
43ed1aa320 | ||
![]() |
51282da51e | ||
![]() |
aaf50c6e7e | ||
![]() |
40cd6fd88b | ||
![]() |
14494e4aae | ||
![]() |
d4e8517e9f | ||
![]() |
526e0cda24 | ||
e468633408 | |||
![]() |
6d59a64eed | ||
94e5aafa19 | |||
0fa5fa40e1 | |||
4caf48bd86 | |||
66aec13ed6 | |||
67825a7668 | |||
facbb8c950 | |||
95c88881d9 | |||
9ad8f35bca | |||
4f722947e2 | |||
![]() |
5420604ef8 | ||
![]() |
47381686b5 | ||
df793193aa | |||
![]() |
3bbe3ba707 | ||
eeb03766b6 | |||
f8ab2c144e | |||
32793ac12b | |||
83ee57adc7 | |||
4cff55daca | |||
cb72bb0427 | |||
![]() |
d2d2b1e25d | ||
![]() |
d56f9c7e6e | ||
518fdd8c03 | |||
20ad7a44a7 | |||
c655d23815 | |||
![]() |
ba3f467244 | ||
![]() |
1a52363218 | ||
![]() |
336ecda7e6 | ||
89191f4014 | |||
399a05a5b5 | |||
3c88c854bf | |||
21b76f1ca1 | |||
d50cf13085 | |||
620ec536c2 | |||
d4ca9ca36d | |||
932f01df0d | |||
19fd865e6f | |||
09fbc91d32 | |||
38537de758 | |||
bb8b428598 | |||
730965812b | |||
c0801297fb | |||
![]() |
959f7bf300 | ||
![]() |
a07fb68e14 | ||
![]() |
3c45f57b96 | ||
![]() |
9e5651a9be | ||
![]() |
41fa06e871 | ||
![]() |
51722821e0 | ||
![]() |
a385f0bab2 | ||
6623616c82 | |||
![]() |
fcf61377ac | ||
![]() |
c8ac7bf8fd | ||
![]() |
20d0221f5d | ||
![]() |
ffffd2deb5 | ||
![]() |
796d104b83 | ||
![]() |
654aa591c4 | ||
![]() |
0a3bbb23e0 | ||
![]() |
462d4fb8b2 | ||
![]() |
eb17390b0a | ||
550bb1aaae | |||
20f67ae8e9 | |||
![]() |
67f351bd50 | ||
![]() |
a87bd3ac50 | ||
![]() |
e2627f175c | ||
![]() |
66a2f88da3 | ||
![]() |
3c9ac0e04d | ||
![]() |
1bdf97d93f | ||
![]() |
08155939c3 | ||
![]() |
03a022c4fa | ||
![]() |
13b9e42dc4 | ||
![]() |
949d59487c | ||
3d695dac97 | |||
4fedb3fb5a | |||
![]() |
25876ffa28 | ||
dba92b0c42 | |||
![]() |
6317418028 | ||
![]() |
59b9694180 | ||
![]() |
47632a3c4b | ||
50578b34d0 | |||
c8afe4bcaf | |||
3f5022cbea | |||
f7751de1c3 | |||
![]() |
194bd25e7b | ||
![]() |
8677a3e56c | ||
![]() |
4e99c459c2 | ||
![]() |
2c0e6a33a4 | ||
![]() |
cbaa62dd78 | ||
![]() |
162c5bca4b | ||
![]() |
3d9f68acc6 | ||
![]() |
7f96e279d7 | ||
0b4e430c70 | |||
![]() |
747d1f45a8 | ||
![]() |
6cf1591688 | ||
![]() |
562cabfbd6 | ||
![]() |
4033361f10 | ||
![]() |
032faaeb73 | ||
![]() |
fd178f6ce5 | ||
![]() |
28030dd470 | ||
![]() |
11fb321674 | ||
3d18255eb1 | |||
c5f04ee9c4 | |||
![]() |
366ed2b666 | ||
![]() |
26899e488e | ||
![]() |
d57925e848 | ||
b03f75367d | |||
![]() |
2cebe86524 | ||
![]() |
0a900088ca | ||
![]() |
cdb1284e9e | ||
![]() |
3a5347f88f | ||
![]() |
e18080c4dc | ||
![]() |
831848e938 | ||
![]() |
54ed70ae4a | ||
![]() |
e3abc25c6b | ||
![]() |
9f9e44bada | ||
![]() |
ff4b6504a1 | ||
![]() |
55c6cdcae8 | ||
![]() |
00f2750937 | ||
![]() |
9c41bfeaa4 | ||
![]() |
3f43469104 | ||
![]() |
89c3f894d7 | ||
![]() |
33ec7babf9 | ||
![]() |
f5026a9cbf | ||
![]() |
b2e8d3cedf | ||
![]() |
6121ccc46f | ||
37ce3305e0 | |||
f02e44bf91 | |||
![]() |
57fc896e59 | ||
![]() |
46b4ec4819 | ||
![]() |
83ccc0ff0a | ||
![]() |
6d70224da4 | ||
![]() |
7b04c7e210 | ||
95189c8f53 | |||
7e84451ac3 | |||
![]() |
15b9615a1c | ||
![]() |
4dc9cfb457 | ||
![]() |
1250617d6c | ||
![]() |
ca5f35aea9 | ||
![]() |
3dfa982b39 | ||
b2a5a94ce0 | |||
d834c8063c | |||
d28f4bd24b | |||
48f4c7286d | |||
d9f80e9de6 | |||
d1e42233a8 | |||
![]() |
6110957921 | ||
d308d7da97 | |||
4d34078678 | |||
8d42ebc2f0 | |||
87cad7eaee | |||
![]() |
b1f1c28c5c | ||
![]() |
b612e925df | ||
![]() |
af629d2442 | ||
e232a641a3 | |||
35495e4d5a | |||
5974160805 | |||
4e16ef35a2 | |||
885d549e84 | |||
173343e049 | |||
c3bcb8d020 | |||
d7de8ae630 | |||
![]() |
d5f529819f | ||
![]() |
d2093444a6 | ||
![]() |
3f15c4324b | ||
219d7fd8c3 | |||
![]() |
c5c6a9fa17 | ||
![]() |
78779fe92f | ||
![]() |
b37a64905b | ||
![]() |
675ac79443 | ||
![]() |
14ea9c2928 | ||
![]() |
ec6084cd37 | ||
![]() |
b65cbb0f78 | ||
fe15db51d8 | |||
761ad38bcc | |||
2a5ed938bb | |||
c5c4e3c7ce | |||
94af6550fa | |||
c767644c8f | |||
a3ee593d0b | |||
733d6db56e | |||
6d938a12f6 | |||
![]() |
8a56531c90 | ||
43332bb6d0 | |||
![]() |
5990dd5879 | ||
![]() |
030a95cdd1 | ||
![]() |
18d3536ffe | ||
![]() |
3b80f53b8e | ||
![]() |
5912c60692 | ||
![]() |
f8dc8a298e | ||
![]() |
a3dd538afb | ||
![]() |
a90b8aa03a | ||
![]() |
313ee79bae | ||
![]() |
97f97448d5 | ||
3677cadcca | |||
![]() |
455b5529b4 | ||
![]() |
60204fef24 | ||
![]() |
45064ec37e | ||
4ecacc7607 | |||
![]() |
43ba27126c | ||
![]() |
527c9ba5dd | ||
d4bf2523a6 | |||
acb4bac5e6 | |||
cbef38ac11 | |||
![]() |
f9ffab62f4 | ||
![]() |
656292e1b1 | ||
![]() |
ed8a065da9 | ||
![]() |
9834a36787 | ||
![]() |
33b9a5c2ce | ||
1eb58a84df | |||
![]() |
c9c35a3e5a | ||
![]() |
e0dd52a4dc | ||
393d813d05 | |||
![]() |
0000e4f28d | ||
e3a3a99317 | |||
6a9f73bd61 | |||
2c3be29016 | |||
8eb10872b8 | |||
d5fd682985 | |||
8f861f7ba2 | |||
![]() |
efe53c831d | ||
![]() |
0dba0a1d6f | ||
![]() |
89c01696cc | ||
![]() |
164f060a40 | ||
![]() |
e347ee5880 | ||
![]() |
a4ea70b33b | ||
![]() |
4433a3db06 | ||
![]() |
e019d3b8d7 | ||
![]() |
1f497e171a | ||
![]() |
cd8c954513 | ||
![]() |
d08d5ffd64 | ||
![]() |
8744eab46d | ||
![]() |
5d7e936aed | ||
![]() |
e786da2605 | ||
![]() |
b6fab829cc | ||
150cb30339 | |||
724d8de9ae | |||
ddcd8cbb10 | |||
f5f4f14b7e | |||
6616ccd3b4 | |||
![]() |
075f89f43c | ||
![]() |
9a836ed072 | ||
552608744d | |||
![]() |
2accbdcf05 | ||
![]() |
ab17bd3150 | ||
d201a29d03 | |||
c4bbcc4617 | |||
82a0ac16f1 | |||
27b48034c5 | |||
![]() |
641e71c141 | ||
![]() |
4fd8da8041 | ||
68dccdfe2f | |||
592361b1a4 | |||
6e4df8830a | |||
7ab95d0144 | |||
![]() |
4ea5622842 | ||
606300a042 | |||
96cf598691 | |||
6b923c7251 | |||
18e57d19db | |||
![]() |
45f3020924 | ||
d8a3cb0d58 | |||
![]() |
b5dc9b6f5a | ||
38a6e6b212 | |||
627519e69c | |||
2f2e0e539a | |||
e42b78e177 | |||
4b19801cdb | |||
3d76354cbb | |||
e2c98ac134 | |||
d4fe76afee | |||
3352c45517 | |||
0e719b8eb0 | |||
ff520b74dc | |||
48bf618ae5 | |||
d6c1202e4b | |||
20452c9387 | |||
64a753116b | |||
![]() |
5ce439ffc4 | ||
![]() |
00f2721640 | ||
![]() |
454a310bbe | ||
![]() |
18952f5109 | ||
7377086aae | |||
9f7cc9d887 | |||
ffa9ea9cd2 | |||
f9654661bb | |||
5ce06d02b4 | |||
c356792d02 | |||
![]() |
90642a8ab5 | ||
![]() |
0ae798d840 | ||
6199e7b74c | |||
![]() |
1e9ac05b63 | ||
![]() |
ed338d9cfa | ||
![]() |
a84e6f7854 | ||
fe21748b2d | |||
8b184f8c03 | |||
5ed22d5c16 | |||
525e0b4518 | |||
e8d94982e4 | |||
38db0b0ff3 | |||
![]() |
e4a8b9621d | ||
![]() |
66ea1c060a | ||
![]() |
50dabfec8c | ||
![]() |
a8722e033c | ||
![]() |
1cec98d180 | ||
97bb2d81b7 | |||
![]() |
9c4d107b5d | ||
![]() |
eaccd029c8 | ||
![]() |
b2c90b0633 | ||
![]() |
1152e117b3 | ||
![]() |
9f3cdeb29e | ||
![]() |
699bfb3987 | ||
![]() |
0695753084 | ||
![]() |
ef0e9ca36c | ||
![]() |
3e9e56ed28 | ||
![]() |
b16cfb9df6 | ||
![]() |
18c3430656 | ||
![]() |
94298c3678 | ||
![]() |
a3d22e829b | ||
![]() |
63ecc10c5e | ||
![]() |
937ef0ea4e | ||
428db02274 | |||
![]() |
960f12d66c | ||
![]() |
aea618061f | ||
![]() |
3995d2b123 | ||
![]() |
891f9b2e87 | ||
![]() |
47efafa722 | ||
![]() |
b19006690c | ||
![]() |
6acef90087 | ||
![]() |
5b7896d16e | ||
![]() |
8a74eceac3 | ||
![]() |
a5f576d912 | ||
![]() |
e0c0f2a350 | ||
![]() |
1ca63be423 | ||
![]() |
eaee55e3a9 | ||
![]() |
1fbaf24d59 | ||
![]() |
1ada55f012 | ||
![]() |
bcbd5bbda6 | ||
![]() |
2a982a4c47 | ||
![]() |
2061640cb6 | ||
![]() |
a4ff83c0d4 | ||
![]() |
e766202a2e | ||
![]() |
0da9c606f2 | ||
![]() |
398984009b | ||
![]() |
3e00866bdf | ||
![]() |
ac3c2bd872 | ||
![]() |
281c2f5b51 | ||
![]() |
2e9e2e20ef | ||
![]() |
ed131f47de | ||
![]() |
853e5ac607 | ||
![]() |
1cffcdb670 | ||
![]() |
a9b1603f9f | ||
![]() |
aee08287eb | ||
![]() |
131e8f6d68 | ||
![]() |
c8544d016d | ||
![]() |
8198e61acc | ||
![]() |
b41ed69b0f | ||
![]() |
5b2cf8b676 | ||
![]() |
5d9116965b | ||
![]() |
07e61d499a | ||
![]() |
9f010d80fb | ||
![]() |
660ba64ce1 | ||
![]() |
29c731d660 | ||
![]() |
df4714e628 | ||
![]() |
a7d6048748 | ||
![]() |
1a40178e8c | ||
![]() |
49ac0278f0 | ||
![]() |
4c74315411 | ||
![]() |
f992a07df9 | ||
e62d9dfa48 | |||
6dd7431ccd | |||
7020bfd521 | |||
0fcf13ef73 | |||
9e37a5a4af | |||
![]() |
9e4e9c197b | ||
172541a368 | |||
9f475c03cb | |||
fbfffa9987 | |||
![]() |
8ea721696f | ||
![]() |
3e5713e479 | ||
![]() |
b7072d48b6 | ||
![]() |
7feefc049c | ||
8ae398d786 | |||
a818e84dcf | |||
33780ef359 | |||
![]() |
516216730b | ||
![]() |
7a69024fb5 | ||
9fcb20a7bd | |||
991acd3917 | |||
f4905d2742 | |||
b7b7283ff9 | |||
22d50dd150 | |||
bc231b51b5 | |||
![]() |
4d17643064 | ||
![]() |
0b510cdc21 | ||
![]() |
a188275608 | ||
![]() |
0617ee99cd | ||
![]() |
4fbde3a0bc | ||
![]() |
9911d22ac3 | ||
![]() |
b14c17c884 | ||
![]() |
3fe232a535 | ||
![]() |
52a0ab5482 | ||
![]() |
b3dec96e1e | ||
![]() |
b639482c4a | ||
![]() |
d68e59fb04 | ||
![]() |
d97f991230 | ||
![]() |
cc780c23f8 | ||
a7fceb644f | |||
312534b635 | |||
8f9f102baf | |||
![]() |
26cc6a26b8 | ||
![]() |
bcf9d59c82 | ||
![]() |
cf7e922dcd | ||
![]() |
ba67bb9412 | ||
![]() |
1271e03192 | ||
![]() |
cdd986c56b | ||
![]() |
ea86b6880f | ||
![]() |
d47de894ab | ||
![]() |
109bd978de | ||
![]() |
25d2ce65e2 | ||
![]() |
07b3ebefc1 | ||
![]() |
e255de6f72 | ||
![]() |
76bbc604ae | ||
![]() |
103bde8a32 | ||
![]() |
57140d2655 | ||
![]() |
f61108bbae | ||
![]() |
05a3738fdb | ||
![]() |
ceb631719b | ||
078056f163 | |||
1adb3d19c7 | |||
![]() |
b5cfe00ba5 | ||
![]() |
46b2fd2749 | ||
![]() |
f1d1a80f4e | ||
![]() |
f3a30276f3 | ||
![]() |
a9579cdd87 | ||
![]() |
2d4c3453b7 | ||
![]() |
1f58125eed | ||
![]() |
fb36da7669 | ||
![]() |
fa1820786a | ||
![]() |
655d0ad77e | ||
![]() |
0098816866 | ||
![]() |
6e08fd614a | ||
![]() |
0680725582 | ||
![]() |
0cb10f9bb1 | ||
7751661f3d | |||
ca5484a984 | |||
![]() |
f7beb5d68e | ||
d6999a3327 | |||
![]() |
541ff01fd1 | ||
c85931cbc5 | |||
7e0d0e2b01 | |||
![]() |
f289be908c | ||
![]() |
42e9fd9431 | ||
5dc9214296 | |||
![]() |
086bad4b47 | ||
![]() |
22d66131f3 | ||
311bb7a4b6 | |||
![]() |
8b10720b23 | ||
6f296a6f76 | |||
61590d39e0 | |||
c7a574fe01 | |||
1b2519cfb8 | |||
9c02aab4fb | |||
![]() |
c89f752ccc | ||
40fd4ccd15 | |||
![]() |
4c0a4a2296 | ||
ddddc686fe | |||
642376b0b6 | |||
3ba9f872ed | |||
bfb4560dc2 | |||
fa8f2290af | |||
c0422134f9 | |||
b11516f758 | |||
14986fbfa1 | |||
34d951aa6b | |||
f96342d33a | |||
5eb6bf1b1d | |||
295e1daa22 | |||
cf0d2197b8 | |||
79358f4271 | |||
12f3634f96 | |||
033dee0216 | |||
1324eaf056 | |||
2e5e3b9d40 | |||
ef26accde0 | |||
8461beba1c | |||
b93e3dfb55 | |||
5ef1dd87a5 | |||
07860d018c | |||
ce5ce12e3b | |||
02c4bbfc58 | |||
bf613448d7 | |||
5095e8a1d6 | |||
0352ca3ef6 | |||
12c5b9c21c | |||
![]() |
be4be9716d | ||
![]() |
ac5785c796 | ||
![]() |
e6b24277b6 | ||
![]() |
dca9f32d3f | ||
![]() |
21a3657da5 | ||
3f141e72b8 | |||
![]() |
e3a81f6091 | ||
3ecc38cc9c | |||
b23f278c3f | |||
e47afffd09 | |||
0f91899aa9 | |||
8e672ea548 | |||
cfc17d59b4 | |||
46e8add16a | |||
![]() |
7f616f20ae | ||
![]() |
133017d2db | ||
![]() |
ee6a058602 | ||
![]() |
6bbdb4fc03 | ||
![]() |
5def26ab93 | ||
![]() |
1657f151f6 | ||
![]() |
a5b55728ba | ||
8b737b4adb | |||
f4e92572eb | |||
b048b016ad | |||
41fc9cf4ca | |||
7edbd3ad0a | |||
de815e271c | |||
ad24f1438f | |||
b6a0426477 | |||
f71dfe50f9 | |||
6b6aaab881 | |||
8bbcb0b337 | |||
a1032abc92 | |||
380c1e5053 | |||
21dbee03f1 | |||
f4ca3976d5 | |||
b02fe536bc | |||
f9b2c0bc63 | |||
![]() |
6e607e6bfe | ||
![]() |
0e854623c1 | ||
![]() |
21c65475f9 | ||
![]() |
97c36cc54e | ||
b30e1f5ba9 | |||
b2d4a799d5 | |||
9030b64dc8 | |||
cb707785cc | |||
f938cc7b0c | |||
![]() |
cacd0f898d | ||
![]() |
f8fffb5d20 | ||
![]() |
9cd0e53d0f | ||
![]() |
b0daab601a | ||
![]() |
291b70036a | ||
![]() |
bfad5889ad | ||
a3fb49adcb | |||
![]() |
e990d98dab | ||
c269546c08 | |||
258c260601 | |||
f11a543233 | |||
ad3342aefb | |||
54fdfd823b | |||
ba9c7015fe | |||
208db9a673 | |||
7f10a67804 | |||
d8080278b3 | |||
08d24b059a | |||
1811989089 | |||
9d91b90d3c | |||
9203663abf | |||
d078ed396f | |||
7c36c0c8e7 | |||
404754bc90 |
@@ -17,8 +17,10 @@ _jsp\.java$
|
||||
\.war$
|
||||
\.zip$
|
||||
^\.
|
||||
^build/
|
||||
^build
|
||||
^pkg-temp/
|
||||
~$
|
||||
/build/
|
||||
/build
|
||||
/classes/
|
||||
^debian/copyright
|
||||
override.properties
|
||||
|
105
.tx/config
@@ -1,47 +1,136 @@
|
||||
[I2P.i2ptunnel]
|
||||
source_file = apps/i2ptunnel/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/i2ptunnel/locale/messages_ar.po
|
||||
trans.cs = apps/i2ptunnel/locale/messages_cs.po
|
||||
trans.da = apps/i2ptunnel/locale/messages_da.po
|
||||
trans.de = apps/i2ptunnel/locale/messages_de.po
|
||||
trans.es = apps/i2ptunnel/locale/messages_es.po
|
||||
trans.fr = apps/i2ptunnel/locale/messages_fr.po
|
||||
trans.hu = apps/i2ptunnel/locale/messages_hu.po
|
||||
trans.it = apps/i2ptunnel/locale/messages_it.po
|
||||
trans.nl = apps/i2ptunnel/locale/messages_nl.po
|
||||
trans.pt = apps/i2ptunnel/locale/messages_pt.po
|
||||
trans.ru = apps/i2ptunnel/locale/messages_ru.po
|
||||
trans.sv_SE = apps/i2ptunnel/locale/messages_sv.po
|
||||
trans.uk_UA = apps/i2ptunnel/locale/messages_uk.po
|
||||
trans.vi = apps/i2ptunnel/locale/messages_vi.po
|
||||
trans.zh_CN = apps/i2ptunnel/locale/messages_zh.po
|
||||
|
||||
[I2P.routerconsole]
|
||||
source_file = apps/routerconsole/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/routerconsole/locale/messages_ar.po
|
||||
trans.cs = apps/routerconsole/locale/messages_cs.po
|
||||
trans.da = apps/routerconsole/locale/messages_da.po
|
||||
trans.de = apps/routerconsole/locale/messages_de.po
|
||||
trans.el = apps/routerconsole/locale/messages_el.po
|
||||
trans.es = apps/routerconsole/locale/messages_es.po
|
||||
trans.et_EE = apps/routerconsole/locale/messages_ee.po
|
||||
trans.fi = apps/routerconsole/locale/messages_fi.po
|
||||
trans.fr = apps/routerconsole/locale/messages_fr.po
|
||||
trans.hu = apps/routerconsole/locale/messages_hu.po
|
||||
trans.it = apps/routerconsole/locale/messages_it.po
|
||||
trans.nl = apps/routerconsole/locale/messages_nl.po
|
||||
trans.pl = apps/routerconsole/locale/messages_pl.po
|
||||
trans.pt = apps/routerconsole/locale/messages_pt.po
|
||||
trans.ru = apps/routerconsole/locale/messages_ru.po
|
||||
trans.sv_SE = apps/routerconsole/locale/messages_sv.po
|
||||
trans.uk_UA = apps/routerconsole/locale/messages_uk.po
|
||||
trans.vi = apps/routerconsole/locale/messages_vi.po
|
||||
trans.zh_CN = apps/routerconsole/locale/messages_zh.po
|
||||
|
||||
[I2P.susidns]
|
||||
source_file = apps/susidns/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.de = apps/susidns/locale/messages_de.po
|
||||
trans.nl = apps/susidns/locale/messages_nl.po
|
||||
trans.ru = apps/susidns/locale/messages_ru.po
|
||||
trans.zh_CN = apps/susidns/locale/messages_zh.po
|
||||
|
||||
[I2P.i2psnark]
|
||||
source_file = apps/i2psnark/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/i2psnark/locale/messages_ar.po
|
||||
trans.cs = apps/i2psnark/locale/messages_cs.po
|
||||
trans.de = apps/i2psnark/locale/messages_de.po
|
||||
trans.es = apps/i2psnark/locale/messages_es.po
|
||||
trans.fr = apps/i2psnark/locale/messages_fr.po
|
||||
trans.hu = apps/i2psnark/locale/messages_hu.po
|
||||
trans.it = apps/i2psnark/locale/messages_it.po
|
||||
trans.nl = apps/i2psnark/locale/messages_nl.po
|
||||
trans.pl = apps/i2psnark/locale/messages_pl.po
|
||||
trans.pt = apps/i2psnark/locale/messages_pt.po
|
||||
trans.ru = apps/i2psnark/locale/messages_ru.po
|
||||
trans.sv_SE = apps/i2psnark/locale/messages_sv.po
|
||||
trans.vi = apps/i2psnark/locale/messages_vi.po
|
||||
trans.zh_CN = apps/i2psnark/locale/messages_zh.po
|
||||
|
||||
[I2P.susidns]
|
||||
source_file = apps/susidns/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/susidns/locale/messages_ar.po
|
||||
trans.cs = apps/susidns/locale/messages_cs.po
|
||||
trans.da = apps/susidns/locale/messages_da.po
|
||||
trans.de = apps/susidns/locale/messages_de.po
|
||||
trans.el = apps/susidns/locale/messages_el.po
|
||||
trans.es = apps/susidns/locale/messages_es.po
|
||||
trans.fr = apps/susidns/locale/messages_fr.po
|
||||
trans.hu = apps/susidns/locale/messages_hu.po
|
||||
trans.it = apps/susidns/locale/messages_it.po
|
||||
trans.nl = apps/susidns/locale/messages_nl.po
|
||||
trans.pl = apps/susidns/locale/messages_pl.po
|
||||
trans.pt = apps/susidns/locale/messages_pt.po
|
||||
trans.ru = apps/susidns/locale/messages_ru.po
|
||||
trans.sv_SE = apps/susidns/locale/messages_sv.po
|
||||
trans.uk_UA = apps/susidns/locale/messages_uk.po
|
||||
trans.vi = apps/susidns/locale/messages_vi.po
|
||||
trans.zh_CN = apps/susidns/locale/messages_zh.po
|
||||
|
||||
[I2P.desktopgui]
|
||||
source_file = apps/desktopgui/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/desktopgui/locale/messages_ar.po
|
||||
trans.cs = apps/desktopgui/locale/messages_cs.po
|
||||
trans.da = apps/desktopgui/locale/messages_da.po
|
||||
trans.de = apps/desktopgui/locale/messages_de.po
|
||||
trans.el = apps/desktopgui/locale/messages_el.po
|
||||
trans.es = apps/desktopgui/locale/messages_es.po
|
||||
trans.fr = apps/desktopgui/locale/messages_fr.po
|
||||
trans.hu = apps/desktopgui/locale/messages_hu.po
|
||||
trans.it = apps/desktopgui/locale/messages_it.po
|
||||
trans.nl = apps/desktopgui/locale/messages_nl.po
|
||||
trans.pl = apps/desktopgui/locale/messages_pl.po
|
||||
trans.ru = apps/desktopgui/locale/messages_ru.po
|
||||
trans.sv_SE = apps/desktopgui/locale/messages_sv.po
|
||||
trans.uk_UA = apps/desktopgui/locale/messages_uk.po
|
||||
trans.vi = apps/desktopgui/locale/messages_vi.po
|
||||
trans.zh_CN = apps/desktopgui/locale/messages_zh.po
|
||||
|
||||
[I2P.susimail]
|
||||
source_file = apps/susimail/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.cs = apps/susimail/locale/messages_cs.po
|
||||
trans.de = apps/susimail/locale/messages_de.po
|
||||
trans.es = apps/susimail/locale/messages_es.po
|
||||
trans.fr = apps/susimail/locale/messages_fr.po
|
||||
trans.hu = apps/susimail/locale/messages_hu.po
|
||||
trans.it = apps/susimail/locale/messages_it.po
|
||||
trans.nl = apps/susimail/locale/messages_nl.po
|
||||
trans.ru = apps/susimail/locale/messages_ru.po
|
||||
trans.sv_SE = apps/susimail/locale/messages_sv.po
|
||||
trans.pl = apps/susimail/locale/messages_pl.po
|
||||
trans.uk_UA = apps/susimail/locale/messages_uk.po
|
||||
trans.vi = apps/susimail/locale/messages_vi.po
|
||||
trans.zh_CN = apps/susimail/locale/messages_zh.po
|
||||
|
||||
[I2P.debconf]
|
||||
source_file = debian/po/templates.pot
|
||||
source_lang = en
|
||||
trans.cs = debian/po/cs.po
|
||||
trans.de = debian/po/de.po
|
||||
trans.el = debian/po/el.po
|
||||
trans.es = debian/po/es.po
|
||||
trans.fr = debian/po/fr.po
|
||||
trans.it = debian/po/it.po
|
||||
trans.hu = debian/po/hu.po
|
||||
trans.pl = debian/po/pl.po
|
||||
trans.ru = debian/po/ru.po
|
||||
trans.sv_SE = debian/po/sv.po
|
||||
trans.uk_UA = debian/po/uk.po
|
||||
|
||||
[main]
|
||||
host = http://www.transifex.net
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
Headless I2P installation instructions
|
||||
Headless (console mode) I2P installation instructions
|
||||
|
||||
1) java -jar i2pinstall.exe -console (you've already done this)
|
||||
|
||||
@@ -6,12 +6,12 @@ This will run the installer in text mode, including running the postinstall.sh
|
||||
script. After that, you may run 'sh i2prouter start'
|
||||
which will start the router and attempt to launch a browser.
|
||||
|
||||
If you do not have an X server running, the browser launch will probably fail, and
|
||||
If you do not have an X server running, the browser launch may fail, and
|
||||
you may use:
|
||||
lynx http://localhost:7657/index.jsp
|
||||
lynx http://localhost:7657/
|
||||
to configure the router.
|
||||
|
||||
If you're having trouble, swing by http://forum.i2p2.de/, check the
|
||||
If you're having trouble, swing by http://forum.i2p/, check the
|
||||
website at http://www.i2p2.de/, or get on irc://irc.freenode.net/#i2p
|
||||
|
||||
I2P will create and store files and configuration data in the user directory
|
||||
@@ -24,22 +24,22 @@ edit the files i2prouter (Linux) and wrapper.config (Linux and Windows)
|
||||
where there are comments labeled "PORTABLE". Do this before you
|
||||
run I2P for the first time.
|
||||
|
||||
To run I2P explicitly:
|
||||
To start I2P:
|
||||
(*nix): sh i2prouter start
|
||||
(win*): I2P.exe
|
||||
(Platforms unsupported by the wrapper - PPC, ARM, etc): sh runplain.sh
|
||||
(non-x86 platforms PPC, ARM, etc): sh runplain.sh
|
||||
|
||||
To stop the router (gracefully):
|
||||
lynx http://localhost:7657/configservice.jsp ("Shutdown gracefully")
|
||||
To stop I2P (gracefully):
|
||||
lynx http://localhost:7657/summaryframe (click "Shutdown")
|
||||
|
||||
To stop the router (immediately):
|
||||
To stop I2P immediately:
|
||||
sh i2prouter stop
|
||||
|
||||
To uninstall I2P:
|
||||
rm -rf $i2pInstallDir
|
||||
rm -rf $I2PInstallDir ~/.i2p
|
||||
|
||||
Supported JVMs:
|
||||
Windows: Latest available from http://java.sun.com/ (1.5+ supported)
|
||||
Linux: Latest available from http://java.sun.com/ (1.5+ supported)
|
||||
FreeBSD: Sun 1.5-compatible (NIO required)
|
||||
various: http://www.kaffe.org/ Sun 1.5-compatible (NIO required)
|
||||
Windows: Latest available from http://java.com/download (1.5+ supported)
|
||||
Linux: Latest available from http://java.com/download (1.5+ supported)
|
||||
FreeBSD: 1.5-compatible (NIO required)
|
||||
Other operating systems and JVMs: See http://trac.i2p2.de/wiki/java
|
||||
|
53
INSTALL.txt
@@ -1,33 +1,68 @@
|
||||
I2P source installation instructions
|
||||
|
||||
Prerequisites to build from source:
|
||||
Java SDK (preferably Sun) 1.5.0 or higher (1.6 recommended)
|
||||
The SDK must have Pack200 support (java.util.jar.Pack200)
|
||||
Java SDK (preferably Oracle/Sun or OpenJDK) 1.6.0 or higher
|
||||
Non-linux operating systems and JVMs: See http://trac.i2p2.de/wiki/java
|
||||
Apache Ant 1.7.0 or higher
|
||||
Optional, For multilanguage support: The xgettext, msgfmt, and msgmerge tools installed
|
||||
The xgettext, msgfmt, and msgmerge tools installed
|
||||
from the GNU gettext package http://www.gnu.org/software/gettext/
|
||||
|
||||
To build and install I2P from source, you must first build
|
||||
and package up the appropriate installer by running:
|
||||
|
||||
ant pkg
|
||||
ant pkg
|
||||
|
||||
On non-x86, use one of the following instead:
|
||||
ant installer-linux
|
||||
ant installer-freebsd
|
||||
ant installer-osx
|
||||
|
||||
|
||||
|
||||
This will produce a few key files:
|
||||
* install.jar: the GUI and console installer
|
||||
* i2pinstall.exe: the GUI and console installer wrapped for cross-platform execution
|
||||
(only created with ant pkg)
|
||||
* i2pupdate.zip: the update package
|
||||
(only created with ant pkg)
|
||||
|
||||
From there, you can run the headless (console mode) installer:
|
||||
java -jar i2pinstall.exe -console
|
||||
or
|
||||
java -jar i2pinstall.jar -console
|
||||
|
||||
Or run the GUI installer:
|
||||
java -jar i2pinstall.exe
|
||||
or
|
||||
java -jar i2pinstall.jar
|
||||
or on Windows, just double-click on i2pinstall.exe.
|
||||
|
||||
Or move the update file into an existing installation directory and restart.
|
||||
Or move the i2pupdate.zip file into an existing installation directory and restart.
|
||||
|
||||
To start I2P:
|
||||
(*nix): sh i2prouter start
|
||||
(win*): I2P.exe or i2prouter.bat
|
||||
(non-x86 platforms PPC, ARM, etc): sh runplain.sh
|
||||
|
||||
To install I2P as a system service:
|
||||
(*nix) sh i2prouter install
|
||||
(win*) install_i2p_service_winnt.bat
|
||||
|
||||
To uninstall I2P as a system service:
|
||||
(*nix) sh i2prouter remove
|
||||
(win*) uninstall_i2p-service_winnt.bat
|
||||
|
||||
To stop I2P (gracefully):
|
||||
lynx http://localhost:7657/summaryframe (click "Shutdown")
|
||||
|
||||
To stop I2P immediately:
|
||||
sh i2prouter stop
|
||||
|
||||
To uninstall I2P:
|
||||
rm -rf $I2PInstallDir ~/.i2p
|
||||
|
||||
Supported JVMs:
|
||||
Windows: Latest available from http://java.sun.com/ (1.5+ supported)
|
||||
Linux: Latest available from http://java.sun.com/ (1.5+ supported)
|
||||
FreeBSD: Sun 1.5-compatible (NIO required)
|
||||
various: http://www.kaffe.org/ Sun 1.5-compatible (NIO required)
|
||||
Windows: Latest available from http://java.com/download (1.5+ supported)
|
||||
Linux: Latest available from http://java.com/download (1.5+ supported)
|
||||
FreeBSD: 1.5-compatible (NIO required)
|
||||
Other operating systems and JVMs: See http://trac.i2p2.de/wiki/java
|
||||
|
112
LICENSE.txt
@@ -2,7 +2,7 @@ This product includes both public domain code and licensed code as described bel
|
||||
For all code, unless otherwise stated in the appropriate license, the following applies:
|
||||
|
||||
|
||||
NO WARRANTY
|
||||
NO WARRANTY
|
||||
|
||||
BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
@@ -29,7 +29,7 @@ POSSIBILITY OF SUCH DAMAGES.
|
||||
LICENSES
|
||||
--------
|
||||
|
||||
Core:
|
||||
Core (i2p.jar):
|
||||
Public domain except as listed below:
|
||||
|
||||
ElGamal and DSA code:
|
||||
@@ -41,8 +41,8 @@ Public domain except as listed below:
|
||||
See licenses/LICENSE-SHA256.txt
|
||||
|
||||
AES code:
|
||||
Under the Cryptix (MIT) license, written by the Cryptix team
|
||||
(That's what our website says but all our AES code looks like it is public domain)
|
||||
Copyright (c) 1995-2005 The Cryptix Foundation Limited.
|
||||
See licenses/LICENSE-Cryptix.txt
|
||||
|
||||
Crypto filters:
|
||||
From the xlattice app - http://xlattice.sourceforge.net/
|
||||
@@ -56,10 +56,6 @@ Public domain except as listed below:
|
||||
Copyright (C) 2001, 2002, Free Software Foundation, Inc.
|
||||
See licenses/LICENSE-LGPLv2.1.txt
|
||||
|
||||
GMP 4.1.3:
|
||||
Copyright 1991, 1996, 1999, 2000 Free Software Foundation, Inc.
|
||||
See licenses/LICENSE-LGPLv2.1.txt
|
||||
|
||||
HashCash code:
|
||||
Copyright 2006 Gregory Rubin grrubin@gmail.com
|
||||
See licenses/LICENSE-HashCash.txt
|
||||
@@ -72,18 +68,24 @@ Public domain except as listed below:
|
||||
Contains some code Copyright 2006 Sun Microsystems, Inc.
|
||||
See licenses/LICENSE-InstallCert.txt
|
||||
|
||||
BlockFile:
|
||||
Copyright (c) 2006, Matthew Estes
|
||||
See licenses/LICENSE-BlockFile.txt
|
||||
|
||||
Router:
|
||||
|
||||
Router (router.jar):
|
||||
Public domain except as listed below:
|
||||
UPnP.java:
|
||||
From freenet
|
||||
See licenses/LICENSE-GPLv2.txt
|
||||
|
||||
UPnP subsystem 1.7:
|
||||
Copyright (C) 2003-2006 Satoshi Konno
|
||||
UPnP subsystem (CyberLink) 2.1:
|
||||
Copyright (C) 2003-2010 Satoshi Konno
|
||||
See licenses/LICENSE-UPnP.txt
|
||||
|
||||
GeoIP data free to use, courtesy http://ip-to-country.webhosting.info/
|
||||
GeoIP: GeoLite databases are licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
|
||||
http://creativecommons.org/licenses/by-sa/3.0/
|
||||
This product includes GeoLite data created by MaxMind, available from http://www.maxmind.com/
|
||||
|
||||
|
||||
Installer:
|
||||
@@ -92,34 +94,34 @@ Installer:
|
||||
See licenses/LICENSE-Launch4j.txt (in binary packages)
|
||||
See installer/lib/launch4j/LICENSE.txt (in source packages)
|
||||
The following projects are used by Launch4j...
|
||||
MinGW binutils (http://www.mingw.org/)
|
||||
MinGW binutils (http://www.mingw.org/)
|
||||
|
||||
Commons BeanUtils (http://jakarta.apache.org/commons/beanutils/)
|
||||
Commons BeanUtils (http://jakarta.apache.org/commons/beanutils/)
|
||||
|
||||
Commons Logging (http://jakarta.apache.org/commons/logging/)
|
||||
See licenses/LICENSE-Apache1.1.txt
|
||||
Commons Logging (http://jakarta.apache.org/commons/logging/)
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
See licenses/NOTICE-Commons-Logging.txt
|
||||
|
||||
XStream (http://xstream.codehaus.org/)
|
||||
XStream (http://xstream.codehaus.org/)
|
||||
Copyright (c) 2003-2004, Joe Walnes
|
||||
See licenses/LICENSE-XStream.txt
|
||||
|
||||
JGoodies Forms (http://www.jgoodies.com/freeware/forms/)
|
||||
JGoodies Forms (http://www.jgoodies.com/freeware/forms/)
|
||||
Copyright (c) 2002-2004 JGoodies Karsten Lentzsch. All rights reserved.
|
||||
See licenses/LICENSE-JGoodies-Forms.txt
|
||||
|
||||
JGoodies Looks (http://www.jgoodies.com/freeware/looks/)
|
||||
JGoodies Looks (http://www.jgoodies.com/freeware/looks/)
|
||||
Copyright (c) 2003 JGoodies Karsten Lentzsch. All rights reserved.
|
||||
See licenses/LICENSE-JGoodies-Looks.txt
|
||||
|
||||
Foxtrot (http://foxtrot.sourceforge.net/)
|
||||
Foxtrot (http://foxtrot.sourceforge.net/)
|
||||
Copyright (c) 2002, Simone Bordet & Marco Cravero. All rights reserved.
|
||||
See licenses/LICENSE-Foxtrot.txt
|
||||
|
||||
Nuvola Icon Theme (http://www.icon-king.com)
|
||||
Nuvola Icon Theme (http://www.icon-king.com)
|
||||
See licenses/LICENSE-LGPLv2.1.txt
|
||||
|
||||
Forms were created using Abeille Forms Designer (https://abeille.dev.java.net/)
|
||||
Forms were created using Abeille Forms Designer (https://abeille.dev.java.net/)
|
||||
|
||||
Izpack 4.3.0:
|
||||
Copyright (c) 2001-2008 Julien Ponge
|
||||
@@ -127,11 +129,18 @@ Installer:
|
||||
|
||||
|
||||
|
||||
Wrapper 3.1.1:
|
||||
Copyright (c) 1999, 2004 Tanuki Software
|
||||
Java Service Wrapper Community Edition 32-bit 3.5.13:
|
||||
Copyright (C) 1999-2011 Tanuki Software, Ltd. All Rights Reserved.
|
||||
See licenses/LICENSE-Wrapper.txt
|
||||
|
||||
|
||||
Jbigi Libraries (jbigi.jar):
|
||||
JNI code public domain.
|
||||
|
||||
GMP 4.3.2 / 5.0.2:
|
||||
Copyright 1991, 1996, 1999, 2000, 2007 Free Software Foundation, Inc.
|
||||
See licenses/LICENSE-LGPLv3.txt
|
||||
|
||||
|
||||
Applications:
|
||||
|
||||
@@ -141,22 +150,23 @@ Applications:
|
||||
|
||||
BOB:
|
||||
Copyright (C) sponge
|
||||
DWTFYWTPL
|
||||
See licenses/COPYING-BOB.txt
|
||||
|
||||
I2PSnark:
|
||||
Copyright (C) 2003 Mark J. Wielaard
|
||||
GPLv2 (or any later version)
|
||||
See licenses/LICENSE-GPLv2.txt
|
||||
Silk icons: See licenses/LICENSE-SilkIcons.txt
|
||||
|
||||
I2PTunnel:
|
||||
(c) 2003 - 2004 mihi
|
||||
GPLv2 with exception.
|
||||
GPLv2 (or any later version) with exception.
|
||||
See licenses/LICENSE-I2PTunnel.txt
|
||||
See licenses/LICENSE-GPLv2.txt
|
||||
|
||||
I2PTunnel SOCKS Proxy:
|
||||
Copyright (c) 2004 by human
|
||||
GPLv2 with exception.
|
||||
GPLv2 (or any later version) with exception.
|
||||
See licenses/LICENSE-I2PTunnel.txt
|
||||
See licenses/LICENSE-GPLv2.txt
|
||||
|
||||
@@ -164,13 +174,13 @@ Applications:
|
||||
By welterde.
|
||||
See licenses/LICENSE-GPLv2.txt
|
||||
|
||||
Jetty 5.1.12:
|
||||
Copyright 2000-2004 Mort Bay Consulting Pty. Ltd.
|
||||
See licenses/LICENSE-Apache1.1.txt
|
||||
Jetty 6.1.26:
|
||||
Copyright 1995-2009 Mort Bay Consulting Pty Ltd
|
||||
See licenses/LICENSE-Jetty.txt
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
See licenses/NOTICE-Commons-Logging.txt
|
||||
|
||||
JRobin 1.4.0:
|
||||
JRobin 1.5.9.1:
|
||||
See licenses/LICENSE-LGPLv2.1.txt
|
||||
|
||||
Ministreaming Lib:
|
||||
@@ -183,13 +193,26 @@ Applications:
|
||||
|
||||
Router console:
|
||||
Public domain.
|
||||
Flag icons: public domain, courtesy mjames@gmail.com http://www.famfamfam.com/
|
||||
Flag icons:
|
||||
- Jersey and EU flag icons: public domain, courtesy Xrmap flag
|
||||
collection http://www.arvernes.com/wiki/index.php/Xrmap
|
||||
- Guernsey and Isle of Man flags from the Open Clip Art Library, released into the public domain
|
||||
- All other flag icons: public domain, courtesy mjames@gmail.com http://www.famfamfam.com/
|
||||
Silk icons: See licenses/LICENSE-SilkIcons.txt
|
||||
FatCow icons: See licenses/LICENSE-FatCowIcons.txt
|
||||
|
||||
GeoIP Data:
|
||||
Copyright (c) 2003 Direct Information Pvt. Ltd. All Rights Reserved.
|
||||
Copyright (c) 2008 MaxMind, Inc. All Rights Reserved.
|
||||
See licenses/LICENSE-GeoIP.txt
|
||||
|
||||
Router Console and I2PSnark themes:
|
||||
"Man with hat over face" & related images licensed under a Creative Commons 2.0 license.
|
||||
Original photos by Florian Kuhlmann. http://www.flickr.com/photos/floriankuhlmann/3117758155
|
||||
|
||||
I2PSnark light theme:
|
||||
"Creative Commons Cat" licensed under a Creative Commons Attribution 3.0 Unported License.
|
||||
Original photo by Boaz Arad. http://www.luxphile.com/2011/01/creative-commons-cat.html
|
||||
|
||||
SAM:
|
||||
Public domain.
|
||||
|
||||
@@ -198,17 +221,27 @@ Applications:
|
||||
|
||||
SusiDNS:
|
||||
Copyright (C) 2005 <susi23@mail.i2p>
|
||||
GPLv2 (or any later version)
|
||||
See licenses/LICENSE-GPLv2.txt
|
||||
Uses Glassfish Standard Tag Library (JSTL) 1.2:
|
||||
Common Development and Distribution License (CDDL) version 1.0 + GNU General Public License (GPL) version 2
|
||||
See https://glassfish.dev.java.net/public/CDDL+GPL.html
|
||||
See licenses/LICENSE-GPLv2.txt
|
||||
|
||||
SusiMail:
|
||||
Copyright (C) 2004-2005 <susi23@mail.i2p>
|
||||
GPLv2 (or any later version)
|
||||
See licenses/LICENSE-GPLv2.txt
|
||||
|
||||
Systray:
|
||||
Public domain.
|
||||
Bundles systray4j code:
|
||||
See licenses/LICENSE-GPLv2.txt
|
||||
Bundles systray4j-2.4.1:
|
||||
See licenses/LICENSE-LGPLv2.1.txt
|
||||
|
||||
Tomcat 6.0.35:
|
||||
Copyright 1999-2011 The Apache Software Foundation
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
See licenses/NOTICE-Tomcat.txt
|
||||
|
||||
|
||||
Other Applications and Libraries
|
||||
@@ -220,8 +253,9 @@ distributions. See the source package for the additional license information.
|
||||
Admin Manager:
|
||||
Public domain
|
||||
|
||||
Atalk:
|
||||
Public domain
|
||||
BOB Demos:
|
||||
Copyright (C) sponge
|
||||
DWTFYWTPL
|
||||
|
||||
Desktopgui
|
||||
Copyright (c) Mathias De Maré
|
||||
@@ -240,7 +274,3 @@ distributions. See the source package for the additional license information.
|
||||
|
||||
SAM Python Library:
|
||||
Public domain.
|
||||
|
||||
I2PSnark/Console themes:
|
||||
"Man with hat over face" & related images licensed under a Creative Commons 2.0 license.
|
||||
Original photos by Florian Kuhlmann. http://www.flickr.com/photos/floriankuhlmann/3117758155
|
||||
|
21
README.txt
@@ -1,17 +1,24 @@
|
||||
Prerequisites to build from source:
|
||||
Java SDK (preferably Sun) 1.5.0 or higher (1.6 recommended)
|
||||
The SDK must have Pack200 support (java.util.jar.Pack200)
|
||||
Java SDK (preferably Oracle/Sun or OpenJDK) 1.6.0 or higher
|
||||
Non-linux operating systems and JVMs: See http://trac.i2p2.de/wiki/java
|
||||
Apache Ant 1.7.0 or higher
|
||||
Optional, For multilanguage support: The xgettext, msgfmt, and msgmerge tools installed
|
||||
from the GNU gettext package http://www.gnu.org/software/gettext/
|
||||
The xgettext, msgfmt, and msgmerge tools installed
|
||||
from the GNU gettext package http://www.gnu.org/software/gettext/
|
||||
|
||||
To build:
|
||||
ant pkg
|
||||
On x86 systems do:
|
||||
ant pkg
|
||||
|
||||
On non-x86, use one of the following instead:
|
||||
ant installer-linux
|
||||
ant installer-freebsd
|
||||
ant installer-osx
|
||||
|
||||
Run 'ant' with no arguments to see other build options.
|
||||
See INSTALL.txt or http://www.i2p2.de/download.html for installation instructions.
|
||||
|
||||
Documentation:
|
||||
http://www.i2p2.de/
|
||||
http://www.i2p2.de/how
|
||||
API: run 'ant javadoc' then start at build/javadoc/index.html
|
||||
|
||||
Latest release:
|
||||
@@ -25,7 +32,7 @@ FAQ:
|
||||
|
||||
Need help?
|
||||
IRC irc.freenode.net #i2p
|
||||
http://forum.i2p2.de/
|
||||
http://forum.i2p/
|
||||
|
||||
Licenses:
|
||||
See LICENSE.txt
|
||||
|
@@ -26,9 +26,9 @@ for i in *.config ; {
|
||||
|
||||
( cd $INST_DIR/eepsite
|
||||
if [ -f jetty.xml ] ; then
|
||||
rm jetty.xml.new
|
||||
echo "Please check ${INST_DIR}/eepsite, as there are new files."
|
||||
else
|
||||
mv jetty.xml.new jetty.xml
|
||||
find $PKG/$INSTALL_DIR/i2p -name "*.xml.new" -exec sh -c 'mv "$0" "${0/.new}"' {} \;
|
||||
fi
|
||||
)
|
||||
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#
|
||||
|
||||
BUILD=1sponge
|
||||
# INSTALL_DIR is referenced from /, don't prefix it with a '/'
|
||||
INSTALL_DIR=opt
|
||||
NAME=i2p
|
||||
ARCH=noarch
|
||||
@@ -104,7 +105,10 @@ sed "s|%INSTALL_PATH|/$INSTALL_DIR/i2p|g" runplain.sh > a
|
||||
sed "s|%SYSTEM_java_io_tmpdir|/$INSTALL_DIR/i2p|g" a > runplain.sh
|
||||
# i2prouter %INSTALL_PATH and %SYSTEM_java_io_tmpdir
|
||||
sed "s|%INSTALL_PATH|/$INSTALL_DIR/i2p|g" i2prouter > a
|
||||
sed "s|%SYSTEM_java_io_tmpdir|/$INSTALL_DIR/i2p|g" a > i2prouter
|
||||
rm i2prouter
|
||||
mv a i2prouter
|
||||
sed "s|%SYSTEM_java_io_tmpdir|/$INSTALL_DIR/i2p|g" i2prouter > a
|
||||
sed "s|#ALLOW_ROOT=true|ALLOW_ROOT=true|g" a > i2prouter
|
||||
|
||||
chmod 744 ./i2prouter
|
||||
chmod 744 ./osid
|
||||
@@ -116,7 +120,7 @@ rm -Rf ./lib/*.dll ./*.bat ./*.exe ./installer ./icons ./a postinstall.sh
|
||||
|
||||
mv $PKG/$INSTALL_DIR/i2p/*.config $PKG/install
|
||||
mv $PKG/$INSTALL_DIR/i2p/blocklist.txt $PKG/$INSTALL_DIR/i2p/blocklist.txt.new
|
||||
mv $PKG/$INSTALL_DIR/i2p/eepsite/jetty.xml $PKG/$INSTALL_DIR/i2p/eepsite/jetty.xml.new
|
||||
find $PKG/$INSTALL_DIR/i2p -name "*.xml" -exec mv {} {}.new \;
|
||||
mv $PKG/$INSTALL_DIR/i2p/eepsite/docroot/index.html $PKG/$INSTALL_DIR/i2p/eepsite/docroot/index.html.new
|
||||
mv $PKG/$INSTALL_DIR/i2p/eepsite/docroot/favicon.ico $PKG/$INSTALL_DIR/i2p/eepsite/docroot/favicon.ico.new
|
||||
sed "s|directory|/$INSTALL_DIR/i2p/|g" $CWD/doinst.sh > $PKG/install/doinst.sh
|
||||
@@ -124,7 +128,7 @@ cat $CWD/slack-desc > $PKG/install/slack-desc
|
||||
|
||||
cd $PKG
|
||||
#
|
||||
# requiredbuilder fucks up REALLY bad, and thinks java is perl?!
|
||||
# requiredbuilder messes up REALLY bad, and thinks java is perl?!
|
||||
# It also did not catch the shell requirements! BOOOOOOOOOOO! HISSSSSSSS!
|
||||
#
|
||||
# requiredbuilder -v -y -s $CWD $PKG
|
||||
|
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="net.i2p.router"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0.0">
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<!-- 3 = 1.5, 2 = 1.1, 1 = 1.0; would probably work with 1 but don't have a 1.0 SDK to test against -->
|
||||
<uses-sdk android:minSdkVersion="2" />
|
||||
<application android:label="@string/app_name">
|
||||
<activity android:name=".I2PAndroid"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTask" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
@@ -1,38 +0,0 @@
|
||||
These instructions are for a recent Android SDK (1.6 or later)..
|
||||
Should also still work with a 1.5 SDK.
|
||||
The build file is not compatible with the 1.1 SDK any more.
|
||||
|
||||
#Download the SDK from http://developer.android.com/sdk/index.html
|
||||
#Unzip the android SDK in ../../
|
||||
#So then the android tools will be in ../../android-sdk-linux_86/tools/
|
||||
#
|
||||
# now go to the available packages tab, check the box and click refresh,
|
||||
# and download an SDK Platform
|
||||
# Since I2P is configured to run on 1.1 or higher
|
||||
# (API 2) download that one. Otherwise you must change the
|
||||
# target in default.properties from android-2 to andriod-x
|
||||
# where x is the API version.
|
||||
|
||||
# create a file local.properties with the following line:
|
||||
# sdk-location=/path/to/your/android-sdk-linux_86
|
||||
|
||||
#then build the android apk file:
|
||||
ant debug
|
||||
|
||||
# Create the android 1.1 (API 2) virtual device
|
||||
# (don't make a custom hardware profile)
|
||||
# A AVD created with the 1.5 SDK will not work with the newer tools
|
||||
../../android-sdk-linux_86/tools/android create avd --name i2p --target 2
|
||||
|
||||
#then run the emulator:
|
||||
../../android-sdk-linux_86/tools/emulator -avd i2p &
|
||||
|
||||
#then wait a couple minutes until the emulator is up
|
||||
#then install the I2P app
|
||||
ant install
|
||||
|
||||
#then run the debugger
|
||||
../../android-sdk-linux_86/tools/ddms &
|
||||
|
||||
#to rebuild and reinstall to emulator:
|
||||
ant reinstall
|
@@ -1,356 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name=".I2PAndroid" default="help">
|
||||
|
||||
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||
It contain the path to the SDK. It should *NOT* be checked in in Version
|
||||
Control Systems. -->
|
||||
<property file="local.properties"/>
|
||||
|
||||
<!-- The build.properties file can be created by you and is never touched
|
||||
by the 'android' tool. This is the place to change some of the default property values
|
||||
used by the Ant rules.
|
||||
Here are some properties you may want to change/update:
|
||||
|
||||
application-package
|
||||
the name of your application package as defined in the manifest. Used by the
|
||||
'uninstall' rule.
|
||||
source-folder
|
||||
the name of the source folder. Default is 'src'.
|
||||
out-folder
|
||||
the name of the output folder. Default is 'bin'.
|
||||
|
||||
Properties related to the SDK location or the project target should be updated
|
||||
using the 'android' tool with the 'update' action.
|
||||
|
||||
This file is an integral part of the build system for your application and
|
||||
should be checked in in Version Control Systems.
|
||||
|
||||
-->
|
||||
<property file="build.properties"/>
|
||||
|
||||
<!-- The default.properties file is created and updated by the 'android' tool, as well
|
||||
as ADT.
|
||||
This file is an integral part of the build system for your application and
|
||||
should be checked in in Version Control Systems. -->
|
||||
<property file="default.properties"/>
|
||||
|
||||
<!-- Custom Android task to deal with the project target, and import the proper rules.
|
||||
This requires ant 1.6.0 or above. -->
|
||||
<path id="android.antlibs">
|
||||
<pathelement path="${sdk-location}/tools/lib/anttasks.jar" />
|
||||
<pathelement path="${sdk-location}/tools/lib/sdklib.jar" />
|
||||
<pathelement path="${sdk-location}/tools/lib/androidprefs.jar" />
|
||||
<pathelement path="${sdk-location}/tools/lib/apkbuilder.jar" />
|
||||
<pathelement path="${sdk-location}/tools/lib/jarutils.jar" />
|
||||
</path>
|
||||
|
||||
<taskdef name="setup"
|
||||
classname="com.android.ant.SetupTask"
|
||||
classpathref="android.antlibs"/>
|
||||
|
||||
<!-- Execute the Android Setup task that will setup some properties specific to the target,
|
||||
and import the rules files.
|
||||
To customize the rules, copy/paste them below the task, and disable import by setting
|
||||
the import attribute to false:
|
||||
<setup import="false" />
|
||||
|
||||
This will ensure that the properties are setup correctly but that your customized
|
||||
targets are used.
|
||||
-->
|
||||
<setup import="false" />
|
||||
|
||||
<!--
|
||||
================================================================================
|
||||
New I2P rules
|
||||
================================================================================
|
||||
-->
|
||||
|
||||
<target name="buildrouter" depends="dirs" >
|
||||
<!-- build router and core -->
|
||||
<ant dir=".." target="buildrouter" />
|
||||
|
||||
<!-- router -->
|
||||
<copy file="../build/router.jar" todir="${external-libs-folder}" />
|
||||
|
||||
<!-- core -->
|
||||
<mkdir dir="tmp" />
|
||||
<unjar src="../build/i2p.jar" dest="tmp/" />
|
||||
<delete file="tmp/net/i2p/util/LogWriter.class" />
|
||||
<!-- org.bouncycastle.crypto already in android
|
||||
but we need a little trickery because our HMac is incompatible...
|
||||
and the libs aren't in the SDK to compile against??? -->
|
||||
<jar destfile="${external-libs-folder}/crypto.jar" >
|
||||
<fileset dir="tmp/" >
|
||||
<include name="org/bouncycastle/crypto/Digest.class" />
|
||||
<include name="org/bouncycastle/crypto/Mac.class" />
|
||||
<include name="org/bouncycastle/crypto/digests/GeneralDigest.class" />
|
||||
<include name="org/bouncycastle/crypto/digests/MD5Digest.class" />
|
||||
</fileset>
|
||||
</jar>
|
||||
<delete>
|
||||
<fileset dir="tmp/" >
|
||||
<include name="org/bouncycastle/crypto/Digest.class" />
|
||||
<include name="org/bouncycastle/crypto/Mac.class" />
|
||||
<include name="org/bouncycastle/crypto/digests/GeneralDigest.class" />
|
||||
<include name="org/bouncycastle/crypto/digests/MD5Digest.class" />
|
||||
</fileset>
|
||||
</delete>
|
||||
<!--
|
||||
<delete dir="tmp/org/bouncycastle/" />
|
||||
<delete file="tmp/net/i2p/crypto/HMACGenerator.class" />
|
||||
-->
|
||||
<delete file="tmp/org/bouncycastle/" />
|
||||
<!-- lots of unneeded stuff could be deleted here -->
|
||||
<jar destfile="${external-libs-folder}/i2p.jar" basedir="tmp/" />
|
||||
|
||||
<!-- some resources -->
|
||||
<mkdir dir="res/drawable/" />
|
||||
<copy file="../installer/resources/themes/console/images/i2plogo.png" todir="res/drawable/" />
|
||||
<copy file="../installer/resources/blocklist.txt" tofile="res/raw/blocklist_txt" />
|
||||
</target>
|
||||
|
||||
<target name="hackcleanup">
|
||||
<delete file="${external-libs-folder}/crypto.jar" />
|
||||
</target>
|
||||
|
||||
<!-- fix for property name change sometime after SDK 1.5 -->
|
||||
<property name="android-jar" value="${android.jar}" />
|
||||
<property name="android-aidl" value="${android.aidl}" />
|
||||
|
||||
<!--
|
||||
================================================================================
|
||||
From here down copied from SDK platforms/android-1.1/templates/android_rules.xml
|
||||
and then modified
|
||||
================================================================================
|
||||
-->
|
||||
|
||||
<!--
|
||||
This rules file is meant to be imported by the custom Ant task:
|
||||
com.android.ant.AndroidInitTask
|
||||
|
||||
The following properties are put in place by the importing task:
|
||||
android-jar, android-aidl, aapt, aidl, and dx
|
||||
|
||||
Additionnaly, the task sets up the following classpath reference:
|
||||
android.target.classpath
|
||||
This is used by the compiler task as the boot classpath.
|
||||
-->
|
||||
|
||||
<!-- Custom tasks -->
|
||||
<taskdef name="aaptexec"
|
||||
classname="com.android.ant.AaptExecLoopTask"
|
||||
classpathref="android.antlibs"/>
|
||||
|
||||
<taskdef name="apkbuilder"
|
||||
classname="com.android.ant.ApkBuilderTask"
|
||||
classpathref="android.antlibs"/>
|
||||
|
||||
<!-- Properties -->
|
||||
|
||||
<property name="android-tools" value="${sdk-location}/tools" />
|
||||
|
||||
<!-- Input directories -->
|
||||
<property name="source-folder" value="src" />
|
||||
<property name="gen-folder" value="gen" />
|
||||
<property name="resource-folder" value="res" />
|
||||
<property name="asset-folder" value="assets" />
|
||||
<property name="source-location" value="${basedir}/${source-folder}" />
|
||||
|
||||
<!-- folder for the 3rd party java libraries -->
|
||||
<property name="external-libs-folder" value="libs" />
|
||||
|
||||
<!-- folder for the native libraries -->
|
||||
<property name="native-libs-folder" value="libs" />
|
||||
|
||||
<!-- Output directories -->
|
||||
<property name="gen-folder" value="gen" />
|
||||
<property name="out-folder" value="bin" />
|
||||
<property name="out-classes" value="${out-folder}/classes" />
|
||||
<property name="out-classes-location" value="${basedir}/${out-classes}"/>
|
||||
<!-- out folders for a parent project if this project is an instrumentation project -->
|
||||
<property name="main-out-folder" value="../${out-folder}" />
|
||||
<property name="main-out-classes" value="${main-out-folder}/classes"/>
|
||||
|
||||
<!-- Intermediate files -->
|
||||
<property name="dex-file" value="classes.dex" />
|
||||
<property name="intermediate-dex" value="${out-folder}/${dex-file}" />
|
||||
<!-- dx does not properly support incorrect / or \ based on the platform
|
||||
and Ant cannot convert them because the parameter is not a valid path.
|
||||
Because of this we have to compute different paths depending on the platform. -->
|
||||
<condition property="intermediate-dex-location"
|
||||
value="${basedir}\${intermediate-dex}"
|
||||
else="${basedir}/${intermediate-dex}" >
|
||||
<os family="windows"/>
|
||||
</condition>
|
||||
|
||||
<!-- The final package file to generate -->
|
||||
<property name="out-debug-package" value="${out-folder}/${ant.project.name}-debug.apk"/>
|
||||
|
||||
<!-- Tools -->
|
||||
<condition property="exe" value=".exe" else=""><os family="windows"/></condition>
|
||||
<property name="adb" value="${android-tools}/adb${exe}"/>
|
||||
|
||||
<!-- rules -->
|
||||
|
||||
<!-- Create the output directories if they don't exist yet. -->
|
||||
<target name="dirs">
|
||||
<echo>Creating output directories if needed...</echo>
|
||||
<mkdir dir="${resource-folder}" />
|
||||
<mkdir dir="${external-libs-folder}" />
|
||||
<mkdir dir="${gen-folder}" />
|
||||
<mkdir dir="${out-folder}" />
|
||||
<mkdir dir="${out-classes}" />
|
||||
</target>
|
||||
|
||||
<!-- Generate the R.java file for this project's resources. -->
|
||||
<target name="resource-src" depends="dirs">
|
||||
<echo>Generating R.java / Manifest.java from the resources...</echo>
|
||||
<exec executable="${aapt}" failonerror="true">
|
||||
<arg value="package" />
|
||||
<arg value="-m" />
|
||||
<arg value="-J" />
|
||||
<arg path="${gen-folder}" />
|
||||
<arg value="-M" />
|
||||
<arg path="AndroidManifest.xml" />
|
||||
<arg value="-S" />
|
||||
<arg path="${resource-folder}" />
|
||||
<arg value="-I" />
|
||||
<arg path="${android-jar}" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<!-- Generate java classes from .aidl files. -->
|
||||
<target name="aidl" depends="dirs">
|
||||
<echo>Compiling aidl files into Java classes...</echo>
|
||||
<apply executable="${aidl}" failonerror="true">
|
||||
<arg value="-p${android-aidl}" />
|
||||
<arg value="-I${source-folder}" />
|
||||
<arg value="-o${gen-folder}" />
|
||||
<fileset dir="${source-folder}">
|
||||
<include name="**/*.aidl"/>
|
||||
</fileset>
|
||||
</apply>
|
||||
</target>
|
||||
|
||||
<!-- Compile this project's .java files into .class files. -->
|
||||
<!-- I2P add buildrouter -->
|
||||
<target name="compile" depends="buildrouter, resource-src, aidl">
|
||||
<javac encoding="ascii" target="1.5" debug="true" extdirs=""
|
||||
destdir="${out-classes}"
|
||||
bootclasspathref="android.target.classpath">
|
||||
<src path="${source-folder}" />
|
||||
<src path="${gen-folder}" />
|
||||
<classpath>
|
||||
<fileset dir="${external-libs-folder}" includes="*.jar"/>
|
||||
<pathelement path="${main-out-classes}"/>
|
||||
</classpath>
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<!-- Convert this project's .class files into .dex files. -->
|
||||
<!-- I2P add hackcleanup -->
|
||||
<target name="dex" depends="compile, hackcleanup">
|
||||
<echo>Converting compiled files and external libraries into ${out-folder}/${dex-file}...</echo>
|
||||
<apply executable="${dx}" failonerror="true" parallel="true">
|
||||
<!-- I2P this is a bad sign that we need this -->
|
||||
<arg value="-JXmx256m" />
|
||||
<arg value="--dex" />
|
||||
<arg value="--output=${intermediate-dex-location}" />
|
||||
<arg path="${out-classes-location}" />
|
||||
<fileset dir="${external-libs-folder}" includes="*.jar"/>
|
||||
</apply>
|
||||
</target>
|
||||
|
||||
<!-- Put the project's resources into the output package file
|
||||
This actually can create multiple resource package in case
|
||||
Some custom apk with specific configuration have been
|
||||
declared in default.properties.
|
||||
-->
|
||||
<target name="package-resources">
|
||||
<echo>Packaging resources</echo>
|
||||
<aaptexec executable="${aapt}"
|
||||
command="package"
|
||||
manifest="AndroidManifest.xml"
|
||||
resources="${resource-folder}"
|
||||
assets="${asset-folder}"
|
||||
androidjar="${android-jar}"
|
||||
outfolder="${out-folder}"
|
||||
basename="${ant.project.name}" />
|
||||
</target>
|
||||
|
||||
<!-- Package the application and sign it with a debug key.
|
||||
This is the default target when building. It is used for debug. -->
|
||||
<target name="debug" depends="dex, package-resources">
|
||||
<apkbuilder
|
||||
outfolder="${out-folder}"
|
||||
basename="${ant.project.name}"
|
||||
signed="true"
|
||||
verbose="false">
|
||||
<file path="${intermediate-dex}" />
|
||||
<sourcefolder path="${source-folder}" />
|
||||
<jarfolder path="${external-libs-folder}" />
|
||||
<nativefolder path="${native-libs-folder}" />
|
||||
</apkbuilder>
|
||||
</target>
|
||||
|
||||
<!-- Package the application without signing it.
|
||||
This allows for the application to be signed later with an official publishing key. -->
|
||||
<target name="release" depends="dex, package-resources">
|
||||
<apkbuilder
|
||||
outfolder="${out-folder}"
|
||||
basename="${ant.project.name}"
|
||||
signed="false"
|
||||
verbose="false">
|
||||
<file path="${intermediate-dex}" />
|
||||
<sourcefolder path="${source-folder}" />
|
||||
<jarfolder path="${external-libs-folder}" />
|
||||
<nativefolder path="${native-libs-folder}" />
|
||||
</apkbuilder>
|
||||
<echo>All generated packages need to be signed with jarsigner before they are published.</echo>
|
||||
</target>
|
||||
|
||||
<!-- Install the package on the default emulator -->
|
||||
<target name="install" depends="debug">
|
||||
<echo>Installing ${out-debug-package} onto default emulator...</echo>
|
||||
<exec executable="${adb}" failonerror="true">
|
||||
<arg value="install" />
|
||||
<arg path="${out-debug-package}" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="reinstall" depends="debug">
|
||||
<echo>Installing ${out-debug-package} onto default emulator...</echo>
|
||||
<exec executable="${adb}" failonerror="true">
|
||||
<arg value="install" />
|
||||
<arg value="-r" />
|
||||
<arg path="${out-debug-package}" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<!-- Uinstall the package from the default emulator -->
|
||||
<target name="uninstall">
|
||||
<echo>Uninstalling ${application-package} from the default emulator...</echo>
|
||||
<exec executable="${adb}" failonerror="true">
|
||||
<arg value="uninstall" />
|
||||
<arg path="${application-package}" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="help">
|
||||
<!-- displays starts at col 13
|
||||
|13 80| -->
|
||||
<echo>Android Ant Build. Available targets:</echo>
|
||||
<echo> help: Displays this help.</echo>
|
||||
<echo> debug: Builds the application and sign it with a debug key.</echo>
|
||||
<echo> release: Builds the application. The generated apk file must be</echo>
|
||||
<echo> signed before it is published.</echo>
|
||||
<echo> install: Installs the debug package onto a running emulator or</echo>
|
||||
<echo> device. This can only be used if the application has </echo>
|
||||
<echo> not yet been installed.</echo>
|
||||
<echo> reinstall: Installs the debug package on a running emulator or</echo>
|
||||
<echo> device that already has the application.</echo>
|
||||
<echo> The signatures must match.</echo>
|
||||
<echo> uninstall: uninstall the application from a running emulator or</echo>
|
||||
<echo> device.</echo>
|
||||
</target>
|
||||
</project>
|
@@ -1,11 +0,0 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system use,
|
||||
# "build.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
|
||||
# Project target.
|
||||
target=android-2
|
@@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World, I2PAndroid"
|
||||
/>
|
||||
<ImageView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/i2plogo"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
@@ -1,3 +0,0 @@
|
||||
logger.defaultLevel=INFO
|
||||
logger.record.net.i2p.router.transport.FIFOBandwidthRefiller=ERROR
|
||||
logger.record.net.i2p.stat.Rate=ERROR
|
@@ -1,22 +0,0 @@
|
||||
# initial router.config
|
||||
# temp directory
|
||||
i2p.dir.temp=/data/data/net.i2p.router/files/tmp
|
||||
i2p.dir.pid=/data/data/net.i2p.router/files/tmp
|
||||
# save memory
|
||||
prng.buffers=2
|
||||
router.decayingBloomFilterM=20
|
||||
stat.full=false
|
||||
i2np.udp.maxConnections=30
|
||||
# no I2CP
|
||||
i2p.dummyClientFacade=true
|
||||
# for now
|
||||
#i2np.ntcp.enable=false
|
||||
#
|
||||
# UDP crashes the JVM, don't know why
|
||||
#
|
||||
i2np.udp.enable=false
|
||||
# no COMM at all!!!
|
||||
#i2p.vmCommSystem=true
|
||||
# not on android
|
||||
i2np.upnp.enable=false
|
||||
routerconsole.geoip.enable=false
|
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">I2PAndroid</string>
|
||||
</resources>
|
@@ -1,142 +0,0 @@
|
||||
package net.i2p.router;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.Resources.NotFoundException;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.router.Router;
|
||||
import net.i2p.router.RouterLaunch;
|
||||
// import net.i2p.util.NativeBigInteger;
|
||||
|
||||
public class I2PAndroid extends Activity
|
||||
{
|
||||
static Context _context;
|
||||
private static final String DIR = "/data/data/net.i2p.router/files";
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.main);
|
||||
|
||||
_context = this; // Activity extends Context
|
||||
debugStuff();
|
||||
initialize();
|
||||
// 300ms per run
|
||||
// 5x slower than java on my server and 50x slower than native on my server
|
||||
// NativeBigInteger.main(null);
|
||||
}
|
||||
|
||||
public void onRestart()
|
||||
{
|
||||
System.err.println("onRestart called");
|
||||
super.onRestart();
|
||||
}
|
||||
|
||||
public void onStart()
|
||||
{
|
||||
System.err.println("onStart called");
|
||||
super.onStart();
|
||||
RouterLaunch.main(null);
|
||||
System.err.println("Router.main finished");
|
||||
}
|
||||
|
||||
public void onResume()
|
||||
{
|
||||
System.err.println("onResume called");
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
public void onPause()
|
||||
{
|
||||
System.err.println("onPause called");
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
public void onStop()
|
||||
{
|
||||
System.err.println("onStop called");
|
||||
super.onStop();
|
||||
|
||||
// from routerconsole ContextHelper
|
||||
List contexts = RouterContext.listContexts();
|
||||
if ( (contexts == null) || (contexts.isEmpty()) )
|
||||
throw new IllegalStateException("No contexts. This is usually because the router is either starting up or shutting down.");
|
||||
RouterContext ctx = (RouterContext)contexts.get(0);
|
||||
|
||||
// shutdown() doesn't return so use shutdownGracefully()
|
||||
ctx.router().shutdownGracefully(Router.EXIT_HARD);
|
||||
System.err.println("shutdown complete");
|
||||
}
|
||||
|
||||
public void onDestroy()
|
||||
{
|
||||
System.err.println("onDestroy called");
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
public static Context getContext() {
|
||||
return _context;
|
||||
}
|
||||
|
||||
private void debugStuff() {
|
||||
System.err.println("java.io.tmpdir" + ": " + System.getProperty("java.io.tmpdir"));
|
||||
System.err.println("java.vendor" + ": " + System.getProperty("java.vendor"));
|
||||
System.err.println("java.version" + ": " + System.getProperty("java.version"));
|
||||
System.err.println("os.arch" + ": " + System.getProperty("os.arch"));
|
||||
System.err.println("os.name" + ": " + System.getProperty("os.name"));
|
||||
System.err.println("os.version" + ": " + System.getProperty("os.version"));
|
||||
System.err.println("user.dir" + ": " + System.getProperty("user.dir"));
|
||||
System.err.println("user.home" + ": " + System.getProperty("user.home"));
|
||||
System.err.println("user.name" + ": " + System.getProperty("user.name"));
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
// Until we can edit the router.config on the device,
|
||||
// copy it from the resource every time.
|
||||
// File f = new I2PFile("router.config");
|
||||
// if (!f.exists()) {
|
||||
copyResourceToFile(R.raw.router_config, "router.config");
|
||||
copyResourceToFile(R.raw.logger_config, "logger.config");
|
||||
copyResourceToFile(R.raw.blocklist_txt, "blocklist.txt");
|
||||
// }
|
||||
|
||||
// Set up the locations so Router and WorkingDir can find them
|
||||
System.setProperty("i2p.dir.base", DIR);
|
||||
System.setProperty("i2p.dir.config", DIR);
|
||||
System.setProperty("wrapper.logfile", DIR + "/wrapper.log");
|
||||
}
|
||||
|
||||
private void copyResourceToFile(int resID, String f) {
|
||||
InputStream in = null;
|
||||
FileOutputStream out = null;
|
||||
|
||||
System.err.println("Creating file " + f + " from resource");
|
||||
byte buf[] = new byte[4096];
|
||||
try {
|
||||
// Context methods
|
||||
in = getResources().openRawResource(resID);
|
||||
out = openFileOutput(f, 0);
|
||||
|
||||
int read = 0;
|
||||
while ( (read = in.read(buf)) != -1)
|
||||
out.write(buf, 0, read);
|
||||
|
||||
} catch (IOException ioe) {
|
||||
} catch (Resources.NotFoundException nfe) {
|
||||
} finally {
|
||||
if (in != null) try { in.close(); } catch (IOException ioe) {}
|
||||
if (out != null) try { out.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,163 +0,0 @@
|
||||
package net.i2p.util;
|
||||
|
||||
/*
|
||||
* public domain
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* bridge to android logging
|
||||
*
|
||||
* @author zzz
|
||||
*/
|
||||
class LogWriter implements Runnable {
|
||||
private final static long CONFIG_READ_ITERVAL = 10 * 1000;
|
||||
private long _lastReadConfig = 0;
|
||||
private long _numBytesInCurrentFile = 0;
|
||||
private OutputStream _currentOut; // = System.out
|
||||
private int _rotationNum = -1;
|
||||
private String _logFilenamePattern;
|
||||
private File _currentFile;
|
||||
private LogManager _manager;
|
||||
|
||||
private boolean _write;
|
||||
|
||||
private LogWriter() { // nop
|
||||
}
|
||||
|
||||
public LogWriter(LogManager manager) {
|
||||
_manager = manager;
|
||||
}
|
||||
|
||||
public void stopWriting() {
|
||||
_write = false;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
_write = true;
|
||||
try {
|
||||
while (_write) {
|
||||
flushRecords();
|
||||
rereadConfig();
|
||||
}
|
||||
System.err.println("Done writing");
|
||||
} catch (Exception e) {
|
||||
System.err.println("Error writing the logs: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void flushRecords() { flushRecords(true); }
|
||||
public void flushRecords(boolean shouldWait) {
|
||||
try {
|
||||
List records = _manager._removeAll();
|
||||
if (records == null) return;
|
||||
for (int i = 0; i < records.size(); i++) {
|
||||
LogRecord rec = (LogRecord) records.get(i);
|
||||
writeRecord(rec);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
} finally {
|
||||
if (shouldWait) {
|
||||
try {
|
||||
synchronized (this) {
|
||||
this.wait(10*1000);
|
||||
}
|
||||
} catch (InterruptedException ie) { // nop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String currentFile() {
|
||||
return _currentFile != null ? _currentFile.getAbsolutePath() : "uninitialized";
|
||||
}
|
||||
|
||||
private void rereadConfig() {
|
||||
long now = Clock.getInstance().now();
|
||||
if (now - _lastReadConfig > CONFIG_READ_ITERVAL) {
|
||||
_manager.rereadConfig();
|
||||
_lastReadConfig = now;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeRecord(LogRecord rec) {
|
||||
if (rec.getThrowable() == null)
|
||||
log(rec.getPriority(), rec.getSource(), rec.getSourceName(), rec.getThreadName(), rec.getMessage());
|
||||
else
|
||||
log(rec.getPriority(), rec.getSource(), rec.getSourceName(), rec.getThreadName(), rec.getMessage(), rec.getThrowable());
|
||||
}
|
||||
|
||||
public void log(int priority, Class src, String name, String threadName, String msg) {
|
||||
if (src != null) {
|
||||
String tag = src.getName();
|
||||
int dot = tag.lastIndexOf(".");
|
||||
if (dot >= 0)
|
||||
tag = tag.substring(dot + 1);
|
||||
android.util.Log.println(toAndroidLevel(priority),
|
||||
tag,
|
||||
'[' + threadName + "] " + msg);
|
||||
} else if (name != null)
|
||||
android.util.Log.println(toAndroidLevel(priority),
|
||||
name,
|
||||
'[' + threadName + "] " + msg);
|
||||
else
|
||||
android.util.Log.println(toAndroidLevel(priority),
|
||||
threadName, msg);
|
||||
}
|
||||
|
||||
public void log(int priority, Class src, String name, String threadName, String msg, Throwable t) {
|
||||
if (src != null) {
|
||||
String tag = src.getName();
|
||||
int dot = tag.lastIndexOf(".");
|
||||
if (dot >= 0)
|
||||
tag = tag.substring(dot + 1);
|
||||
android.util.Log.println(toAndroidLevel(priority),
|
||||
tag,
|
||||
'[' + threadName + "] " + msg +
|
||||
' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
|
||||
} else if (name != null)
|
||||
android.util.Log.println(toAndroidLevel(priority),
|
||||
name,
|
||||
'[' + threadName + "] " + msg +
|
||||
' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
|
||||
else
|
||||
android.util.Log.println(toAndroidLevel(priority),
|
||||
threadName,
|
||||
msg + ' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
|
||||
}
|
||||
|
||||
private static int toAndroidLevel(int level) {
|
||||
switch (level) {
|
||||
case Log.DEBUG:
|
||||
return android.util.Log.DEBUG;
|
||||
case Log.INFO:
|
||||
return android.util.Log.INFO;
|
||||
case Log.WARN:
|
||||
return android.util.Log.WARN;
|
||||
case Log.ERROR:
|
||||
case Log.CRIT:
|
||||
default:
|
||||
return android.util.Log.ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String replace(String pattern, int num) {
|
||||
char c[] = pattern.toCharArray();
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int i = 0; i < c.length; i++) {
|
||||
if ( (c[i] != '#') && (c[i] != '@') )
|
||||
buf.append(c[i]);
|
||||
else
|
||||
buf.append(num);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
@@ -1,17 +1,9 @@
|
||||
/**
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
* Everyone is permitted to copy and distribute verbatim or modified
|
||||
* copies of this license document, and changing it is allowed as long
|
||||
* as the name is changed.
|
||||
*
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
*
|
||||
* 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
*
|
||||
* See...
|
||||
*
|
||||
@@ -19,7 +11,7 @@
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and liscense questions.
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB.Demos.echo.echoclient;
|
||||
|
||||
@@ -55,7 +47,7 @@ public class Main {
|
||||
// exit on anything not legal
|
||||
break;
|
||||
}
|
||||
c = (char)(b & 0x7f); // We only really give a fuck about ASCII
|
||||
c = (char)(b & 0x7f); // We only care about ASCII
|
||||
S = new String(S + c);
|
||||
}
|
||||
return S;
|
||||
|
@@ -1,17 +1,9 @@
|
||||
/**
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
* Everyone is permitted to copy and distribute verbatim or modified
|
||||
* copies of this license document, and changing it is allowed as long
|
||||
* as the name is changed.
|
||||
*
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
*
|
||||
* 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
*
|
||||
* See...
|
||||
*
|
||||
@@ -19,7 +11,7 @@
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and liscense questions.
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB.Demos.echo.echoserver;
|
||||
|
||||
@@ -52,7 +44,7 @@ public class Main {
|
||||
if(b < 20) {
|
||||
break;
|
||||
}
|
||||
c = (char)(b & 0x7f); // We only really give a fuck about ASCII
|
||||
c = (char)(b & 0x7f); // We only care about ASCII
|
||||
S = new String(S + c);
|
||||
}
|
||||
return S;
|
||||
|
@@ -71,6 +71,7 @@
|
||||
nbproject/build-impl.xml file.
|
||||
|
||||
-->
|
||||
|
||||
<target depends="jar" description="Build BOB into a SINGLE JAR." name="onejar">
|
||||
<!-- Make needed working dirs -->
|
||||
<mkdir dir="${dist.dir}/lib" />
|
||||
|
@@ -26,7 +26,7 @@ dist.dir=dist
|
||||
dist.jar=${dist.dir}/BOB.jar
|
||||
dist.javadoc.dir=${dist.dir}/javadoc
|
||||
endorsed.classpath=
|
||||
excludes=
|
||||
excludes=**/*.html,**/*.txt
|
||||
file.reference.build-javadoc=../../i2p.i2p/build/javadoc
|
||||
file.reference.i2p.jar=../../core/java/build/i2p.jar
|
||||
file.reference.i2ptunnel.jar=../i2ptunnel/java/build/i2ptunnel.jar
|
||||
|
@@ -1,17 +1,9 @@
|
||||
/**
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
* Everyone is permitted to copy and distribute verbatim or modified
|
||||
* copies of this license document, and changing it is allowed as long
|
||||
* as the name is changed.
|
||||
*
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
*
|
||||
* 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
*
|
||||
* See...
|
||||
*
|
||||
@@ -19,7 +11,7 @@
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and liscense questions.
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
@@ -38,7 +30,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.client.streaming.RetransmissionTimer;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SimpleScheduler;
|
||||
import net.i2p.util.SimpleTimer2;
|
||||
@@ -116,7 +107,6 @@ import net.i2p.util.SimpleTimer2;
|
||||
*/
|
||||
public class BOB {
|
||||
|
||||
private final static Log _log = new Log(BOB.class);
|
||||
public final static String PROP_CONFIG_LOCATION = "BOB.config";
|
||||
public final static String PROP_BOB_PORT = "BOB.port";
|
||||
public final static String PROP_BOB_HOST = "BOB.host";
|
||||
@@ -138,7 +128,7 @@ public class BOB {
|
||||
*/
|
||||
public static void info(String arg) {
|
||||
System.out.println("INFO:" + arg);
|
||||
_log.info(arg);
|
||||
(new Log(BOB.class)).info(arg);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,7 +138,7 @@ public class BOB {
|
||||
*/
|
||||
public static void warn(String arg) {
|
||||
System.out.println("WARNING:" + arg);
|
||||
_log.warn(arg);
|
||||
(new Log(BOB.class)).warn(arg);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,7 +148,7 @@ public class BOB {
|
||||
*/
|
||||
public static void error(String arg) {
|
||||
System.out.println("ERROR: " + arg);
|
||||
_log.error(arg);
|
||||
(new Log(BOB.class)).error(arg);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,12 +172,11 @@ public class BOB {
|
||||
// Re-reading the config file in each thread is pretty damn stupid.
|
||||
String configLocation = System.getProperty(PROP_CONFIG_LOCATION, "bob.config");
|
||||
// This is here just to ensure there is no interference with our threadgroups.
|
||||
RetransmissionTimer Y = RetransmissionTimer.getInstance();
|
||||
SimpleScheduler Y1 = SimpleScheduler.getInstance();
|
||||
SimpleTimer2 Y2 = SimpleTimer2.getInstance();
|
||||
i = Y.hashCode();
|
||||
i = Y1.hashCode();
|
||||
i = Y2.hashCode();
|
||||
Log _log = new Log(BOB.class);
|
||||
try {
|
||||
{
|
||||
File cfg = new File(configLocation);
|
||||
@@ -263,6 +252,7 @@ public class BOB {
|
||||
|
||||
i = 0;
|
||||
boolean g = false;
|
||||
spin.set(true);
|
||||
try {
|
||||
info("BOB is now running.");
|
||||
listener = new ServerSocket(Integer.parseInt(props.getProperty(PROP_BOB_PORT)), 10, InetAddress.getByName(props.getProperty(PROP_BOB_HOST)));
|
||||
|
@@ -1,17 +1,9 @@
|
||||
/**
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
* Everyone is permitted to copy and distribute verbatim or modified
|
||||
* copies of this license document, and changing it is allowed as long
|
||||
* as the name is changed.
|
||||
*
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
*
|
||||
* 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
*
|
||||
* See...
|
||||
*
|
||||
@@ -19,7 +11,7 @@
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and liscense questions.
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
@@ -29,6 +21,7 @@ import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintStream;
|
||||
import java.net.Socket;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -53,7 +46,7 @@ public class DoCMDS implements Runnable {
|
||||
|
||||
// FIX ME
|
||||
// I need a better way to do versioning, but this will do for now.
|
||||
public static final String BMAJ = "00", BMIN = "00", BREV = "0F", BEXT = "";
|
||||
public static final String BMAJ = "00", BMIN = "00", BREV = "10", BEXT = "";
|
||||
public static final String BOBversion = BMAJ + "." + BMIN + "." + BREV + BEXT;
|
||||
private Socket server;
|
||||
private Properties props;
|
||||
@@ -399,7 +392,7 @@ public class DoCMDS implements Runnable {
|
||||
*/
|
||||
private boolean is64ok(String data) {
|
||||
try {
|
||||
Destination x = new Destination(data);
|
||||
new Destination(data);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
@@ -434,7 +427,7 @@ public class DoCMDS implements Runnable {
|
||||
if (token.countTokens() != 0) {
|
||||
Command = token.nextToken();
|
||||
Command =
|
||||
Command.toLowerCase();
|
||||
Command.toLowerCase(Locale.US);
|
||||
if (token.countTokens() != 0) {
|
||||
Arg = token.nextToken();
|
||||
} else {
|
||||
|
@@ -1,17 +1,9 @@
|
||||
/**
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
* Everyone is permitted to copy and distribute verbatim or modified
|
||||
* copies of this license document, and changing it is allowed as long
|
||||
* as the name is changed.
|
||||
*
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
*
|
||||
* 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
*
|
||||
* See...
|
||||
*
|
||||
@@ -19,7 +11,7 @@
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and liscense questions.
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
@@ -41,7 +33,6 @@ public class I2Plistener implements Runnable {
|
||||
|
||||
private NamedDB info, database;
|
||||
private Log _log;
|
||||
// private int tgwatch;
|
||||
public I2PSocketManager socketManager;
|
||||
public I2PServerSocket serverSocket;
|
||||
private AtomicBoolean lives;
|
||||
@@ -95,7 +86,7 @@ public class I2Plistener implements Runnable {
|
||||
|
||||
}
|
||||
} catch (I2PException e) {
|
||||
// bad shit
|
||||
// bad stuff
|
||||
System.out.println("Exception " + e);
|
||||
}
|
||||
} finally {
|
||||
@@ -103,7 +94,7 @@ public class I2Plistener implements Runnable {
|
||||
serverSocket.close();
|
||||
} catch (I2PException ex) {
|
||||
}
|
||||
// System.out.println("I2Plistener: Close");
|
||||
// System.out.println("I2Plistener: Close");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,17 +1,9 @@
|
||||
/**
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
* Everyone is permitted to copy and distribute verbatim or modified
|
||||
* copies of this license document, and changing it is allowed as long
|
||||
* as the name is changed.
|
||||
*
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
*
|
||||
* 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
*
|
||||
* See...
|
||||
*
|
||||
@@ -19,7 +11,7 @@
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and liscense questions.
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
|
@@ -1,17 +1,9 @@
|
||||
/**
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
* Everyone is permitted to copy and distribute verbatim or modified
|
||||
* copies of this license document, and changing it is allowed as long
|
||||
* as the name is changed.
|
||||
*
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
*
|
||||
* 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
*
|
||||
* See...
|
||||
*
|
||||
@@ -19,7 +11,7 @@
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and liscense questions.
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
|
@@ -1,17 +1,9 @@
|
||||
/**
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
* Everyone is permitted to copy and distribute verbatim or modified
|
||||
* copies of this license document, and changing it is allowed as long
|
||||
* as the name is changed.
|
||||
*
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
*
|
||||
* 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
*
|
||||
* See...
|
||||
*
|
||||
@@ -19,7 +11,7 @@
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and liscense questions.
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
@@ -108,16 +100,6 @@ public class MUXlisten implements Runnable {
|
||||
this.listener = new ServerSocket(port, backlog, host);
|
||||
}
|
||||
socketManager = I2PSocketManagerFactory.createManager(prikey, Q);
|
||||
// I2PException, IOException, RuntimeException
|
||||
// To bad we can't just catch and enumerate....
|
||||
// } catch (I2PException e) {
|
||||
// Something went bad.
|
||||
// this.database.getWriteLock();
|
||||
// this.info.getWriteLock();
|
||||
// this.info.add("STARTING", new Boolean(false));
|
||||
// this.info.releaseWriteLock();
|
||||
// this.database.releaseWriteLock();
|
||||
// throw new I2PException(e);
|
||||
} catch (IOException e) {
|
||||
// Something went bad.
|
||||
this.database.getWriteLock();
|
||||
@@ -194,7 +176,6 @@ public class MUXlisten implements Runnable {
|
||||
lock.set(false);
|
||||
return;
|
||||
}
|
||||
// socketManager.addDisconnectListener(new DisconnectListener());
|
||||
lives.set(true);
|
||||
lock.set(false);
|
||||
quit:
|
||||
@@ -313,14 +294,14 @@ public class MUXlisten implements Runnable {
|
||||
|
||||
// Hopefully nuke stuff here...
|
||||
{
|
||||
String boner = tg.getName();
|
||||
String groupName = tg.getName();
|
||||
try {
|
||||
_log.warn("destroySocketManager " + boner);
|
||||
_log.warn("destroySocketManager " + groupName);
|
||||
socketManager.destroySocketManager();
|
||||
_log.warn("destroySocketManager Successful" + boner);
|
||||
_log.warn("destroySocketManager Successful" + groupName);
|
||||
} catch (Exception e) {
|
||||
// nop
|
||||
_log.warn("destroySocketManager Failed" + boner);
|
||||
_log.warn("destroySocketManager Failed" + groupName);
|
||||
_log.warn(e.toString());
|
||||
}
|
||||
}
|
||||
@@ -344,26 +325,25 @@ public class MUXlisten implements Runnable {
|
||||
|
||||
// Wait around till all threads are collected.
|
||||
if (tg != null) {
|
||||
String boner = tg.getName();
|
||||
// System.out.println("BOB: MUXlisten: Starting thread collection for: " + boner);
|
||||
_log.warn("BOB: MUXlisten: Starting thread collection for: " + boner);
|
||||
// tg.interrupt(); // give my stuff a small smack again.
|
||||
String groupName = tg.getName();
|
||||
// System.out.println("BOB: MUXlisten: Starting thread collection for: " + groupName);
|
||||
_log.warn("BOB: MUXlisten: Starting thread collection for: " + groupName);
|
||||
if (tg.activeCount() + tg.activeGroupCount() != 0) {
|
||||
// visit(tg, 0, boner);
|
||||
// visit(tg, 0, groupName);
|
||||
int foo = tg.activeCount() + tg.activeGroupCount();
|
||||
// hopefully no longer needed!
|
||||
// int bar = lives;
|
||||
// System.out.println("BOB: MUXlisten: Waiting on threads for " + boner);
|
||||
// System.out.println("\nBOB: MUXlisten: ThreadGroup dump BEGIN " + boner);
|
||||
// visit(tg, 0, boner);
|
||||
// System.out.println("BOB: MUXlisten: ThreadGroup dump END " + boner + "\n");
|
||||
// System.out.println("BOB: MUXlisten: Waiting on threads for " + groupName);
|
||||
// System.out.println("\nBOB: MUXlisten: ThreadGroup dump BEGIN " + groupName);
|
||||
// visit(tg, 0, groupName);
|
||||
// System.out.println("BOB: MUXlisten: ThreadGroup dump END " + groupName + "\n");
|
||||
// Happily spin forever :-(
|
||||
while (foo != 0) {
|
||||
foo = tg.activeCount() + tg.activeGroupCount();
|
||||
// if (lives != bar && lives != 0) {
|
||||
// System.out.println("\nBOB: MUXlisten: ThreadGroup dump BEGIN " + boner);
|
||||
// visit(tg, 0, boner);
|
||||
// System.out.println("BOB: MUXlisten: ThreadGroup dump END " + boner + "\n");
|
||||
// System.out.println("\nBOB: MUXlisten: ThreadGroup dump BEGIN " + groupName);
|
||||
// visit(tg, 0, groupName);
|
||||
// System.out.println("BOB: MUXlisten: ThreadGroup dump END " + groupName + "\n");
|
||||
// }
|
||||
// bar = lives;
|
||||
try {
|
||||
@@ -373,8 +353,8 @@ public class MUXlisten implements Runnable {
|
||||
}
|
||||
}
|
||||
}
|
||||
// System.out.println("BOB: MUXlisten: Threads went away. Success: " + boner);
|
||||
_log.warn("BOB: MUXlisten: Threads went away. Success: " + boner);
|
||||
// System.out.println("BOB: MUXlisten: Threads went away. Success: " + groupName);
|
||||
_log.warn("BOB: MUXlisten: Threads went away. Success: " + groupName);
|
||||
tg.destroy();
|
||||
// Zap reference to the ThreadGroup so the JVM can GC it.
|
||||
tg = null;
|
||||
|
@@ -1,17 +1,9 @@
|
||||
/**
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
* Everyone is permitted to copy and distribute verbatim or modified
|
||||
* copies of this license document, and changing it is allowed as long
|
||||
* as the name is changed.
|
||||
*
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
*
|
||||
* 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
*
|
||||
* See...
|
||||
*
|
||||
@@ -19,11 +11,10 @@
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and liscense questions.
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
import net.i2p.client.streaming.RetransmissionTimer;
|
||||
import net.i2p.util.SimpleScheduler;
|
||||
import net.i2p.util.SimpleTimer2;
|
||||
|
||||
@@ -40,7 +31,6 @@ public class Main {
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// THINK THINK THINK THINK THINK THINK
|
||||
RetransmissionTimer Y = RetransmissionTimer.getInstance();
|
||||
SimpleScheduler Y1 = SimpleScheduler.getInstance();
|
||||
SimpleTimer2 Y2 = SimpleTimer2.getInstance();
|
||||
|
||||
@@ -48,6 +38,5 @@ public class Main {
|
||||
|
||||
Y2.stop();
|
||||
Y1.stop();
|
||||
Y.stop();
|
||||
}
|
||||
}
|
||||
|
@@ -1,17 +1,9 @@
|
||||
/**
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
* Everyone is permitted to copy and distribute verbatim or modified
|
||||
* copies of this license document, and changing it is allowed as long
|
||||
* as the name is changed.
|
||||
*
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
*
|
||||
* 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
*
|
||||
* See...
|
||||
*
|
||||
@@ -19,7 +11,7 @@
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and liscense questions.
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
|
@@ -1,17 +1,9 @@
|
||||
/**
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
* Everyone is permitted to copy and distribute verbatim or modified
|
||||
* copies of this license document, and changing it is allowed as long
|
||||
* as the name is changed.
|
||||
*
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
*
|
||||
* 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
*
|
||||
* See...
|
||||
*
|
||||
@@ -19,7 +11,7 @@
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and liscense questions.
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
@@ -95,14 +87,9 @@ public class TCPio implements Runnable {
|
||||
if (b > 0) {
|
||||
Aout.write(a, 0, b);
|
||||
} else if (b == 0) {
|
||||
// Will this die? We'll see.
|
||||
while(Ain.available() == 0) {
|
||||
Thread.sleep(20);
|
||||
}
|
||||
// Thread.yield(); // this should act like a mini sleep.
|
||||
// if (Ain.available() == 0) {
|
||||
// Thread.sleep(10);
|
||||
// }
|
||||
} else {
|
||||
/* according to the specs:
|
||||
*
|
||||
|
@@ -1,17 +1,9 @@
|
||||
/**
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
* Everyone is permitted to copy and distribute verbatim or modified
|
||||
* copies of this license document, and changing it is allowed as long
|
||||
* as the name is changed.
|
||||
*
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
*
|
||||
* 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
*
|
||||
* See...
|
||||
*
|
||||
@@ -19,7 +11,7 @@
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and liscense questions.
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
@@ -27,8 +19,6 @@ import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketTimeoutException;
|
||||
// import net.i2p.client.I2PSession;
|
||||
// import net.i2p.client.I2PSessionException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import net.i2p.client.streaming.I2PServerSocket;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
|
@@ -1,17 +1,9 @@
|
||||
/**
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
* Everyone is permitted to copy and distribute verbatim or modified
|
||||
* copies of this license document, and changing it is allowed as long
|
||||
* as the name is changed.
|
||||
*
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
*
|
||||
* 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
*
|
||||
* See...
|
||||
*
|
||||
@@ -19,7 +11,7 @@
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and liscense questions.
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
@@ -30,6 +22,7 @@ import java.io.OutputStream;
|
||||
import java.net.ConnectException;
|
||||
import java.net.NoRouteToHostException;
|
||||
import java.net.Socket;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
@@ -93,7 +86,7 @@ public class TCPtoI2P implements Runnable {
|
||||
// exit on anything not legal
|
||||
break;
|
||||
}
|
||||
c = (char) (b & 0x7f); // We only really give a fuck about ASCII
|
||||
c = (char) (b & 0x7f); // We only care about ASCII
|
||||
S = new String(S + c);
|
||||
}
|
||||
return S;
|
||||
@@ -107,20 +100,18 @@ public class TCPtoI2P implements Runnable {
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
private void Emsg(String e, OutputStream out) throws IOException {
|
||||
// Debugging System.out.println("ERROR TCPtoI2P: " + e);
|
||||
// Debugging System.out.println("ERROR TCPtoI2P: " + e);
|
||||
out.write("ERROR ".concat(e).getBytes());
|
||||
out.write(13);
|
||||
out.write(10);
|
||||
out.flush();
|
||||
}
|
||||
|
||||
// private void rlock() throws Exception {
|
||||
private void rlock() {
|
||||
database.getReadLock();
|
||||
info.getReadLock();
|
||||
}
|
||||
|
||||
// private void runlock() throws Exception {
|
||||
private void runlock() {
|
||||
info.releaseReadLock();
|
||||
database.releaseReadLock();
|
||||
@@ -144,7 +135,7 @@ public class TCPtoI2P implements Runnable {
|
||||
in = sock.getInputStream();
|
||||
out = sock.getOutputStream();
|
||||
line = lnRead(in);
|
||||
input = line.toLowerCase();
|
||||
input = line.toLowerCase(Locale.US);
|
||||
Destination dest = null;
|
||||
if (input.endsWith(".i2p")) {
|
||||
//dest = I2PTunnel.destFromName(input);
|
||||
|
@@ -1,17 +1,9 @@
|
||||
/**
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
* Everyone is permitted to copy and distribute verbatim or modified
|
||||
* copies of this license document, and changing it is allowed as long
|
||||
* as the name is changed.
|
||||
*
|
||||
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
*
|
||||
* 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
*
|
||||
* See...
|
||||
*
|
||||
@@ -19,7 +11,7 @@
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and liscense questions.
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
@@ -111,7 +103,7 @@ public class UDPIOthread implements I2PSessionListener, Runnable {
|
||||
* @param size
|
||||
*/
|
||||
public void messageAvailable(I2PSession session, int msgId, long size) {
|
||||
// _log.debug("Message available: id = " + msgId + " size = " + size);
|
||||
// _log.debug("Message available: id = " + msgId + " size = " + size);
|
||||
try {
|
||||
byte msg[] = session.receiveMessage(msgId);
|
||||
out.write(msg);
|
||||
|
@@ -51,8 +51,12 @@
|
||||
<!-- unused for now, as we oddly ship addressbook as a .war -->
|
||||
<target name="jar" depends="compile, changes">
|
||||
<jar basedir="${build}" destfile="${dist}/${jar}">
|
||||
<!-- set if unset -->
|
||||
<property name="workspace.changes" value="" />
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="addressbook.Daemon"/>
|
||||
<attribute name="Implementation-Version" value="${full.version}" />
|
||||
<attribute name="Built-By" value="${build.built-by}" />
|
||||
<attribute name="Build-Date" value="${build.timestamp}" />
|
||||
<attribute name="Base-Revision" value="${workspace.version}" />
|
||||
<attribute name="Workspace-Changes" value="${workspace.changes}" />
|
||||
@@ -67,8 +71,12 @@
|
||||
<copy todir="${dist}/tmp/WEB-INF/classes">
|
||||
<fileset dir="${build}"/>
|
||||
</copy>
|
||||
<!-- set if unset -->
|
||||
<property name="workspace.changes.tr" value="" />
|
||||
<war basedir="${dist}/tmp" webxml="web.xml" destfile="${dist}/${war}">
|
||||
<manifest>
|
||||
<attribute name="Implementation-Version" value="${full.version}" />
|
||||
<attribute name="Built-By" value="${build.built-by}" />
|
||||
<attribute name="Build-Date" value="${build.timestamp}" />
|
||||
<attribute name="Base-Revision" value="${workspace.version}" />
|
||||
<attribute name="Workspace-Changes" value="${workspace.changes.tr}" />
|
||||
@@ -81,9 +89,17 @@
|
||||
<uptodate property="war.uptodate" targetfile="${dist}/${war}">
|
||||
<srcfiles dir= "." includes="${build}/**/*.class, web.xml"/>
|
||||
</uptodate>
|
||||
<condition property="shouldListChanges" >
|
||||
<and>
|
||||
<not>
|
||||
<isset property="war.uptodate" />
|
||||
</not>
|
||||
<isset property="mtn.available" />
|
||||
</and>
|
||||
</condition>
|
||||
</target>
|
||||
|
||||
<target name="changes">
|
||||
<target name="changes" depends="warUpToDate" if="shouldListChanges" >
|
||||
<exec executable="mtn" outputproperty="workspace.changes" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="list" />
|
||||
<arg value="changed" />
|
||||
|
@@ -23,12 +23,14 @@ package net.i2p.addressbook;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.util.EepGet;
|
||||
import net.i2p.util.SecureFile;
|
||||
|
||||
/**
|
||||
* An address book for storing human readable names mapped to base64 i2p
|
||||
@@ -40,11 +42,12 @@ import net.i2p.util.EepGet;
|
||||
*/
|
||||
class AddressBook {
|
||||
|
||||
private String location;
|
||||
|
||||
private Map addresses;
|
||||
|
||||
private final String location;
|
||||
/** either addresses or subFile will be non-null, but not both */
|
||||
private final Map<String, String> addresses;
|
||||
private final File subFile;
|
||||
private boolean modified;
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
/**
|
||||
* Construct an AddressBook from the contents of the Map addresses.
|
||||
@@ -53,8 +56,10 @@ class AddressBook {
|
||||
* A Map containing human readable addresses as keys, mapped to
|
||||
* base64 i2p destinations.
|
||||
*/
|
||||
public AddressBook(Map addresses) {
|
||||
public AddressBook(Map<String, String> addresses) {
|
||||
this.addresses = addresses;
|
||||
this.subFile = null;
|
||||
this.location = null;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -82,6 +87,7 @@ class AddressBook {
|
||||
}
|
||||
*/
|
||||
static final long MAX_SUB_SIZE = 3 * 1024 * 1024l; //about 5,000 hosts
|
||||
|
||||
/**
|
||||
* Construct an AddressBook from the Subscription subscription. If the
|
||||
* address book at subscription has not changed since the last time it was
|
||||
@@ -90,33 +96,46 @@ class AddressBook {
|
||||
*
|
||||
* Yes, the EepGet fetch() is done in this constructor.
|
||||
*
|
||||
* This stores the subscription in a temporary file and does not read the whole thing into memory.
|
||||
* An AddressBook created with this constructor may not be modified or written using write().
|
||||
* It may be a merge source (an parameter for another AddressBook's merge())
|
||||
* but may not be a merge target (this.merge() will throw an exception).
|
||||
*
|
||||
* @param subscription
|
||||
* A Subscription instance pointing at a remote address book.
|
||||
* @param proxyHost hostname of proxy
|
||||
* @param proxyPort port number of proxy
|
||||
*/
|
||||
public AddressBook(Subscription subscription, String proxyHost, int proxyPort) {
|
||||
File tmp = new File(I2PAppContext.getGlobalContext().getTempDir(), "addressbook.tmp");
|
||||
Map<String, String> a = null;
|
||||
File subf = null;
|
||||
try {
|
||||
File tmp = SecureFile.createTempFile("addressbook", null, I2PAppContext.getGlobalContext().getTempDir());
|
||||
EepGet get = new EepGet(I2PAppContext.getGlobalContext(), true,
|
||||
proxyHost, proxyPort, 0, -1l, MAX_SUB_SIZE, tmp.getAbsolutePath(), null,
|
||||
subscription.getLocation(), true, subscription.getEtag(), subscription.getLastModified(), null);
|
||||
if (get.fetch()) {
|
||||
subscription.setEtag(get.getETag());
|
||||
subscription.setLastModified(get.getLastModified());
|
||||
subscription.setLastFetched(I2PAppContext.getGlobalContext().clock().now());
|
||||
subf = tmp;
|
||||
} else {
|
||||
a = Collections.EMPTY_MAP;
|
||||
tmp.delete();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
a = Collections.EMPTY_MAP;
|
||||
}
|
||||
this.addresses = a;
|
||||
this.subFile = subf;
|
||||
this.location = subscription.getLocation();
|
||||
EepGet get = new EepGet(I2PAppContext.getGlobalContext(), true,
|
||||
proxyHost, proxyPort, 0, -1l, MAX_SUB_SIZE, tmp.getAbsolutePath(), null,
|
||||
subscription.getLocation(), true, subscription.getEtag(), subscription.getLastModified(), null);
|
||||
if (get.fetch()) {
|
||||
subscription.setEtag(get.getETag());
|
||||
subscription.setLastModified(get.getLastModified());
|
||||
subscription.setLastFetched(I2PAppContext.getGlobalContext().clock().now());
|
||||
}
|
||||
try {
|
||||
this.addresses = ConfigParser.parse(tmp);
|
||||
} catch (IOException exp) {
|
||||
this.addresses = new HashMap();
|
||||
}
|
||||
tmp.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an AddressBook from the contents of the file at file. If the
|
||||
* file cannot be read, construct an empty AddressBook
|
||||
* file cannot be read, construct an empty AddressBook.
|
||||
* This reads the entire file into memory.
|
||||
* The resulting map is modifiable and may be a merge target.
|
||||
*
|
||||
* @param file
|
||||
* A File pointing at a file with lines in the format
|
||||
@@ -125,22 +144,38 @@ class AddressBook {
|
||||
*/
|
||||
public AddressBook(File file) {
|
||||
this.location = file.toString();
|
||||
Map<String, String> a;
|
||||
try {
|
||||
this.addresses = ConfigParser.parse(file);
|
||||
a = ConfigParser.parse(file);
|
||||
} catch (IOException exp) {
|
||||
this.addresses = new HashMap();
|
||||
a = new HashMap();
|
||||
}
|
||||
this.addresses = a;
|
||||
this.subFile = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Map containing the addresses in the AddressBook.
|
||||
*
|
||||
* @return A Map containing the addresses in the AddressBook, where the key
|
||||
* is a human readable name, and the value is a base64 i2p
|
||||
* destination.
|
||||
* Return an iterator over the addresses in the AddressBook.
|
||||
* @since 0.8.7
|
||||
*/
|
||||
public Map getAddresses() {
|
||||
return this.addresses;
|
||||
public Iterator<Map.Entry<String, String>> iterator() {
|
||||
if (this.subFile != null)
|
||||
return new ConfigIterator(this.subFile);
|
||||
return this.addresses.entrySet().iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the temp file or clear the map.
|
||||
* @since 0.8.7
|
||||
*/
|
||||
public void delete() {
|
||||
if (this.subFile != null) {
|
||||
this.subFile.delete();
|
||||
} else if (this.addresses != null) {
|
||||
try {
|
||||
this.addresses.clear();
|
||||
} catch (UnsupportedOperationException uoe) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,29 +183,32 @@ class AddressBook {
|
||||
*
|
||||
* @return A String representing either an abstract path, or a url,
|
||||
* depending on how the instance was constructed.
|
||||
* Will be null if created with the Map constructor.
|
||||
*/
|
||||
public String getLocation() {
|
||||
return this.location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string representation of the contents of the AddressBook.
|
||||
* Return a string representation of the origin of the AddressBook.
|
||||
*
|
||||
* @return A String representing the contents of the AddressBook.
|
||||
* @return A String representing the origin of the AddressBook.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.addresses.toString();
|
||||
if (this.location != null)
|
||||
return "Book from " + this.location;
|
||||
return "Map containing " + this.addresses.size() + " entries";
|
||||
}
|
||||
|
||||
private static final int MIN_DEST_LENGTH = 516;
|
||||
private static final int MAX_DEST_LENGTH = MIN_DEST_LENGTH + 100; // longer than any known cert type for now
|
||||
|
||||
/**
|
||||
* Do basic validation of the hostname and dest
|
||||
* Do basic validation of the hostname
|
||||
* hostname was already converted to lower case by ConfigParser.parse()
|
||||
*/
|
||||
private static boolean valid(String host, String dest) {
|
||||
public static boolean isValidKey(String host) {
|
||||
return
|
||||
host.endsWith(".i2p") &&
|
||||
host.length() > 4 &&
|
||||
@@ -194,8 +232,15 @@ class AddressBook {
|
||||
(! host.equals("console.i2p")) &&
|
||||
(! host.endsWith(".proxy.i2p")) &&
|
||||
(! host.endsWith(".router.i2p")) &&
|
||||
(! host.endsWith(".console.i2p")) &&
|
||||
(! host.endsWith(".console.i2p"))
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do basic validation of the b64 dest, without bothering to instantiate it
|
||||
*/
|
||||
private static boolean isValidDest(String dest) {
|
||||
return
|
||||
// null cert ends with AAAA but other zero-length certs would be AA
|
||||
((dest.length() == MIN_DEST_LENGTH && dest.endsWith("AA")) ||
|
||||
(dest.length() > MIN_DEST_LENGTH && dest.length() <= MAX_DEST_LENGTH)) &&
|
||||
@@ -216,18 +261,21 @@ class AddressBook {
|
||||
* @param overwrite True to overwrite
|
||||
* @param log
|
||||
* The log to write messages about new addresses or conflicts to.
|
||||
*
|
||||
* @throws IllegalStateException if this was created with the Subscription constructor.
|
||||
*/
|
||||
public void merge(AddressBook other, boolean overwrite, Log log) {
|
||||
Iterator otherIter = other.addresses.keySet().iterator();
|
||||
if (this.addresses == null)
|
||||
throw new IllegalStateException();
|
||||
for (Iterator<Map.Entry<String, String>> iter = other.iterator(); iter.hasNext(); ) {
|
||||
Map.Entry<String, String> entry = iter.next();
|
||||
String otherKey = entry.getKey();
|
||||
String otherValue = entry.getValue();
|
||||
|
||||
while (otherIter.hasNext()) {
|
||||
String otherKey = (String) otherIter.next();
|
||||
String otherValue = (String) other.addresses.get(otherKey);
|
||||
|
||||
if (valid(otherKey, otherValue)) {
|
||||
if (isValidKey(otherKey) && isValidDest(otherValue)) {
|
||||
if (this.addresses.containsKey(otherKey) && !overwrite) {
|
||||
if (!this.addresses.get(otherKey).equals(otherValue)
|
||||
&& log != null) {
|
||||
if (DEBUG && log != null &&
|
||||
!this.addresses.get(otherKey).equals(otherValue)) {
|
||||
log.append("Conflict for " + otherKey + " from "
|
||||
+ other.location
|
||||
+ ". Destination in remote address book is "
|
||||
@@ -252,8 +300,12 @@ class AddressBook {
|
||||
*
|
||||
* @param file
|
||||
* The file to write the contents of this AddressBook too.
|
||||
*
|
||||
* @throws IllegalStateException if this was created with the Subscription constructor.
|
||||
*/
|
||||
public void write(File file) {
|
||||
if (this.addresses == null)
|
||||
throw new IllegalStateException();
|
||||
if (this.modified) {
|
||||
try {
|
||||
ConfigParser.write(this.addresses, file);
|
||||
@@ -267,8 +319,17 @@ class AddressBook {
|
||||
* Write this AddressBook out to the file it was read from. Requires that
|
||||
* AddressBook was constructed from a file on the local filesystem. If the
|
||||
* file cannot be writen to, this method will silently fail.
|
||||
*
|
||||
* @throws IllegalStateException if this was not created with the File constructor.
|
||||
*/
|
||||
public void write() {
|
||||
if (this.location == null || this.location.startsWith("http://"))
|
||||
throw new IllegalStateException();
|
||||
this.write(new File(this.location));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() {
|
||||
delete();
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (c) 2004 Ragnarok
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* 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
|
||||
* COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
package net.i2p.addressbook;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* A class to iterate through a hosts.txt or config file without
|
||||
* reading the whole thing into memory.
|
||||
* Keys are always converted to lower case.
|
||||
*
|
||||
* Callers should iterate all the way through or call close()
|
||||
* to ensure the underlying stream is closed.
|
||||
*
|
||||
* @since 0.8.7
|
||||
*/
|
||||
class ConfigIterator implements Iterator<Map.Entry<String, String>> {
|
||||
|
||||
private BufferedReader input;
|
||||
private ConfigEntry next;
|
||||
|
||||
/**
|
||||
* A dummy iterator in which hasNext() is always false.
|
||||
*/
|
||||
public ConfigIterator() {}
|
||||
|
||||
/**
|
||||
* An iterator over the key/value pairs in the file.
|
||||
*/
|
||||
public ConfigIterator(File file) {
|
||||
try {
|
||||
FileInputStream fileStream = new FileInputStream(file);
|
||||
input = new BufferedReader(new InputStreamReader(fileStream));
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
if (input == null)
|
||||
return false;
|
||||
if (next != null)
|
||||
return true;
|
||||
try {
|
||||
String inputLine = input.readLine();
|
||||
while (inputLine != null) {
|
||||
inputLine = ConfigParser.stripComments(inputLine);
|
||||
String[] splitLine = inputLine.split("=");
|
||||
if (splitLine.length == 2) {
|
||||
next = new ConfigEntry(splitLine[0].trim().toLowerCase(Locale.US), splitLine[1].trim());
|
||||
return true;
|
||||
}
|
||||
inputLine = input.readLine();
|
||||
}
|
||||
} catch (IOException ioe) {}
|
||||
try { input.close(); } catch (IOException ioe) {}
|
||||
input = null;
|
||||
next = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public Map.Entry<String, String> next() {
|
||||
if (!hasNext())
|
||||
throw new NoSuchElementException();
|
||||
Map.Entry<String, String> rv = next;
|
||||
next = null;
|
||||
return rv;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (input != null) {
|
||||
try { input.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() {
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* The object returned by the iterator.
|
||||
*/
|
||||
private static class ConfigEntry implements Map.Entry<String, String> {
|
||||
private final String key;
|
||||
private final String value;
|
||||
|
||||
public ConfigEntry(String k, String v) {
|
||||
key = k;
|
||||
value = v;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String setValue(String v) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return key.hashCode() ^ value.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Map.Entry))
|
||||
return false;
|
||||
Map.Entry e = (Map.Entry) o;
|
||||
return key.equals(e.getKey()) && value.equals(e.getValue());
|
||||
}
|
||||
}
|
||||
}
|
@@ -30,13 +30,14 @@ import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.StringReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import net.i2p.util.SecureFile;
|
||||
import net.i2p.util.SecureFileOutputStream;
|
||||
import net.i2p.util.SystemVersion;
|
||||
|
||||
/**
|
||||
* Utility class providing methods to parse and write files in config file
|
||||
@@ -49,7 +50,7 @@ import net.i2p.util.SecureFileOutputStream;
|
||||
*/
|
||||
class ConfigParser {
|
||||
|
||||
private static final boolean isWindows = System.getProperty("os.name").startsWith("Win");
|
||||
private static final boolean isWindows = SystemVersion.isWindows();
|
||||
|
||||
/**
|
||||
* Strip the comments from a String. Lines that begin with '#' and ';' are
|
||||
@@ -85,15 +86,15 @@ class ConfigParser {
|
||||
* if the BufferedReader cannot be read.
|
||||
*
|
||||
*/
|
||||
public static Map parse(BufferedReader input) throws IOException {
|
||||
Map result = new HashMap();
|
||||
public static Map<String, String> parse(BufferedReader input) throws IOException {
|
||||
Map<String, String> result = new HashMap();
|
||||
String inputLine;
|
||||
inputLine = input.readLine();
|
||||
while (inputLine != null) {
|
||||
inputLine = ConfigParser.stripComments(inputLine);
|
||||
String[] splitLine = inputLine.split("=");
|
||||
if (splitLine.length == 2) {
|
||||
result.put(splitLine[0].trim().toLowerCase(), splitLine[1].trim());
|
||||
result.put(splitLine[0].trim().toLowerCase(Locale.US), splitLine[1].trim());
|
||||
}
|
||||
inputLine = input.readLine();
|
||||
}
|
||||
@@ -111,11 +112,11 @@ class ConfigParser {
|
||||
* @throws IOException
|
||||
* if file cannot be read.
|
||||
*/
|
||||
public static Map parse(File file) throws IOException {
|
||||
public static Map<String, String> parse(File file) throws IOException {
|
||||
FileInputStream fileStream = new FileInputStream(file);
|
||||
BufferedReader input = new BufferedReader(new InputStreamReader(
|
||||
fileStream));
|
||||
Map rv = ConfigParser.parse(input);
|
||||
Map<String, String> rv = ConfigParser.parse(input);
|
||||
try {
|
||||
fileStream.close();
|
||||
} catch (IOException ioe) {}
|
||||
@@ -132,7 +133,7 @@ class ConfigParser {
|
||||
* @throws IOException
|
||||
* if file cannot be read.
|
||||
*/
|
||||
public static Map parse(String string) throws IOException {
|
||||
public static Map<String, String> parse(String string) throws IOException {
|
||||
StringReader stringReader = new StringReader(string);
|
||||
BufferedReader input = new BufferedReader(stringReader);
|
||||
return ConfigParser.parse(input);
|
||||
@@ -149,14 +150,13 @@ class ConfigParser {
|
||||
* @return A Map containing the key, value pairs from file, or if file
|
||||
* cannot be read, map.
|
||||
*/
|
||||
public static Map parse(File file, Map map) {
|
||||
Map result;
|
||||
public static Map<String, String> parse(File file, Map<String, String> map) {
|
||||
Map<String, String> result;
|
||||
try {
|
||||
result = ConfigParser.parse(file);
|
||||
for (Iterator iter = map.keySet().iterator(); iter.hasNext(); ) {
|
||||
String key = (String) iter.next();
|
||||
if (!result.containsKey(key))
|
||||
result.put(key, map.get(key));
|
||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||
if (!result.containsKey(entry.getKey()))
|
||||
result.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
} catch (IOException exp) {
|
||||
result = map;
|
||||
@@ -177,9 +177,9 @@ class ConfigParser {
|
||||
* @throws IOException
|
||||
* if input cannot be read.
|
||||
*/
|
||||
public static List parseSubscriptions(BufferedReader input)
|
||||
public static List<String> parseSubscriptions(BufferedReader input)
|
||||
throws IOException {
|
||||
List result = new LinkedList();
|
||||
List<String> result = new LinkedList();
|
||||
String inputLine = input.readLine();
|
||||
while (inputLine != null) {
|
||||
inputLine = ConfigParser.stripComments(inputLine).trim();
|
||||
@@ -201,11 +201,11 @@ class ConfigParser {
|
||||
* @throws IOException
|
||||
* if file cannot be read.
|
||||
*/
|
||||
public static List parseSubscriptions(File file) throws IOException {
|
||||
public static List<String> parseSubscriptions(File file) throws IOException {
|
||||
FileInputStream fileStream = new FileInputStream(file);
|
||||
BufferedReader input = new BufferedReader(new InputStreamReader(
|
||||
fileStream));
|
||||
List rv = ConfigParser.parseSubscriptions(input);
|
||||
List<String> rv = ConfigParser.parseSubscriptions(input);
|
||||
try {
|
||||
fileStream.close();
|
||||
} catch (IOException ioe) {}
|
||||
@@ -221,7 +221,7 @@ class ConfigParser {
|
||||
* @throws IOException
|
||||
* if string cannot be read.
|
||||
*/
|
||||
public static List parseSubscriptions(String string) throws IOException {
|
||||
public static List<String> parseSubscriptions(String string) throws IOException {
|
||||
StringReader stringReader = new StringReader(string);
|
||||
BufferedReader input = new BufferedReader(stringReader);
|
||||
return ConfigParser.parseSubscriptions(input);
|
||||
@@ -238,8 +238,8 @@ class ConfigParser {
|
||||
* @return A List consisting of one element for each line in file, or if
|
||||
* file cannot be read, list.
|
||||
*/
|
||||
public static List parseSubscriptions(File file, List list) {
|
||||
List result;
|
||||
public static List<String> parseSubscriptions(File file, List<String> list) {
|
||||
List<String> result;
|
||||
try {
|
||||
result = ConfigParser.parseSubscriptions(file);
|
||||
} catch (IOException exp) {
|
||||
@@ -263,12 +263,9 @@ class ConfigParser {
|
||||
* @throws IOException
|
||||
* if the BufferedWriter cannot be written to.
|
||||
*/
|
||||
public static void write(Map map, BufferedWriter output) throws IOException {
|
||||
Iterator keyIter = map.keySet().iterator();
|
||||
|
||||
while (keyIter.hasNext()) {
|
||||
String key = (String) keyIter.next();
|
||||
output.write(key + "=" + (String) map.get(key));
|
||||
public static void write(Map<String, String> map, BufferedWriter output) throws IOException {
|
||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||
output.write(entry.getKey() + '=' + entry.getValue());
|
||||
output.newLine();
|
||||
}
|
||||
output.close();
|
||||
@@ -288,7 +285,7 @@ class ConfigParser {
|
||||
* @throws IOException
|
||||
* if file cannot be written to.
|
||||
*/
|
||||
public static void write(Map map, File file) throws IOException {
|
||||
public static void write(Map<String, String> map, File file) throws IOException {
|
||||
boolean success = false;
|
||||
if (!isWindows) {
|
||||
File tmp = SecureFile.createTempFile("temp-", ".tmp", file.getAbsoluteFile().getParentFile());
|
||||
@@ -318,12 +315,10 @@ class ConfigParser {
|
||||
* @throws IOException
|
||||
* if output cannot be written to.
|
||||
*/
|
||||
public static void writeSubscriptions(List list, BufferedWriter output)
|
||||
public static void writeSubscriptions(List<String> list, BufferedWriter output)
|
||||
throws IOException {
|
||||
Iterator iter = list.iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
output.write((String) iter.next());
|
||||
for (String s : list) {
|
||||
output.write(s);
|
||||
output.newLine();
|
||||
}
|
||||
output.close();
|
||||
@@ -340,7 +335,7 @@ class ConfigParser {
|
||||
* @throws IOException
|
||||
* if output cannot be written to.
|
||||
*/
|
||||
public static void writeSubscriptions(List list, File file)
|
||||
public static void writeSubscriptions(List<String> list, File file)
|
||||
throws IOException {
|
||||
ConfigParser.writeSubscriptions(list, new BufferedWriter(
|
||||
new OutputStreamWriter(new SecureFileOutputStream(file), "UTF-8")));
|
||||
|
@@ -22,13 +22,20 @@
|
||||
package net.i2p.addressbook;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.naming.NamingService;
|
||||
import net.i2p.client.naming.SingleFileNamingService;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.SecureDirectory;
|
||||
|
||||
/**
|
||||
@@ -41,6 +48,7 @@ public class Daemon {
|
||||
public static final String VERSION = "2.0.4";
|
||||
private static final Daemon _instance = new Daemon();
|
||||
private boolean _running;
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
/**
|
||||
* Update the router and published address books using remote data from the
|
||||
@@ -49,29 +57,166 @@ public class Daemon {
|
||||
* @param master
|
||||
* The master AddressBook. This address book is never
|
||||
* overwritten, so it is safe for the user to write to.
|
||||
* It is only merged to the published addressbook.
|
||||
* May be null.
|
||||
* @param router
|
||||
* The router AddressBook. This is the address book read by
|
||||
* client applications.
|
||||
* @param published
|
||||
* The published AddressBook. This address book is published on
|
||||
* the user's eepsite so that others may subscribe to it.
|
||||
* May be null.
|
||||
* If non-null, overwrite with the new addressbook.
|
||||
* @param subscriptions
|
||||
* A SubscriptionList listing the remote address books to update
|
||||
* from.
|
||||
* @param log
|
||||
* The log to write changes and conflicts to.
|
||||
* May be null.
|
||||
*/
|
||||
public void update(AddressBook master, AddressBook router,
|
||||
public static void update(AddressBook master, AddressBook router,
|
||||
File published, SubscriptionList subscriptions, Log log) {
|
||||
router.merge(master, true, null);
|
||||
Iterator iter = subscriptions.iterator();
|
||||
Iterator<AddressBook> iter = subscriptions.iterator();
|
||||
while (iter.hasNext()) {
|
||||
// yes, the EepGet fetch() is done in next()
|
||||
router.merge((AddressBook) iter.next(), false, log);
|
||||
router.merge(iter.next(), false, log);
|
||||
}
|
||||
router.write();
|
||||
if (published != null)
|
||||
if (published != null) {
|
||||
if (master != null)
|
||||
router.merge(master, true, null);
|
||||
router.write(published);
|
||||
}
|
||||
subscriptions.write();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the router and published address books using remote data from the
|
||||
* subscribed address books listed in subscriptions.
|
||||
* Merging of the "master" addressbook is NOT supported.
|
||||
*
|
||||
* @param router
|
||||
* The NamingService to update, generally the root NamingService from the context.
|
||||
* @param published
|
||||
* The published AddressBook. This address book is published on
|
||||
* the user's eepsite so that others may subscribe to it.
|
||||
* May be null.
|
||||
* If non-null, overwrite with the new addressbook.
|
||||
* @param subscriptions
|
||||
* A SubscriptionList listing the remote address books to update
|
||||
* from.
|
||||
* @param log
|
||||
* The log to write changes and conflicts to.
|
||||
* May be null.
|
||||
* @since 0.8.7
|
||||
*/
|
||||
public static void update(NamingService router, File published, SubscriptionList subscriptions, Log log) {
|
||||
// If the NamingService is a database, we look up as we go.
|
||||
// If it is a text file, we do things differently, to avoid O(n**2) behavior
|
||||
// when scanning large subscription results (i.e. those that return the whole file, not just the new entries) -
|
||||
// we load all the known hostnames into a Set one time.
|
||||
// This also has the advantage of not flushing the NamingService's LRU cache.
|
||||
String nsClass = router.getClass().getSimpleName();
|
||||
boolean isTextFile = nsClass.equals("HostsTxtNamingService") || nsClass.equals("SingleFileNamingService");
|
||||
Set<String> knownNames = null;
|
||||
|
||||
NamingService publishedNS = null;
|
||||
Iterator<AddressBook> iter = subscriptions.iterator();
|
||||
while (iter.hasNext()) {
|
||||
// yes, the EepGet fetch() is done in next()
|
||||
long start = System.currentTimeMillis();
|
||||
AddressBook sub = iter.next();
|
||||
long end = System.currentTimeMillis();
|
||||
// SubscriptionIterator puts in a dummy AddressBook with no location if no fetch is done
|
||||
if (DEBUG && log != null && sub.getLocation() != null)
|
||||
log.append("Fetch of " + sub.getLocation() + " took " + (end - start));
|
||||
start = end;
|
||||
int old = 0, nnew = 0, invalid = 0, conflict = 0, total = 0;
|
||||
for (Iterator<Map.Entry<String, String>> eIter = sub.iterator(); eIter.hasNext(); ) {
|
||||
Map.Entry<String, String> entry = eIter.next();
|
||||
String key = entry.getKey();
|
||||
boolean isKnown;
|
||||
Destination oldDest = null;
|
||||
if (isTextFile) {
|
||||
if (knownNames == null) {
|
||||
// load the hostname set
|
||||
Properties opts = new Properties();
|
||||
opts.setProperty("file", "hosts.txt");
|
||||
knownNames = router.getNames(opts);
|
||||
}
|
||||
isKnown = knownNames.contains(key);
|
||||
} else {
|
||||
oldDest = router.lookup(key);
|
||||
isKnown = oldDest != null;
|
||||
}
|
||||
try {
|
||||
if (!isKnown) {
|
||||
if (AddressBook.isValidKey(key)) {
|
||||
Destination dest = new Destination(entry.getValue());
|
||||
Properties props = new Properties();
|
||||
props.setProperty("s", sub.getLocation());
|
||||
boolean success = router.put(key, dest, props);
|
||||
if (log != null) {
|
||||
if (success)
|
||||
log.append("New address " + key +
|
||||
" added to address book. From: " + sub.getLocation());
|
||||
else
|
||||
log.append("Save to naming service " + router + " failed for new key " + key);
|
||||
}
|
||||
// now update the published addressbook
|
||||
if (published != null) {
|
||||
if (publishedNS == null)
|
||||
publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath());
|
||||
success = publishedNS.putIfAbsent(key, dest);
|
||||
if (!success) {
|
||||
try {
|
||||
log.append("Save to published address book " + published.getCanonicalPath() + " failed for new key " + key);
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
if (isTextFile)
|
||||
// keep track for later dup check
|
||||
knownNames.add(key);
|
||||
nnew++;
|
||||
} else if (log != null) {
|
||||
log.append("Bad hostname " + key + " from "
|
||||
+ sub.getLocation());
|
||||
invalid++;
|
||||
}
|
||||
} else if (false && DEBUG && log != null) {
|
||||
// lookup the conflict if we haven't yet (O(n**2) for text file)
|
||||
if (isTextFile)
|
||||
oldDest = router.lookup(key);
|
||||
if (oldDest != null && !oldDest.toBase64().equals(entry.getValue())) {
|
||||
log.append("Conflict for " + key + " from "
|
||||
+ sub.getLocation()
|
||||
+ ". Destination in remote address book is "
|
||||
+ entry.getValue());
|
||||
conflict++;
|
||||
} else {
|
||||
old++;
|
||||
}
|
||||
} else {
|
||||
old++;
|
||||
}
|
||||
} catch (DataFormatException dfe) {
|
||||
if (log != null)
|
||||
log.append("Invalid b64 for " + key + " From: " + sub.getLocation());
|
||||
invalid++;
|
||||
}
|
||||
total++;
|
||||
}
|
||||
if (DEBUG && log != null && total > 0) {
|
||||
log.append("Merge of " + sub.getLocation() + " into " + router +
|
||||
" took " + (System.currentTimeMillis() - start) + " ms with " +
|
||||
total + " total, " +
|
||||
nnew + " new, " +
|
||||
old + " old, " +
|
||||
invalid + " invalid, " +
|
||||
conflict + " conflicts");
|
||||
}
|
||||
sub.delete();
|
||||
}
|
||||
subscriptions.write();
|
||||
}
|
||||
|
||||
@@ -83,44 +228,80 @@ public class Daemon {
|
||||
* @param home
|
||||
* The directory containing addressbook's configuration files.
|
||||
*/
|
||||
public void update(Map settings, String home) {
|
||||
File masterFile = new File(home, (String) settings
|
||||
.get("master_addressbook"));
|
||||
File routerFile = new File(home, (String) settings
|
||||
.get("router_addressbook"));
|
||||
public static void update(Map<String, String> settings, String home) {
|
||||
File published = null;
|
||||
if ("true".equals(settings.get("should_publish")))
|
||||
published = new File(home, (String) settings
|
||||
boolean should_publish = Boolean.parseBoolean(settings.get("should_publish"));
|
||||
if (should_publish)
|
||||
published = new File(home, settings
|
||||
.get("published_addressbook"));
|
||||
File subscriptionFile = new File(home, (String) settings
|
||||
File subscriptionFile = new File(home, settings
|
||||
.get("subscriptions"));
|
||||
File logFile = new File(home, (String) settings.get("log"));
|
||||
File etagsFile = new File(home, (String) settings.get("etags"));
|
||||
File lastModifiedFile = new File(home, (String) settings
|
||||
File logFile = new File(home, settings.get("log"));
|
||||
File etagsFile = new File(home, settings.get("etags"));
|
||||
File lastModifiedFile = new File(home, settings
|
||||
.get("last_modified"));
|
||||
File lastFetchedFile = new File(home, (String) settings
|
||||
File lastFetchedFile = new File(home, settings
|
||||
.get("last_fetched"));
|
||||
long delay;
|
||||
try {
|
||||
delay = Long.parseLong((String) settings.get("update_delay"));
|
||||
delay = Long.parseLong(settings.get("update_delay"));
|
||||
} catch (NumberFormatException nfe) {
|
||||
delay = 12;
|
||||
}
|
||||
delay *= 60 * 60 * 1000;
|
||||
|
||||
AddressBook master = new AddressBook(masterFile);
|
||||
AddressBook router = new AddressBook(routerFile);
|
||||
|
||||
List defaultSubs = new LinkedList();
|
||||
List<String> defaultSubs = new LinkedList();
|
||||
// defaultSubs.add("http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/hosts.txt");
|
||||
defaultSubs.add("http://www.i2p2.i2p/hosts.txt");
|
||||
|
||||
SubscriptionList subscriptions = new SubscriptionList(subscriptionFile,
|
||||
etagsFile, lastModifiedFile, lastFetchedFile, delay, defaultSubs, (String) settings
|
||||
.get("proxy_host"), Integer.parseInt((String) settings.get("proxy_port")));
|
||||
etagsFile, lastModifiedFile, lastFetchedFile, delay, defaultSubs, settings
|
||||
.get("proxy_host"), Integer.parseInt(settings.get("proxy_port")));
|
||||
Log log = new Log(logFile);
|
||||
|
||||
update(master, router, published, subscriptions, log);
|
||||
// If false, add hosts via naming service; if true, write hosts.txt file directly
|
||||
// Default false
|
||||
if (Boolean.parseBoolean(settings.get("update_direct"))) {
|
||||
// Direct hosts.txt access
|
||||
File routerFile = new File(home, settings.get("router_addressbook"));
|
||||
AddressBook master;
|
||||
if (should_publish) {
|
||||
File masterFile = new File(home, settings.get("master_addressbook"));
|
||||
master = new AddressBook(masterFile);
|
||||
} else {
|
||||
master = null;
|
||||
}
|
||||
AddressBook router = new AddressBook(routerFile);
|
||||
update(master, router, published, subscriptions, log);
|
||||
} else {
|
||||
// Naming service - no merging of master to router and published is supported.
|
||||
update(getNamingService(settings.get("naming_service")), published, subscriptions, log);
|
||||
}
|
||||
}
|
||||
|
||||
/** depth-first search */
|
||||
private static NamingService searchNamingService(NamingService ns, String srch)
|
||||
{
|
||||
String name = ns.getName();
|
||||
if (name.equals(srch) || name.endsWith('/' + srch) || name.endsWith('\\' + srch))
|
||||
return ns;
|
||||
List<NamingService> list = ns.getNamingServices();
|
||||
if (list != null) {
|
||||
for (NamingService nss : list) {
|
||||
NamingService rv = searchNamingService(nss, srch);
|
||||
if (rv != null)
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return the configured NamingService, or the root NamingService */
|
||||
private static NamingService getNamingService(String srch)
|
||||
{
|
||||
NamingService root = I2PAppContext.getGlobalContext().namingService();
|
||||
NamingService rv = searchNamingService(root, srch);
|
||||
return rv != null ? rv : root;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,7 +330,7 @@ public class Daemon {
|
||||
homeFile = new SecureDirectory(System.getProperty("user.dir"));
|
||||
}
|
||||
|
||||
Map defaultSettings = new HashMap();
|
||||
Map<String, String> defaultSettings = new HashMap();
|
||||
defaultSettings.put("proxy_host", "127.0.0.1");
|
||||
defaultSettings.put("proxy_port", "4444");
|
||||
defaultSettings.put("master_addressbook", "../userhosts.txt");
|
||||
@@ -162,6 +343,8 @@ public class Daemon {
|
||||
defaultSettings.put("last_modified", "last_modified");
|
||||
defaultSettings.put("last_fetched", "last_fetched");
|
||||
defaultSettings.put("update_delay", "12");
|
||||
defaultSettings.put("update_direct", "false");
|
||||
defaultSettings.put("naming_service", "hosts.txt");
|
||||
|
||||
if (!homeFile.exists()) {
|
||||
boolean created = homeFile.mkdirs();
|
||||
@@ -173,7 +356,7 @@ public class Daemon {
|
||||
|
||||
File settingsFile = new File(homeFile, settingsLocation);
|
||||
|
||||
Map settings = ConfigParser.parse(settingsFile, defaultSettings);
|
||||
Map<String, String> settings = ConfigParser.parse(settingsFile, defaultSettings);
|
||||
// wait
|
||||
try {
|
||||
Thread.sleep(5*60*1000 + I2PAppContext.getGlobalContext().random().nextLong(5*60*1000));
|
||||
@@ -181,7 +364,7 @@ public class Daemon {
|
||||
} catch (InterruptedException ie) {}
|
||||
|
||||
while (_running) {
|
||||
long delay = Long.parseLong((String) settings.get("update_delay"));
|
||||
long delay = Long.parseLong(settings.get("update_delay"));
|
||||
if (delay < 1) {
|
||||
delay = 1;
|
||||
}
|
||||
|
@@ -21,13 +21,18 @@
|
||||
|
||||
package net.i2p.addressbook;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.naming.NamingServiceUpdater;
|
||||
|
||||
/**
|
||||
* A thread that waits five minutes, then runs the addressbook daemon.
|
||||
*
|
||||
* @author Ragnarok
|
||||
*
|
||||
*/
|
||||
class DaemonThread extends Thread {
|
||||
public class DaemonThread extends Thread implements NamingServiceUpdater {
|
||||
|
||||
private String[] args;
|
||||
|
||||
@@ -49,11 +54,22 @@ class DaemonThread extends Thread {
|
||||
// Thread.sleep(5 * 60 * 1000);
|
||||
//} catch (InterruptedException exp) {
|
||||
//}
|
||||
I2PAppContext.getGlobalContext().namingService().registerUpdater(this);
|
||||
Daemon.main(this.args);
|
||||
I2PAppContext.getGlobalContext().namingService().unregisterUpdater(this);
|
||||
}
|
||||
|
||||
public void halt() {
|
||||
Daemon.stop();
|
||||
interrupt();
|
||||
}
|
||||
|
||||
/**
|
||||
* The NamingServiceUpdater interface
|
||||
* @param options ignored
|
||||
* @since 0.8.7
|
||||
*/
|
||||
public void update(Properties options) {
|
||||
interrupt();
|
||||
}
|
||||
}
|
||||
|
@@ -42,8 +42,8 @@ import javax.servlet.http.HttpServletResponse;
|
||||
*/
|
||||
public class Servlet extends HttpServlet {
|
||||
private DaemonThread thread;
|
||||
private String nonce;
|
||||
private static final String PROP_NONCE = "addressbook.nonce";
|
||||
//private String nonce;
|
||||
//private static final String PROP_NONCE = "addressbook.nonce";
|
||||
|
||||
/**
|
||||
* Hack to allow susidns to kick the daemon when the subscription list changes.
|
||||
@@ -54,15 +54,15 @@ public class Servlet extends HttpServlet {
|
||||
*/
|
||||
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
//System.err.println("Got request nonce = " + request.getParameter("nonce"));
|
||||
if (this.thread != null && request.getParameter("wakeup") != null &&
|
||||
this.nonce != null && this.nonce.equals(request.getParameter("nonce"))) {
|
||||
//System.err.println("Sending interrupt");
|
||||
this.thread.interrupt();
|
||||
// no output
|
||||
} else {
|
||||
//if (this.thread != null && request.getParameter("wakeup") != null &&
|
||||
// this.nonce != null && this.nonce.equals(request.getParameter("nonce"))) {
|
||||
// //System.err.println("Sending interrupt");
|
||||
// this.thread.interrupt();
|
||||
// // no output
|
||||
//} else {
|
||||
PrintWriter out = response.getWriter();
|
||||
out.write("I2P addressbook OK");
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -75,16 +75,16 @@ public class Servlet extends HttpServlet {
|
||||
} catch (ServletException exp) {
|
||||
System.err.println("Addressbook init exception: " + exp);
|
||||
}
|
||||
this.nonce = "" + Math.abs((new Random()).nextLong());
|
||||
//this.nonce = "" + Math.abs((new Random()).nextLong());
|
||||
// put the nonce where susidns can get it
|
||||
System.setProperty(PROP_NONCE, this.nonce);
|
||||
//System.setProperty(PROP_NONCE, this.nonce);
|
||||
String[] args = new String[1];
|
||||
args[0] = config.getInitParameter("home");
|
||||
this.thread = new DaemonThread(args);
|
||||
this.thread.setDaemon(true);
|
||||
this.thread.setName("Addressbook");
|
||||
this.thread.start();
|
||||
System.out.println("INFO: Starting Addressbook " + Daemon.VERSION);
|
||||
//System.out.println("INFO: Starting Addressbook " + Daemon.VERSION);
|
||||
//System.out.println("INFO: config root under " + args[0]);
|
||||
}
|
||||
|
||||
|
@@ -26,7 +26,6 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper; // debug
|
||||
|
||||
/**
|
||||
* An iterator over the subscriptions in a SubscriptionList. Note that this iterator
|
||||
@@ -35,9 +34,9 @@ import net.i2p.data.DataHelper; // debug
|
||||
*
|
||||
* @author Ragnarok
|
||||
*/
|
||||
class SubscriptionIterator implements Iterator {
|
||||
class SubscriptionIterator implements Iterator<AddressBook> {
|
||||
|
||||
private Iterator subIterator;
|
||||
private Iterator<Subscription> subIterator;
|
||||
private String proxyHost;
|
||||
private int proxyPort;
|
||||
private final long delay;
|
||||
@@ -51,7 +50,7 @@ class SubscriptionIterator implements Iterator {
|
||||
* @param proxyHost proxy hostname
|
||||
* @param proxyPort proxt port number
|
||||
*/
|
||||
public SubscriptionIterator(List subscriptions, long delay, String proxyHost, int proxyPort) {
|
||||
public SubscriptionIterator(List<Subscription> subscriptions, long delay, String proxyHost, int proxyPort) {
|
||||
this.subIterator = subscriptions.iterator();
|
||||
this.delay = delay;
|
||||
this.proxyHost = proxyHost;
|
||||
@@ -72,8 +71,8 @@ class SubscriptionIterator implements Iterator {
|
||||
* see java.util.Iterator#next()
|
||||
* @return an AddressBook (empty if the minimum delay has not been met)
|
||||
*/
|
||||
public Object next() {
|
||||
Subscription sub = (Subscription) this.subIterator.next();
|
||||
public AddressBook next() {
|
||||
Subscription sub = this.subIterator.next();
|
||||
if (sub.getLastFetched() + this.delay < I2PAppContext.getGlobalContext().clock().now()) {
|
||||
//System.err.println("Fetching addressbook from " + sub.getLocation());
|
||||
return new AddressBook(sub, this.proxyHost, this.proxyPort);
|
||||
|
@@ -24,7 +24,6 @@ package net.i2p.addressbook;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -37,7 +36,7 @@ import java.util.Map;
|
||||
*/
|
||||
class SubscriptionList {
|
||||
|
||||
private List subscriptions;
|
||||
private List<Subscription> subscriptions;
|
||||
|
||||
private File etagsFile;
|
||||
|
||||
@@ -68,7 +67,7 @@ class SubscriptionList {
|
||||
* @param proxyPort proxy port number
|
||||
*/
|
||||
public SubscriptionList(File locationsFile, File etagsFile,
|
||||
File lastModifiedFile, File lastFetchedFile, long delay, List defaultSubs, String proxyHost,
|
||||
File lastModifiedFile, File lastFetchedFile, long delay, List<String> defaultSubs, String proxyHost,
|
||||
int proxyPort) {
|
||||
this.subscriptions = new LinkedList();
|
||||
this.etagsFile = etagsFile;
|
||||
@@ -77,11 +76,10 @@ class SubscriptionList {
|
||||
this.delay = delay;
|
||||
this.proxyHost = proxyHost;
|
||||
this.proxyPort = proxyPort;
|
||||
Map etags;
|
||||
Map lastModified;
|
||||
Map lastFetched;
|
||||
String location;
|
||||
List locations = ConfigParser.parseSubscriptions(locationsFile,
|
||||
Map<String, String> etags;
|
||||
Map<String, String> lastModified;
|
||||
Map<String, String> lastFetched;
|
||||
List<String> locations = ConfigParser.parseSubscriptions(locationsFile,
|
||||
defaultSubs);
|
||||
try {
|
||||
etags = ConfigParser.parse(etagsFile);
|
||||
@@ -98,12 +96,10 @@ class SubscriptionList {
|
||||
} catch (IOException exp) {
|
||||
lastFetched = new HashMap();
|
||||
}
|
||||
Iterator iter = locations.iterator();
|
||||
while (iter.hasNext()) {
|
||||
location = (String) iter.next();
|
||||
this.subscriptions.add(new Subscription(location, (String) etags.get(location),
|
||||
(String) lastModified.get(location),
|
||||
(String) lastFetched.get(location)));
|
||||
for (String location : locations) {
|
||||
this.subscriptions.add(new Subscription(location, etags.get(location),
|
||||
lastModified.get(location),
|
||||
lastFetched.get(location)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,13 +121,10 @@ class SubscriptionList {
|
||||
* won't be read back correctly; the '=' should be escaped.
|
||||
*/
|
||||
public void write() {
|
||||
Iterator iter = this.subscriptions.iterator();
|
||||
Subscription sub;
|
||||
Map etags = new HashMap();
|
||||
Map lastModified = new HashMap();
|
||||
Map lastFetched = new HashMap();
|
||||
while (iter.hasNext()) {
|
||||
sub = (Subscription) iter.next();
|
||||
Map<String, String> etags = new HashMap();
|
||||
Map<String, String> lastModified = new HashMap();
|
||||
Map<String, String> lastFetched = new HashMap();
|
||||
for (Subscription sub : this.subscriptions) {
|
||||
if (sub.getEtag() != null) {
|
||||
etags.put(sub.getLocation(), sub.getEtag());
|
||||
}
|
||||
|
@@ -1,381 +0,0 @@
|
||||
package net.i2p.client;
|
||||
|
||||
/*
|
||||
* free (adj.): unencumbered; not under the control of others
|
||||
* Written by jrandom in 2003 and released into the public domain
|
||||
* with no warranty of any kind, either expressed or implied.
|
||||
* It probably won't make your computer catch on fire, or eat
|
||||
* your children, but it might. Use at your own risk.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* ATalk - anonymous talk, demonstrating a trivial I2P usage scenario.
|
||||
* Run this class with no arguments for a manual.
|
||||
*
|
||||
* @author jrandom
|
||||
*/
|
||||
public class ATalk implements I2PSessionListener, Runnable {
|
||||
/** logging hook - status messages are piped to this */
|
||||
private final static Log _log = new Log(ATalk.class);
|
||||
|
||||
/** platform independent newline */
|
||||
private final static String NL = System.getProperty("line.separator");
|
||||
|
||||
/** the current session */
|
||||
private I2PSession _session;
|
||||
|
||||
/** who am i */
|
||||
private Destination _myDestination;
|
||||
|
||||
/** who are you? */
|
||||
private Destination _peerDestination;
|
||||
|
||||
/** location of my secret key file */
|
||||
private String _myKeyFile;
|
||||
|
||||
/** location of their public key */
|
||||
private String _theirDestinationFile;
|
||||
|
||||
/** where the application reads input from. currently set to standard input */
|
||||
private BufferedReader _in;
|
||||
|
||||
/** where the application sends output to. currently set to standard output */
|
||||
private BufferedWriter _out;
|
||||
|
||||
/** string that messages must begin with to be treated as files */
|
||||
private final static String FILE_COMMAND = ".file: ";
|
||||
|
||||
/** the, erm, manual */
|
||||
private final static String MANUAL = "ATalk: Anonymous Talk, a demo program for the Invisible Internet Project SDK"
|
||||
+ NL
|
||||
+ "To generate a new destination:"
|
||||
+ NL
|
||||
+ "\tATalk [fileToSavePrivateKeyIn] [fileToSavePublicKeyIn]"
|
||||
+ NL
|
||||
+ "To talk to another destination:"
|
||||
+ NL
|
||||
+ "\tATalk [myPrivateKeyFile] [peerPublicKey] [shouldLogToScreen]"
|
||||
+ NL
|
||||
+ "shouldLogToScreen is 'true' or 'false', depending on whether you want log info on the screen"
|
||||
+ NL
|
||||
+ "When talking to another destination, messages are sent after you hit return"
|
||||
+ NL
|
||||
+ "To send a file, send a message saying:"
|
||||
+ NL
|
||||
+ "\t"
|
||||
+ FILE_COMMAND
|
||||
+ "[filenameToSend]"
|
||||
+ NL
|
||||
+ "The peer will then recieve the file and be notified of where it has been saved"
|
||||
+ NL
|
||||
+ "To end the talk session, enter a period on a line by itself and hit return"
|
||||
+ NL;
|
||||
|
||||
public final static String PROP_CONFIG_LOCATION = "configFile";
|
||||
|
||||
private static final SimpleDateFormat _fmt = new SimpleDateFormat("hh:mm:ss.SSS");
|
||||
|
||||
/** Construct the talk engine, but don't connect yet */
|
||||
public ATalk(String myKeyFile, String theirDestFile) {
|
||||
_myKeyFile = myKeyFile;
|
||||
_theirDestinationFile = theirDestFile;
|
||||
}
|
||||
|
||||
/** Actually start up the connection to the I2P network.
|
||||
* Successful connect does not mean the peer is online or reachable.
|
||||
*
|
||||
* @throws IOException if there is a problem reading in the keys from the files specified
|
||||
* @throws DataFormatException if the key files are not in the valid format
|
||||
* @throws I2PSessionException if there is a problem contacting the I2P router
|
||||
*/
|
||||
public void connect() throws IOException, I2PSessionException, DataFormatException {
|
||||
I2PClient client = I2PClientFactory.createClient();
|
||||
File myFile = new File(_myKeyFile);
|
||||
Properties props = new Properties();
|
||||
String configLocation = System.getProperty(PROP_CONFIG_LOCATION, "atalk.config");
|
||||
try {
|
||||
props.load(new FileInputStream(configLocation));
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
_log.warn("Unable to load up the ATalk config file " + configLocation);
|
||||
}
|
||||
// Provide any router or client API configuration here.
|
||||
if (!props.containsKey(I2PClient.PROP_TCP_HOST))
|
||||
props.setProperty(I2PClient.PROP_TCP_HOST, "localhost");
|
||||
if (!props.containsKey(I2PClient.PROP_TCP_PORT))
|
||||
props.setProperty(I2PClient.PROP_TCP_PORT, "7654");
|
||||
if (!props.containsKey(I2PClient.PROP_RELIABILITY))
|
||||
props.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_BEST_EFFORT);
|
||||
_session = client.createSession(new FileInputStream(myFile), props);
|
||||
_session.setSessionListener(this);
|
||||
_session.connect();
|
||||
|
||||
File peerDestFile = new File(_theirDestinationFile);
|
||||
_peerDestination = new Destination();
|
||||
_peerDestination.readBytes(new FileInputStream(peerDestFile));
|
||||
return;
|
||||
}
|
||||
|
||||
/** Actual bulk processing of the application, reading in user input,
|
||||
* sending messages, and displaying results. When this function exits, the
|
||||
* application is complete.
|
||||
*
|
||||
*/
|
||||
public void run() {
|
||||
try {
|
||||
connect();
|
||||
_in = new BufferedReader(new InputStreamReader(System.in));
|
||||
_out = new BufferedWriter(new OutputStreamWriter(System.out));
|
||||
|
||||
_out.write("Starting up anonymous talk session" + NL);
|
||||
|
||||
while (true) {
|
||||
String line = _in.readLine();
|
||||
if ((line == null) || (line.trim().length() <= 0)) continue;
|
||||
if (".".equals(line)) {
|
||||
boolean ok = _session.sendMessage(_peerDestination, ("Peer disconnected at " + now()).getBytes());
|
||||
// ignore ok, we're closing
|
||||
break;
|
||||
}
|
||||
if (line.startsWith(FILE_COMMAND) && (line.trim().length() > FILE_COMMAND.length())) {
|
||||
try {
|
||||
String file = line.substring(FILE_COMMAND.length());
|
||||
boolean sent = sendFile(file);
|
||||
if (!sent) {
|
||||
_out.write("Failed sending the file: " + file + NL);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
_out.write("Error sending the file: " + ioe.getMessage() + NL);
|
||||
_log.error("Error sending the file", ioe);
|
||||
}
|
||||
} else {
|
||||
boolean ok = _session.sendMessage(_peerDestination, ("[" + now() + "] " + line).getBytes());
|
||||
if (!ok) {
|
||||
_out.write("Failed sending message. Peer disconnected?" + NL);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error running", ioe);
|
||||
} catch (I2PSessionException ise) {
|
||||
_log.error("Error communicating", ise);
|
||||
} catch (DataFormatException dfe) {
|
||||
_log.error("Peer destination file is not valid", dfe);
|
||||
} finally {
|
||||
try {
|
||||
_log.debug("Exiting anonymous talk session");
|
||||
if (_out != null) _out.write("Exiting anonymous talk session");
|
||||
} catch (IOException ioe) {
|
||||
// ignored
|
||||
}
|
||||
if (_session != null) {
|
||||
try {
|
||||
_session.destroySession();
|
||||
} catch (I2PSessionException ise) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException ie) { // nop!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String now() {
|
||||
Date now = new Date(Clock.getInstance().now());
|
||||
return _fmt.format(now);
|
||||
}
|
||||
|
||||
/** Send the given file to the current peer. This works by sending a message
|
||||
* saying ".file: filename\nbodyOfFile", where filename is the name of the file
|
||||
* (which the recipient will be shown), and the bodyOfFile is the set of raw
|
||||
* bytes in the file.
|
||||
*
|
||||
* @throws IOException if the file could not be found or read
|
||||
* @return false if the file could not be sent to the peer
|
||||
*/
|
||||
private boolean sendFile(String filename) throws IOException, I2PSessionException {
|
||||
_log.debug("Sending file [" + filename + "]");
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
|
||||
baos.write((FILE_COMMAND + filename + "\n").getBytes());
|
||||
FileInputStream fin = new FileInputStream(filename);
|
||||
byte buf[] = new byte[4096];
|
||||
try {
|
||||
while (true) {
|
||||
int len = fin.read(buf);
|
||||
if (len == -1) break;
|
||||
baos.write(buf, 0, len);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
_log.debug("Failed reading the file", ioe);
|
||||
return false;
|
||||
}
|
||||
baos.close();
|
||||
byte val[] = baos.toByteArray();
|
||||
_log.debug("Sending " + filename + " with a full payload of " + val.length);
|
||||
try {
|
||||
boolean rv = _session.sendMessage(_peerDestination, val);
|
||||
_log.debug("Sending " + filename + " complete: rv = " + rv);
|
||||
return rv;
|
||||
} catch (Throwable t) {
|
||||
_log.error("Error sending file", t);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** I2PSessionListener.messageAvailable requires this method to be called whenever
|
||||
* I2P wants to tell the session that a message is available. ATalk always grabs
|
||||
* the message immediately and either processes it as a "send file" command (passing
|
||||
* it off to handleRecieveFile(..) or simply displays the
|
||||
* message to the user.
|
||||
*
|
||||
*/
|
||||
public void messageAvailable(I2PSession session, int msgId, long size) {
|
||||
_log.debug("Message available: id = " + msgId + " size = " + size);
|
||||
try {
|
||||
byte msg[] = session.receiveMessage(msgId);
|
||||
// inefficient way to just read the first line of text, but its easy
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(msg)));
|
||||
String line = reader.readLine();
|
||||
if (line.startsWith(FILE_COMMAND)) {
|
||||
handleRecieveFile(line, msg);
|
||||
} else {
|
||||
// not a file command, so just plop 'er out on the screen
|
||||
_out.write(now() + " --> " + new String(msg));
|
||||
_out.write(NL);
|
||||
_out.flush();
|
||||
}
|
||||
} catch (I2PSessionException ise) {
|
||||
_log.error("Error fetching available message", ise);
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error writing out the message", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
/** React to a file being sent our way from the peer via {@link #sendFile sendFile}
|
||||
* by saving the file to a temporary location and displaying where, what, and how large
|
||||
* it is.
|
||||
*
|
||||
* @param firstline the first line of the message that, according to the sendFile
|
||||
* implementation, contains the command and the filename that it was stored
|
||||
* at on the peer's computer
|
||||
* @param msg the entire message recieved, including the firstline
|
||||
*/
|
||||
private void handleRecieveFile(String firstline, byte msg[]) throws IOException {
|
||||
_log.debug("handleRecieveFile called");
|
||||
File f = File.createTempFile("recieve", ".dat", new File("."));
|
||||
FileOutputStream fos = new FileOutputStream(f);
|
||||
int lineLen = firstline.getBytes().length + "\n".getBytes().length;
|
||||
int lenToCopy = msg.length - lineLen;
|
||||
byte buf[] = new byte[lenToCopy];
|
||||
System.arraycopy(msg, lineLen, buf, 0, lenToCopy);
|
||||
fos.write(buf);
|
||||
fos.close();
|
||||
String name = firstline.substring(FILE_COMMAND.length());
|
||||
_out.write("Recieved a file called [" + name + "] of size [" + lenToCopy + "] bytes, saved as ["
|
||||
+ f.getAbsolutePath() + "]" + NL);
|
||||
_out.flush();
|
||||
}
|
||||
|
||||
/** driver */
|
||||
public static void main(String args[]) {
|
||||
I2PAppContext context = new I2PAppContext();
|
||||
if (args.length == 2) {
|
||||
String myKeyFile = args[0];
|
||||
String myDestinationFile = args[1];
|
||||
boolean success = generateKeys(myKeyFile, myDestinationFile);
|
||||
if (success)
|
||||
_log.debug("Keys generated (private key file: " + myKeyFile + " destination file: " + myDestinationFile
|
||||
+ ")");
|
||||
else
|
||||
_log.debug("Keys generation failed");
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException ie) { // nop
|
||||
}
|
||||
} else if (args.length == 3) {
|
||||
_log.debug("Starting chat");
|
||||
String myKeyfile = args[0];
|
||||
String peerDestFile = args[1];
|
||||
String shouldLog = args[2];
|
||||
if (Boolean.TRUE.toString().equalsIgnoreCase(shouldLog))
|
||||
context.logManager().setDisplayOnScreen(true);
|
||||
else
|
||||
context.logManager().setDisplayOnScreen(false);
|
||||
String logFile = args[2];
|
||||
Thread talkThread = new I2PThread(new ATalk(myKeyfile, peerDestFile));
|
||||
talkThread.start();
|
||||
} else {
|
||||
System.out.println(MANUAL);
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException ie) { // nop
|
||||
}
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/** Generate a new Destination, saving that destination and the associated
|
||||
* private keys in the privKeyFile, and also saving the destination without
|
||||
* any private keys to destinationFile.
|
||||
*
|
||||
* @param privKeyFile private key file, including the destination and the various
|
||||
* private keys, as defined by {@link I2PClient#createDestination I2PClient.createDestination}
|
||||
* @param destinationFile file in which the Destination is serialized in
|
||||
*/
|
||||
private static boolean generateKeys(String privKeyFile, String destinationFile) {
|
||||
try {
|
||||
Destination d = I2PClientFactory.createClient().createDestination(new FileOutputStream(privKeyFile));
|
||||
FileOutputStream fos = new FileOutputStream(destinationFile);
|
||||
d.writeBytes(fos);
|
||||
fos.flush();
|
||||
fos.close();
|
||||
return true;
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error generating keys", ioe);
|
||||
} catch (I2PException ipe) {
|
||||
_log.error("Error generating keys", ipe);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** required by {@link I2PSessionListener I2PSessionListener} to notify of disconnect */
|
||||
public void disconnected(I2PSession session) {
|
||||
_log.debug("Disconnected");
|
||||
}
|
||||
|
||||
/** required by {@link I2PSessionListener I2PSessionListener} to notify of error */
|
||||
public void errorOccurred(I2PSession session, String message, Throwable error) {
|
||||
_log.debug("Error occurred: " + message, error);
|
||||
}
|
||||
|
||||
/** required by {@link I2PSessionListener I2PSessionListener} to notify of abuse */
|
||||
public void reportAbuse(I2PSession session, int severity) {
|
||||
_log.debug("Abuse reported of severity " + severity);
|
||||
}
|
||||
}
|
||||
|
9
apps/desktopgui/.classpath
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/i2p_router"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/i2p_sdk"/>
|
||||
<classpathentry kind="lib" path="/lib/wrapper/all/wrapper.jar"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="output" path="build"/>
|
||||
</classpath>
|
17
apps/desktopgui/.project
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>desktopgui</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
@@ -9,6 +9,7 @@
|
||||
<property name="javadoc" value="javadoc"/>
|
||||
|
||||
<property name="javac.compilerargs" value=""/>
|
||||
<property name="require.gettext" value="true" />
|
||||
|
||||
<target name="init">
|
||||
<mkdir dir="${build}"/>
|
||||
@@ -29,8 +30,7 @@
|
||||
<compilerarg line="${javac.compilerargs}" />
|
||||
<classpath>
|
||||
<pathelement location="../../core/java/build/i2p.jar" />
|
||||
<!-- doesn't matter if we're not on win32, we just need the java classes, not the platform-dependent code -->
|
||||
<pathelement location="../../installer/lib/wrapper/win32/wrapper.jar" />
|
||||
<pathelement location="../../installer/lib/wrapper/all/wrapper.jar" />
|
||||
<pathelement location="../../router/java/build/router.jar" />
|
||||
</classpath>
|
||||
</javac>
|
||||
@@ -39,17 +39,20 @@
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<target name="jar" depends="compile">
|
||||
<exec executable="sh" osfamily="unix" failifexecutionfails="true" >
|
||||
<target name="bundle" >
|
||||
<exec executable="sh" osfamily="unix" failifexecutionfails="true" failonerror="${require.gettext}" >
|
||||
<arg value="./bundle-messages.sh" />
|
||||
</exec>
|
||||
<exec executable="sh" osfamily="mac" failifexecutionfails="true" >
|
||||
<exec executable="sh" osfamily="mac" failifexecutionfails="true" failonerror="${require.gettext}" >
|
||||
<arg value="./bundle-messages.sh" />
|
||||
</exec>
|
||||
<!-- multi-lang is optional -->
|
||||
<exec executable="sh" osfamily="windows" failifexecutionfails="false" >
|
||||
<arg value="./bundle-messages.sh" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="listChangedFiles" depends="jarUpToDate" if="shouldListChanges" >
|
||||
<exec executable="mtn" outputproperty="workspace.changes" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="list" />
|
||||
<arg value="changed" />
|
||||
@@ -61,6 +64,11 @@
|
||||
<arg value="[:space:]" />
|
||||
<arg value="," />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="jar" depends="compile, bundle, listChangedFiles" unless="jar.uptodate" >
|
||||
<!-- set if unset -->
|
||||
<property name="workspace.changes.tr" value="" />
|
||||
<jar basedir="${build}" destfile="${dist}/${jar}">
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="net.i2p.desktopgui.Main"/>
|
||||
@@ -71,6 +79,20 @@
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="jarUpToDate">
|
||||
<uptodate property="jar.uptodate" targetfile="${dist}/${jar}" >
|
||||
<srcfiles dir= "." includes="build/**/*.class" />
|
||||
</uptodate>
|
||||
<condition property="shouldListChanges" >
|
||||
<and>
|
||||
<not>
|
||||
<isset property="jar.uptodate" />
|
||||
</not>
|
||||
<isset property="mtn.available" />
|
||||
</and>
|
||||
</condition>
|
||||
</target>
|
||||
|
||||
<target name="javadoc">
|
||||
<mkdir dir="${build}" />
|
||||
<mkdir dir="${build}/${javadoc}" />
|
||||
@@ -88,15 +110,15 @@
|
||||
</target>
|
||||
|
||||
<target name="poupdate">
|
||||
<exec executable="sh" osfamily="unix" failifexecutionfails="true" >
|
||||
<exec executable="sh" osfamily="unix" failifexecutionfails="true" failonerror="true" >
|
||||
<arg value="./bundle-messages.sh" />
|
||||
<arg value="-p" />
|
||||
</exec>
|
||||
<exec executable="sh" osfamily="mac" failifexecutionfails="true" >
|
||||
<exec executable="sh" osfamily="mac" failifexecutionfails="true" failonerror="true" >
|
||||
<arg value="./bundle-messages.sh" />
|
||||
<arg value="-p" />
|
||||
</exec>
|
||||
<exec executable="sh" osfamily="windows" failifexecutionfails="true" >
|
||||
<exec executable="sh" osfamily="windows" failifexecutionfails="true" failonerror="true" >
|
||||
<arg value="./bundle-messages.sh" />
|
||||
<arg value="-p" />
|
||||
</exec>
|
||||
|
@@ -13,6 +13,7 @@
|
||||
CLASS=net.i2p.desktopgui.messages
|
||||
TMPFILE=build/javafiles.txt
|
||||
export TZ=UTC
|
||||
RC=0
|
||||
|
||||
if [ "$1" = "-p" ]
|
||||
then
|
||||
@@ -76,15 +77,17 @@ do
|
||||
-o ${i}t
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo 'Warning - xgettext failed, not updating translations'
|
||||
echo "ERROR - xgettext failed on ${i}, not updating translations"
|
||||
rm -f ${i}t
|
||||
RC=1
|
||||
break
|
||||
fi
|
||||
msgmerge -U --backup=none $i ${i}t
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo 'Warning - msgmerge failed, not updating translations'
|
||||
echo "ERROR - msgmerge failed on ${i}, not updating translations"
|
||||
rm -f ${i}t
|
||||
RC=1
|
||||
break
|
||||
fi
|
||||
rm -f ${i}t
|
||||
@@ -101,11 +104,13 @@ do
|
||||
msgfmt --java --statistics -r $CLASS -l $LG -d build $i
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo 'Warning - msgfmt failed, not updating translations'
|
||||
echo "ERROR - msgfmt failed on ${i}, not updating translations"
|
||||
# msgfmt leaves the class file there so the build would work the next time
|
||||
find build -name messages_${LG}.class -exec rm -f {} \;
|
||||
RC=1
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
rm -f $TMPFILE
|
||||
# todo: return failure
|
||||
exit 0
|
||||
exit $RC
|
||||
|
55
apps/desktopgui/locale/messages_ar.po
Normal file
@@ -0,0 +1,55 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
# foo <foo@bar>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P desktopgui\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-20 11:53+0000\n"
|
||||
"PO-Revision-Date: 2011-02-26 19:46-0000\n"
|
||||
"Last-Translator: hamada <hamada@mail.i2p>\n"
|
||||
"Language-Team: duck <duck@mail.i2p>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
msgstr "ابدأ I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "I2P is starting!"
|
||||
msgstr "جاري تشغيل I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "Starting"
|
||||
msgstr "جاري البدأ"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr " تشغيل متصفح I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
|
||||
msgid "Configure desktopgui"
|
||||
msgstr "اعدادات"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:67
|
||||
msgid "Restart I2P"
|
||||
msgstr "اعادة تشغيل"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:85
|
||||
msgid "Stop I2P"
|
||||
msgstr "توقيف I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "اعدادات الأيقونة"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "هل ترغب في تفعيل الأيقونة؟"
|
||||
|
55
apps/desktopgui/locale/messages_cs.po
Normal file
@@ -0,0 +1,55 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: https://trac.i2p2.de/\n"
|
||||
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
|
||||
"PO-Revision-Date: 2012-02-12 19:44+0000\n"
|
||||
"Last-Translator: Waseihou Watashi <waseihou@gmail.com>\n"
|
||||
"Language-Team: Czech (http://www.transifex.net/projects/p/I2P/language/cs/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: cs\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
msgstr "Spustit I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P startuje!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "Starting"
|
||||
msgstr "Startuji"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Spouštím I2P Browser"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
|
||||
msgid "Configure desktopgui"
|
||||
msgstr "Nastavuji desktopgui"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:67
|
||||
msgid "Restart I2P"
|
||||
msgstr "Restart I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:85
|
||||
msgid "Stop I2P"
|
||||
msgstr "Zastavit I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "Nastavení ikony na liště (tray icon)"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "Zapnout ikonu na liště?"
|
57
apps/desktopgui/locale/messages_da.po
Normal file
@@ -0,0 +1,57 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# <kia___@hushmail.com>, 2011.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: https://trac.i2p2.de/\n"
|
||||
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
|
||||
"PO-Revision-Date: 2011-07-12 19:41+0000\n"
|
||||
"Last-Translator: KIA <kia___@hushmail.com>\n"
|
||||
"Language-Team: Danish (http://www.transifex.net/projects/p/I2P/team/da/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: da\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
msgstr "Start I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P starter nu!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "Starting"
|
||||
msgstr "Starter"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Start I2P Browseren"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
|
||||
msgid "Configure desktopgui"
|
||||
msgstr "Konfigurer desktopgui"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:67
|
||||
msgid "Restart I2P"
|
||||
msgstr "Genstart I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:85
|
||||
msgid "Stop I2P"
|
||||
msgstr "Stop I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "Konfiguration af processbar ikonet"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "Skal processbar ikonet være aktivt?"
|
||||
|
||||
|
55
apps/desktopgui/locale/messages_de.po
Normal file
@@ -0,0 +1,55 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
# foo <foo@bar>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: https://trac.i2p2.de/\n"
|
||||
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
|
||||
"PO-Revision-Date: 2011-03-22 15:49+0000\n"
|
||||
"Last-Translator: blabla <blabla@trash-mail.com>\n"
|
||||
"Language-Team: German <>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: de\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
msgstr "I2P starten"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P startet gerade!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "Starting"
|
||||
msgstr "Startend"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "I2P-Browser öffnen"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
|
||||
msgid "Configure desktopgui"
|
||||
msgstr "Desktopgui konfigurieren"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:67
|
||||
msgid "Restart I2P"
|
||||
msgstr "I2P neustarten"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:85
|
||||
msgid "Stop I2P"
|
||||
msgstr "I2P beenden"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "Systemleistensymbol konfigurieren"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "Systemleistensymbol aktivieren?"
|
56
apps/desktopgui/locale/messages_el.po
Normal file
@@ -0,0 +1,56 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
# <lixtetrax@grhack.net>, 2012.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: https://trac.i2p2.de/\n"
|
||||
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
|
||||
"PO-Revision-Date: 2012-07-02 11:28+0000\n"
|
||||
"Last-Translator: lixtetrax <lixtetrax@grhack.net>\n"
|
||||
"Language-Team: Greek (http://www.transifex.com/projects/p/I2P/language/el/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: el\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
msgstr "Έναρξη Ι2Ρ"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "I2P is starting!"
|
||||
msgstr "Το Ι2Ρ ξεκίνησε!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "Starting"
|
||||
msgstr "Έναρξη"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Έναρξη φυλλομετρητή Ι2Ρ"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
|
||||
msgid "Configure desktopgui"
|
||||
msgstr "Παραμετροποίηση desktopgui"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:67
|
||||
msgid "Restart I2P"
|
||||
msgstr "Επανεκκίνηση Ι2Ρ"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:85
|
||||
msgid "Stop I2P"
|
||||
msgstr "Τερματισμός Ι2Ρ"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "Παραμετροποίηση εικονιδίου"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "Ενεργοποίηση εικονιδίου;"
|
@@ -8,10 +8,11 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P desktopgui\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-20 11:53+0000\n"
|
||||
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
|
||||
"PO-Revision-Date: 2010-06-15 14:09+0100\n"
|
||||
"Last-Translator: duck <duck@mail.i2p>\n"
|
||||
"Language-Team: duck <duck@mail.i2p>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
56
apps/desktopgui/locale/messages_es.po
Normal file
@@ -0,0 +1,56 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
# foo <foo@bar>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: https://trac.i2p2.de/\n"
|
||||
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
|
||||
"PO-Revision-Date: 2011-04-02 23:57+0100\n"
|
||||
"Last-Translator: mixxy <m1xxy@mail.i2p>\n"
|
||||
"Language-Team: Spanish (Castilian) <None>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: es\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
msgstr "Iniciar I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P está iniciando!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "Starting"
|
||||
msgstr "Iniciando"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Lanzar navegador I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
|
||||
msgid "Configure desktopgui"
|
||||
msgstr "Configurar desktopgui"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:67
|
||||
msgid "Restart I2P"
|
||||
msgstr "Reiniciar I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:85
|
||||
msgid "Stop I2P"
|
||||
msgstr "Detener I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "Configuración del ícono de la barra de tareas"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "¿Debería estar activado el ícono de la barra de tareas?"
|
||||
|
56
apps/desktopgui/locale/messages_fr.po
Normal file
@@ -0,0 +1,56 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
# foo <foo@bar>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P desktopgui\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
|
||||
"PO-Revision-Date: 2011-03-30 21:58+0100\n"
|
||||
"Last-Translator: magma <magma@mail.i2p>\n"
|
||||
"Language-Team: duck <duck@mail.i2p>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
msgstr "Démarrer I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P démarre!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "Starting"
|
||||
msgstr "Démarrage"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Lancer le navigateur"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
|
||||
msgid "Configure desktopgui"
|
||||
msgstr "Configurer l'interface de bureau"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:67
|
||||
msgid "Restart I2P"
|
||||
msgstr "Redémarrer I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:85
|
||||
msgid "Stop I2P"
|
||||
msgstr "Arrêter I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "Configuration de l'icône de notification"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "Activer l'icône de notification"
|
||||
|
55
apps/desktopgui/locale/messages_hu.po
Normal file
@@ -0,0 +1,55 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: https://trac.i2p2.de/\n"
|
||||
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
|
||||
"PO-Revision-Date: 2012-06-01 16:28+0000\n"
|
||||
"Last-Translator: AdminLMH <lehetmashogy@i2pmail.org>\n"
|
||||
"Language-Team: Hungarian (http://www.transifex.net/projects/p/I2P/language/hu/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: hu\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
msgstr "I2P indítása"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P indul!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "Starting"
|
||||
msgstr "indítás"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "I2P Böngésző Indítása"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
|
||||
msgid "Configure desktopgui"
|
||||
msgstr "Asztali Grafikus Felület Beállítása"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:67
|
||||
msgid "Restart I2P"
|
||||
msgstr "I2P Újraindítása"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:85
|
||||
msgid "Stop I2P"
|
||||
msgstr "I2P Leállítása"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "Tálcaikon beállítása"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "Tálcaikon engedélyezve legyen?"
|
57
apps/desktopgui/locale/messages_it.po
Normal file
@@ -0,0 +1,57 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
# <bovas85@gmail.com>, 2012.
|
||||
# <jokjok@hotmail.it>, 2011.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: https://trac.i2p2.de/\n"
|
||||
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
|
||||
"PO-Revision-Date: 2012-06-01 12:21+0000\n"
|
||||
"Last-Translator: Leelium <bovas85@gmail.com>\n"
|
||||
"Language-Team: Italian (http://www.transifex.net/projects/p/I2P/language/it/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: it\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
msgstr "Avvia I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "I2P is starting!"
|
||||
msgstr "Avvio di I2P in corso!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "Starting"
|
||||
msgstr "Avvio"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Avvia il Browser I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
|
||||
msgid "Configure desktopgui"
|
||||
msgstr "Configura desktopgui"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:67
|
||||
msgid "Restart I2P"
|
||||
msgstr "Riavvia I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:85
|
||||
msgid "Stop I2P"
|
||||
msgstr "Ferma I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "Configurazione dell'icona nell'area di notifica"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "Vuoi che l'icona nelll'rea di notifica venga abilitata?"
|
57
apps/desktopgui/locale/messages_pl.po
Normal file
@@ -0,0 +1,57 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# <b790979@klzlk.com>, 2011.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: https://trac.i2p2.de/\n"
|
||||
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
|
||||
"PO-Revision-Date: 2011-05-25 18:36+0000\n"
|
||||
"Last-Translator: PolishAnon <b790979@klzlk.com>\n"
|
||||
"Language-Team: Polish (http://www.transifex.net/projects/p/I2P/team/pl/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: pl\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
msgstr "Uruchom I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "I2P is starting!"
|
||||
msgstr "Uruchamianie I2P!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "Starting"
|
||||
msgstr "Uruchamianie"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Uruchom Przeglądarke I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
|
||||
msgid "Configure desktopgui"
|
||||
msgstr "Skonfiguruj intrefejs pulpitu (desktopgui)"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:67
|
||||
msgid "Restart I2P"
|
||||
msgstr "Zrestartuj I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:85
|
||||
msgid "Stop I2P"
|
||||
msgstr "Zatrzymaj I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "Konfiguracja ikony zasobnika"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "Czy ikona zasobnika powinna być aktywna?"
|
||||
|
||||
|
56
apps/desktopgui/locale/messages_sv.po
Normal file
@@ -0,0 +1,56 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
# 123hund123 <M8R-ra4r1r@mailinator.com>, 2011.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: https://trac.i2p2.de/\n"
|
||||
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
|
||||
"PO-Revision-Date: 2011-03-22 15:49+0000\n"
|
||||
"Last-Translator: 123hund123 <M8R-ra4r1r@mailinator.com>\n"
|
||||
"Language-Team: Swedish (Sweden) (http://www.transifex.net/projects/p/I2P/language/sv_SE/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: sv_SE\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
msgstr "Starta I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P startas!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "Starting"
|
||||
msgstr "Startar"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Öppna I2P browser"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
|
||||
msgid "Configure desktopgui"
|
||||
msgstr "Konfigurera desktopgui"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:67
|
||||
msgid "Restart I2P"
|
||||
msgstr "Starta om I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:85
|
||||
msgid "Stop I2P"
|
||||
msgstr "Stoppar I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "Ikonpanelskonfiguration"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "Ska ikonpanelen vara aktiverad?"
|
57
apps/desktopgui/locale/messages_uk.po
Normal file
@@ -0,0 +1,57 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# <gribua@gmail.com>, 2011.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: https://trac.i2p2.de/\n"
|
||||
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
|
||||
"PO-Revision-Date: 2011-06-19 14:01+0000\n"
|
||||
"Last-Translator: Pharmasolin <gribua@gmail.com>\n"
|
||||
"Language-Team: Ukrainian (Ukraine) (http://www.transifex.net/projects/p/I2P/team/uk_UA/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: uk_UA\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
msgstr "Запустити I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P запускається!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "Starting"
|
||||
msgstr "Запускається"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Запустити I2P Браузер"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
|
||||
msgid "Configure desktopgui"
|
||||
msgstr "Настроїти вигляд інтерфейсу"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:67
|
||||
msgid "Restart I2P"
|
||||
msgstr "Перезапустити I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:85
|
||||
msgid "Stop I2P"
|
||||
msgstr "Зупинити I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "Настройка трей-іконки"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "Чм повинна трей-іконка бути включена?"
|
||||
|
||||
|
57
apps/desktopgui/locale/messages_vi.po
Normal file
@@ -0,0 +1,57 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# dich_tran <tran.nathan@gmail.com>, 2011.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: https://trac.i2p2.de/\n"
|
||||
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
|
||||
"PO-Revision-Date: 2011-04-12 06:13+0000\n"
|
||||
"Last-Translator: dich_tran <tran.nathan@gmail.com>\n"
|
||||
"Language-Team: Vietnamese (http://www.transifex.net/projects/p/I2P/team/vi/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: vi\n"
|
||||
"Plural-Forms: nplurals=1; plural=0\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
msgstr "Khởi động I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P đang bắt đầu"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
|
||||
msgid "Starting"
|
||||
msgstr "Bắt đầu"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Kích hoạt trình duyệt I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
|
||||
msgid "Configure desktopgui"
|
||||
msgstr "Cấu hình giao diện"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:67
|
||||
msgid "Restart I2P"
|
||||
msgstr "Khởi động lại I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:85
|
||||
msgid "Stop I2P"
|
||||
msgstr "Ngưng I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "Cấu hình tray icon"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "Cần dùng tray icon?"
|
||||
|
||||
|
@@ -1,14 +1,23 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# ducki2p <ducki2p@gmail.com>, 2011.
|
||||
# walking <walking@i2pmail.org>, 2011.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-02-16 17:10+0000\n"
|
||||
"PO-Revision-Date: \n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: https://trac.i2p2.de/\n"
|
||||
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
|
||||
"PO-Revision-Date: 2011-03-24 09:18+0000\n"
|
||||
"Last-Translator: walking <walking@i2pmail.org>\n"
|
||||
"Language-Team: Chinese (China) (http://www.transifex.net/projects/p/I2P/team/zh_CN/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: zh_CN\n"
|
||||
"Plural-Forms: nplurals=1; plural=0\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
|
||||
msgid "Start I2P"
|
||||
@@ -28,7 +37,7 @@ msgstr "正在启动I2P浏览器"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
|
||||
msgid "Configure desktopgui"
|
||||
msgstr "界面设置"
|
||||
msgstr "设置desktopgui"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:67
|
||||
msgid "Restart I2P"
|
||||
@@ -38,13 +47,12 @@ msgstr "重启 I2P"
|
||||
msgid "Stop I2P"
|
||||
msgstr "停止 I2P"
|
||||
|
||||
#. Translate interface
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:26
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
|
||||
msgid "Tray icon configuration"
|
||||
msgstr "托盘图标配置"
|
||||
|
||||
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
|
||||
msgid "Should tray icon be enabled?"
|
||||
msgstr "显示托盘图标。"
|
||||
msgstr "是否启用托盘图标?"
|
||||
|
||||
#~ msgid "Browser not found"
|
||||
#~ msgstr "Browser niet gevonden"
|
||||
#~ msgid "The default browser for your system was not found."
|
||||
#~ msgstr "De standaard webbrowser voor je systeem werd niet gevonden."
|
||||
|
||||
|
@@ -1,106 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project basedir="." default="all" name="fortuna">
|
||||
|
||||
<property name="cvs.base.dir" value="java/gnu-crypto" />
|
||||
<property name="cvs.etc.dir" value="${cvs.base.dir}/etc" />
|
||||
<property name="cvs.lib.dir" value="${cvs.base.dir}/lib" />
|
||||
<property name="cvs.object.dir" value="${cvs.base.dir}/classes" />
|
||||
<property name="cvs.base.crypto.object.dir" value="${cvs.object.dir}/gnu/crypto" />
|
||||
<property name="cvs.cipher.object.dir" value="${cvs.base.crypto.object.dir}/cipher" />
|
||||
<property name="cvs.hash.object.dir" value="${cvs.base.crypto.object.dir}/hash" />
|
||||
<property name="cvs.prng.object.dir" value="${cvs.base.crypto.object.dir}/prng" />
|
||||
|
||||
<patternset id="fortuna.files">
|
||||
<include name="${cvs.base.crypto.object.dir}/Registry.class"/>
|
||||
<include name="${cvs.prng.object.dir}/Fortuna*.class"/>
|
||||
<include name="${cvs.prng.object.dir}/BasePRNG.class"/>
|
||||
<include name="${cvs.prng.object.dir}/RandomEventListener.class"/>
|
||||
<include name="${cvs.prng.object.dir}/IRandom.class"/>
|
||||
<include name="${cvs.cipher.object.dir}/CipherFactory.class"/>
|
||||
<include name="${cvs.cipher.object.dir}/IBlockCipher.class"/>
|
||||
<include name="${cvs.hash.object.dir}/HashFactory.class"/>
|
||||
<include name="${cvs.hash.object.dir}/IMessageDigest.class"/>
|
||||
</patternset>
|
||||
|
||||
<target name="all" depends="build,jar"
|
||||
description="Create and test the custom Fortuna library" />
|
||||
|
||||
<target name="build" depends="-init,checkout"
|
||||
description="Build the source and tests">
|
||||
<ant dir="${cvs.base.dir}" target="jar" />
|
||||
</target>
|
||||
|
||||
<target name="builddep" />
|
||||
|
||||
<target name="checkout" depends="-init" unless="cvs.source.available"
|
||||
description="Check out GNU Crypto sources from CVS HEAD">
|
||||
<cvs cvsRoot=":ext:anoncvs@savannah.gnu.org:/cvsroot/gnu-crypto"
|
||||
cvsRsh="ssh"
|
||||
dest="java"
|
||||
package="gnu-crypto" />
|
||||
</target>
|
||||
|
||||
<target name="clean"
|
||||
description="Remove generated tests and object files">
|
||||
<ant dir="${cvs.base.dir}" target="clean" />
|
||||
</target>
|
||||
|
||||
<target name="cleandep" />
|
||||
|
||||
<target name="compile" />
|
||||
|
||||
<target name="distclean" depends="clean"
|
||||
description="Remove all generated files">
|
||||
<delete dir="build" />
|
||||
<delete dir="jartemp" />
|
||||
<!--
|
||||
Annoyingly the GNU Crypto distclean task called here doesn't clean
|
||||
*all* derived files from java/gnu-crypto/lib like it should.....
|
||||
-->
|
||||
<ant dir="${cvs.base.dir}" target="distclean" />
|
||||
<!--
|
||||
.....and so we mop up the rest ourselves.
|
||||
-->
|
||||
<delete dir="${cvs.lib.dir}" />
|
||||
</target>
|
||||
|
||||
<target name="-init">
|
||||
<available property="cvs.source.available" file="${cvs.base.dir}" />
|
||||
</target>
|
||||
|
||||
<target name="jar" depends="build"
|
||||
description="Create the custom Fortuna jar library">
|
||||
<delete dir="build" />
|
||||
<delete dir="jartemp" />
|
||||
<mkdir dir="build" />
|
||||
<mkdir dir="jartemp/${cvs.object.dir}" />
|
||||
<copy todir="jartemp">
|
||||
<fileset dir=".">
|
||||
<patternset refid="fortuna.files" />
|
||||
</fileset>
|
||||
</copy>
|
||||
<jar basedir="jartemp/${cvs.object.dir}" jarfile="build/fortuna.jar">
|
||||
<manifest>
|
||||
<section name="fortuna">
|
||||
<attribute name="Implementation-Title" value="I2P Custom GNU Crypto Fortuna Library" />
|
||||
<attribute name="Implementation-Version" value="CVS HEAD" />
|
||||
<attribute name="Implementation-Vendor" value="Free Software Foundation" />
|
||||
<attribute name="Implementation-Vendor-Id" value="FSF" />
|
||||
<attribute name="Implementation-URL" value="http://www.gnu.org/software/gnu-crypto" />
|
||||
</section>
|
||||
</manifest>
|
||||
</jar>
|
||||
<delete dir="jartemp" />
|
||||
</target>
|
||||
|
||||
<target name="test" depends="jar"
|
||||
description="Perform crypto tests on custom Fortuna jar library" />
|
||||
<!--
|
||||
Add this when Fortuna tests are added to GNU Crypto, else write some
|
||||
-->
|
||||
|
||||
<target name="update" depends="checkout"
|
||||
description="Update GNU Crypto sources to latest CVS HEAD">
|
||||
<cvs command="update -d" cvsRsh="ssh" dest="java/gnu-crypto" />
|
||||
</target>
|
||||
</project>
|
11
apps/i2psnark/.classpath
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="java/src"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/i2p_sdk"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/ministreaming"/>
|
||||
<classpathentry kind="lib" path="/jetty/jettylib/javax.servlet.jar"/>
|
||||
<classpathentry kind="lib" path="/jetty/jettylib/jetty-util.jar"/>
|
||||
<classpathentry kind="lib" path="/jetty/jettylib/org.mortbay.jetty.jar"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="output" path="java/build/obj"/>
|
||||
</classpath>
|
17
apps/i2psnark/.project
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>i2psnark</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
Before Width: | Height: | Size: 464 B After Width: | Height: | Size: 464 B |
BIN
apps/i2psnark/icons/basket_put.png
Normal file
After Width: | Height: | Size: 733 B |
Before Width: | Height: | Size: 587 B After Width: | Height: | Size: 587 B |
Before Width: | Height: | Size: 673 B After Width: | Height: | Size: 673 B |
Before Width: | Height: | Size: 882 B After Width: | Height: | Size: 882 B |
Before Width: | Height: | Size: 889 B After Width: | Height: | Size: 889 B |
Before Width: | Height: | Size: 766 B After Width: | Height: | Size: 766 B |
Before Width: | Height: | Size: 653 B After Width: | Height: | Size: 653 B |
Before Width: | Height: | Size: 537 B After Width: | Height: | Size: 537 B |
Before Width: | Height: | Size: 578 B After Width: | Height: | Size: 578 B |
Before Width: | Height: | Size: 591 B After Width: | Height: | Size: 591 B |
Before Width: | Height: | Size: 385 B After Width: | Height: | Size: 385 B |
Before Width: | Height: | Size: 853 B After Width: | Height: | Size: 853 B |
Before Width: | Height: | Size: 635 B After Width: | Height: | Size: 635 B |
Before Width: | Height: | Size: 294 B After Width: | Height: | Size: 294 B |
Before Width: | Height: | Size: 591 B After Width: | Height: | Size: 591 B |
Before Width: | Height: | Size: 589 B After Width: | Height: | Size: 589 B |
Before Width: | Height: | Size: 591 B After Width: | Height: | Size: 591 B |
Before Width: | Height: | Size: 537 B After Width: | Height: | Size: 537 B |
@@ -19,10 +19,14 @@
|
||||
<pathelement location="../../ministreaming/java/build/obj" />
|
||||
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.jar" />
|
||||
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
||||
<pathelement location="../../jetty/jettylib/jetty-util.jar" />
|
||||
</classpath>
|
||||
</depend>
|
||||
</target>
|
||||
|
||||
<property name="javac.compilerargs" value="" />
|
||||
<property name="require.gettext" value="true" />
|
||||
|
||||
<target name="compile" depends="depend">
|
||||
<mkdir dir="./build" />
|
||||
<mkdir dir="./build/obj" />
|
||||
@@ -31,12 +35,12 @@
|
||||
debug="true" deprecation="on" source="1.5" target="1.5"
|
||||
destdir="./build/obj"
|
||||
includeAntRuntime="false"
|
||||
classpath="../../../core/java/build/i2p.jar:../../jetty/jettylib/org.mortbay.jetty.jar:../../jetty/jettylib/javax.servlet.jar:../../ministreaming/java/build/mstreaming.jar" >
|
||||
classpath="../../../core/java/build/i2p.jar:../../jetty/jettylib/org.mortbay.jetty.jar:../../jetty/jettylib/javax.servlet.jar:../../jetty/jettylib/jetty-util.jar:../../ministreaming/java/build/mstreaming.jar" >
|
||||
<compilerarg line="${javac.compilerargs}" />
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="jar" depends="builddep, compile, jarUpToDate" unless="jar.uptodate" >
|
||||
<target name="listChangedFiles" depends="jarUpToDate" if="shouldListChanges" >
|
||||
<exec executable="mtn" outputproperty="workspace.changes" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="list" />
|
||||
<arg value="changed" />
|
||||
@@ -48,10 +52,17 @@
|
||||
<arg value="[:space:]" />
|
||||
<arg value="," />
|
||||
</exec>
|
||||
<jar destfile="./build/i2psnark.jar" basedir="./build/obj" includes="**/*.class" excludes="**/I2PSnarkServlet*.class **/messages_*.class">
|
||||
</target>
|
||||
|
||||
<target name="jar" depends="builddep, compile, jarUpToDate, listChangedFiles" unless="jar.uptodate" >
|
||||
<!-- set if unset -->
|
||||
<property name="workspace.changes.tr" value="" />
|
||||
<jar destfile="./build/i2psnark.jar" basedir="./build/obj" includes="**/*.class" excludes="**/I2PSnarkServlet*.class **/FetchAndAdd*.class **/messages_*.class">
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="org.klomp.snark.Snark" />
|
||||
<attribute name="Class-Path" value="i2p.jar mstreaming.jar streaming.jar" />
|
||||
<attribute name="Implementation-Version" value="${full.version}" />
|
||||
<attribute name="Built-By" value="${build.built-by}" />
|
||||
<attribute name="Build-Date" value="${build.timestamp}" />
|
||||
<attribute name="Base-Revision" value="${workspace.version}" />
|
||||
<attribute name="Workspace-Changes" value="${workspace.changes.tr}" />
|
||||
@@ -61,8 +72,19 @@
|
||||
|
||||
<target name="jarUpToDate">
|
||||
<uptodate property="jar.uptodate" targetfile="build/i2psnark.jar" >
|
||||
<srcfiles dir= "build/obj" includes="**/*.class" excludes="**/I2PSnarkServlet*.class **/messages_*.class" />
|
||||
<srcfiles dir= "build/obj" includes="**/*.class" excludes="**/I2PSnarkServlet*.class **/FetchAndAdd*.class **/messages_*.class" />
|
||||
</uptodate>
|
||||
<condition property="shouldListChanges" >
|
||||
<and>
|
||||
<not>
|
||||
<isset property="jar.uptodate" />
|
||||
</not>
|
||||
<not>
|
||||
<isset property="war.uptodate" />
|
||||
</not>
|
||||
<isset property="mtn.available" />
|
||||
</and>
|
||||
</condition>
|
||||
</target>
|
||||
|
||||
<!-- Ideally we would include
|
||||
@@ -72,31 +94,39 @@
|
||||
- So we must continue to duplicate everything in the war.
|
||||
<classes dir="./build/obj" includes="**/I2PSnarkServlet*.class" />
|
||||
-->
|
||||
<target name="war" depends="jar, bundle, warUpToDate" unless="war.uptodate" >
|
||||
<war destfile="../i2psnark.war" webxml="../web.xml" basedir="../" includes="_icons/*" >
|
||||
<target name="war" depends="jar, bundle, warUpToDate, listChangedFiles" unless="war.uptodate" >
|
||||
<!-- set if unset -->
|
||||
<property name="workspace.changes.tr" value="" />
|
||||
<copy todir="build/icons/.icons" >
|
||||
<fileset dir="../icons/" />
|
||||
</copy>
|
||||
<war destfile="../i2psnark.war" webxml="../web.xml" >
|
||||
<!-- include only the web stuff, as of 0.7.12 the router will add i2psnark.jar to the classpath for the war -->
|
||||
<classes dir="./build/obj" includes="**/web/*.class" />
|
||||
<fileset dir="build/icons/" />
|
||||
<manifest>
|
||||
<attribute name="Implementation-Version" value="${full.version}" />
|
||||
<attribute name="Built-By" value="${build.built-by}" />
|
||||
<attribute name="Build-Date" value="${build.timestamp}" />
|
||||
<attribute name="Base-Revision" value="${workspace.version}" />
|
||||
<attribute name="Workspace-Changes" value="${workspace.changes}" />
|
||||
<attribute name="Workspace-Changes" value="${workspace.changes.tr}" />
|
||||
</manifest>
|
||||
</war>
|
||||
</target>
|
||||
|
||||
<target name="warUpToDate">
|
||||
<uptodate property="war.uptodate" targetfile="../i2psnark.war" >
|
||||
<srcfiles dir= "." includes="build/obj/org/klomp/snark/web/*.class ../_icons/* ../web.xml" />
|
||||
<srcfiles dir= "." includes="build/obj/org/klomp/snark/web/*.class ../icons/* ../web.xml" />
|
||||
</uptodate>
|
||||
</target>
|
||||
|
||||
<target name="bundle" depends="compile">
|
||||
<!-- Update the messages_*.po files.
|
||||
We need to supply the bat file for windows, and then change the fail property to true -->
|
||||
<exec executable="sh" osfamily="unix" failifexecutionfails="true" >
|
||||
<exec executable="sh" osfamily="unix" failifexecutionfails="true" failonerror="${require.gettext}" >
|
||||
<arg value="./bundle-messages.sh" />
|
||||
</exec>
|
||||
<exec executable="sh" osfamily="mac" failifexecutionfails="true" >
|
||||
<exec executable="sh" osfamily="mac" failifexecutionfails="true" failonerror="${require.gettext}" >
|
||||
<arg value="./bundle-messages.sh" />
|
||||
</exec>
|
||||
<!-- multi-lang is optional -->
|
||||
@@ -107,15 +137,15 @@
|
||||
|
||||
<target name="poupdate" depends="builddep, compile">
|
||||
<!-- Update the messages_*.po files. -->
|
||||
<exec executable="sh" osfamily="unix" failifexecutionfails="true" >
|
||||
<exec executable="sh" osfamily="unix" failifexecutionfails="true" failonerror="true" >
|
||||
<arg value="./bundle-messages.sh" />
|
||||
<arg value="-p" />
|
||||
</exec>
|
||||
<exec executable="sh" osfamily="mac" failifexecutionfails="true" >
|
||||
<exec executable="sh" osfamily="mac" failifexecutionfails="true" failonerror="true" >
|
||||
<arg value="./bundle-messages.sh" />
|
||||
<arg value="-p" />
|
||||
</exec>
|
||||
<exec executable="sh" osfamily="windows" failifexecutionfails="true" >
|
||||
<exec executable="sh" osfamily="windows" failifexecutionfails="true" failonerror="true" >
|
||||
<arg value="./bundle-messages.sh" />
|
||||
<arg value="-p" />
|
||||
</exec>
|
||||
|
@@ -12,6 +12,7 @@
|
||||
CLASS=org.klomp.snark.web.messages
|
||||
TMPFILE=build/javafiles.txt
|
||||
export TZ=UTC
|
||||
RC=0
|
||||
|
||||
if [ "$1" = "-p" ]
|
||||
then
|
||||
@@ -67,15 +68,17 @@ do
|
||||
-o ${i}t
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo 'Warning - xgettext failed, not updating translations'
|
||||
echo "ERROR - xgettext failed on ${i}, not updating translations"
|
||||
rm -f ${i}t
|
||||
RC=1
|
||||
break
|
||||
fi
|
||||
msgmerge -U --backup=none $i ${i}t
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo 'Warning - msgmerge failed, not updating translations'
|
||||
echo "ERROR - msgmerge failed on ${i}, not updating translations"
|
||||
rm -f ${i}t
|
||||
RC=1
|
||||
break
|
||||
fi
|
||||
rm -f ${i}t
|
||||
@@ -92,11 +95,13 @@ do
|
||||
msgfmt --java --statistics -r $CLASS -l $LG -d build/obj $i
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo 'Warning - msgfmt failed, not updating translations'
|
||||
echo "ERROR - msgfmt failed on ${i}, not updating translations"
|
||||
# msgfmt leaves the class file there so the build would work the next time
|
||||
find build/obj -name messages_${LG}.class -exec rm -f {} \;
|
||||
RC=1
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
rm -f $TMPFILE
|
||||
# todo: return failure
|
||||
exit 0
|
||||
exit $RC
|
||||
|
76
apps/i2psnark/java/src/net/i2p/kademlia/KBucket.java
Normal file
@@ -0,0 +1,76 @@
|
||||
package net.i2p.kademlia;
|
||||
/*
|
||||
* free (adj.): unencumbered; not under the control of others
|
||||
* Written by jrandom in 2003 and released into the public domain
|
||||
* with no warranty of any kind, either expressed or implied.
|
||||
* It probably won't make your computer catch on fire, or eat
|
||||
* your children, but it might. Use at your own risk.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.data.SimpleDataStructure;
|
||||
|
||||
/**
|
||||
* Group, without inherent ordering, a set of keys a certain distance away from
|
||||
* a local key, using XOR as the distance metric
|
||||
*
|
||||
* Refactored from net.i2p.router.networkdb.kademlia
|
||||
* @since 0.9.2
|
||||
*/
|
||||
public interface KBucket<T extends SimpleDataStructure> {
|
||||
|
||||
/**
|
||||
* Lowest order high bit for difference keys.
|
||||
* The lower-bounds distance of this bucket is 2**begin.
|
||||
* If begin == 0, this is the closest bucket.
|
||||
*/
|
||||
public int getRangeBegin();
|
||||
|
||||
/**
|
||||
* Highest high bit for the difference keys.
|
||||
* The upper-bounds distance of this bucket is (2**(end+1)) - 1.
|
||||
* If begin == end, the bucket cannot be split further.
|
||||
* If end == (numbits - 1), this is the furthest bucket.
|
||||
*/
|
||||
public int getRangeEnd();
|
||||
|
||||
/**
|
||||
* Number of keys already contained in this kbucket
|
||||
*/
|
||||
public int getKeyCount();
|
||||
|
||||
/**
|
||||
* Add the peer to the bucket
|
||||
*
|
||||
* @return true if added
|
||||
*/
|
||||
public boolean add(T key);
|
||||
|
||||
/**
|
||||
* Remove the key from the bucket
|
||||
* @return true if the key existed in the bucket before removing it, else false
|
||||
*/
|
||||
public boolean remove(T key);
|
||||
|
||||
/**
|
||||
* Update the last-changed timestamp to now.
|
||||
*/
|
||||
public void setLastChanged();
|
||||
|
||||
/**
|
||||
* The last-changed timestamp
|
||||
*/
|
||||
public long getLastChanged();
|
||||
|
||||
/**
|
||||
* Retrieve all routing table entries stored in the bucket
|
||||
* @return set of Hash structures
|
||||
*/
|
||||
public Set<T> getEntries();
|
||||
|
||||
public void getEntries(SelectionCollector<T> collector);
|
||||
|
||||
public void clear();
|
||||
}
|
150
apps/i2psnark/java/src/net/i2p/kademlia/KBucketImpl.java
Normal file
@@ -0,0 +1,150 @@
|
||||
package net.i2p.kademlia;
|
||||
/*
|
||||
* free (adj.): unencumbered; not under the control of others
|
||||
* Written by jrandom in 2003 and released into the public domain
|
||||
* with no warranty of any kind, either expressed or implied.
|
||||
* It probably won't make your computer catch on fire, or eat
|
||||
* your children, but it might. Use at your own risk.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.SimpleDataStructure;
|
||||
import net.i2p.util.ConcurrentHashSet;
|
||||
|
||||
/**
|
||||
* A concurrent implementation using ConcurrentHashSet.
|
||||
* The max size (K) may be temporarily exceeded due to concurrency,
|
||||
* a pending split, or the behavior of the supplied trimmer,
|
||||
* as explained below.
|
||||
* The creator is responsible for splits.
|
||||
*
|
||||
* This class has no knowledge of the DHT base used for XORing,
|
||||
* and thus there are no validity checks in add/remove.
|
||||
*
|
||||
* The begin and end values are immutable.
|
||||
* All entries in this bucket will have at least one bit different
|
||||
* from us in the range [begin, end] inclusive.
|
||||
* Splits must be implemented by creating two new buckets
|
||||
* and discarding this one.
|
||||
*
|
||||
* The keys are kept in a Set and are NOT sorted by last-seen.
|
||||
* Per-key last-seen-time, failures, etc. must be tracked elsewhere.
|
||||
*
|
||||
* If this bucket is full (i.e. begin == end && size == max)
|
||||
* then add() will call KBucketTrimmer.trim() do
|
||||
* (possibly) remove older entries, and indicate whether
|
||||
* to add the new entry. If the trimmer returns true without
|
||||
* removing entries, this KBucket will exceed the max size.
|
||||
*
|
||||
* Refactored from net.i2p.router.networkdb.kademlia
|
||||
* @since 0.9.2
|
||||
*/
|
||||
class KBucketImpl<T extends SimpleDataStructure> implements KBucket<T> {
|
||||
/**
|
||||
* set of Hash objects for the peers in the kbucket
|
||||
*/
|
||||
private final Set<T> _entries;
|
||||
/** include if any bits equal or higher to this bit (in big endian order) */
|
||||
private final int _begin;
|
||||
/** include if no bits higher than this bit (inclusive) are set */
|
||||
private final int _end;
|
||||
private final int _max;
|
||||
private final KBucketTrimmer _trimmer;
|
||||
/** when did we last shake things up */
|
||||
private long _lastChanged;
|
||||
private final I2PAppContext _context;
|
||||
|
||||
/**
|
||||
* All entries in this bucket will have at least one bit different
|
||||
* from us in the range [begin, end] inclusive.
|
||||
*/
|
||||
public KBucketImpl(I2PAppContext context, int begin, int end, int max, KBucketTrimmer trimmer) {
|
||||
if (begin > end)
|
||||
throw new IllegalArgumentException(begin + " > " + end);
|
||||
_context = context;
|
||||
_entries = new ConcurrentHashSet(max + 4);
|
||||
_begin = begin;
|
||||
_end = end;
|
||||
_max = max;
|
||||
_trimmer = trimmer;
|
||||
}
|
||||
|
||||
public int getRangeBegin() { return _begin; }
|
||||
|
||||
public int getRangeEnd() { return _end; }
|
||||
|
||||
public int getKeyCount() {
|
||||
return _entries.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an unmodifiable view; not a copy
|
||||
*/
|
||||
public Set<T> getEntries() {
|
||||
return Collections.unmodifiableSet(_entries);
|
||||
}
|
||||
|
||||
public void getEntries(SelectionCollector<T> collector) {
|
||||
for (T h : _entries) {
|
||||
collector.add(h);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
_entries.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets last-changed if rv is true OR if the peer is already present.
|
||||
* Calls the trimmer if begin == end and we are full.
|
||||
* If begin != end then add it and caller must do bucket splitting.
|
||||
* @return true if added
|
||||
*/
|
||||
public boolean add(T peer) {
|
||||
if (_begin != _end || _entries.size() < _max ||
|
||||
_entries.contains(peer) || _trimmer.trim(this, peer)) {
|
||||
// do this even if already contains, to call setLastChanged()
|
||||
boolean rv = _entries.add(peer);
|
||||
setLastChanged();
|
||||
return rv;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if removed. Does NOT set lastChanged.
|
||||
*/
|
||||
public boolean remove(T peer) {
|
||||
boolean rv = _entries.remove(peer);
|
||||
//if (rv)
|
||||
// setLastChanged();
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the last-changed timestamp to now.
|
||||
*/
|
||||
public void setLastChanged() {
|
||||
_lastChanged = _context.clock().now();
|
||||
}
|
||||
|
||||
/**
|
||||
* The last-changed timestamp, which actually indicates last-added or last-seen.
|
||||
*/
|
||||
public long getLastChanged() {
|
||||
return _lastChanged;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder(1024);
|
||||
buf.append(_entries.size());
|
||||
buf.append(" entries in (").append(_begin).append(',').append(_end);
|
||||
buf.append(") : ").append(_entries.toString());
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
780
apps/i2psnark/java/src/net/i2p/kademlia/KBucketSet.java
Normal file
@@ -0,0 +1,780 @@
|
||||
package net.i2p.kademlia;
|
||||
/*
|
||||
* free (adj.): unencumbered; not under the control of others
|
||||
* Written by jrandom in 2003 and released into the public domain
|
||||
* with no warranty of any kind, either expressed or implied.
|
||||
* It probably won't make your computer catch on fire, or eat
|
||||
* your children, but it might. Use at your own risk.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.SimpleDataStructure;
|
||||
import net.i2p.util.LHMCache;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* In-memory storage of buckets sorted by the XOR metric from the base (us)
|
||||
* passed in via the constructor.
|
||||
* This starts with one bucket covering the whole key space, and
|
||||
* may eventually be split to a max of the number of bits in the data type
|
||||
* (160 for SHA1Hash or 256 for Hash),
|
||||
* times 2**(B-1) for Kademlia value B.
|
||||
*
|
||||
* Refactored from net.i2p.router.networkdb.kademlia
|
||||
* @since 0.9.2
|
||||
*/
|
||||
public class KBucketSet<T extends SimpleDataStructure> {
|
||||
private final Log _log;
|
||||
private final I2PAppContext _context;
|
||||
private final T _us;
|
||||
|
||||
/**
|
||||
* The bucket list is locked by _bucketsLock, however the individual
|
||||
* buckets are not locked. Users may see buckets that have more than
|
||||
* the maximum k entries, or may have adds and removes silently fail
|
||||
* when they appear to succeed.
|
||||
*
|
||||
* Closest values are in bucket 0, furthest are in the last bucket.
|
||||
*/
|
||||
private final List<KBucket> _buckets;
|
||||
private final Range<T> _rangeCalc;
|
||||
private final KBucketTrimmer _trimmer;
|
||||
|
||||
/**
|
||||
* Locked for reading only when traversing all the buckets.
|
||||
* Locked for writing only when splitting a bucket.
|
||||
* Adds/removes/gets from individual buckets are not locked.
|
||||
*/
|
||||
private final ReentrantReadWriteLock _bucketsLock = new ReentrantReadWriteLock(false);
|
||||
|
||||
private final int KEYSIZE_BITS;
|
||||
private final int NUM_BUCKETS;
|
||||
private final int BUCKET_SIZE;
|
||||
private final int B_VALUE;
|
||||
private final int B_FACTOR;
|
||||
|
||||
/**
|
||||
* Use the default trim strategy, which removes a random entry.
|
||||
* @param us the local identity (typically a SHA1Hash or Hash)
|
||||
* The class must have a zero-argument constructor.
|
||||
* @param max the Kademlia value "k", the max per bucket, k >= 4
|
||||
* @param b the Kademlia value "b", split buckets an extra 2**(b-1) times,
|
||||
* b > 0, use 1 for bittorrent, Kademlia paper recommends 5
|
||||
*/
|
||||
public KBucketSet(I2PAppContext context, T us, int max, int b) {
|
||||
this(context, us, max, b, new RandomTrimmer(context, max));
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the supplied trim strategy.
|
||||
*/
|
||||
public KBucketSet(I2PAppContext context, T us, int max, int b, KBucketTrimmer trimmer) {
|
||||
_us = us;
|
||||
_context = context;
|
||||
_log = context.logManager().getLog(KBucketSet.class);
|
||||
_trimmer = trimmer;
|
||||
if (max <= 4 || b <= 0 || b > 8)
|
||||
throw new IllegalArgumentException();
|
||||
KEYSIZE_BITS = us.length() * 8;
|
||||
B_VALUE = b;
|
||||
B_FACTOR = 1 << (b - 1);
|
||||
NUM_BUCKETS = KEYSIZE_BITS * B_FACTOR;
|
||||
BUCKET_SIZE = max;
|
||||
_buckets = createBuckets();
|
||||
_rangeCalc = new Range(us, B_VALUE);
|
||||
// this verifies the zero-argument constructor
|
||||
makeKey(new byte[us.length()]);
|
||||
}
|
||||
|
||||
private void getReadLock() {
|
||||
_bucketsLock.readLock().lock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lock if we can. Non-blocking.
|
||||
* @return true if the lock was acquired
|
||||
*/
|
||||
private boolean tryReadLock() {
|
||||
return _bucketsLock.readLock().tryLock();
|
||||
}
|
||||
|
||||
private void releaseReadLock() {
|
||||
_bucketsLock.readLock().unlock();
|
||||
}
|
||||
|
||||
/** @return true if the lock was acquired */
|
||||
private boolean getWriteLock() {
|
||||
try {
|
||||
boolean rv = _bucketsLock.writeLock().tryLock(3000, TimeUnit.MILLISECONDS);
|
||||
if ((!rv) && _log.shouldLog(Log.WARN))
|
||||
_log.warn("no lock, size is: " + _bucketsLock.getQueueLength(), new Exception("rats"));
|
||||
return rv;
|
||||
} catch (InterruptedException ie) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void releaseWriteLock() {
|
||||
_bucketsLock.writeLock().unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the peer is new to the bucket it goes in, or false if it was
|
||||
* already in it. Always returns false on an attempt to add ourselves.
|
||||
*
|
||||
*/
|
||||
public boolean add(T peer) {
|
||||
KBucket bucket;
|
||||
getReadLock();
|
||||
try {
|
||||
bucket = getBucket(peer);
|
||||
} finally { releaseReadLock(); }
|
||||
if (bucket != null) {
|
||||
if (bucket.add(peer)) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Peer " + peer + " added to bucket " + bucket);
|
||||
if (shouldSplit(bucket)) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Splitting bucket " + bucket);
|
||||
split(bucket.getRangeBegin());
|
||||
//testAudit(this, _log);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Peer " + peer + " NOT added to bucket " + bucket);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Failed to add, probably us: " + peer);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* No lock required.
|
||||
* FIXME will split the closest buckets too far if B > 1 and K < 2**B
|
||||
* Won't ever really happen and if it does it still works.
|
||||
*/
|
||||
private boolean shouldSplit(KBucket b) {
|
||||
return
|
||||
b.getRangeBegin() != b.getRangeEnd() &&
|
||||
b.getKeyCount() > BUCKET_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabs the write lock.
|
||||
* Caller must NOT have the read lock.
|
||||
* The bucket should be splittable (range start != range end).
|
||||
* @param r the range start of the bucket to be split
|
||||
*/
|
||||
private void split(int r) {
|
||||
if (!getWriteLock())
|
||||
return;
|
||||
try {
|
||||
locked_split(r);
|
||||
} finally { releaseWriteLock(); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates two or more new buckets. The old bucket is replaced and discarded.
|
||||
*
|
||||
* Caller must hold write lock
|
||||
* The bucket should be splittable (range start != range end).
|
||||
* @param r the range start of the bucket to be split
|
||||
*/
|
||||
private void locked_split(int r) {
|
||||
int b = pickBucket(r);
|
||||
while (shouldSplit(_buckets.get(b))) {
|
||||
KBucket<T> b0 = _buckets.get(b);
|
||||
// Each bucket gets half the keyspace.
|
||||
// When B_VALUE = 1, or the bucket is larger than B_FACTOR, then
|
||||
// e.g. 0-159 => 0-158, 159-159
|
||||
// When B_VALUE > 1, and the bucket is smaller than B_FACTOR, then
|
||||
// e.g. 1020-1023 => 1020-1021, 1022-1023
|
||||
int s1, e1, s2, e2;
|
||||
s1 = b0.getRangeBegin();
|
||||
e2 = b0.getRangeEnd();
|
||||
if (B_VALUE == 1 ||
|
||||
((s1 & (B_FACTOR - 1)) == 0 &&
|
||||
((e2 + 1) & (B_FACTOR - 1)) == 0 &&
|
||||
e2 > s1 + B_FACTOR)) {
|
||||
// The bucket is a "whole" kbucket with a range > B_FACTOR,
|
||||
// so it should be split into two "whole" kbuckets each with
|
||||
// a range >= B_FACTOR.
|
||||
// Log split
|
||||
s2 = e2 + 1 - B_FACTOR;
|
||||
} else {
|
||||
// The bucket is the smallest "whole" kbucket with a range == B_FACTOR,
|
||||
// or B_VALUE > 1 and the bucket has already been split.
|
||||
// Start or continue splitting down to a depth B_VALUE.
|
||||
// Linear split
|
||||
s2 = s1 + ((1 + e2 - s1) / 2);
|
||||
}
|
||||
e1 = s2 - 1;
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Splitting (" + s1 + ',' + e2 + ") -> (" + s1 + ',' + e1 + ") (" + s2 + ',' + e2 + ')');
|
||||
KBucket<T> b1 = createBucket(s1, e1);
|
||||
KBucket<T> b2 = createBucket(s2, e2);
|
||||
for (T key : b0.getEntries()) {
|
||||
if (getRange(key) < s2)
|
||||
b1.add(key);
|
||||
else
|
||||
b2.add(key);
|
||||
}
|
||||
_buckets.set(b, b1);
|
||||
_buckets.add(b + 1, b2);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Split bucket at idx " + b +
|
||||
":\n" + b0 +
|
||||
"\ninto: " + b1 +
|
||||
"\nand: " + b2);
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("State is now: " + toString());
|
||||
|
||||
if (b2.getKeyCount() > BUCKET_SIZE) {
|
||||
// should be rare... too hard to call _trimmer from here
|
||||
// (and definitely not from inside the write lock)
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("All went into 2nd bucket after split");
|
||||
}
|
||||
// loop if all the entries went in the first bucket
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The current number of entries.
|
||||
*/
|
||||
public int size() {
|
||||
int rv = 0;
|
||||
getReadLock();
|
||||
try {
|
||||
for (KBucket b : _buckets) {
|
||||
rv += b.getKeyCount();
|
||||
}
|
||||
} finally { releaseReadLock(); }
|
||||
return rv;
|
||||
}
|
||||
|
||||
public boolean remove(T entry) {
|
||||
KBucket kbucket;
|
||||
getReadLock();
|
||||
try {
|
||||
kbucket = getBucket(entry);
|
||||
} finally { releaseReadLock(); }
|
||||
boolean removed = kbucket.remove(entry);
|
||||
return removed;
|
||||
}
|
||||
|
||||
/** @since 0.8.8 */
|
||||
public void clear() {
|
||||
getReadLock();
|
||||
try {
|
||||
for (KBucket b : _buckets) {
|
||||
b.clear();
|
||||
}
|
||||
} finally { releaseReadLock(); }
|
||||
_rangeCalc.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a copy in a new set
|
||||
*/
|
||||
public Set<T> getAll() {
|
||||
Set<T> all = new HashSet(256);
|
||||
getReadLock();
|
||||
try {
|
||||
for (KBucket b : _buckets) {
|
||||
all.addAll(b.getEntries());
|
||||
}
|
||||
} finally { releaseReadLock(); }
|
||||
return all;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a copy in a new set
|
||||
*/
|
||||
public Set<T> getAll(Set<T> toIgnore) {
|
||||
Set<T> all = getAll();
|
||||
all.removeAll(toIgnore);
|
||||
return all;
|
||||
}
|
||||
|
||||
public void getAll(SelectionCollector<T> collector) {
|
||||
getReadLock();
|
||||
try {
|
||||
for (KBucket b : _buckets) {
|
||||
b.getEntries(collector);
|
||||
}
|
||||
} finally { releaseReadLock(); }
|
||||
}
|
||||
|
||||
/**
|
||||
* The keys closest to us.
|
||||
* Returned list will never contain us.
|
||||
* @return non-null, closest first
|
||||
*/
|
||||
public List<T> getClosest(int max) {
|
||||
return getClosest(max, Collections.EMPTY_SET);
|
||||
}
|
||||
|
||||
/**
|
||||
* The keys closest to us.
|
||||
* Returned list will never contain us.
|
||||
* @return non-null, closest first
|
||||
*/
|
||||
public List<T> getClosest(int max, Collection<T> toIgnore) {
|
||||
List<T> rv = new ArrayList(max);
|
||||
int count = 0;
|
||||
getReadLock();
|
||||
try {
|
||||
// start at first (closest) bucket
|
||||
for (int i = 0; i < _buckets.size() && count < max; i++) {
|
||||
Set<T> entries = _buckets.get(i).getEntries();
|
||||
// add the whole bucket except for ignores,
|
||||
// extras will be trimmed after sorting
|
||||
for (T e : entries) {
|
||||
if (!toIgnore.contains(e)) {
|
||||
rv.add(e);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally { releaseReadLock(); }
|
||||
Comparator comp = new XORComparator(_us);
|
||||
Collections.sort(rv, comp);
|
||||
int sz = rv.size();
|
||||
for (int i = sz - 1; i >= max; i--) {
|
||||
rv.remove(i);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* The keys closest to the key.
|
||||
* Returned list will never contain us.
|
||||
* @return non-null, closest first
|
||||
*/
|
||||
public List<T> getClosest(T key, int max) {
|
||||
return getClosest(key, max, Collections.EMPTY_SET);
|
||||
}
|
||||
|
||||
/**
|
||||
* The keys closest to the key.
|
||||
* Returned list will never contain us.
|
||||
* @return non-null, closest first
|
||||
*/
|
||||
public List<T> getClosest(T key, int max, Collection<T> toIgnore) {
|
||||
if (key.equals(_us))
|
||||
return getClosest(max, toIgnore);
|
||||
List<T> rv = new ArrayList(max);
|
||||
int count = 0;
|
||||
getReadLock();
|
||||
try {
|
||||
int start = pickBucket(key);
|
||||
// start at closest bucket, then to the smaller (closer to us) buckets
|
||||
for (int i = start; i >= 0 && count < max; i--) {
|
||||
Set<T> entries = _buckets.get(i).getEntries();
|
||||
for (T e : entries) {
|
||||
if (!toIgnore.contains(e)) {
|
||||
rv.add(e);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// then the farther from us buckets if necessary
|
||||
for (int i = start + 1; i < _buckets.size() && count < max; i++) {
|
||||
Set<T> entries = _buckets.get(i).getEntries();
|
||||
for (T e : entries) {
|
||||
if (!toIgnore.contains(e)) {
|
||||
rv.add(e);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally { releaseReadLock(); }
|
||||
Comparator comp = new XORComparator(key);
|
||||
Collections.sort(rv, comp);
|
||||
int sz = rv.size();
|
||||
for (int i = sz - 1; i >= max; i--) {
|
||||
rv.remove(i);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* The bucket number (NOT the range number) that the xor of the key goes in
|
||||
* Caller must hold read lock
|
||||
* @return 0 to max-1 or -1 for us
|
||||
*/
|
||||
private int pickBucket(T key) {
|
||||
int range = getRange(key);
|
||||
if (range < 0)
|
||||
return -1;
|
||||
int rv = pickBucket(range);
|
||||
if (rv >= 0) {
|
||||
return rv;
|
||||
}
|
||||
_log.error("Key does not fit in any bucket?! WTF!\nKey : ["
|
||||
+ DataHelper.toHexString(key.getData()) + "]"
|
||||
+ "\nUs : " + _us
|
||||
+ "\nDelta: ["
|
||||
+ DataHelper.toHexString(DataHelper.xor(_us.getData(), key.getData()))
|
||||
+ "]", new Exception("WTF"));
|
||||
_log.error(toString());
|
||||
throw new IllegalStateException("pickBucket returned " + rv);
|
||||
//return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returned list is a copy of the bucket list, closest first,
|
||||
* with the actual buckets (not a copy).
|
||||
*
|
||||
* Primarily for testing. You shouldn't ever need to get all the buckets.
|
||||
* Use getClosest() or getAll() instead to get the keys.
|
||||
*
|
||||
* @return non-null
|
||||
*/
|
||||
List<KBucket<T>> getBuckets() {
|
||||
getReadLock();
|
||||
try {
|
||||
return new ArrayList(_buckets);
|
||||
} finally { releaseReadLock(); }
|
||||
}
|
||||
|
||||
/**
|
||||
* The bucket that the xor of the key goes in
|
||||
* Caller must hold read lock
|
||||
* @return null if key is us
|
||||
*/
|
||||
private KBucket getBucket(T key) {
|
||||
int bucket = pickBucket(key);
|
||||
if (bucket < 0)
|
||||
return null;
|
||||
return _buckets.get(bucket);
|
||||
}
|
||||
|
||||
/**
|
||||
* The bucket number that contains this range number
|
||||
* Caller must hold read lock or write lock
|
||||
* @return 0 to max-1 or -1 for us
|
||||
*/
|
||||
private int pickBucket(int range) {
|
||||
// If B is small, a linear search from back to front
|
||||
// is most efficient since most of the keys are at the end...
|
||||
// If B is larger, there's a lot of sub-buckets
|
||||
// of equal size to be checked so a binary search is better
|
||||
if (B_VALUE <= 3) {
|
||||
for (int i = _buckets.size() - 1; i >= 0; i--) {
|
||||
KBucket b = _buckets.get(i);
|
||||
if (range >= b.getRangeBegin() && range <= b.getRangeEnd())
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
} else {
|
||||
KBucket dummy = new DummyBucket(range);
|
||||
return Collections.binarySearch(_buckets, dummy, new BucketComparator());
|
||||
}
|
||||
}
|
||||
|
||||
private List<KBucket> createBuckets() {
|
||||
// just an initial size
|
||||
List<KBucket> buckets = new ArrayList(4 * B_FACTOR);
|
||||
buckets.add(createBucket(0, NUM_BUCKETS -1));
|
||||
return buckets;
|
||||
}
|
||||
|
||||
private KBucket createBucket(int start, int end) {
|
||||
if (end - start >= B_FACTOR &&
|
||||
(((end + 1) & B_FACTOR - 1) != 0 ||
|
||||
(start & B_FACTOR - 1) != 0))
|
||||
throw new IllegalArgumentException("Sub-bkt crosses K-bkt boundary: " + start + '-' + end);
|
||||
KBucket bucket = new KBucketImpl(_context, start, end, BUCKET_SIZE, _trimmer);
|
||||
return bucket;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of bits minus 1 (range number) for the xor of the key.
|
||||
* Package private for testing only. Others shouldn't need this.
|
||||
* @return 0 to max-1 or -1 for us
|
||||
*/
|
||||
int getRange(T key) {
|
||||
return _rangeCalc.getRange(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* For every bucket that hasn't been updated in this long,
|
||||
* or isn't close to full,
|
||||
* generate a random key that would be a member of that bucket.
|
||||
* The returned keys may be searched for to "refresh" the buckets.
|
||||
* @return non-null, closest first
|
||||
*/
|
||||
public List<T> getExploreKeys(long age) {
|
||||
List<T> rv = new ArrayList(_buckets.size());
|
||||
long old = _context.clock().now() - age;
|
||||
getReadLock();
|
||||
try {
|
||||
for (KBucket b : _buckets) {
|
||||
int curSize = b.getKeyCount();
|
||||
// Always explore the closest bucket
|
||||
if ((b.getRangeBegin() == 0) ||
|
||||
(b.getLastChanged() < old || curSize < BUCKET_SIZE * 3 / 4))
|
||||
rv.add(generateRandomKey(b));
|
||||
}
|
||||
} finally { releaseReadLock(); }
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random key to go within this bucket
|
||||
* Package private for testing only. Others shouldn't need this.
|
||||
*/
|
||||
T generateRandomKey(KBucket bucket) {
|
||||
int begin = bucket.getRangeBegin();
|
||||
int end = bucket.getRangeEnd();
|
||||
// number of fixed bits, out of B_VALUE - 1 bits
|
||||
int fixed = 0;
|
||||
int bsz = 1 + end - begin;
|
||||
// compute fixed = B_VALUE - log2(bsz)
|
||||
// e.g for B=4, B_FACTOR=8, sz 4-> fixed 1, sz 2->fixed 2, sz 1 -> fixed 3
|
||||
while (bsz < B_FACTOR) {
|
||||
fixed++;
|
||||
bsz <<= 1;
|
||||
}
|
||||
int fixedBits = 0;
|
||||
if (fixed > 0) {
|
||||
// 0x01, 03, 07, 0f, ...
|
||||
int mask = (1 << fixed) - 1;
|
||||
// fixed bits masked from begin
|
||||
fixedBits = (begin >> (B_VALUE - (fixed + 1))) & mask;
|
||||
}
|
||||
int obegin = begin;
|
||||
int oend = end;
|
||||
begin >>= (B_VALUE - 1);
|
||||
end >>= (B_VALUE - 1);
|
||||
// we need randomness for [0, begin) bits
|
||||
BigInteger variance;
|
||||
// 00000000rrrr
|
||||
if (begin > 0)
|
||||
variance = new BigInteger(begin - fixed, _context.random());
|
||||
else
|
||||
variance = BigInteger.ZERO;
|
||||
// we need nonzero randomness for [begin, end] bits
|
||||
int numNonZero = 1 + end - begin;
|
||||
if (numNonZero == 1) {
|
||||
// 00001000rrrr
|
||||
variance = variance.setBit(begin);
|
||||
// fixed bits as the 'main' bucket is split
|
||||
// 00001fffrrrr
|
||||
if (fixed > 0)
|
||||
variance = variance.or(BigInteger.valueOf(fixedBits).shiftLeft(begin - fixed));
|
||||
} else {
|
||||
// dont span main bucket boundaries with depth > 1
|
||||
if (fixed > 0)
|
||||
throw new IllegalStateException("WTF " + bucket);
|
||||
BigInteger nonz;
|
||||
if (numNonZero <= 62) {
|
||||
// add one to ensure nonzero
|
||||
long nz = 1 + _context.random().nextLong((1l << numNonZero) - 1);
|
||||
nonz = BigInteger.valueOf(nz);
|
||||
} else {
|
||||
// loop to ensure nonzero
|
||||
do {
|
||||
nonz = new BigInteger(numNonZero, _context.random());
|
||||
} while (nonz.equals(BigInteger.ZERO));
|
||||
}
|
||||
// shift left and or-in the nonzero randomness
|
||||
if (begin > 0)
|
||||
nonz = nonz.shiftLeft(begin);
|
||||
// 0000nnnnrrrr
|
||||
variance = variance.or(nonz);
|
||||
}
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("SB(" + obegin + ',' + oend + ") KB(" + begin + ',' + end + ") fixed=" + fixed + " fixedBits=" + fixedBits + " numNonZ=" + numNonZero);
|
||||
byte data[] = variance.toByteArray();
|
||||
T key = makeKey(data);
|
||||
byte[] hash = DataHelper.xor(key.getData(), _us.getData());
|
||||
T rv = makeKey(hash);
|
||||
|
||||
// DEBUG
|
||||
//int range = getRange(rv);
|
||||
//if (range < obegin || range > oend) {
|
||||
// throw new IllegalStateException("Generate random key failed range=" + range + " for " + rv + " meant for bucket " + bucket);
|
||||
//}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a new SimpleDataStrucure from the data
|
||||
* @param data size <= SDS length, else throws IAE
|
||||
* Can be 1 bigger if top byte is zero
|
||||
*/
|
||||
private T makeKey(byte[] data) {
|
||||
int len = _us.length();
|
||||
int dlen = data.length;
|
||||
if (dlen > len + 1 ||
|
||||
(dlen == len + 1 && data[0] != 0))
|
||||
throw new IllegalArgumentException("bad length " + dlen + " > " + len);
|
||||
T rv;
|
||||
try {
|
||||
rv = (T) _us.getClass().newInstance();
|
||||
} catch (Exception e) {
|
||||
_log.error("fail", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (dlen == len) {
|
||||
rv.setData(data);
|
||||
} else {
|
||||
byte[] ndata = new byte[len];
|
||||
if (dlen == len + 1) {
|
||||
// one bigger
|
||||
System.arraycopy(data, 1, ndata, 0, len);
|
||||
} else {
|
||||
// smaller
|
||||
System.arraycopy(data, 0, ndata, len - dlen, dlen);
|
||||
}
|
||||
rv.setData(ndata);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
private static class Range<T extends SimpleDataStructure> {
|
||||
private final int _bValue;
|
||||
private final BigInteger _bigUs;
|
||||
private final Map<T, Integer> _distanceCache;
|
||||
|
||||
public Range(T us, int bValue) {
|
||||
_bValue = bValue;
|
||||
_bigUs = new BigInteger(1, us.getData());
|
||||
_distanceCache = new LHMCache(256);
|
||||
}
|
||||
|
||||
/** @return 0 to max-1 or -1 for us */
|
||||
public int getRange(T key) {
|
||||
Integer rv;
|
||||
synchronized (_distanceCache) {
|
||||
rv = _distanceCache.get(key);
|
||||
if (rv == null) {
|
||||
// easy way when _bValue == 1
|
||||
//rv = Integer.valueOf(_bigUs.xor(new BigInteger(1, key.getData())).bitLength() - 1);
|
||||
BigInteger xor = _bigUs.xor(new BigInteger(1, key.getData()));
|
||||
int range = xor.bitLength() - 1;
|
||||
if (_bValue > 1) {
|
||||
int toShift = range + 1 - _bValue;
|
||||
int highbit = range;
|
||||
range <<= _bValue - 1;
|
||||
if (toShift >= 0) {
|
||||
int extra = xor.clearBit(highbit).shiftRight(toShift).intValue();
|
||||
range += extra;
|
||||
//Log log = I2PAppContext.getGlobalContext().logManager().getLog(KBucketSet.class);
|
||||
//if (log.shouldLog(Log.DEBUG))
|
||||
// log.debug("highbit " + highbit + " toshift " + toShift + " extra " + extra + " new " + range);
|
||||
}
|
||||
}
|
||||
rv = Integer.valueOf(range);
|
||||
_distanceCache.put(key, rv);
|
||||
}
|
||||
}
|
||||
return rv.intValue();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
synchronized (_distanceCache) {
|
||||
_distanceCache.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For Collections.binarySearch.
|
||||
* getRangeBegin == getRangeEnd.
|
||||
*/
|
||||
private static class DummyBucket<T extends SimpleDataStructure> implements KBucket<T> {
|
||||
private final int r;
|
||||
|
||||
public DummyBucket(int range) {
|
||||
r = range;
|
||||
}
|
||||
|
||||
public int getRangeBegin() { return r; }
|
||||
public int getRangeEnd() { return r; }
|
||||
|
||||
public int getKeyCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Set<T> getEntries() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void getEntries(SelectionCollector<T> collector) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void clear() {}
|
||||
|
||||
public boolean add(T peer) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public boolean remove(T peer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setLastChanged() {}
|
||||
|
||||
public long getLastChanged() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For Collections.binarySearch.
|
||||
* Returns equal for any overlap.
|
||||
*/
|
||||
private static class BucketComparator implements Comparator<KBucket> {
|
||||
public int compare(KBucket l, KBucket r) {
|
||||
if (l.getRangeEnd() < r.getRangeBegin())
|
||||
return -1;
|
||||
if (l.getRangeBegin() > r.getRangeEnd())
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder(1024);
|
||||
buf.append("Bucket set rooted on: ").append(_us.toString())
|
||||
.append(" K=").append(BUCKET_SIZE)
|
||||
.append(" B=").append(B_VALUE)
|
||||
.append(" with ").append(size())
|
||||
.append(" keys in ").append(_buckets.size()).append(" buckets:\n");
|
||||
getReadLock();
|
||||
try {
|
||||
int len = _buckets.size();
|
||||
for (int i = 0; i < len; i++) {
|
||||
KBucket b = _buckets.get(i);
|
||||
buf.append("* Bucket ").append(i).append("/").append(len).append(": ");
|
||||
buf.append(b.toString()).append("\n");
|
||||
}
|
||||
} finally { releaseReadLock(); }
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
20
apps/i2psnark/java/src/net/i2p/kademlia/KBucketTrimmer.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package net.i2p.kademlia;
|
||||
|
||||
import net.i2p.data.SimpleDataStructure;
|
||||
|
||||
/**
|
||||
* Called when a kbucket can no longer be split and is too big
|
||||
* @since 0.9.2
|
||||
*/
|
||||
public interface KBucketTrimmer<K extends SimpleDataStructure> {
|
||||
/**
|
||||
* Called from add() just before adding the entry.
|
||||
* You may call getEntries() and/or remove() from here.
|
||||
* Do NOT call add().
|
||||
* To always discard a newer entry, always return false.
|
||||
*
|
||||
* @param kbucket the kbucket that is now too big
|
||||
* @return true to actually add the entry.
|
||||
*/
|
||||
public boolean trim(KBucket<K> kbucket, K toAdd);
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
package net.i2p.kademlia;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.SimpleDataStructure;
|
||||
|
||||
/**
|
||||
* Removes a random element, but only if the bucket hasn't changed in 5 minutes.
|
||||
* @since 0.9.2
|
||||
*/
|
||||
public class RandomIfOldTrimmer<T extends SimpleDataStructure> extends RandomTrimmer<T> {
|
||||
|
||||
public RandomIfOldTrimmer(I2PAppContext ctx, int max) {
|
||||
super(ctx, max);
|
||||
}
|
||||
|
||||
public boolean trim(KBucket<T> kbucket, T toAdd) {
|
||||
if (kbucket.getLastChanged() > _ctx.clock().now() - 5*60*1000)
|
||||
return false;
|
||||
return super.trim(kbucket, toAdd);
|
||||
}
|
||||
}
|
31
apps/i2psnark/java/src/net/i2p/kademlia/RandomTrimmer.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package net.i2p.kademlia;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.SimpleDataStructure;
|
||||
|
||||
/**
|
||||
* Removes a random element. Not resistant to flooding.
|
||||
* @since 0.9.2
|
||||
*/
|
||||
public class RandomTrimmer<T extends SimpleDataStructure> implements KBucketTrimmer<T> {
|
||||
protected final I2PAppContext _ctx;
|
||||
private final int _max;
|
||||
|
||||
public RandomTrimmer(I2PAppContext ctx, int max) {
|
||||
_ctx = ctx;
|
||||
_max = max;
|
||||
}
|
||||
|
||||
public boolean trim(KBucket<T> kbucket, T toAdd) {
|
||||
List<T> e = new ArrayList(kbucket.getEntries());
|
||||
int sz = e.size();
|
||||
// concurrency
|
||||
if (sz < _max)
|
||||
return true;
|
||||
T toRemove = e.get(_ctx.random().nextInt(sz));
|
||||
return kbucket.remove(toRemove);
|
||||
}
|
||||
}
|
13
apps/i2psnark/java/src/net/i2p/kademlia/RejectTrimmer.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package net.i2p.kademlia;
|
||||
|
||||
import net.i2p.data.SimpleDataStructure;
|
||||
|
||||
/**
|
||||
* Removes nothing and always rejects the add. Flood resistant..
|
||||
* @since 0.9.2
|
||||
*/
|
||||
public class RejectTrimmer<T extends SimpleDataStructure> implements KBucketTrimmer<T> {
|
||||
public boolean trim(KBucket<T> kbucket, T toAdd) {
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
package net.i2p.kademlia;
|
||||
|
||||
import net.i2p.data.SimpleDataStructure;
|
||||
|
||||
/**
|
||||
* Visit kbuckets, gathering matches
|
||||
* @since 0.9.2
|
||||
*/
|
||||
public interface SelectionCollector<T extends SimpleDataStructure> {
|
||||
public void add(T entry);
|
||||
}
|
28
apps/i2psnark/java/src/net/i2p/kademlia/XORComparator.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package net.i2p.kademlia;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.SimpleDataStructure;
|
||||
|
||||
/**
|
||||
* Help sort Hashes in relation to a base key using the XOR metric
|
||||
*
|
||||
* @since 0.9.2
|
||||
*/
|
||||
class XORComparator<T extends SimpleDataStructure> implements Comparator<T> {
|
||||
private final byte[] _base;
|
||||
|
||||
/**
|
||||
* @param target key to compare distances with
|
||||
*/
|
||||
public XORComparator(T target) {
|
||||
_base = target.getData();
|
||||
}
|
||||
|
||||
public int compare(T lhs, T rhs) {
|
||||
byte lhsDelta[] = DataHelper.xor(lhs.getData(), _base);
|
||||
byte rhsDelta[] = DataHelper.xor(rhs.getData(), _base);
|
||||
return DataHelper.compareTo(lhsDelta, rhsDelta);
|
||||
}
|
||||
}
|
6
apps/i2psnark/java/src/net/i2p/kademlia/package.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<html><body><p>
|
||||
This is a major rewrite of KBucket, KBucketSet, and KBucketImpl from net.i2p.router.networkdb.kademlia.
|
||||
The classes are now generic to support SHA1. SHA256, or other key lengths.
|
||||
The long-term goal is to prove out this new implementation in i2psnark,
|
||||
then move it to core, then convert the network database to use it.
|
||||
</p></body></html>
|
@@ -39,7 +39,6 @@ public class BitField
|
||||
this.size = size;
|
||||
int arraysize = ((size-1)/8)+1;
|
||||
bitfield = new byte[arraysize];
|
||||
this.count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,7 +59,6 @@ public class BitField
|
||||
// cleared or clear them explicitly ourselves.
|
||||
System.arraycopy(bitfield, 0, this.bitfield, 0, arraysize);
|
||||
|
||||
this.count = 0;
|
||||
for (int i = 0; i < size; i++)
|
||||
if (get(i))
|
||||
this.count++;
|
||||
@@ -99,9 +97,11 @@ public class BitField
|
||||
throw new IndexOutOfBoundsException(Integer.toString(bit));
|
||||
int index = bit/8;
|
||||
int mask = 128 >> (bit % 8);
|
||||
if ((bitfield[index] & mask) == 0) {
|
||||
count++;
|
||||
bitfield[index] |= mask;
|
||||
synchronized(this) {
|
||||
if ((bitfield[index] & mask) == 0) {
|
||||
count++;
|
||||
bitfield[index] |= mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
60
apps/i2psnark/java/src/org/klomp/snark/CompleteListener.java
Normal file
@@ -0,0 +1,60 @@
|
||||
/* CompleteListener - Callback for Snark events
|
||||
|
||||
Copyright (C) 2003 Mark J. Wielaard
|
||||
|
||||
This file is part of Snark.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package org.klomp.snark;
|
||||
|
||||
/**
|
||||
* Callback for Snark events.
|
||||
* @since 0.9.4 moved from Snark.java
|
||||
*/
|
||||
public interface CompleteListener {
|
||||
public void torrentComplete(Snark snark);
|
||||
public void updateStatus(Snark snark);
|
||||
|
||||
/**
|
||||
* We transitioned from magnet mode, we have now initialized our
|
||||
* metainfo and storage. The listener should now call getMetaInfo()
|
||||
* and save the data to disk.
|
||||
*
|
||||
* @return the new name for the torrent or null on error
|
||||
* @since 0.8.4
|
||||
*/
|
||||
public String gotMetaInfo(Snark snark);
|
||||
|
||||
/**
|
||||
* @since 0.9
|
||||
*/
|
||||
public void fatal(Snark snark, String error);
|
||||
|
||||
/**
|
||||
* @since 0.9.2
|
||||
*/
|
||||
public void addMessage(Snark snark, String message);
|
||||
|
||||
/**
|
||||
* @since 0.9.4
|
||||
*/
|
||||
public void gotPiece(Snark snark);
|
||||
|
||||
// not really listeners but the easiest way to get back to an optional SnarkManager
|
||||
public long getSavedTorrentTime(Snark snark);
|
||||
public BitField getSavedTorrentBitField(Snark snark);
|
||||
}
|
@@ -29,8 +29,12 @@ import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.streaming.I2PServerSocket;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.ObjectCounter;
|
||||
import net.i2p.util.SimpleScheduler;
|
||||
import net.i2p.util.SimpleTimer;
|
||||
|
||||
/**
|
||||
* Accepts connections on a TCP port and routes them to sub-acceptors.
|
||||
@@ -41,11 +45,15 @@ public class ConnectionAcceptor implements Runnable
|
||||
private I2PServerSocket serverSocket;
|
||||
private PeerAcceptor peeracceptor;
|
||||
private Thread thread;
|
||||
private I2PSnarkUtil _util;
|
||||
private final I2PSnarkUtil _util;
|
||||
private final ObjectCounter<Hash> _badCounter = new ObjectCounter();
|
||||
|
||||
private boolean stop;
|
||||
private boolean socketChanged;
|
||||
|
||||
private static final int MAX_BAD = 2;
|
||||
private static final long BAD_CLEAN_INTERVAL = 30*60*1000;
|
||||
|
||||
public ConnectionAcceptor(I2PSnarkUtil util) { _util = util; }
|
||||
|
||||
public synchronized void startAccepting(PeerCoordinatorSet set, I2PServerSocket socket) {
|
||||
@@ -59,6 +67,7 @@ public class ConnectionAcceptor implements Runnable
|
||||
thread = new I2PAppThread(this, "I2PSnark acceptor");
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
_util.getContext().simpleScheduler().addPeriodicEvent(new Cleaner(), BAD_CLEAN_INTERVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,11 +79,10 @@ public class ConnectionAcceptor implements Runnable
|
||||
this.peeracceptor = peeracceptor;
|
||||
_util = util;
|
||||
|
||||
socketChanged = false;
|
||||
stop = false;
|
||||
thread = new I2PAppThread(this, "I2PSnark acceptor");
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
_util.getContext().simpleScheduler().addPeriodicEvent(new Cleaner(), BAD_CLEAN_INTERVAL);
|
||||
}
|
||||
|
||||
public void halt()
|
||||
@@ -138,7 +146,13 @@ public class ConnectionAcceptor implements Runnable
|
||||
}
|
||||
} else {
|
||||
if (socket.getPeerDestination().equals(_util.getMyDestination())) {
|
||||
_util.debug("Incoming connection from myself", Snark.ERROR);
|
||||
_log.error("Incoming connection from myself");
|
||||
try { socket.close(); } catch (IOException ioe) {}
|
||||
continue;
|
||||
}
|
||||
if (_badCounter.count(socket.getPeerDestination().calculateHash()) >= MAX_BAD) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Rejecting connection from " + socket.getPeerDestination().calculateHash() + " after " + MAX_BAD + " failures");
|
||||
try { socket.close(); } catch (IOException ioe) {}
|
||||
continue;
|
||||
}
|
||||
@@ -149,13 +163,13 @@ public class ConnectionAcceptor implements Runnable
|
||||
catch (I2PException ioe)
|
||||
{
|
||||
if (!socketChanged) {
|
||||
_util.debug("Error while accepting: " + ioe, Snark.ERROR);
|
||||
_log.error("Error while accepting", ioe);
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
_util.debug("Error while accepting: " + ioe, Snark.ERROR);
|
||||
_log.error("Error while accepting", ioe);
|
||||
stop = true;
|
||||
}
|
||||
// catch oom?
|
||||
@@ -171,10 +185,12 @@ public class ConnectionAcceptor implements Runnable
|
||||
}
|
||||
|
||||
private class Handler implements Runnable {
|
||||
private I2PSocket _socket;
|
||||
private final I2PSocket _socket;
|
||||
|
||||
public Handler(I2PSocket socket) {
|
||||
_socket = socket;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
InputStream in = _socket.getInputStream();
|
||||
@@ -182,13 +198,23 @@ public class ConnectionAcceptor implements Runnable
|
||||
// this is for the readahead in PeerAcceptor.connection()
|
||||
in = new BufferedInputStream(in);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Handling socket from " + _socket.getPeerDestination().calculateHash().toBase64());
|
||||
_log.debug("Handling socket from " + _socket.getPeerDestination().calculateHash());
|
||||
peeracceptor.connection(_socket, in, out);
|
||||
} catch (PeerAcceptor.ProtocolException ihe) {
|
||||
_badCounter.increment(_socket.getPeerDestination().calculateHash());
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Protocol error from " + _socket.getPeerDestination().calculateHash(), ihe);
|
||||
try { _socket.close(); } catch (IOException ignored) { }
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Error handling connection from " + _socket.getPeerDestination().calculateHash().toBase64(), ioe);
|
||||
_log.debug("Error handling connection from " + _socket.getPeerDestination().calculateHash(), ioe);
|
||||
try { _socket.close(); } catch (IOException ignored) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 0.9.1 */
|
||||
private class Cleaner implements SimpleTimer.TimedEvent {
|
||||
public void timeReached() { _badCounter.clear(); }
|
||||
}
|
||||
}
|
||||
|