mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-12 07:42:48 +00:00
Compare commits
2686 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4930b61a38 | ||
|
|
9cc2cf362f | ||
|
|
ed93fb34ab | ||
|
|
3d32474da8 | ||
|
|
3233c318ea | ||
|
|
c9a263c589 | ||
|
|
6e39ec6e26 | ||
|
|
d38a6cc7ea | ||
|
|
7f6ee7a46b | ||
|
|
34b77fcad4 | ||
|
|
3b3f45d49b | ||
|
|
3284a13fee | ||
|
|
fc9ffee2e3 | ||
|
|
3a672cb2a9 | ||
|
|
4b8e342309 | ||
|
|
5a2fa71b03 | ||
|
|
9a57ef9cbf | ||
|
|
59ca9bf480 | ||
|
|
7cce07bc99 | ||
|
|
0ae66f75ce | ||
|
|
cee7b5cb54 | ||
|
|
1585152341 | ||
|
|
8e699c2bfd | ||
|
|
904a3115a6 | ||
|
|
a506cf47ad | ||
|
|
7689c15413 | ||
|
|
f907113c19 | ||
|
|
140f962201 | ||
|
|
c23d907f12 | ||
|
|
ed782e7508 | ||
|
|
0732526465 | ||
|
|
39a4963782 | ||
|
|
37ce6b195a | ||
|
|
7aa6d36258 | ||
|
|
991017fc41 | ||
|
|
5f548c7679 | ||
|
|
d14aacf03e | ||
|
|
39ff4d22e9 | ||
|
|
8462493cbf | ||
|
|
47b8bd1728 | ||
|
|
657fd671ea | ||
|
|
315c475b79 | ||
|
|
b800b4ec1d | ||
|
|
208ac32fa2 | ||
|
|
641476d40f | ||
|
|
491c8ab4c1 | ||
|
|
5ef8a6e887 | ||
|
|
d694d47d22 | ||
|
|
ecdc1b9bb0 | ||
|
|
9c757108ca | ||
|
|
5243e54641 | ||
|
|
70e7454c21 | ||
|
|
2644a529f0 | ||
|
|
eaee98ee1f | ||
|
|
575a46d9d4 | ||
|
|
bcadbd1b10 | ||
|
|
ead9daf1ba | ||
|
|
22949e6dfd | ||
|
|
49986b05bc | ||
|
|
2fa7af4614 | ||
|
|
2d857c4b1b | ||
|
|
2b63f57b4c | ||
|
|
4085c72496 | ||
|
|
6f9956990c | ||
|
|
9bf5862def | ||
|
|
e1d98bb7f6 | ||
|
|
e5cd006bce | ||
|
|
58242e1b63 | ||
|
|
4e86835163 | ||
|
|
ab4ac04c88 | ||
|
|
2c1887a635 | ||
|
|
1c82281b77 | ||
|
|
43ac92b615 | ||
|
|
8813684040 | ||
|
|
58f36bb321 | ||
|
|
4c2f56626a | ||
|
|
e3337d764a | ||
|
|
214817ed17 | ||
|
|
116a4ec705 | ||
|
|
bbaad22982 | ||
|
|
a7250af303 | ||
|
|
6545a21369 | ||
|
|
416f03c05b | ||
|
|
8c0c8e8e01 | ||
|
|
79315efd1f | ||
|
|
a61130aebb | ||
|
|
5a51a0ba06 | ||
|
|
0d0b56739d | ||
|
|
eb1816c9ff | ||
|
|
50ae892d5e | ||
|
|
5a79b3d74a | ||
|
|
460599ef75 | ||
|
|
830bb72d6f | ||
|
|
b11c26cc1c | ||
|
|
152290db7e | ||
|
|
20b198681b | ||
|
|
2bf106a1b3 | ||
|
|
2c445059f2 | ||
|
|
d8b08cd943 | ||
|
|
ab59f64f57 | ||
|
|
42e3457884 | ||
|
|
31f3dd42e7 | ||
|
|
5fab8e404d | ||
|
|
701df09971 | ||
|
|
d350da3135 | ||
|
|
ab7dea4f20 | ||
|
|
b297efb532 | ||
|
|
eaabdb5cac | ||
|
|
066aee3045 | ||
|
|
ff1ec0260e | ||
|
|
7cb3188fbc | ||
|
|
9b9022f8df | ||
|
|
68e049d3af | ||
|
|
86ddf17db0 | ||
|
|
a655500047 | ||
|
|
714f885dac | ||
|
|
b0d8f552c5 | ||
|
|
63cb69cb96 | ||
|
|
266974cb59 | ||
|
|
bcf54b0aa3 | ||
|
|
d86855ad7a | ||
|
|
d0c67bbe16 | ||
|
|
4242352852 | ||
|
|
f299689573 | ||
|
|
baf457e6d4 | ||
|
|
0c7e871ef0 | ||
|
|
87ce804b4a | ||
|
|
2a258a2c3f | ||
|
|
a40518c7da | ||
|
|
31deaa4a79 | ||
|
|
736ea055a8 | ||
|
|
a39aec0bae | ||
|
|
8bef3eb1f4 | ||
|
|
244d88dfda | ||
|
|
76e1dd41e4 | ||
|
|
e39187a063 | ||
|
|
cd2ba4aa7f | ||
|
|
0de19420f6 | ||
|
|
f3000d0c84 | ||
|
|
fc5b0471d9 | ||
|
|
264bce4ddd | ||
|
|
0f41570c80 | ||
|
|
8723c91db9 | ||
|
|
f85c8896d9 | ||
|
|
f0d4f56327 | ||
|
|
3d5c05e4e6 | ||
|
|
018da09f14 | ||
|
|
60a64af28d | ||
|
|
13a2013229 | ||
|
|
1941b5c769 | ||
|
|
21e2c41c6b | ||
|
|
589781721a | ||
|
|
2ce57a65ff | ||
|
|
2aa77025c3 | ||
|
|
8e1856a90a | ||
|
|
ca619c80b6 | ||
|
|
25ff699425 | ||
|
|
879b4c0a2c | ||
|
|
45d07a3d0b | ||
|
|
788354d81e | ||
|
|
b7ce89e568 | ||
|
|
8d81a259c7 | ||
|
|
3019761204 | ||
|
|
6120a4c5e4 | ||
|
|
533ed2a876 | ||
|
|
d4e4055d57 | ||
|
|
ee51ad8e29 | ||
|
|
bdd50c5f37 | ||
|
|
3d88612690 | ||
|
|
630d54c95a | ||
|
|
3cedd8cf07 | ||
|
|
929f326dd2 | ||
|
|
ff8c648c23 | ||
|
|
8bceb5ce36 | ||
|
|
8f2703e8b2 | ||
|
|
c394eef7b8 | ||
|
|
f9921ae362 | ||
|
|
fff0c6cd8e | ||
|
|
59872bf335 | ||
|
|
656854186c | ||
|
|
6596bff8ec | ||
|
|
eaafd9d61c | ||
|
|
5378bfc5c7 | ||
|
|
abeeeeb611 | ||
|
|
ca3655a409 | ||
|
|
6cf5100645 | ||
|
|
51628aea08 | ||
|
|
3395f5fb0e | ||
|
|
d2cd079541 | ||
|
|
fc35e3b8c5 | ||
|
|
085b4f5f2e | ||
|
|
fd58645dd2 | ||
|
|
200787ede2 | ||
|
|
9cdba04fe9 | ||
|
|
e92c87630d | ||
|
|
d4e93a6de3 | ||
|
|
4670857c15 | ||
|
|
e8d8aedd1f | ||
|
|
87372da730 | ||
|
|
3b40b62d04 | ||
|
|
c41cbf2a07 | ||
|
|
1a3faa8db1 | ||
|
|
4ce79baac7 | ||
|
|
056b70b4ce | ||
|
|
4806b3b9bf | ||
|
|
2a8f0000b2 | ||
|
|
dd2d846c02 | ||
|
|
2ae87eee4e | ||
|
|
4be23027ed | ||
|
|
c19bbb2403 | ||
|
|
edb871f514 | ||
|
|
9c5937df96 | ||
|
|
be6082df8e | ||
|
|
66354de219 | ||
|
|
458a40f74e | ||
|
|
0821384ac6 | ||
|
|
e01650f21d | ||
|
|
8dd06cf197 | ||
|
|
93732b4c1e | ||
|
|
2cc63069c6 | ||
|
|
6270ecef8c | ||
|
|
9293ae76bf | ||
|
|
74d3f7e1fd | ||
|
|
2fd023a239 | ||
|
|
c8a2bdf78b | ||
|
|
3cd604562c | ||
|
|
7c6c0dba53 | ||
|
|
ec2f3f49ef | ||
|
|
8bba7c64bc | ||
|
|
ffd2483e67 | ||
|
|
0467de890a | ||
|
|
0ae0155cba | ||
|
|
f4feb7703b | ||
|
|
a14aab67de | ||
|
|
106d804357 | ||
|
|
a1020307a0 | ||
|
|
6c70b4ce05 | ||
|
|
2a292efb56 | ||
|
|
82b1a34a36 | ||
|
|
0e68638af3 | ||
|
|
d3e276bf80 | ||
|
|
fc585bcdec | ||
|
|
2a24ae90c1 | ||
|
|
8da2a6a147 | ||
|
|
7d71e702d8 | ||
|
|
38d18ca11a | ||
|
|
32d9563a15 | ||
|
|
18f7e52562 | ||
|
|
fec541373d | ||
|
|
ff600e9aa0 | ||
|
|
a49357b19e | ||
|
|
4b997c29ee | ||
|
|
d321839669 | ||
|
|
c27fda09dd | ||
|
|
23eb84db35 | ||
|
|
bef91ea7fe | ||
|
|
459633fb4c | ||
|
|
f1c8489270 | ||
|
|
2d10c8f15b | ||
|
|
106cdb74e5 | ||
|
|
22b038810a | ||
|
|
45750e1b29 | ||
|
|
26419fba28 | ||
|
|
ac0123d249 | ||
|
|
f4ff66de30 | ||
|
|
747b73cb95 | ||
|
|
161e100a24 | ||
|
|
3ae738f453 | ||
|
|
d14d4a2527 | ||
|
|
860da464df | ||
|
|
4e2000abfe | ||
|
|
5834a59816 | ||
|
|
b28b76ddf7 | ||
|
|
91e4f4b786 | ||
|
|
9b554fb2c4 | ||
|
|
f97ead4f5f | ||
|
|
5af22d6ee6 | ||
|
|
1d16df6a92 | ||
|
|
e7bc946760 | ||
|
|
cf1e1f5899 | ||
|
|
2f8372d629 | ||
|
|
d84e4effce | ||
|
|
0c1b91b762 | ||
|
|
c8990d06d9 | ||
|
|
b0a55882b2 | ||
|
|
d1fa44e816 | ||
|
|
199ea40980 | ||
|
|
66fc476e1e | ||
|
|
6b347200d9 | ||
|
|
8a908a7cf9 | ||
|
|
0bcc11c9bc | ||
|
|
0247a21a93 | ||
|
|
cf1f483526 | ||
|
|
3f9aa8d8fa | ||
|
|
d6d1f8512d | ||
|
|
2b2c233977 | ||
|
|
7640e6a29f | ||
|
|
b0ca8a0872 | ||
|
|
9e767771fc | ||
|
|
6c8d7a8c19 | ||
|
|
15ef57c6d0 | ||
|
|
f37c502fd8 | ||
|
|
945b0e6eca | ||
|
|
84a0a1987c | ||
|
|
11b68f1934 | ||
|
|
202d9a2c0c | ||
|
|
bf84e82577 | ||
|
|
abca9a2d61 | ||
|
|
d34286c421 | ||
|
|
bb2bdbc0e1 | ||
|
|
e7747f7d66 | ||
|
|
7a5060dc52 | ||
|
|
426379dc47 | ||
|
|
cd0fd06b0d | ||
|
|
4e3488c677 | ||
|
|
061ad355bb | ||
|
|
2679b7554b | ||
|
|
62c9cad484 | ||
|
|
4cbdbbaac9 | ||
|
|
9ed296ae71 | ||
|
|
e8d0960cef | ||
|
|
2023115ff8 | ||
|
|
7790ae9e6f | ||
|
|
206da7a1b8 | ||
|
|
14eaba9ec3 | ||
|
|
2919bc3f7f | ||
|
|
1c01671ec6 | ||
|
|
fe632ea32a | ||
|
|
5b368252ac | ||
|
|
8cca953590 | ||
|
|
4b4a2029c4 | ||
|
|
6aa85357b6 | ||
|
|
eae62ec09b | ||
|
|
18d96266bc | ||
|
|
4529fd6787 | ||
|
|
4a99a2a07d | ||
|
|
4b63b3aa0b | ||
|
|
fc860c3a07 | ||
|
|
2f147ec000 | ||
|
|
0a7a190cd1 | ||
|
|
3366dfe32a | ||
|
|
baff4bd8cc | ||
|
|
fb109db33d | ||
|
|
2f5971532e | ||
|
|
ab13806276 | ||
|
|
3ae26bd6e6 | ||
|
|
27ef3489a0 | ||
|
|
b6eb275b22 | ||
|
|
57cc8ab977 | ||
|
|
99034904f8 | ||
|
|
a0ffcbcee4 | ||
|
|
260affd037 | ||
|
|
d7b1b8d3d5 | ||
|
|
50129ad8ac | ||
|
|
5c9cb5e6a2 | ||
|
|
4051391039 | ||
|
|
8f3bd3f209 | ||
|
|
85816877c6 | ||
|
|
87087b8acd | ||
|
|
775bb85efb | ||
|
|
21ce5856b3 | ||
|
|
f5226e0008 | ||
|
|
a745fe2eed | ||
|
|
5f3048bd09 | ||
|
|
6a5818e107 | ||
|
|
dfdfd6c98e | ||
|
|
3090b05eb4 | ||
|
|
ee674f919f | ||
|
|
813bb6af96 | ||
|
|
aecbff725f | ||
|
|
6679fef2be | ||
|
|
c070ed056a | ||
|
|
2c6ed302b7 | ||
|
|
0eb85161aa | ||
|
|
940145b368 | ||
|
|
a30315276b | ||
|
|
6366eb9d99 | ||
|
|
44e967184a | ||
|
|
2ec425ae4b | ||
|
|
0d7d16005a | ||
|
|
5b5cbaa66a | ||
|
|
03550c7076 | ||
|
|
930fde056a | ||
|
|
8d758560d8 | ||
|
|
7b87cdaed8 | ||
|
|
c2f97e6454 | ||
|
|
88eb3e7af0 | ||
|
|
949211a137 | ||
|
|
39d8da3536 | ||
|
|
ae27e85bf7 | ||
|
|
f2d19162d2 | ||
|
|
d36e118bf6 | ||
|
|
02c1aef48b | ||
|
|
6f3d9b4be3 | ||
|
|
f06cc6630b | ||
|
|
8171628ee5 | ||
|
|
1cb76625d3 | ||
|
|
ebeadfc57e | ||
|
|
cca597a9c0 | ||
|
|
940db715f4 | ||
|
|
ec2b038493 | ||
|
|
ba0cb4f10e | ||
|
|
e764a180d8 | ||
|
|
bc19e7843c | ||
|
|
f57f97c4bd | ||
|
|
b32474bb1a | ||
|
|
0a20e8f268 | ||
|
|
9d4d939b89 | ||
|
|
c1e6e73bb1 | ||
|
|
620c957a44 | ||
|
|
64ce7eef16 | ||
|
|
fc7915ab4c | ||
|
|
26aaa283a9 | ||
|
|
a29c67563c | ||
|
|
17f7a9b510 | ||
|
|
3df5fd21cd | ||
|
|
99076f1942 | ||
|
|
3368eeb03e | ||
|
|
68237911ba | ||
|
|
f9e4f6eb6b | ||
|
|
8b74a8d6ac | ||
|
|
08f84cd712 | ||
|
|
452d10f368 | ||
|
|
8b3fb743cf | ||
|
|
7667e11973 | ||
|
|
53a5498fc5 | ||
|
|
e4d52401cf | ||
|
|
9670519a21 | ||
|
|
b1485b181a | ||
|
|
47a6928890 | ||
|
|
c1e167e330 | ||
|
|
e2b3b5b58c | ||
|
|
e6b70baae0 | ||
|
|
b40aa91b41 | ||
|
|
a13b17ec6c | ||
|
|
b32a507a1b | ||
|
|
d6e01e8cee | ||
|
|
c79ba3c349 | ||
|
|
12ca972761 | ||
|
|
657ad214cb | ||
|
|
39acf1c5e8 | ||
|
|
075ae1e301 | ||
|
|
705d51aa42 | ||
|
|
ef0493ddf3 | ||
|
|
1b455883d2 | ||
|
|
e4897b7bdd | ||
|
|
37f86f9518 | ||
|
|
28fc15028a | ||
|
|
179d6062e4 | ||
|
|
c521f385a6 | ||
|
|
b8214fce66 | ||
|
|
03a14d8342 | ||
|
|
48638eaa20 | ||
|
|
170777300e | ||
|
|
32311acd01 | ||
|
|
b9cbaf8f10 | ||
|
|
8d86b6c2d2 | ||
|
|
555f560ecd | ||
|
|
dba4815616 | ||
|
|
cf42611187 | ||
|
|
90c691df2b | ||
|
|
13fa23c568 | ||
|
|
124c58d48f | ||
|
|
a034600024 | ||
|
|
e0e600df05 | ||
|
|
92f5ae5a84 | ||
|
|
d57ddec302 | ||
|
|
bb3dc10f24 | ||
|
|
2cc50938a4 | ||
|
|
ba475d3128 | ||
|
|
ed81fb54ec | ||
|
|
8481da2405 | ||
|
|
ecb7303e35 | ||
|
|
9cb45eb7df | ||
|
|
6855e62f0a | ||
|
|
17b61db40a | ||
|
|
7b52499463 | ||
|
|
f67f99c227 | ||
|
|
0430ebf95c | ||
|
|
f602de437e | ||
|
|
a573b20888 | ||
|
|
488ae529ad | ||
|
|
6e823c6e87 | ||
|
|
7d35500e6b | ||
|
|
a17105fd46 | ||
|
|
b289d2baf4 | ||
|
|
f2e0abf1dc | ||
|
|
528154f1a2 | ||
|
|
bc71840f06 | ||
|
|
cd15b677ec | ||
|
|
1acb12edf5 | ||
|
|
008de93bbe | ||
|
|
4e834baa9a | ||
|
|
96e0e4ab5a | ||
|
|
381fe19335 | ||
|
|
ff99ca7cdf | ||
|
|
60f95cd9ea | ||
|
|
28bbeac763 | ||
|
|
e97e0bacd1 | ||
|
|
abfdfe67e8 | ||
|
|
992371b4cf | ||
|
|
07eeddc5e1 | ||
|
|
3b70c89e07 | ||
|
|
444db4c242 | ||
|
|
cb845ebff5 | ||
|
|
6112578d07 | ||
|
|
ae68fcb78a | ||
|
|
8d8d63c94c | ||
|
|
1d6f00859d | ||
|
|
397251b0f4 | ||
|
|
537b0dfa1a | ||
|
|
0acca7fe69 | ||
|
|
bac60f2067 | ||
|
|
f82b7e2a13 | ||
|
|
9e6d088757 | ||
|
|
c915719f85 | ||
|
|
f55135578c | ||
|
|
139eca0177 | ||
|
|
a8e625e99d | ||
|
|
a92a32b862 | ||
|
|
9da5cd0180 | ||
|
|
a6f2e502e7 | ||
|
|
69d8c2e554 | ||
|
|
70ba608850 | ||
|
|
75182f7205 | ||
|
|
41caa4415c | ||
|
|
c611cc7268 | ||
|
|
d14ec7d7d2 | ||
|
|
4ca19e33c2 | ||
|
|
1a0db878bf | ||
|
|
53eb9aca2b | ||
|
|
caccabd4e5 | ||
|
|
d0e0ac5fac | ||
|
|
7d81a3f4a5 | ||
|
|
f95b7529eb | ||
|
|
6a4fd46479 | ||
|
|
b01b1e4758 | ||
|
|
014b0b9944 | ||
|
|
5904f6df8b | ||
|
|
0f293bfc2b | ||
|
|
cfbedec719 | ||
|
|
666ae244b3 | ||
|
|
c13e93d63e | ||
|
|
c2585b5525 | ||
|
|
1d021c2790 | ||
|
|
cc418e5dab | ||
|
|
c7acdfadf2 | ||
|
|
869d873d5c | ||
|
|
3271634e7a | ||
|
|
4854c231e1 | ||
|
|
7a18fa887d | ||
|
|
6c4a0f9363 | ||
|
|
f7731d38f6 | ||
|
|
df3f4de7c3 | ||
|
|
10c43c9edc | ||
|
|
fe4b53a463 | ||
|
|
5b1f987ed1 | ||
|
|
48d778c4b3 | ||
|
|
7d086e9524 | ||
|
|
6e9433c7a8 | ||
|
|
39299e5cc1 | ||
|
|
eeab0efa56 | ||
|
|
77e45756f2 | ||
|
|
9cdcffbe4b | ||
|
|
50850cf8a2 | ||
|
|
35587658cd | ||
|
|
4661c98c17 | ||
|
|
7928659f70 | ||
|
|
f80f6445a6 | ||
|
|
336c2f4fe1 | ||
|
|
bfcb40bf6b | ||
|
|
051c2701ab | ||
|
|
028ee58580 | ||
|
|
801e3dfacf | ||
|
|
4171bd3bae | ||
|
|
73fb1c3a17 | ||
|
|
d65234ed51 | ||
|
|
58c5df729b | ||
|
|
632cc918b4 | ||
|
|
f870a49f42 | ||
|
|
d844799b3b | ||
|
|
3ea1145486 | ||
|
|
d4716fc03c | ||
|
|
16227594ef | ||
|
|
65cdb07f0c | ||
|
|
eb73e82279 | ||
|
|
d6fbfddddd | ||
|
|
1339a44402 | ||
|
|
b8215d8ac8 | ||
|
|
289d92c97d | ||
|
|
6c39c77fc5 | ||
|
|
69c3a7640b | ||
|
|
e8b0458f16 | ||
|
|
6b89639f90 | ||
|
|
9b25f7325a | ||
|
|
0093f9877a | ||
|
|
cf0b5d3715 | ||
|
|
616f7e74db | ||
|
|
14c812a39c | ||
|
|
1e52751344 | ||
|
|
d7ac6e516a | ||
|
|
c2436c46e6 | ||
|
|
e3585a6eb0 | ||
|
|
38608b1b0f | ||
|
|
2b634dab32 | ||
|
|
91acc51cd1 | ||
|
|
dc54ba67e4 | ||
|
|
35521b553a | ||
|
|
70a744558c | ||
|
|
4b789ff7e9 | ||
|
|
306657a118 | ||
|
|
be765e4cb9 | ||
|
|
b5857da877 | ||
|
|
3ad055ef3a | ||
|
|
3d00c477fc | ||
|
|
c2912d612a | ||
|
|
a3c7525249 | ||
|
|
f81025631e | ||
|
|
9c03c58de2 | ||
|
|
0ffd60b8cf | ||
|
|
d5baa6601c | ||
|
|
19eeef0aad | ||
|
|
e76392e330 | ||
|
|
a1cc9ac642 | ||
|
|
67c3af3bf8 | ||
|
|
843e1ed400 | ||
|
|
4bca6bf6f5 | ||
|
|
960b25408f | ||
|
|
45bc106de7 | ||
|
|
d151e36ea8 | ||
|
|
56cada6a0c | ||
|
|
a0b2d77bef | ||
|
|
030fd00232 | ||
|
|
d21f39160f | ||
|
|
4265a94bfe | ||
|
|
652d1e3de8 | ||
|
|
b33cff4cb7 | ||
|
|
e0fe84a856 | ||
|
|
783ffdb7fd | ||
|
|
cb3ac6987e | ||
|
|
5a83e58428 | ||
|
|
3f02ab0ead | ||
|
|
99c58fc561 | ||
|
|
a86df17ceb | ||
|
|
5d04ccbe51 | ||
|
|
61dc357bb3 | ||
|
|
d7cb2f850d | ||
|
|
bfe0a4a8ac | ||
|
|
0ec7909ec3 | ||
|
|
b5b912e2c4 | ||
|
|
9504a593e9 | ||
|
|
f8f28c8942 | ||
|
|
8fc7d63cf8 | ||
|
|
c513649df4 | ||
|
|
a6911825b0 | ||
|
|
eddabab5e4 | ||
|
|
3eee69de2d | ||
|
|
068d83bce8 | ||
|
|
7f649ccf23 | ||
|
|
808b830942 | ||
|
|
d669816a1b | ||
|
|
e40689b9cc | ||
|
|
709cf18aef | ||
|
|
e57cad6c3f | ||
|
|
4f94caa1b9 | ||
|
|
78a682e4b6 | ||
|
|
21d030dbfb | ||
|
|
72da553ed9 | ||
|
|
b78606d94f | ||
|
|
a6f719a402 | ||
|
|
e0fbd148ef | ||
|
|
2f91289880 | ||
|
|
462b755a60 | ||
|
|
0a2ecaa393 | ||
|
|
dedf03bb81 | ||
|
|
64f056b57d | ||
|
|
90df9fa1bf | ||
|
|
eae6e6381e | ||
|
|
04a18e0a97 | ||
|
|
06aece31cf | ||
|
|
e0296d6c3c | ||
|
|
5ffb5f01cc | ||
|
|
8576ad58bd | ||
|
|
c4860f6c29 | ||
|
|
850310b034 | ||
|
|
a29c781295 | ||
|
|
599673690c | ||
|
|
7deda53b7c | ||
|
|
5ecae52bf1 | ||
|
|
ac2d0edb2f | ||
|
|
ae632654d2 | ||
|
|
88f5f21dbb | ||
|
|
49e5510953 | ||
|
|
a6644f7477 | ||
|
|
10265d8667 | ||
|
|
8be708fe5b | ||
|
|
5facfafbd5 | ||
|
|
11761d1769 | ||
|
|
2c14488b93 | ||
|
|
c127bce73b | ||
|
|
af79a2a59e | ||
|
|
ee66476d62 | ||
|
|
40f9261d48 | ||
|
|
69205594cc | ||
|
|
d943f66abc | ||
|
|
b2385b46cf | ||
|
|
2af32d6665 | ||
|
|
5c58db3bb4 | ||
|
|
24a9491203 | ||
|
|
5511bd8e85 | ||
|
|
f1ca2b3a3a | ||
|
|
10fcefe346 | ||
|
|
0bfc11f1ba | ||
|
|
96998a5498 | ||
|
|
2da5299924 | ||
|
|
83b40b25d6 | ||
|
|
05f30b3e28 | ||
|
|
116a61beb1 | ||
|
|
8c86bb8024 | ||
|
|
41bb2c2663 | ||
|
|
e7b9cd8ee8 | ||
|
|
3019b9f320 | ||
|
|
60872d7d7c | ||
|
|
a37c1143ca | ||
|
|
4e08ee1833 | ||
|
|
7563870d11 | ||
|
|
12c5a57415 | ||
|
|
101680d603 | ||
|
|
d819d5d324 | ||
|
|
90cdffa067 | ||
|
|
080640a171 | ||
|
|
950a64f756 | ||
|
|
b50cef742d | ||
|
|
4f50935aa2 | ||
|
|
44f62e5e27 | ||
|
|
59e89e7664 | ||
|
|
5d464364a8 | ||
|
|
2112299586 | ||
|
|
c771964a40 | ||
|
|
a199ec2813 | ||
|
|
a28b3fff49 | ||
|
|
5bcd95f01f | ||
|
|
c84494b36b | ||
|
|
7e3a5b7ce8 | ||
|
|
fbfd11de2c | ||
|
|
9657d183f8 | ||
|
|
b98098b1f0 | ||
|
|
1ae14e5a3d | ||
|
|
7a92a3b729 | ||
|
|
457c688346 | ||
|
|
c609b18698 | ||
|
|
5ff0bb2100 | ||
|
|
90944bb1a2 | ||
|
|
07571741c5 | ||
|
|
14ccc8bc4c | ||
|
|
5cb936fa00 | ||
|
|
c6f025f40e | ||
|
|
a2b92c0745 | ||
|
|
6884463ba2 | ||
|
|
167d0e82f9 | ||
|
|
42e77de6a3 | ||
|
|
58b4a8395b | ||
|
|
d0dc04001e | ||
|
|
e101aa9fc8 | ||
|
|
6a7c399c2d | ||
|
|
b3e1341e44 | ||
|
|
ebdc7ddf20 | ||
|
|
f30ce8b210 | ||
|
|
76cccfaabd | ||
|
|
440d76647d | ||
|
|
2cc2fade06 | ||
|
|
e50173c7dc | ||
|
|
3318cf9aec | ||
|
|
b37230f6db | ||
|
|
1bf57a90df | ||
|
|
d2db202a2d | ||
|
|
08857606dc | ||
|
|
72e389041c | ||
|
|
d41c0b10c8 | ||
|
|
898ae53672 | ||
|
|
9e20cfee0e | ||
|
|
9af8da7aad | ||
|
|
c9be2b89f9 | ||
|
|
388f66c9b3 | ||
|
|
cd5a5d332f | ||
|
|
cb9a1dbb4f | ||
|
|
814541f6d9 | ||
|
|
89cbcceac4 | ||
|
|
10f7858453 | ||
|
|
922af7c405 | ||
|
|
e9f8e56895 | ||
|
|
3eb069a50c | ||
|
|
f1fbf995f7 | ||
|
|
86af889dfb | ||
|
|
b3492356e6 | ||
|
|
b2489b4318 | ||
|
|
a5a7e7ac56 | ||
|
|
74cbfc68a1 | ||
|
|
6423306980 | ||
|
|
c5b62ce1ee | ||
|
|
e538e0e077 | ||
|
|
9314e451c8 | ||
|
|
3b61e2854a | ||
|
|
03222d834b | ||
|
|
cb9743e567 | ||
|
|
66ad366a4f | ||
|
|
864ad8546e | ||
|
|
58789c52cd | ||
|
|
a762253e24 | ||
|
|
10d893ee9b | ||
|
|
acbc0717d4 | ||
|
|
1e19860585 | ||
|
|
09941b9aa9 | ||
|
|
2a5e8c4a47 | ||
|
|
686e0eea9f | ||
|
|
91f2184003 | ||
|
|
3e577ccf4f | ||
|
|
ea0b205455 | ||
|
|
16cf7a5e0a | ||
|
|
56abea7427 | ||
|
|
461a143a2b | ||
|
|
f65e357d2b | ||
|
|
4a31532897 | ||
|
|
29cd1a1b8f | ||
|
|
cd4be1f308 | ||
|
|
acae38ab9e | ||
|
|
a52cdbfe43 | ||
|
|
f233cde9a9 | ||
|
|
ceb8ba2e15 | ||
|
|
aab54011b3 | ||
|
|
691e266bef | ||
|
|
c6b2334fa3 | ||
|
|
69b5da766c | ||
|
|
a393cf4109 | ||
|
|
1b120466ee | ||
|
|
c8c533cc23 | ||
|
|
1e8deacf2e | ||
|
|
3595b5931a | ||
|
|
c7f923c5b0 | ||
|
|
25f9eb782b | ||
|
|
2009c3d4f1 | ||
|
|
c3632bc54a | ||
|
|
d9c87a21a6 | ||
|
|
2e76b23c9a | ||
|
|
9529f12c28 | ||
|
|
55b81cc1a1 | ||
|
|
c4caad7720 | ||
|
|
2563b4fc92 | ||
|
|
6f3c05545d | ||
|
|
414a8cb0ba | ||
|
|
c84c7250ba | ||
|
|
c7b6faf96a | ||
|
|
fe37afc0d7 | ||
|
|
478a10aa41 | ||
|
|
d033470817 | ||
|
|
7ad8a8ab55 | ||
|
|
a15c7f221d | ||
|
|
d7cb291fb2 | ||
|
|
563faa98de | ||
|
|
9c62ed4595 | ||
|
|
fe694e1fe1 | ||
|
|
bc2aa79f9a | ||
|
|
48aca642e3 | ||
|
|
15651a931e | ||
|
|
68e7983c70 | ||
|
|
8f0237610e | ||
|
|
b75d4f73e7 | ||
|
|
b3c5933a23 | ||
|
|
331857c9e6 | ||
|
|
57ea4987f7 | ||
|
|
d95ba866b8 | ||
|
|
1721543e5c | ||
|
|
46ccbcbff6 | ||
|
|
fc33576bac | ||
|
|
366bc00b70 | ||
|
|
d5cd3a111f | ||
|
|
94e400a5d6 | ||
|
|
7dd249f754 | ||
|
|
12ae1bb5e5 | ||
|
|
248f176c1f | ||
|
|
1871a7c3d0 | ||
|
|
59b3dcb5cf | ||
|
|
fb87590c82 | ||
|
|
38c4de3fc7 | ||
|
|
ae67408d13 | ||
|
|
42da8cd297 | ||
|
|
887cb6d0cd | ||
|
|
aeaf2d0b20 | ||
|
|
932e472986 | ||
|
|
e845987503 | ||
|
|
531b1197a7 | ||
|
|
52ad6242f4 | ||
|
|
969b34057b | ||
|
|
e110f70b5c | ||
|
|
e997db7a23 | ||
|
|
c4b695f78d | ||
|
|
75463b8331 | ||
|
|
882c25f292 | ||
|
|
9c8100043e | ||
|
|
031e10133c | ||
|
|
4087326f45 | ||
|
|
f9bc22ec6a | ||
|
|
26cd99c66e | ||
|
|
9334aad906 | ||
|
|
c695c53259 | ||
|
|
5c4397ab30 | ||
|
|
5c34d087d9 | ||
|
|
559bd169bd | ||
|
|
f8c969f5a5 | ||
|
|
c5253c7a31 | ||
|
|
53f15fde07 | ||
|
|
814f9cb566 | ||
|
|
af0db599b0 | ||
|
|
104368bd84 | ||
|
|
99461a178e | ||
|
|
feb3230160 | ||
|
|
be1a16a601 | ||
|
|
8e044b0e6d | ||
|
|
40e93a5f9e | ||
|
|
435eb6e2b3 | ||
|
|
8c88cc017a | ||
|
|
ed95cc160a | ||
|
|
2f067a3f65 | ||
|
|
498a82784d | ||
|
|
b5708825a7 | ||
|
|
a724ffab25 | ||
|
|
de34ef91d7 | ||
|
|
248a9383a0 | ||
|
|
78b4ad291c | ||
|
|
3f9dff9aac | ||
|
|
443854222c | ||
|
|
283544c7f3 | ||
|
|
49faa79bdc | ||
|
|
7670049a31 | ||
|
|
0cd642bca7 | ||
|
|
fe3c92ecce | ||
|
|
a969e24177 | ||
|
|
7b0fa6c889 | ||
|
|
fa60d8120e | ||
|
|
8b7649b90c | ||
|
|
687834c99e | ||
|
|
54c25ccbf5 | ||
|
|
e160a6198c | ||
|
|
e69d36d54f | ||
|
|
844c43e044 | ||
|
|
194712fd3b | ||
|
|
30f675aafa | ||
|
|
695266e907 | ||
|
|
3db44dacae | ||
|
|
62c1bc0a20 | ||
|
|
3863885c71 | ||
|
|
238e2b72ee | ||
|
|
a65ab3b0e0 | ||
|
|
aba8a8f4fc | ||
|
|
0448c2b437 | ||
|
|
0ada0cf525 | ||
|
|
7fa12662c4 | ||
|
|
bc9c4e8dee | ||
|
|
8004af2519 | ||
|
|
21e87ebc11 | ||
|
|
70d8afa6e9 | ||
|
|
847f865438 | ||
|
|
2cda777900 | ||
|
|
432a7276e2 | ||
|
|
533f7c45eb | ||
|
|
a1cdc2b68a | ||
|
|
9c4d533695 | ||
|
|
ad03491ee6 | ||
|
|
4b9dfc8990 | ||
|
|
a46f64cd1e | ||
|
|
b1e7163689 | ||
|
|
c931279960 | ||
|
|
12b25fdf6e | ||
|
|
c0e2649ed6 | ||
|
|
593c127257 | ||
|
|
9f6a09277e | ||
|
|
dd47884661 | ||
|
|
a01c226dc4 | ||
|
|
47f5e37205 | ||
|
|
51c9211cf4 | ||
|
|
7869e541f6 | ||
|
|
e0daca5693 | ||
|
|
e8e512f1fa | ||
|
|
37ce171061 | ||
|
|
e01986e2b3 | ||
|
|
433416fef8 | ||
|
|
2d4ad02356 | ||
|
|
3b81d3fea4 | ||
|
|
e785697a64 | ||
|
|
4ffe9304ba | ||
|
|
b1eec3a5d3 | ||
|
|
fcdd30b2d3 | ||
|
|
ec87c740a7 | ||
|
|
6b737d2c1b | ||
|
|
f7f4ba5e90 | ||
|
|
5466720d75 | ||
|
|
7c3cf316f1 | ||
|
|
d71aed309f | ||
|
|
d6beb60bf7 | ||
|
|
61d76a273f | ||
|
|
6d18e2f447 | ||
|
|
1c1c68df8d | ||
|
|
f6539737de | ||
|
|
fe9ff62297 | ||
|
|
7c85f15a6c | ||
|
|
6b366b2443 | ||
|
|
a8b77359df | ||
|
|
e7fab7d4bf | ||
|
|
59556ab030 | ||
|
|
128e2a1d9e | ||
|
|
e236302256 | ||
|
|
dfe28c8855 | ||
|
|
4b616344fa | ||
|
|
1ecd580061 | ||
|
|
21dcb4f290 | ||
|
|
b2b35d7dc1 | ||
|
|
a1501dcde8 | ||
|
|
3319ad03b8 | ||
|
|
fe1c60b5cf | ||
|
|
591dd9e662 | ||
|
|
bb6c15b00a | ||
|
|
6af28ead87 | ||
|
|
fcf459158d | ||
|
|
e76ef2a8a1 | ||
|
|
3c92bea519 | ||
|
|
12c703c1c3 | ||
|
|
376f47e030 | ||
|
|
ceedd4d968 | ||
|
|
c595636999 | ||
|
|
6e5cd10399 | ||
|
|
57a684d5ac | ||
|
|
5534eb4707 | ||
|
|
b2d5546cf8 | ||
|
|
f653ba63bf | ||
|
|
0396b6d521 | ||
|
|
94b36bb65e | ||
|
|
b4fd6e876e | ||
|
|
775e100d2c | ||
|
|
4cb02d0bf2 | ||
|
|
ae538337ba | ||
|
|
62a7beec21 | ||
|
|
45e18a1832 | ||
|
|
f6adddb4a8 | ||
|
|
38fc351532 | ||
|
|
01be6fa309 | ||
|
|
e06bbaf303 | ||
|
|
bb7b152af5 | ||
|
|
5504920ba3 | ||
|
|
c74a359c46 | ||
|
|
ee9dc6ce59 | ||
|
|
62e8ec34d1 | ||
|
|
6a5254c475 | ||
|
|
2802a06a08 | ||
|
|
8ac430813d | ||
|
|
3e61b8c17a | ||
|
|
9e277d1596 | ||
|
|
4c9d5244a5 | ||
|
|
87cc277b38 | ||
|
|
3115c23762 | ||
|
|
31030c6514 | ||
|
|
7b8ffc9981 | ||
|
|
a75bccfbc4 | ||
|
|
f97229f05a | ||
|
|
ac2ef9e0ea | ||
|
|
c2803b80e8 | ||
|
|
7a6876bc62 | ||
|
|
819f81f702 | ||
|
|
036d3b59a3 | ||
|
|
782a836db0 | ||
|
|
bd46b78785 | ||
|
|
f908dd0e55 | ||
|
|
0bbf38141a | ||
|
|
f188366e26 | ||
|
|
fd60621a8e | ||
|
|
60b7f2c61b | ||
|
|
3e3d53daef | ||
|
|
d64a48e0ee | ||
|
|
0a7b2ab52c | ||
|
|
8a69f1087b | ||
|
|
f24f03906f | ||
|
|
fa56e8c0ce | ||
|
|
fc406d1657 | ||
|
|
9dcefd0e1e | ||
|
|
a2dc53d43d | ||
|
|
b9c4fab96e | ||
|
|
fa07dbd7ec | ||
|
|
9b382d7a11 | ||
|
|
75b78bfb72 | ||
|
|
b234f7aba2 | ||
|
|
bff069f83c | ||
|
|
616b07ff6b | ||
|
|
b26f812399 | ||
|
|
321061125f | ||
|
|
6469e2ccca | ||
|
|
c4646bf87f | ||
|
|
716364182d | ||
|
|
1971e149fb | ||
|
|
7939d62ef0 | ||
|
|
4c1f1e4e57 | ||
|
|
09170f76fe | ||
|
|
9e1edf8685 | ||
|
|
e7fe299504 | ||
|
|
b90edffe28 | ||
|
|
f361092ed9 | ||
|
|
a1e0f0ba95 | ||
|
|
5f218a43fd | ||
|
|
7fe470fc76 | ||
|
|
d490c25807 | ||
|
|
340f33b475 | ||
|
|
7518c4a9be | ||
|
|
db413aadfd | ||
|
|
5433e5771e | ||
|
|
e2e50bc0fc | ||
|
|
27245ce6f6 | ||
|
|
d4634dc683 | ||
|
|
8c08fc671c | ||
|
|
a2d40580d7 | ||
|
|
0011af7adf | ||
|
|
1764106606 | ||
|
|
3356544706 | ||
|
|
335e012b6a | ||
|
|
a458da8f92 | ||
|
|
9fb45c5b5a | ||
|
|
aae4e94998 | ||
|
|
d935a4f0a8 | ||
|
|
5c331d8276 | ||
|
|
13b9de6778 | ||
|
|
dc0e8de9b0 | ||
|
|
90a2335267 | ||
|
|
99c4e48038 | ||
|
|
4bd4d59af5 | ||
|
|
8219abc552 | ||
|
|
d6a87d3c43 | ||
|
|
a3adac3787 | ||
|
|
6fc82f3824 | ||
|
|
bcca27ee20 | ||
|
|
3702cb7e7c | ||
|
|
49653d3e31 | ||
|
|
ddb8430341 | ||
|
|
91a3cb0f21 | ||
|
|
765c325441 | ||
|
|
659768783f | ||
|
|
e756906a0e | ||
|
|
136b6a7673 | ||
|
|
068f01368f | ||
|
|
f23d47e5d2 | ||
|
|
09aed7ee89 | ||
|
|
d56b44f3a5 | ||
|
|
9e4c25761c | ||
|
|
54f2cc9709 | ||
|
|
31a7e2b3b4 | ||
|
|
00ab3daa0c | ||
|
|
bbf0228aa7 | ||
|
|
6550199751 | ||
|
|
10f361fcd0 | ||
|
|
4a0ae17401 | ||
|
|
8537070575 | ||
|
|
9cbcd4b5e3 | ||
|
|
4fa4e617b7 | ||
|
|
2e598a7caf | ||
|
|
031eb23dc8 | ||
|
|
edd718c580 | ||
|
|
392a041c2b | ||
|
|
8727bfc265 | ||
|
|
84e39203bb | ||
|
|
97e9802255 | ||
|
|
8c6bd44929 | ||
|
|
ed5511dc08 | ||
|
|
aa57e89e21 | ||
|
|
c2f6ff759b | ||
|
|
45ff7cdd0c | ||
|
|
ce36a0111a | ||
|
|
b61f5482d4 | ||
|
|
40b5defe18 | ||
|
|
e40d1b36f7 | ||
|
|
60a2867af2 | ||
|
|
bfdad916a2 | ||
|
|
498ff803db | ||
|
|
c8789492dc | ||
|
|
1723836014 | ||
|
|
2d6bc8d7d7 | ||
|
|
7448c4adde | ||
|
|
a221736eee | ||
|
|
382bead548 | ||
|
|
f9479b34cb | ||
|
|
925696ca65 | ||
|
|
7682ad9a60 | ||
|
|
3e92d295e4 | ||
|
|
661d336dd5 | ||
|
|
d1a00c684e | ||
|
|
db034e079a | ||
|
|
7d983a548b | ||
|
|
8311f5c611 | ||
|
|
628791e5a5 | ||
|
|
df857266b6 | ||
|
|
ddb3d8945d | ||
|
|
7f5908b622 | ||
|
|
24f7b9387a | ||
|
|
756818f940 | ||
|
|
2131f8d330 | ||
|
|
8ae2ffda89 | ||
|
|
75b97a5a65 | ||
|
|
7b99039c34 | ||
|
|
3ca7b10ad4 | ||
|
|
779c2a22d0 | ||
|
|
147a18b34a | ||
|
|
4382c8d28b | ||
|
|
944ebccfe9 | ||
|
|
fd1b0b997a | ||
|
|
abe912c610 | ||
|
|
66fcdf7c7a | ||
|
|
4e13a19339 | ||
|
|
7dd3c007c7 | ||
|
|
0d392a0442 | ||
|
|
7e4a704bd1 | ||
|
|
bf5e956087 | ||
|
|
2ccc3326ec | ||
|
|
83f7d5c95a | ||
|
|
2c129447fd | ||
|
|
b50339e8e7 | ||
|
|
8ff5b365dd | ||
|
|
1f0985689d | ||
|
|
3089bbf2b8 | ||
|
|
5feeb65cf0 | ||
|
|
715e74186c | ||
|
|
3a03fe5a15 | ||
|
|
d343560108 | ||
|
|
2b6db268cf | ||
|
|
14abdd57f3 | ||
|
|
1f3e4d2d9a | ||
|
|
29bfcb0a31 | ||
|
|
301845943c | ||
|
|
b0017c5460 | ||
|
|
0b61d22652 | ||
|
|
70b95135e6 | ||
|
|
a3d925ac1d | ||
|
|
cf9a03f698 | ||
|
|
7f8240dfde | ||
|
|
f8b152972f | ||
|
|
95875c55fc | ||
|
|
7fadde0b37 | ||
|
|
e36c79f713 | ||
|
|
2252071866 | ||
|
|
b700ed8e31 | ||
|
|
e1fd587ddd | ||
|
|
f74de4cb86 | ||
|
|
6c1572c9b8 | ||
|
|
60a1f49a5c | ||
|
|
740167202f | ||
|
|
e0017c8a97 | ||
|
|
4a78c1bb28 | ||
|
|
1d3f723ccc | ||
|
|
77408b7bde | ||
|
|
0cd1bd6d8b | ||
|
|
881d2ce31e | ||
|
|
ad79ead93d | ||
|
|
17a748c796 | ||
|
|
583599b19f | ||
|
|
044fe56b43 | ||
|
|
b46da19b74 | ||
|
|
d635783d07 | ||
|
|
f79e13af38 | ||
|
|
34e6474ad9 | ||
|
|
5c96e0c812 | ||
|
|
921a2b41f0 | ||
|
|
a8cec967ac | ||
|
|
044c500cc0 | ||
|
|
a917ec9ea2 | ||
|
|
d4ccc88676 | ||
|
|
12c85c4e60 | ||
|
|
90c0267bc1 | ||
|
|
8963bf08aa | ||
|
|
ede4f818fd | ||
|
|
126f63c0a2 | ||
|
|
aea8629272 | ||
|
|
5138bcb1c7 | ||
|
|
cc50dc076a | ||
|
|
bf576f0097 | ||
|
|
377747b061 | ||
|
|
870a98ccc3 | ||
|
|
8eda3efa28 | ||
|
|
e2c3cc9685 | ||
|
|
2a6e71a753 | ||
|
|
340d273f83 | ||
|
|
54c63726b0 | ||
|
|
cb80ab2965 | ||
|
|
c48e772115 | ||
|
|
aa78fc14b5 | ||
|
|
399fb9aa70 | ||
|
|
ec3c91ac14 | ||
|
|
fae0603413 | ||
|
|
9af837c24d | ||
|
|
cc2b418f7f | ||
|
|
6ddc30ffc7 | ||
|
|
aa7d63f2ff | ||
|
|
50f2ef548c | ||
|
|
b9637f7185 | ||
|
|
88138c38cf | ||
|
|
5ad0da1750 | ||
|
|
9deb647303 | ||
|
|
b856c45b9c | ||
|
|
f0f1ebe013 | ||
|
|
34beff117a | ||
|
|
e2e8746044 | ||
|
|
78446fd99c | ||
|
|
daa258ea6d | ||
|
|
54c85ef8b9 | ||
|
|
de512c5923 | ||
|
|
8fd133ff19 | ||
|
|
f5ba931115 | ||
|
|
3370e40fe1 | ||
|
|
e509e8f354 | ||
|
|
aaef2f7c84 | ||
|
|
369aa5854f | ||
|
|
9d12e485e5 | ||
|
|
dc54fc707e | ||
|
|
212a5ebc2e | ||
|
|
2d2e769e96 | ||
|
|
bba35c1486 | ||
|
|
0a902ebf61 | ||
|
|
70c0f4b936 | ||
|
|
e19fa59b63 | ||
|
|
30d351b0c1 | ||
|
|
818314c5db | ||
|
|
700e4bb29d | ||
|
|
8ad4a1341f | ||
|
|
d87acc2d1b | ||
|
|
f2349b1092 | ||
|
|
7824b66f5b | ||
|
|
83048fb2fe | ||
|
|
9dde1a0bd4 | ||
|
|
bc9092d7db | ||
|
|
56b959b9f9 | ||
|
|
b3796e0aaa | ||
|
|
d24083b257 | ||
|
|
83ec9f773a | ||
|
|
9ceccbe9a4 | ||
|
|
35a4912449 | ||
|
|
01e008cedd | ||
|
|
d8af26e75a | ||
|
|
03ddb109ec | ||
|
|
2fd8496bc1 | ||
|
|
8d7640894d | ||
|
|
c5a657f540 | ||
|
|
1ea43e513d | ||
|
|
c9e11de2a7 | ||
|
|
f644fc5725 | ||
|
|
49278a7f9c | ||
|
|
b0728260e9 | ||
|
|
92ada55e5a | ||
|
|
8840ae6ae2 | ||
|
|
21dab22f17 | ||
|
|
10a849c27e | ||
|
|
236489aecf | ||
|
|
7108c66e3b | ||
|
|
797acbe911 | ||
|
|
0bf66deb3c | ||
|
|
d2f3e9faf4 | ||
|
|
37f1390473 | ||
|
|
9b5f21a650 | ||
|
|
8267920749 | ||
|
|
6c85e4be4f | ||
|
|
23a87304cc | ||
|
|
c14b39da5f | ||
|
|
57eee2466b | ||
|
|
5d66d1c28c | ||
|
|
fb47ca6d35 | ||
|
|
0013053fae | ||
|
|
1abbb11b44 | ||
|
|
54903adeff | ||
|
|
c08618f7e9 | ||
|
|
d578f7f81e | ||
|
|
043c6018b4 | ||
|
|
d0965cca05 | ||
|
|
b8ac67e240 | ||
|
|
350d584af8 | ||
|
|
e3e75376ec | ||
|
|
ab753abfa0 | ||
|
|
bab7877fa1 | ||
|
|
10f8101314 | ||
|
|
530626dab7 | ||
|
|
b96d28a42b | ||
|
|
3444bee47f | ||
|
|
cf3abe5096 | ||
|
|
ecdda69fab | ||
|
|
fc3fe9292f | ||
|
|
d396053872 | ||
|
|
e9a2389300 | ||
|
|
678a9a2e42 | ||
|
|
124032e3e9 | ||
|
|
4beac54bd9 | ||
|
|
39493bcd9a | ||
|
|
f96771e753 | ||
|
|
62f94a7948 | ||
|
|
e9b7221292 | ||
|
|
5fea1d2675 | ||
|
|
7a492e3612 | ||
|
|
b893df3348 | ||
|
|
742b5b705f | ||
|
|
0153d21f3b | ||
|
|
695ad5fe2d | ||
|
|
d8ca0580a8 | ||
|
|
525fc0ae5b | ||
|
|
311f18bebf | ||
|
|
d49a5166ac | ||
|
|
e560dd839f | ||
|
|
6f8d385dfa | ||
|
|
086544e367 | ||
|
|
eed0297ed5 | ||
|
|
b467515719 | ||
|
|
75df0d91ba | ||
|
|
05c0dfac12 | ||
|
|
bcde80fc4f | ||
|
|
5f6b996d22 | ||
|
|
74a3a2b56a | ||
|
|
b07d01f102 | ||
|
|
eed3959749 | ||
|
|
278b2344fe | ||
|
|
05095954c9 | ||
|
|
6fef4b080e | ||
|
|
259111d0e8 | ||
|
|
a707748893 | ||
|
|
130ae133c1 | ||
|
|
1d387d7452 | ||
|
|
612726d9f6 | ||
|
|
5888ddaab1 | ||
|
|
e6cecb9595 | ||
|
|
e36e507463 | ||
|
|
3c10f7a122 | ||
|
|
ca8c34f966 | ||
|
|
8355fee16a | ||
|
|
7f3c697b6e | ||
|
|
0d1fa8e884 | ||
|
|
2e0a4aafa7 | ||
|
|
bfecb5a135 | ||
|
|
850da13622 | ||
|
|
b284d39e05 | ||
|
|
23d8de8962 | ||
|
|
3065059da7 | ||
|
|
e2ed15fa02 | ||
|
|
b92814c933 | ||
|
|
12c084c8c0 | ||
|
|
e4caf96bcb | ||
|
|
10982f4d8f | ||
|
|
6b38abd57b | ||
|
|
58105dbd4e | ||
|
|
d0b1bf4e26 | ||
|
|
aa7b3a73f5 | ||
|
|
852375be00 | ||
|
|
9a80730f38 | ||
|
|
24a1b130f9 | ||
|
|
e2fe4a6e9b | ||
|
|
4f5b6528a1 | ||
|
|
10828ad063 | ||
|
|
b6031d5f4b | ||
|
|
5c29d7aba9 | ||
|
|
bdbefe334d | ||
|
|
77a3d03385 | ||
|
|
468982ffe4 | ||
|
|
2750343de5 | ||
|
|
3c0128a680 | ||
|
|
4522456d55 | ||
|
|
dcc538ff32 | ||
|
|
a22f7358cd | ||
|
|
aac85a14f0 | ||
|
|
a676b2aa10 | ||
|
|
df934c1707 | ||
|
|
eaec0c8ea5 | ||
|
|
4f0f50c62d | ||
|
|
b4ece65726 | ||
|
|
562dd67e16 | ||
|
|
da646a8986 | ||
|
|
b9b2782c3c | ||
|
|
f1c087116f | ||
|
|
9dcf130d67 | ||
|
|
ed7183936d | ||
|
|
e5342f4054 | ||
|
|
2e173d4abf | ||
|
|
ca632c9e90 | ||
|
|
c94a92b30d | ||
|
|
84fea82043 | ||
|
|
d608e2b7ad | ||
|
|
d19d8e7914 | ||
|
|
9c3eee0b00 | ||
|
|
bf5181d9ca | ||
|
|
989cb6dd2e | ||
|
|
cf31f8d06f | ||
|
|
c7cd62b449 | ||
|
|
2b5b017253 | ||
|
|
630c6ef7b5 | ||
|
|
ee88272216 | ||
|
|
bd7ec18c19 | ||
|
|
42626d9e16 | ||
|
|
fc6611b2d9 | ||
|
|
4f27752468 | ||
|
|
9bc1790320 | ||
|
|
3fbe286e5a | ||
|
|
aa22bd8464 | ||
|
|
cf686d4f83 | ||
|
|
267f134d44 | ||
|
|
d4fa98de68 | ||
|
|
790e04ed3e | ||
|
|
772306cac8 | ||
|
|
30a19fc899 | ||
|
|
6a30a902c9 | ||
|
|
883b71ca70 | ||
|
|
11b5d11e9e | ||
|
|
6d83c60c40 | ||
|
|
cc2b430e68 | ||
|
|
9d7d8075d1 | ||
|
|
fe87623674 | ||
|
|
91dc87e7c4 | ||
|
|
fb0df75de0 | ||
|
|
e1792c1ea5 | ||
|
|
d5113377e2 | ||
|
|
eb9ca23250 | ||
|
|
05a8204508 | ||
|
|
e041b2eee6 | ||
|
|
0a4ab7e38f | ||
|
|
c4ad0f76e6 | ||
|
|
0f1edcd57d | ||
|
|
118d565534 | ||
|
|
1dfb95f719 | ||
|
|
33f807d9a1 | ||
|
|
926fb83e33 | ||
|
|
2b324b7eb9 | ||
|
|
157ec8af2d | ||
|
|
f14f167297 | ||
|
|
4fe67652ff | ||
|
|
c5bccc5474 | ||
|
|
f8fdbe3dbc | ||
|
|
c9cd8de9c6 | ||
|
|
3e1343dc6b | ||
|
|
bc4e6566e7 | ||
|
|
16509ac3db | ||
|
|
f803544195 | ||
|
|
8eb07800b3 | ||
|
|
538b325150 | ||
|
|
cd3c3c3bad | ||
|
|
8c91014cd8 | ||
|
|
6312eb91be | ||
|
|
d2ae7e164a | ||
|
|
627a686f90 | ||
|
|
57527f9f67 | ||
|
|
14d0d395f2 | ||
|
|
edd7263f06 | ||
|
|
2a9e89b34f | ||
|
|
dd1f5a2268 | ||
|
|
8a0466d81d | ||
|
|
fb9d3842e4 | ||
|
|
8c3823545d | ||
|
|
75989342b0 | ||
|
|
46151720f8 | ||
|
|
9109b20852 | ||
|
|
6b059e0063 | ||
|
|
92dee7ea3c | ||
|
|
604bf03f3a | ||
|
|
f217f2b2c5 | ||
|
|
92bafa7ecd | ||
|
|
6afee8f117 | ||
|
|
1ef7c1d25b | ||
|
|
7db7bbe464 | ||
|
|
57151d6043 | ||
|
|
5d660e073a | ||
|
|
4982cb4d1f | ||
|
|
24ce90fc72 | ||
|
|
75b6c5215f | ||
|
|
d8fb226ec4 | ||
|
|
95c74b2ccd | ||
|
|
f0e7f0acf8 | ||
|
|
1fcc9dc654 | ||
|
|
7c0f51e24b | ||
|
|
29c0e6e4f4 | ||
|
|
56a1a2d917 | ||
|
|
4871e64b03 | ||
|
|
809e0e8c59 | ||
|
|
4305d054d6 | ||
|
|
9860c8fee1 | ||
|
|
7ebf011fcd | ||
|
|
4a1b714ca4 | ||
|
|
4c1d41c12e | ||
|
|
6ba799132c | ||
|
|
e5d8fcd198 | ||
|
|
f31d6ffb8c | ||
|
|
2608b95b4b | ||
|
|
2bf8c40cff | ||
|
|
b5ab74fd38 | ||
|
|
556fbf0c4c | ||
|
|
4c7a2be06a | ||
|
|
6dbcfb32d2 | ||
|
|
efeadcc0f4 | ||
|
|
297772e009 | ||
|
|
aa9e673ed7 | ||
|
|
4e781961e9 | ||
|
|
884060eb9b | ||
|
|
07e59e63f9 | ||
|
|
ac28b12fa8 | ||
|
|
257f45b768 | ||
|
|
acfbea6d49 | ||
|
|
6c60c07f16 | ||
|
|
bff8402fe8 | ||
|
|
f6f1f1992c | ||
|
|
194f345470 | ||
|
|
2bf7e9c968 | ||
|
|
c930f43cbe | ||
|
|
a518d08839 | ||
|
|
cdf650fba9 | ||
|
|
bdb34f9f4e | ||
|
|
0be3480729 | ||
|
|
495283e2d4 | ||
|
|
842609ddcb | ||
|
|
1310c72647 | ||
|
|
cc6dde96c1 | ||
|
|
cc7b2d26e5 | ||
|
|
1781a52147 | ||
|
|
0ba449c8ba | ||
|
|
f6e28c4975 | ||
|
|
6bcd4242f1 | ||
|
|
9851265d4f | ||
|
|
098646c5ff | ||
|
|
0e5cd6dc2f | ||
|
|
2fcb2b9232 | ||
|
|
fcf78a5da7 | ||
|
|
72c4be35e8 | ||
|
|
5d0c2a1414 | ||
|
|
7bb638e3b8 | ||
|
|
7448753257 | ||
|
|
6e662337ff | ||
|
|
270b68a893 | ||
|
|
cefb2bede0 | ||
|
|
47852122d0 | ||
|
|
00055fa2e8 | ||
|
|
bd93f76950 | ||
|
|
803b1f2115 | ||
|
|
3cdd2daf08 | ||
|
|
4e0afc55e6 | ||
|
|
e160318eef | ||
|
|
56c60fba23 | ||
|
|
9e82d132ce | ||
|
|
a70c95b79e | ||
|
|
d5b524e309 | ||
|
|
e6fe6b5b76 | ||
|
|
d1926bcad1 | ||
|
|
fa451fc55c | ||
|
|
5da9b3a803 | ||
|
|
93c58d0b24 | ||
|
|
23a6a6f8fc | ||
|
|
63f546497b | ||
|
|
c55d83281a | ||
|
|
35f1db09a9 | ||
|
|
34965f610d | ||
|
|
eaeb547938 | ||
|
|
15d5b2ac49 | ||
|
|
992b11c450 | ||
|
|
0017fb7ffe | ||
|
|
3240ce21b8 | ||
|
|
207798b09a | ||
|
|
543eea4f4e | ||
|
|
6d223d5526 | ||
|
|
3d9ca32e95 | ||
|
|
90abc61c56 | ||
|
|
6a0217688f | ||
|
|
b798169c6e | ||
|
|
7e56aad51a | ||
|
|
e325ffc681 | ||
|
|
516e78ea54 | ||
|
|
c21cec002c | ||
|
|
f89279cf11 | ||
|
|
44f25864d9 | ||
|
|
7f20eca892 | ||
|
|
2c8df0ee6b | ||
|
|
e8f33a4784 | ||
|
|
58ccefa407 | ||
|
|
e8cad948e3 | ||
|
|
53e2b9693a | ||
|
|
559613689d | ||
|
|
a01cff9ce6 | ||
|
|
62860e4919 | ||
|
|
5e5fb37774 | ||
|
|
d6fd0c4ca0 | ||
|
|
7cf773e2d3 | ||
|
|
f5b77d50b5 | ||
|
|
757a548edf | ||
|
|
17124989a9 | ||
|
|
75bad132fc | ||
|
|
391c738959 | ||
|
|
8655e2456e | ||
|
|
17ec70fc09 | ||
|
|
9ce71013df | ||
|
|
5ab8ca0868 | ||
|
|
4c0d1d3ad2 | ||
|
|
0277e52bd5 | ||
|
|
cf18bf2966 | ||
|
|
324293f4cb | ||
|
|
52d9cf080e | ||
|
|
590efc1040 | ||
|
|
5eeaffd38e | ||
|
|
07e7b98c70 | ||
|
|
873d34157d | ||
|
|
47df1fb7d4 | ||
|
|
1a59b6a3b4 | ||
|
|
0109f1e524 | ||
|
|
37d5a2cf3e | ||
|
|
3af7c67757 | ||
|
|
26f661a5dd | ||
|
|
057cfb30f1 | ||
|
|
1a42f946dc | ||
|
|
e05052b079 | ||
|
|
7d5b62b61f | ||
|
|
a75353da6d | ||
|
|
083fe959e2 | ||
|
|
480b24d9f0 | ||
|
|
aecf860b26 | ||
|
|
bd369cc451 | ||
|
|
07143a4353 | ||
|
|
bf7521a6ab | ||
|
|
fdeceb9a74 | ||
|
|
52d03d0071 | ||
|
|
29a893b193 | ||
|
|
cf4074cc80 | ||
|
|
cb2ed5bb7c | ||
|
|
2ba3656ffd | ||
|
|
cd9e9e9f45 | ||
|
|
f9d0096744 | ||
|
|
935f70a346 | ||
|
|
5109746b1c | ||
|
|
1684ec163f | ||
|
|
3a973b80ac | ||
|
|
ed03cb5c17 | ||
|
|
54b26869d5 | ||
|
|
cb279bf662 | ||
|
|
9d2de2b756 | ||
|
|
e6b7e66bbe | ||
|
|
45876d0828 | ||
|
|
b6a04a3456 | ||
|
|
f4d0076344 | ||
|
|
d572bb0c5d | ||
|
|
2ac69176e1 | ||
|
|
00847cdc6b | ||
|
|
fbedb426ce | ||
|
|
6dc113aa80 | ||
|
|
ebe23f1379 | ||
|
|
06d219db8e | ||
|
|
16bffdf7ab | ||
|
|
c648bd5b31 | ||
|
|
6e065affe5 | ||
|
|
4ee9acb8a7 | ||
|
|
20458564b2 | ||
|
|
c848056438 | ||
|
|
b33a7c46ce | ||
|
|
a4ee7d25d1 | ||
|
|
58c860ba11 | ||
|
|
90d1ed87fd | ||
|
|
df35989742 | ||
|
|
23dbd0c8c3 | ||
|
|
257d81ddd1 | ||
|
|
1d01f6af98 | ||
|
|
715b8c629f | ||
|
|
a63e1bb2dc | ||
|
|
5965578c56 | ||
|
|
4671c44b2d | ||
|
|
052c2c1575 | ||
|
|
4b30cb3083 | ||
|
|
585ce45a5e | ||
|
|
6899c91ebe | ||
|
|
7fb0e8b30b | ||
|
|
a1387c7c17 | ||
|
|
ffe6d58a58 | ||
|
|
2a59cda77e | ||
|
|
8c38543357 | ||
|
|
2742831fb9 | ||
|
|
6bcbd14d5a | ||
|
|
cf875a51fd | ||
|
|
c34e136be9 | ||
|
|
c3295f4878 | ||
|
|
705e7bd577 | ||
|
|
285a2a7061 | ||
|
|
fd68bc7cfd | ||
|
|
28307fd4c9 | ||
|
|
7dcc3dbcd1 | ||
|
|
72b2be51ec | ||
|
|
9775ecde99 | ||
|
|
c0f026a9b3 | ||
|
|
ac86e664c7 | ||
|
|
c39e001a95 | ||
|
|
8067cdb5f2 | ||
|
|
9d18cbe74e | ||
|
|
d1fc37ff9e | ||
|
|
7fbe8e47d4 | ||
|
|
d7c5690f17 | ||
|
|
d3069b0f5b | ||
|
|
ebd3929c0d | ||
|
|
9a1a6c56b4 | ||
|
|
b6f744c732 | ||
|
|
a9bb6734e7 | ||
|
|
e4e17a2c95 | ||
|
|
8bb3a2e1d7 | ||
|
|
f88d56b2f8 | ||
|
|
5b0489cdb4 | ||
|
|
b8a939a894 | ||
|
|
2b02843453 | ||
|
|
5be72672fe | ||
|
|
549d3bd09a | ||
|
|
868017cf1a | ||
|
|
3478de50a1 | ||
|
|
63704454a3 | ||
|
|
b08f29cb71 | ||
|
|
d62e85757f | ||
|
|
c3f1b08b6a | ||
|
|
fc95c9872f | ||
|
|
09f7dabd5e | ||
|
|
4fd1471f11 | ||
|
|
85e83934a1 | ||
|
|
ba5382b70e | ||
|
|
b0d2032488 | ||
|
|
162fbdd17b | ||
|
|
0413a87eb4 | ||
|
|
c1dc1a1a45 | ||
|
|
077cf13a1f | ||
|
|
a416c37ebd | ||
|
|
12ead6cc7e | ||
|
|
5f6de800a0 | ||
|
|
d6587be7bc | ||
|
|
afc39febed | ||
|
|
b54b9b4ecc | ||
|
|
5d19a008ce | ||
|
|
3233c9c003 | ||
|
|
c88257b038 | ||
|
|
0874c72819 | ||
|
|
d66ebbd904 | ||
|
|
1a3573bf17 | ||
|
|
e6c083f589 | ||
|
|
759060f47e | ||
|
|
715f78e26a | ||
|
|
db69845ded | ||
|
|
ff90224ba8 | ||
|
|
720b74d89e | ||
|
|
05e1a22d5b | ||
|
|
cf11e6ba65 | ||
|
|
1ddb60b6e7 | ||
|
|
5420254b36 | ||
|
|
55b3c22d99 | ||
|
|
fed84f875c | ||
|
|
1842e03315 | ||
|
|
d033cd54b8 | ||
|
|
2dc6ab3896 | ||
|
|
6d66cc68ed | ||
|
|
51d760f29f | ||
|
|
a4154e76c5 | ||
|
|
524f3b2d57 | ||
|
|
d474baeeea | ||
|
|
22ba8bdef8 | ||
|
|
d43e3db978 | ||
|
|
26ccb4c94a | ||
|
|
c128957723 | ||
|
|
66867bf949 | ||
|
|
e1d5873bdf | ||
|
|
b03facd828 | ||
|
|
4e743649be | ||
|
|
fab518fc98 | ||
|
|
fa609366d4 | ||
|
|
569fd474c2 | ||
|
|
d4f6254551 | ||
|
|
e31ed6dc2f | ||
|
|
8449e9794a | ||
|
|
07a9242dba | ||
|
|
097da55a2c | ||
|
|
97a5ed2d1a | ||
|
|
caaafa192b | ||
|
|
53d777a2d5 | ||
|
|
fc6d22db32 | ||
|
|
d58a666445 | ||
|
|
22d95c7b51 | ||
|
|
b1cd677711 | ||
|
|
1208296dc0 | ||
|
|
cfc7fed31c | ||
|
|
beb3eda438 | ||
|
|
c94bc2bc2b | ||
|
|
e4e70ece3f | ||
|
|
0fa34f7f67 | ||
|
|
55602b9be6 | ||
|
|
749df0536f | ||
|
|
2037d2631a | ||
|
|
de0153a1c4 | ||
|
|
d93d754972 | ||
|
|
a5ce4f6c36 | ||
|
|
05d8cd50b5 | ||
|
|
af5cd5cc75 | ||
|
|
4090a31d19 | ||
|
|
163fe1731b | ||
|
|
eef9124d1b | ||
|
|
56eebb95ee | ||
|
|
88b5c724f2 | ||
|
|
65b1756978 | ||
|
|
108beae7a8 | ||
|
|
2773410de4 | ||
|
|
e7656873c1 | ||
|
|
332f7056f7 | ||
|
|
027cb8dc6b | ||
|
|
c7386b139b | ||
|
|
f5c4fdc82a | ||
|
|
8352ec4e5d | ||
|
|
8192bb0aaf | ||
|
|
b13924701e | ||
|
|
17e6ae813f | ||
|
|
dab31d0166 | ||
|
|
0e7baf027b | ||
|
|
26275ba66c | ||
|
|
7098e5c7eb | ||
|
|
4747f14a2c | ||
|
|
692691938c | ||
|
|
a200505ae5 | ||
|
|
8ba79252c8 | ||
|
|
6456654307 | ||
|
|
21501815dd | ||
|
|
d56cb2ab4b | ||
|
|
4fead237f0 | ||
|
|
6282fad518 | ||
|
|
175bb329e4 | ||
|
|
9be3064904 | ||
|
|
98450ee2db | ||
|
|
931af6a072 | ||
|
|
202146e4ce | ||
|
|
9693795c4c | ||
|
|
cd9ee9d84b | ||
|
|
42a9b847ec | ||
|
|
d92a5b1074 | ||
|
|
f7f7cf576a | ||
|
|
26f4b5c98e | ||
|
|
70f19e809b | ||
|
|
0905332f1d | ||
|
|
df172fa840 | ||
|
|
ce044dbb76 | ||
|
|
7c26be3242 | ||
|
|
bf1ee89b27 | ||
|
|
a0bdae4f9c | ||
|
|
64feaa05f4 | ||
|
|
5ea3f24304 | ||
|
|
c9d36cd713 | ||
|
|
2c75c9daf9 | ||
|
|
d971416d12 | ||
|
|
1f1dcead3d | ||
|
|
d38a6e329f | ||
|
|
f73f53c486 | ||
|
|
b8279d424c | ||
|
|
98a509ed97 | ||
|
|
7c1e79cbc5 | ||
|
|
7fab31fbe3 | ||
|
|
2c724d5eee | ||
|
|
6dbe9febce | ||
|
|
d754d210cd | ||
|
|
62adbe69ff | ||
|
|
f3da6d23cb | ||
|
|
a4d5ec491e | ||
|
|
bed86da8ae | ||
|
|
0c4b6cd071 | ||
|
|
f9df4294f3 | ||
|
|
0765613778 | ||
|
|
1fa6e7f3b1 | ||
|
|
2b1b8da58d | ||
|
|
756213c5f5 | ||
|
|
bc67859672 | ||
|
|
a99885cd43 | ||
|
|
44d472ddd3 | ||
|
|
7228b11e3f | ||
|
|
0bec99fbd4 | ||
|
|
3c5adebcd3 | ||
|
|
edc5e272db | ||
|
|
6403b2f468 | ||
|
|
cbe6dbe7a1 | ||
|
|
3ebd69db1b | ||
|
|
a3898fae0f | ||
|
|
75c856ed3f | ||
|
|
d081485e6a | ||
|
|
bb5688b1be | ||
|
|
6f83f0bd4e | ||
|
|
99b068b313 | ||
|
|
e229c8c3d7 | ||
|
|
6b499e2a8b | ||
|
|
a756a9feba | ||
|
|
d0ca0cb308 | ||
|
|
86f85525dd | ||
|
|
ad354c4c48 | ||
|
|
b5bb1657d2 | ||
|
|
1275458c3f | ||
|
|
ac971c1a19 | ||
|
|
7d91d4300b | ||
|
|
e972b942e6 | ||
|
|
4896364952 | ||
|
|
ca21b6be93 | ||
|
|
d4b3dde853 | ||
|
|
1aceeb7116 | ||
|
|
930b3bcf5c | ||
|
|
937c06a0c9 | ||
|
|
77cc15a77a | ||
|
|
d5d7286cb6 | ||
|
|
bf64dd21fd | ||
|
|
36b5d86eda | ||
|
|
1bf5ae9c8d | ||
|
|
5c2ead741c | ||
|
|
b31e5d7764 | ||
|
|
e5ef3e3019 | ||
|
|
d696550494 | ||
|
|
5fe0440916 | ||
|
|
d545ac4c51 | ||
|
|
23eb8691a8 | ||
|
|
f849e2c414 | ||
|
|
1f527c5013 | ||
|
|
65dfacac4b | ||
|
|
c0e7d05b5c | ||
|
|
67ab574e98 | ||
|
|
846e6d3bda | ||
|
|
9707cb4471 | ||
|
|
7c15b54ccc | ||
|
|
1af930441c | ||
|
|
9257d648bf | ||
|
|
f890ae696a | ||
|
|
82828524fe | ||
|
|
d120c328c9 | ||
|
|
449a29b817 | ||
|
|
ce18332b52 | ||
|
|
3b7a1d7149 | ||
|
|
17e822757b | ||
|
|
a388ff198d | ||
|
|
cc2457f7d5 | ||
|
|
c6375e414d | ||
|
|
e825d77736 | ||
|
|
ce026f4099 | ||
|
|
9a2dd8bc92 | ||
|
|
a073b1db9c | ||
|
|
cf0cb9558a | ||
|
|
0aecfe2dae | ||
|
|
764091dfbb | ||
|
|
ab1fa4db8c | ||
|
|
9123e63a33 | ||
|
|
ba7ca4f372 | ||
|
|
1e25e9f58f | ||
|
|
9b4660b458 | ||
|
|
16a5c6b2c8 | ||
|
|
fcea0cda21 | ||
|
|
6177eb8398 | ||
|
|
ac443fa61f | ||
|
|
08f2b5bc84 | ||
|
|
de56442660 | ||
|
|
3d98f675f3 | ||
|
|
67c9086b74 | ||
|
|
e47722ecb2 | ||
|
|
2b750ea49f | ||
|
|
58e42397f8 | ||
|
|
bd353e004a | ||
|
|
f347143b3d | ||
|
|
c1952523cd | ||
|
|
1afe0cb45f | ||
|
|
7075a8ed81 | ||
|
|
d83ca54b36 | ||
|
|
e0aead0be2 | ||
|
|
94b6dd65ee | ||
|
|
c147b41013 | ||
|
|
3a55339114 | ||
|
|
2dd7030579 | ||
|
|
e7a12f8e38 | ||
|
|
0525e8ed5c | ||
|
|
1d091bafe9 | ||
|
|
814ef37f75 | ||
|
|
94fed25975 | ||
|
|
56341de5eb | ||
|
|
3c589dac19 | ||
|
|
0eb278ad3b | ||
|
|
b494cc5219 | ||
|
|
618fce8d32 | ||
|
|
ce0c638005 | ||
|
|
15d3d12098 | ||
|
|
76b4a45f98 | ||
|
|
535fc6cd63 | ||
|
|
3308ac7d83 | ||
|
|
a1fd312bb1 | ||
|
|
b096651e10 | ||
|
|
44f939c841 | ||
|
|
d68cdce2d5 | ||
|
|
43fdc4a1ce | ||
|
|
cb2f2b94ee | ||
|
|
4722410e5e | ||
|
|
55b4bfa1fe | ||
|
|
4d7aa62a10 | ||
|
|
86506cd4f8 | ||
|
|
1532879c64 | ||
|
|
af1212897c | ||
|
|
34a806578a | ||
|
|
12d92fd5db | ||
|
|
bae0bc02a6 | ||
|
|
99974ddc8b | ||
|
|
f30a9752e2 | ||
|
|
c90985d309 | ||
|
|
bd222d6e3c | ||
|
|
0c01b0ded9 | ||
|
|
e5fb681615 | ||
|
|
c9698e4848 | ||
|
|
0e7694ca94 | ||
|
|
f4e6cf4439 | ||
|
|
e4921733df | ||
|
|
69a449a073 | ||
|
|
30328548f7 | ||
|
|
57f3592411 | ||
|
|
1c24031dd2 | ||
|
|
3d47ef9d74 | ||
|
|
6488894210 | ||
|
|
2f0d31b4b6 | ||
|
|
b2376058a1 | ||
|
|
e981ff4e7d | ||
|
|
b126ca0606 | ||
|
|
40b08f2494 | ||
|
|
8211fa6ce4 | ||
|
|
706dd1d6c5 | ||
|
|
6bc3b8dc6d | ||
|
|
faf23aa0d4 | ||
|
|
18b3821e06 | ||
|
|
1bd700ee52 | ||
|
|
38783e7fa1 | ||
|
|
dcbb35089f | ||
|
|
f33cc3fb3b | ||
|
|
1b3766d802 | ||
|
|
da8b043612 | ||
|
|
ed42f70248 | ||
|
|
0204d3c6a6 | ||
|
|
81f91aebc2 | ||
|
|
de6bba4609 | ||
|
|
c3a3cc76d8 | ||
|
|
74ff489e63 | ||
|
|
55b47bcb8e | ||
|
|
bcd8712ec3 | ||
|
|
b212aa0db3 | ||
|
|
8390e88e27 | ||
|
|
bc95700dcf | ||
|
|
12c6594c9b | ||
|
|
d800a51da4 | ||
|
|
73502fab0d | ||
|
|
2425711734 | ||
|
|
6be5bda8c9 | ||
|
|
2abcde03ad | ||
|
|
69ef1da58c | ||
|
|
8df32cd540 | ||
|
|
3aa06d0851 | ||
|
|
e611e97339 | ||
|
|
3000c8b349 | ||
|
|
6f88d04ac4 | ||
|
|
1c16ce8cf0 | ||
|
|
070728429b | ||
|
|
918f76f96a | ||
|
|
4202c4bf20 | ||
|
|
eab2baa363 | ||
|
|
dc436e72f9 | ||
|
|
b74a97a4f6 | ||
|
|
2ef695da97 | ||
|
|
db437e7a45 | ||
|
|
538a50c9e8 | ||
|
|
0fe53dc5cf | ||
|
|
8b80f8ee05 | ||
|
|
2cee364692 | ||
|
|
3e7c7f51fa | ||
|
|
2f9063c1d6 | ||
|
|
65496ace20 | ||
|
|
64c7a0ad0d | ||
|
|
5046d5b181 | ||
|
|
6f8c91b651 | ||
|
|
e0db20c0cf | ||
|
|
e1e2c1c740 | ||
|
|
655b6300f5 | ||
|
|
d7f6c0775a | ||
|
|
a3d863f83b | ||
|
|
deb4c428fd | ||
|
|
b8e94b1d30 | ||
|
|
a151216e5e | ||
|
|
e09950d3fb | ||
|
|
3206e101f5 | ||
|
|
c6a648fad7 | ||
|
|
904eeddf36 | ||
|
|
07597dfd45 | ||
|
|
4360c360a4 | ||
|
|
befd8b0cb2 | ||
|
|
3f90fcae48 | ||
|
|
8ec1839f5d | ||
|
|
fb9735ef46 | ||
|
|
138de19e1e | ||
|
|
d3ae920bd0 | ||
|
|
f37f56d4f1 | ||
|
|
a0e4253edc | ||
|
|
c3d5634efa | ||
|
|
c05b2c5c59 | ||
|
|
f763a9ef56 | ||
|
|
81e6df0d57 | ||
|
|
d83fc02597 | ||
|
|
95c8bb4252 | ||
|
|
c1729addce | ||
|
|
3e3b034252 | ||
|
|
9d0c7f6ec7 | ||
|
|
c5a803a146 | ||
|
|
5f55ed2a40 | ||
|
|
7afcf92539 | ||
|
|
57da2e4af5 | ||
|
|
f837252ff1 | ||
|
|
fd128c7180 | ||
|
|
ea4b60a602 | ||
|
|
b73a6905a1 | ||
|
|
655d829314 | ||
|
|
1173a85c85 | ||
|
|
40791d886d | ||
|
|
7221887330 | ||
|
|
3c5a2f55c2 | ||
|
|
0b098a2eee | ||
|
|
1765d3c866 | ||
|
|
1fedf5b332 | ||
|
|
f94836783c | ||
|
|
2aecb2a4a3 | ||
|
|
bf1bceec87 | ||
|
|
01a3ac50af | ||
|
|
3ff9355e7b | ||
|
|
94ac890859 | ||
|
|
3d3d8b5b7b | ||
|
|
1788a68b1c | ||
|
|
480f44f16c | ||
|
|
161e36fd56 | ||
|
|
9a089482dc | ||
|
|
fc31b463b1 | ||
|
|
539f8f91bd | ||
|
|
830e84adc4 | ||
|
|
40f2a128b8 | ||
|
|
e6e3853dc7 | ||
|
|
1786890e32 | ||
|
|
435d1e3da7 | ||
|
|
642a24dc9c | ||
|
|
eab4e1cfa1 | ||
|
|
a9d8039082 | ||
|
|
2113b6f4bb | ||
|
|
7d493774c7 | ||
|
|
de0fc87c1c | ||
|
|
f0871e4f5e | ||
|
|
1b37c8affd | ||
|
|
3e29f2bdc2 | ||
|
|
3f4af438c5 | ||
|
|
2cb13bf852 | ||
|
|
0098387fbf | ||
|
|
7e07919d9d | ||
|
|
71baad59df | ||
|
|
9365d33243 | ||
|
|
3c18d841fa | ||
|
|
7dcb567e53 | ||
|
|
7a424e6b12 | ||
|
|
302bbc5dbd | ||
|
|
97a51c130f | ||
|
|
00d53714f9 | ||
|
|
a07063f119 | ||
|
|
9393be7a49 | ||
|
|
1eb390680d | ||
|
|
9d331715c0 | ||
|
|
0665bc6e4b | ||
|
|
855255d73e | ||
|
|
35d4cca8bb | ||
|
|
b38748ad1a | ||
|
|
22979d9365 | ||
|
|
be3592adf6 | ||
|
|
a5f6069967 | ||
|
|
c481d2bcbb | ||
|
|
a1649f774e | ||
|
|
22155df759 | ||
|
|
7f31ec3398 | ||
|
|
153ac88672 | ||
|
|
121714c040 | ||
|
|
bd43cf2442 | ||
|
|
c7e578ac0d | ||
|
|
0fd8c98301 | ||
|
|
e36e79a474 | ||
|
|
0b919f4fd2 | ||
|
|
25839d0bb5 | ||
|
|
7f538266ea | ||
|
|
364932238a | ||
|
|
34024291af | ||
|
|
a58e8d47c6 | ||
|
|
28ec26462a | ||
|
|
caeda30b72 | ||
|
|
41918d619c | ||
|
|
bfa690b6f7 | ||
|
|
035ca7ef61 | ||
|
|
206d00ed8c | ||
|
|
9fb84d66be | ||
|
|
525378a145 | ||
|
|
398428d711 | ||
|
|
f508f3f20b | ||
|
|
987dac9ee0 | ||
|
|
9bb32f41f1 | ||
|
|
bf7ba17932 | ||
|
|
7bec333017 | ||
|
|
1bfd67dfc6 | ||
|
|
943ad0e93f | ||
|
|
72c44efd84 | ||
|
|
642901d5aa | ||
|
|
d9205a85d5 | ||
|
|
3a7ee13ece | ||
|
|
4802145e8f | ||
|
|
7df79d9339 | ||
|
|
678599c7d4 | ||
|
|
92736f22e8 | ||
|
|
3998bdbfc1 | ||
|
|
1110c5d37d | ||
|
|
a1c20ce866 | ||
|
|
4776a7bcbe | ||
|
|
c4764ff916 | ||
|
|
bd429f3d4f | ||
|
|
479510be0e | ||
|
|
c90bde3187 | ||
|
|
cdfbf05e8c | ||
|
|
64f773c886 | ||
|
|
444077505b | ||
|
|
deb295f738 | ||
|
|
34f607fe49 | ||
|
|
3ac9ff0dcc | ||
|
|
628528da5a | ||
|
|
45ff05d47d | ||
|
|
0dde260c05 | ||
|
|
3aebc17bff | ||
|
|
dcf368632c | ||
|
|
5ab3336c91 | ||
|
|
6fef314423 | ||
|
|
6643e4969f | ||
|
|
f7086d0a4d | ||
|
|
8987d29bee | ||
|
|
8fd216b4f6 | ||
|
|
cb6c3fb0b6 | ||
|
|
eac43dc62b | ||
|
|
dea910cd3e | ||
|
|
39ee59c26e | ||
|
|
ded154fd28 | ||
|
|
ce97902897 | ||
|
|
05136ff09d | ||
|
|
7bf34d1fae | ||
|
|
54357bcf8f | ||
|
|
f44336d57d | ||
|
|
a1a90fd41f | ||
|
|
adab114674 | ||
|
|
33d9877599 | ||
|
|
47acada2cb | ||
|
|
dd788c5631 | ||
|
|
e4c795f15c | ||
|
|
a43d53ac6e | ||
|
|
cadb9e8bfe | ||
|
|
f3f257a626 | ||
|
|
e8271c8a4b | ||
|
|
4e5cdd6abb | ||
|
|
8ca615c301 | ||
|
|
bc0b52293e | ||
|
|
7e3e9ee9d2 | ||
|
|
65ebc344ac | ||
|
|
5fb171edff | ||
|
|
574d735a81 | ||
|
|
b25cfb0e0b | ||
|
|
929cf433b9 | ||
|
|
711d2541f5 | ||
|
|
ca674304c5 | ||
|
|
a8ac819139 | ||
|
|
a44e0e0f4b | ||
|
|
0c70a4636a | ||
|
|
7ea86f6506 | ||
|
|
7376a72dd7 | ||
|
|
981c6868ad | ||
|
|
aaea0c5d2e | ||
|
|
bfd9940248 | ||
|
|
dd30b78fd6 | ||
|
|
cac3cefd98 | ||
|
|
6365c5efb5 | ||
|
|
c126ccd744 | ||
|
|
16987fe143 | ||
|
|
2a1e7a427d | ||
|
|
7383ead106 | ||
|
|
2700510039 | ||
|
|
55ef4b225f | ||
|
|
9a25ad7f24 | ||
|
|
1f4a086fb6 | ||
|
|
ffd703622e | ||
|
|
5bd7692323 | ||
|
|
6684a18730 | ||
|
|
0dc6ebc325 | ||
|
|
ffbd6d8782 | ||
|
|
b2e612fb79 | ||
|
|
d9c91f9c47 | ||
|
|
ad17090a0f | ||
|
|
7d997ca8e6 | ||
|
|
1d9e89812a | ||
|
|
4c114680a4 | ||
|
|
1f6ecdfdb9 | ||
|
|
0832a41a38 | ||
|
|
9b2dd6a137 | ||
|
|
e8538d606a | ||
|
|
99c19bae21 | ||
|
|
850d769273 | ||
|
|
39344a601d | ||
|
|
5296507665 | ||
|
|
0d308c7c0e | ||
|
|
8e5e5c689f | ||
|
|
09fe44a6b3 | ||
|
|
46d2a13288 | ||
|
|
501c4e4bac | ||
|
|
523a170c3e | ||
|
|
08d12a5c84 | ||
|
|
922f720cf6 | ||
|
|
16208dc172 | ||
|
|
eaf222a756 | ||
|
|
ae295bd9b6 | ||
|
|
ae07c0171d | ||
|
|
27eede190a | ||
|
|
d23f38b4f3 | ||
|
|
a34f9e082e | ||
|
|
cb80a7aa42 | ||
|
|
79c9a9f03a | ||
|
|
5e42c96267 | ||
|
|
898f44ddda | ||
|
|
196af01707 | ||
|
|
f5be3cd8f9 | ||
|
|
2215ad74ff | ||
|
|
df25a22469 | ||
|
|
0df4a723e9 | ||
|
|
39d72d5811 | ||
|
|
f17c4c1d57 | ||
|
|
78c9d526c3 | ||
|
|
4baf007fb8 | ||
|
|
daa76dcff0 | ||
|
|
d5ab243cfd | ||
|
|
a8ee0377d5 | ||
|
|
c3980cb165 | ||
|
|
8183e3201b | ||
|
|
de6f76758d | ||
|
|
9b4b533f2f | ||
|
|
69c7ae5e3f | ||
|
|
114d90bec8 | ||
|
|
3f6f149584 | ||
|
|
8598283735 | ||
|
|
81ba1e6177 | ||
|
|
10619248c6 | ||
|
|
389e4b8b69 | ||
|
|
18d0da4ea3 | ||
|
|
3adb579cf1 | ||
|
|
2c1504f93c | ||
|
|
03115cbf93 | ||
|
|
1bc871162d | ||
|
|
f28f791fff | ||
|
|
fd85d0ef35 | ||
|
|
16437867ff | ||
|
|
08df13b16e | ||
|
|
06a7bb531b | ||
|
|
94f3d201e1 | ||
|
|
7f6aad20fb | ||
|
|
11e0f7ed8e | ||
|
|
085b3bc1f2 | ||
|
|
05af306a8d | ||
|
|
4430073fab | ||
|
|
3891e4d66d | ||
|
|
69d906f7dd | ||
|
|
c9ec9cf00e | ||
|
|
2c1324656b | ||
|
|
94a1978ce4 | ||
|
|
e2920d9702 | ||
|
|
b987d38505 | ||
|
|
5266b56f43 | ||
|
|
ade64693bd | ||
|
|
254baa19f3 | ||
|
|
1410693eae | ||
|
|
254693bf86 | ||
|
|
74130008f7 | ||
|
|
6607232a5d | ||
|
|
cc18b5f38e | ||
|
|
d31d3c58ad | ||
|
|
d17d4fa106 | ||
|
|
a6d37a49a2 | ||
|
|
1da8729e09 | ||
|
|
6a209ba3a8 | ||
|
|
a7523015f7 | ||
|
|
7613557528 | ||
|
|
3092d4bbe9 | ||
|
|
df2933d40d | ||
|
|
1370f89864 | ||
|
|
8b7969d6ea | ||
|
|
a4f57e164b | ||
|
|
50ac66f79b | ||
|
|
cbf7ad61f3 | ||
|
|
16cd15b048 | ||
|
|
baa18fb0f7 | ||
|
|
f9da9fbfed | ||
|
|
6c9428a3c9 | ||
|
|
f1b48ff009 | ||
|
|
a73a65a45b | ||
|
|
3f49b509d2 | ||
|
|
45f57198cc | ||
|
|
fe660580a4 | ||
|
|
c0024cc7b2 | ||
|
|
24af8e3da2 | ||
|
|
0f1cf243fd | ||
|
|
8a3bba48e3 | ||
|
|
236c7afe9e | ||
|
|
26d64208d1 | ||
|
|
254331485a | ||
|
|
d6aa43fcda | ||
|
|
fbc5ac8052 | ||
|
|
77a66f079f | ||
|
|
3cce757adc | ||
|
|
b9eec7e438 | ||
|
|
9bc75eaf24 | ||
|
|
4b40a58c0e | ||
|
|
273a65724d | ||
|
|
8be32257e7 | ||
|
|
26f0e2bc2d | ||
|
|
0380e404bd | ||
|
|
3b06368569 | ||
|
|
6bcf53195f | ||
|
|
bc2a721a0a | ||
|
|
56076d4d0e | ||
|
|
9fc0726504 | ||
|
|
298928dc44 | ||
|
|
c0c2a4b968 | ||
|
|
2b13386d7b | ||
|
|
6aaa5fb0bf | ||
|
|
892174997b | ||
|
|
f100404362 | ||
|
|
3f1b567129 | ||
|
|
14735d5eb5 | ||
|
|
91c734d02e | ||
|
|
8e776a252b | ||
|
|
3fdb4c03ab | ||
|
|
aff561d8c3 | ||
|
|
799efb0629 | ||
|
|
ee449a94c8 | ||
|
|
fb59255095 | ||
|
|
0be13d1d27 | ||
|
|
96547d0ca8 | ||
|
|
790cde028b | ||
|
|
c9dbd81178 | ||
|
|
0bcae125c2 | ||
|
|
3d59e13dd8 | ||
|
|
c52524a215 | ||
|
|
4c12de6203 | ||
|
|
7cf85c5e71 | ||
|
|
37bb8868de | ||
|
|
5d06bb964b | ||
|
|
3e3c0083c7 | ||
|
|
792759c414 | ||
|
|
cf3dc5a6ff | ||
|
|
9d71a0409c | ||
|
|
f0c80837a6 | ||
|
|
1d34bb173e | ||
|
|
1f2c1d0760 | ||
|
|
3abc18d7ba | ||
|
|
ccbcb9f418 | ||
|
|
74cdadec9f | ||
|
|
6132017f82 | ||
|
|
9357e8ecf8 | ||
|
|
9247b0fbd2 | ||
|
|
0e7b069cd8 | ||
|
|
dcc1caaf68 | ||
|
|
708ee232bc | ||
|
|
5a8a9bfd69 | ||
|
|
94194fea46 | ||
|
|
0c9b9fe8bb | ||
|
|
ceb6e1e95f | ||
|
|
d58b3d54b1 | ||
|
|
a204f59ecb | ||
|
|
d87667a0c2 | ||
|
|
6f5baa8414 | ||
|
|
b9519391c2 | ||
|
|
5cbb5d2541 | ||
|
|
08d7980d80 | ||
|
|
44d8e62689 | ||
|
|
5bf7796004 | ||
|
|
e57f3596a1 | ||
|
|
f288e58c81 | ||
|
|
0316dfc6f2 | ||
|
|
28ec3d48fa | ||
|
|
c3a8f202ab | ||
|
|
c95b89e98c | ||
|
|
b9e143d956 | ||
|
|
261647a012 | ||
|
|
4483971776 | ||
|
|
9dea9539b4 | ||
|
|
855cb0f906 | ||
|
|
07a96a703e | ||
|
|
e30d1bbd04 | ||
|
|
334cab82c2 | ||
|
|
736bc1f02f | ||
|
|
c3f880e758 | ||
|
|
34f6f50a07 | ||
|
|
d9b55101e5 | ||
|
|
ab1e8a35c6 | ||
|
|
f534410e57 | ||
|
|
d3d7ff4818 | ||
|
|
8b308c1c08 | ||
|
|
dfdd3cf18f | ||
|
|
ea378c5565 | ||
|
|
15b751107e | ||
|
|
d0b8650edf | ||
|
|
ac4c43c3e6 | ||
|
|
4b6e992a47 | ||
|
|
a62c7bfef1 | ||
|
|
53f74d052f | ||
|
|
3da76496b0 | ||
|
|
12c7f00c44 | ||
|
|
2c595284d8 | ||
|
|
67e74756f4 | ||
|
|
a7d0998bc0 | ||
|
|
4347b91b89 | ||
|
|
432a37857d | ||
|
|
f37f578b1d | ||
|
|
35abb4df92 | ||
|
|
e5b9a5e849 | ||
|
|
e67f385574 | ||
|
|
c37e25e76b | ||
|
|
543ca16b6f | ||
|
|
b52cd4969b | ||
|
|
465cb6d327 | ||
|
|
09351996a4 | ||
|
|
1df2d7b8eb | ||
|
|
ef43af19ab | ||
|
|
a8dc417cd9 | ||
|
|
df9ef1e733 | ||
|
|
209bcf905e | ||
|
|
d69b5c5ab6 | ||
|
|
1c628a97ad | ||
|
|
37b6255e42 | ||
|
|
e12f9d10e7 | ||
|
|
abc3a2cc3c | ||
|
|
5abf2e3c43 | ||
|
|
b9f741e635 | ||
|
|
c4ed55d801 | ||
|
|
7c12c5aee3 | ||
|
|
df733fbaa5 | ||
|
|
d51741df72 | ||
|
|
cc6e845364 | ||
|
|
f70b548fb6 | ||
|
|
26905b1260 | ||
|
|
313e25adf1 | ||
|
|
14356a7739 | ||
|
|
82c65e423b | ||
|
|
5102f7a9cb | ||
|
|
10de637496 | ||
|
|
6d66223bf6 | ||
|
|
fb62e1eb75 | ||
|
|
cb3a1fd095 | ||
|
|
fd9f816050 | ||
|
|
5631b1a728 | ||
|
|
0a28cabd57 | ||
|
|
13e25ef164 | ||
|
|
fa956596dc | ||
|
|
fbf4a4323b | ||
|
|
28c5e9b4ec | ||
|
|
252a7ed7d6 | ||
|
|
898d1dc138 | ||
|
|
b59ed8c9d2 | ||
|
|
8db93b874c | ||
|
|
2f60b5b674 | ||
|
|
ceed000c58 | ||
|
|
cccb722ba8 | ||
|
|
12566f51af | ||
|
|
beff6216fe | ||
|
|
bb662b8861 | ||
|
|
a26e0b4d48 | ||
|
|
4e6ea7f9f7 | ||
|
|
2feb3ea651 | ||
|
|
b54522c60f | ||
|
|
e4f0e2b399 | ||
|
|
632e77c1cf | ||
|
|
aab024f18d | ||
|
|
2b8157ce2a | ||
|
|
a61a8176f1 | ||
|
|
555ecb095d | ||
|
|
78768082a1 | ||
|
|
726f5475b0 | ||
|
|
47eee5ddd5 | ||
|
|
6e27837cbf | ||
|
|
b468baf7ac | ||
|
|
891ad9c1f0 | ||
|
|
1c17ea3b14 | ||
|
|
21d45023d3 | ||
|
|
5e015bc669 | ||
|
|
3a5741f70f | ||
|
|
625f23af13 | ||
|
|
65ecf4b3a2 | ||
|
|
c6e5948534 | ||
|
|
586498331b | ||
|
|
b9cbb0dac5 | ||
|
|
ab24ae1da8 | ||
|
|
56b195a899 |
201
.circleci/config.yml
Normal file
201
.circleci/config.yml
Normal file
@@ -0,0 +1,201 @@
|
||||
version: 2
|
||||
|
||||
defaults: &defaults
|
||||
working_directory: /go/src/github.com/tendermint/tendermint
|
||||
docker:
|
||||
- image: circleci/golang:1.10.0
|
||||
environment:
|
||||
GOBIN: /tmp/workspace/bin
|
||||
|
||||
jobs:
|
||||
setup_dependencies:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- run: mkdir -p /tmp/workspace/bin
|
||||
- run: mkdir -p /tmp/workspace/profiles
|
||||
- checkout
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v1-pkg-cache
|
||||
- run:
|
||||
name: tools
|
||||
command: |
|
||||
export PATH="$GOBIN:$PATH"
|
||||
make get_tools
|
||||
- run:
|
||||
name: dependencies
|
||||
command: |
|
||||
export PATH="$GOBIN:$PATH"
|
||||
make get_vendor_deps
|
||||
- run:
|
||||
name: binaries
|
||||
command: |
|
||||
export PATH="$GOBIN:$PATH"
|
||||
make install
|
||||
- persist_to_workspace:
|
||||
root: /tmp/workspace
|
||||
paths:
|
||||
- bin
|
||||
- profiles
|
||||
- save_cache:
|
||||
key: v1-pkg-cache
|
||||
paths:
|
||||
- /go/pkg
|
||||
- save_cache:
|
||||
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
|
||||
paths:
|
||||
- /go/src/github.com/tendermint/tendermint
|
||||
|
||||
setup_abci:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- restore_cache:
|
||||
key: v1-pkg-cache
|
||||
- restore_cache:
|
||||
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
name: Checkout abci
|
||||
command: |
|
||||
commit=$(bash scripts/dep_utils/parse.sh abci)
|
||||
go get -v -u -d github.com/tendermint/abci/...
|
||||
cd /go/src/github.com/tendermint/abci
|
||||
git checkout "$commit"
|
||||
- run:
|
||||
working_directory: /go/src/github.com/tendermint/abci
|
||||
name: Install abci
|
||||
command: |
|
||||
set -ex
|
||||
export PATH="$GOBIN:$PATH"
|
||||
make get_tools
|
||||
make get_vendor_deps
|
||||
make install
|
||||
- run: ls -lah /tmp/workspace/bin
|
||||
- persist_to_workspace:
|
||||
root: /tmp/workspace
|
||||
paths:
|
||||
- "bin/abci*"
|
||||
|
||||
lint:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- restore_cache:
|
||||
key: v1-pkg-cache
|
||||
- restore_cache:
|
||||
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
name: metalinter
|
||||
command: |
|
||||
set -ex
|
||||
export PATH="$GOBIN:$PATH"
|
||||
make metalinter
|
||||
|
||||
test_apps:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- restore_cache:
|
||||
key: v1-pkg-cache
|
||||
- restore_cache:
|
||||
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: sudo apt-get update && sudo apt-get install -y --no-install-recommends bsdmainutils
|
||||
- run:
|
||||
name: Run tests
|
||||
command: bash test/app/test.sh
|
||||
|
||||
test_cover:
|
||||
<<: *defaults
|
||||
parallelism: 4
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- restore_cache:
|
||||
key: v1-pkg-cache
|
||||
- restore_cache:
|
||||
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
name: Run tests
|
||||
command: |
|
||||
for pkg in $(go list github.com/tendermint/tendermint/... | grep -v /vendor/ | circleci tests split --split-by=timings); do
|
||||
id=$(basename "$pkg")
|
||||
|
||||
go test -timeout 5m -race -coverprofile=/tmp/workspace/profiles/$id.out -covermode=atomic "$pkg"
|
||||
done
|
||||
- persist_to_workspace:
|
||||
root: /tmp/workspace
|
||||
paths:
|
||||
- "profiles/*"
|
||||
|
||||
test_persistence:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- restore_cache:
|
||||
key: v1-pkg-cache
|
||||
- restore_cache:
|
||||
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
name: Run tests
|
||||
command: bash test/persist/test_failure_indices.sh
|
||||
|
||||
test_p2p:
|
||||
environment:
|
||||
GOBIN: /home/circleci/.go_workspace/bin
|
||||
GOPATH: /home/circleci/.go_workspace
|
||||
machine:
|
||||
image: circleci/classic:latest
|
||||
steps:
|
||||
- checkout
|
||||
- run: mkdir -p $GOPATH/src/github.com/tendermint
|
||||
- run: ln -sf /home/circleci/project $GOPATH/src/github.com/tendermint/tendermint
|
||||
- run: bash test/circleci/p2p.sh
|
||||
|
||||
upload_coverage:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- restore_cache:
|
||||
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run:
|
||||
name: gather
|
||||
command: |
|
||||
set -ex
|
||||
|
||||
echo "mode: atomic" > coverage.txt
|
||||
for prof in $(ls /tmp/workspace/profiles/); do
|
||||
tail -n +2 /tmp/workspace/profiles/"$prof" >> coverage.txt
|
||||
done
|
||||
- run:
|
||||
name: upload
|
||||
command: bash <(curl -s https://codecov.io/bash) -f coverage.txt
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
test-suite:
|
||||
jobs:
|
||||
- setup_dependencies
|
||||
- setup_abci:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
- lint:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
- test_apps:
|
||||
requires:
|
||||
- setup_abci
|
||||
- test_cover:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
- test_persistence:
|
||||
requires:
|
||||
- setup_abci
|
||||
- test_p2p
|
||||
- upload_coverage:
|
||||
requires:
|
||||
- test_cover
|
||||
16
.editorconfig
Normal file
16
.editorconfig
Normal file
@@ -0,0 +1,16 @@
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.{sh,Makefile}]
|
||||
indent_style = tab
|
||||
|
||||
[*.proto]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
4
.github/CODEOWNERS
vendored
Normal file
4
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# CODEOWNERS: https://help.github.com/articles/about-codeowners/
|
||||
|
||||
# Everything goes through Bucky and Anton. For now.
|
||||
* @ebuchman @melekes
|
||||
44
.github/ISSUE_TEMPLATE
vendored
Normal file
44
.github/ISSUE_TEMPLATE
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
<!-- Thanks for filing an issue! Before hitting the button, please answer these questions.-->
|
||||
|
||||
**Is this a BUG REPORT or FEATURE REQUEST?** (choose one):
|
||||
|
||||
<!--
|
||||
If this is a BUG REPORT, please:
|
||||
- Fill in as much of the template below as you can.
|
||||
|
||||
If this is a FEATURE REQUEST, please:
|
||||
- Describe *in detail* the feature/behavior/change you'd like to see.
|
||||
|
||||
In both cases, be ready for followup questions, and please respond in a timely
|
||||
manner. We might ask you to provide additional logs and data (tendermint & app)
|
||||
in a case of bug.
|
||||
-->
|
||||
|
||||
**Tendermint version** (use `tendermint version` or `git rev-parse --verify HEAD` if installed from source):
|
||||
|
||||
|
||||
**ABCI app** (name for built-in, URL for self-written if it's publicly available):
|
||||
|
||||
|
||||
**Merkleeyes version** (use `git rev-parse --verify HEAD`, skip if you don't use it):
|
||||
|
||||
|
||||
**Environment**:
|
||||
- **OS** (e.g. from /etc/os-release):
|
||||
- **Install tools**:
|
||||
- **Others**:
|
||||
|
||||
|
||||
**What happened**:
|
||||
|
||||
|
||||
**What you expected to happen**:
|
||||
|
||||
|
||||
**How to reproduce it** (as minimally and precisely as possible):
|
||||
|
||||
**Logs (you can paste a part showing an error or attach the whole file)**:
|
||||
|
||||
**`/dump_consensus_state` output for consensus bugs**
|
||||
|
||||
**Anything else do we need to know**:
|
||||
6
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
6
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
<!-- Thanks for filing a PR! Before hitting the button, please check the following items.-->
|
||||
|
||||
* [ ] Updated all relevant documentation in docs
|
||||
* [ ] Updated all code comments where relevant
|
||||
* [ ] Wrote tests
|
||||
* [ ] Updated CHANGELOG.md
|
||||
16
.gitignore
vendored
16
.gitignore
vendored
@@ -9,3 +9,19 @@ rpc/test/.tendermint
|
||||
.tendermint
|
||||
remote_dump
|
||||
.revision
|
||||
vendor
|
||||
.vagrant
|
||||
test/p2p/data/
|
||||
test/logs
|
||||
.glide
|
||||
coverage.txt
|
||||
docs/_build
|
||||
docs/tools
|
||||
docs/abci-spec.rst
|
||||
*.log
|
||||
|
||||
scripts/wal2json/wal2json
|
||||
scripts/cutWALUntil/cutWALUntil
|
||||
|
||||
.idea/
|
||||
*.iml
|
||||
|
||||
664
CHANGELOG.md
Normal file
664
CHANGELOG.md
Normal file
@@ -0,0 +1,664 @@
|
||||
# Changelog
|
||||
|
||||
## Roadmap
|
||||
|
||||
BREAKING CHANGES:
|
||||
- Better support for injecting randomness
|
||||
- Upgrade consensus for more real-time use of evidence
|
||||
|
||||
FEATURES:
|
||||
- Use the chain as its own CA for nodes and validators
|
||||
- Tooling to run multiple blockchains/apps, possibly in a single process
|
||||
- State syncing (without transaction replay)
|
||||
- Add authentication and rate-limitting to the RPC
|
||||
|
||||
IMPROVEMENTS:
|
||||
- Improve subtleties around mempool caching and logic
|
||||
- Consensus optimizations:
|
||||
- cache block parts for faster agreement after round changes
|
||||
- propagate block parts rarest first
|
||||
- Better testing of the consensus state machine (ie. use a DSL)
|
||||
- Auto compiled serialization/deserialization code instead of go-wire reflection
|
||||
|
||||
BUG FIXES:
|
||||
- Graceful handling/recovery for apps that have non-determinism or fail to halt
|
||||
- Graceful handling/recovery for violations of safety, or liveness
|
||||
|
||||
## 0.18.0 (April 6th, 2018)
|
||||
|
||||
BREAKING:
|
||||
|
||||
- [types] Merkle tree uses different encoding for varints (see tmlibs v0.8.0)
|
||||
- [types] ValidtorSet.GetByAddress returns -1 if no validator found
|
||||
- [p2p] require all addresses come with an ID no matter what
|
||||
- [rpc] Listening address must contain tcp:// or unix:// prefix
|
||||
|
||||
FEATURES:
|
||||
|
||||
- [rpc] StartHTTPAndTLSServer (not used yet)
|
||||
- [rpc] Include validator's voting power in `/status`
|
||||
- [rpc] `/tx` and `/tx_search` responses now include the transaction hash
|
||||
- [rpc] Include peer NodeIDs in `/net_info`
|
||||
|
||||
IMPROVEMENTS:
|
||||
- [config] trim whitespace from elements of lists (like `persistent_peers`)
|
||||
- [rpc] `/tx_search` results are sorted by height
|
||||
- [p2p] do not try to connect to ourselves (ok, maybe only once)
|
||||
- [p2p] seeds respond with a bias towards good peers
|
||||
|
||||
BUG FIXES:
|
||||
- [rpc] fix subscribing using an abci.ResponseDeliverTx tag
|
||||
- [rpc] fix tx_indexers matchRange
|
||||
- [rpc] fix unsubscribing (see tmlibs v0.8.0)
|
||||
|
||||
## 0.17.1 (March 27th, 2018)
|
||||
|
||||
BUG FIXES:
|
||||
- [types] Actually support `app_state` in genesis as `AppStateJSON`
|
||||
|
||||
## 0.17.0 (March 27th, 2018)
|
||||
|
||||
BREAKING:
|
||||
- [types] WriteSignBytes -> SignBytes
|
||||
|
||||
IMPROVEMENTS:
|
||||
- [all] renamed `dummy` (`persistent_dummy`) to `kvstore` (`persistent_kvstore`) (name "dummy" is deprecated and will not work in the next breaking release)
|
||||
- [docs] note on determinism (docs/determinism.rst)
|
||||
- [genesis] `app_options` field is deprecated. please rename it to `app_state` in your genesis file(s). `app_options` will not work in the next breaking release
|
||||
- [p2p] dial seeds directly without potential peers
|
||||
- [p2p] exponential backoff for addrs in the address book
|
||||
- [p2p] mark peer as good if it contributed enough votes or block parts
|
||||
- [p2p] stop peer if it sends incorrect data, msg to unknown channel, msg we did not expect
|
||||
- [p2p] when `auth_enc` is true, all dialed peers must have a node ID in their address
|
||||
- [spec] various improvements
|
||||
- switched from glide to dep internally for package management
|
||||
- [wire] prep work for upgrading to new go-wire (which is now called go-amino)
|
||||
|
||||
FEATURES:
|
||||
- [config] exposed `auth_enc` flag to enable/disable encryption
|
||||
- [config] added the `--p2p.private_peer_ids` flag and `PrivatePeerIDs` config variable (see config for description)
|
||||
- [rpc] added `/health` endpoint, which returns empty result for now
|
||||
- [types/priv_validator] new format and socket client, allowing for remote signing
|
||||
|
||||
BUG FIXES:
|
||||
- [consensus] fix liveness bug by introducing ValidBlock mechanism
|
||||
|
||||
## 0.16.0 (February 20th, 2018)
|
||||
|
||||
BREAKING CHANGES:
|
||||
- [config] use $TMHOME/config for all config and json files
|
||||
- [p2p] old `--p2p.seeds` is now `--p2p.persistent_peers` (persistent peers to which TM will always connect to)
|
||||
- [p2p] now `--p2p.seeds` only used for getting addresses (if addrbook is empty; not persistent)
|
||||
- [p2p] NodeInfo: remove RemoteAddr and add Channels
|
||||
- we must have at least one overlapping channel with peer
|
||||
- we only send msgs for channels the peer advertised
|
||||
- [p2p/conn] pong timeout
|
||||
- [lite] comment out IAVL related code
|
||||
|
||||
FEATURES:
|
||||
- [p2p] added new `/dial_peers&persistent=_` **unsafe** endpoint
|
||||
- [p2p] persistent node key in `$THMHOME/config/node_key.json`
|
||||
- [p2p] introduce peer ID and authenticate peers by ID using addresses like `ID@IP:PORT`
|
||||
- [p2p/pex] new seed mode crawls the network and serves as a seed.
|
||||
- [config] MempoolConfig.CacheSize
|
||||
- [config] P2P.SeedMode (`--p2p.seed_mode`)
|
||||
|
||||
IMPROVEMENT:
|
||||
- [p2p/pex] stricter rules in the PEX reactor for better handling of abuse
|
||||
- [p2p] various improvements to code structure including subpackages for `pex` and `conn`
|
||||
- [docs] new spec!
|
||||
- [all] speed up the tests!
|
||||
|
||||
BUG FIX:
|
||||
- [blockchain] StopPeerForError on timeout
|
||||
- [consensus] StopPeerForError on a bad Maj23 message
|
||||
- [state] flush mempool conn before calling commit
|
||||
- [types] fix priv val signing things that only differ by timestamp
|
||||
- [mempool] fix memory leak causing zombie peers
|
||||
- [p2p/conn] fix potential deadlock
|
||||
|
||||
## 0.15.0 (December 29, 2017)
|
||||
|
||||
BREAKING CHANGES:
|
||||
- [p2p] enable the Peer Exchange reactor by default
|
||||
- [types] add Timestamp field to Proposal/Vote
|
||||
- [types] add new fields to Header: TotalTxs, ConsensusParamsHash, LastResultsHash, EvidenceHash
|
||||
- [types] add Evidence to Block
|
||||
- [types] simplify ValidateBasic
|
||||
- [state] updates to support changes to the header
|
||||
- [state] Enforce <1/3 of validator set can change at a time
|
||||
|
||||
FEATURES:
|
||||
- [state] Send indices of absent validators and addresses of byzantine validators in BeginBlock
|
||||
- [state] Historical ConsensusParams and ABCIResponses
|
||||
- [docs] Specification for the base Tendermint data structures.
|
||||
- [evidence] New evidence reactor for gossiping and managing evidence
|
||||
- [rpc] `/block_results?height=X` returns the DeliverTx results for a given height.
|
||||
|
||||
IMPROVEMENTS:
|
||||
- [consensus] Better handling of corrupt WAL file
|
||||
|
||||
BUG FIXES:
|
||||
- [lite] fix race
|
||||
- [state] validate block.Header.ValidatorsHash
|
||||
- [p2p] allow seed addresses to be prefixed with eg. `tcp://`
|
||||
- [p2p] use consistent key to refer to peers so we dont try to connect to existing peers
|
||||
- [cmd] fix `tendermint init` to ignore files that are there and generate files that aren't.
|
||||
|
||||
## 0.14.0 (December 11, 2017)
|
||||
|
||||
BREAKING CHANGES:
|
||||
- consensus/wal: removed separator
|
||||
- rpc/client: changed Subscribe/Unsubscribe/UnsubscribeAll funcs signatures to be identical to event bus.
|
||||
|
||||
FEATURES:
|
||||
- new `tendermint lite` command (and `lite/proxy` pkg) for running a light-client RPC proxy.
|
||||
NOTE it is currently insecure and its APIs are not yet covered by semver
|
||||
|
||||
IMPROVEMENTS:
|
||||
- rpc/client: can act as event bus subscriber (See https://github.com/tendermint/tendermint/issues/945).
|
||||
- p2p: use exponential backoff from seconds to hours when attempting to reconnect to persistent peer
|
||||
- config: moniker defaults to the machine's hostname instead of "anonymous"
|
||||
|
||||
BUG FIXES:
|
||||
- p2p: no longer exit if one of the seed addresses is incorrect
|
||||
|
||||
## 0.13.0 (December 6, 2017)
|
||||
|
||||
BREAKING CHANGES:
|
||||
- abci: update to v0.8 using gogo/protobuf; includes tx tags, vote info in RequestBeginBlock, data.Bytes everywhere, use int64, etc.
|
||||
- types: block heights are now `int64` everywhere
|
||||
- types & node: EventSwitch and EventCache have been replaced by EventBus and EventBuffer; event types have been overhauled
|
||||
- node: EventSwitch methods now refer to EventBus
|
||||
- rpc/lib/types: RPCResponse is no longer a pointer; WSRPCConnection interface has been modified
|
||||
- rpc/client: WaitForOneEvent takes an EventsClient instead of types.EventSwitch
|
||||
- rpc/client: Add/RemoveListenerForEvent are now Subscribe/Unsubscribe
|
||||
- rpc/core/types: ResultABCIQuery wraps an abci.ResponseQuery
|
||||
- rpc: `/subscribe` and `/unsubscribe` take `query` arg instead of `event`
|
||||
- rpc: `/status` returns the LatestBlockTime in human readable form instead of in nanoseconds
|
||||
- mempool: cached transactions return an error instead of an ABCI response with BadNonce
|
||||
|
||||
FEATURES:
|
||||
- rpc: new `/unsubscribe_all` WebSocket RPC endpoint
|
||||
- rpc: new `/tx_search` endpoint for filtering transactions by more complex queries
|
||||
- p2p/trust: new trust metric for tracking peers. See ADR-006
|
||||
- config: TxIndexConfig allows to set what DeliverTx tags to index
|
||||
|
||||
IMPROVEMENTS:
|
||||
- New asynchronous events system using `tmlibs/pubsub`
|
||||
- logging: Various small improvements
|
||||
- consensus: Graceful shutdown when app crashes
|
||||
- tests: Fix various non-deterministic errors
|
||||
- p2p: more defensive programming
|
||||
|
||||
BUG FIXES:
|
||||
- consensus: fix panic where prs.ProposalBlockParts is not initialized
|
||||
- p2p: fix panic on bad channel
|
||||
|
||||
## 0.12.1 (November 27, 2017)
|
||||
|
||||
BUG FIXES:
|
||||
- upgrade tmlibs dependency to enable Windows builds for Tendermint
|
||||
|
||||
## 0.12.0 (October 27, 2017)
|
||||
|
||||
BREAKING CHANGES:
|
||||
- rpc/client: websocket ResultsCh and ErrorsCh unified in ResponsesCh.
|
||||
- rpc/client: ABCIQuery no longer takes `prove`
|
||||
- state: remove GenesisDoc from state.
|
||||
- consensus: new binary WAL format provides efficiency and uses checksums to detect corruption
|
||||
- use scripts/wal2json to convert to json for debugging
|
||||
|
||||
FEATURES:
|
||||
- new `certifiers` pkg contains the tendermint light-client library (name subject to change)!
|
||||
- rpc: `/genesis` includes the `app_options` .
|
||||
- rpc: `/abci_query` takes an additional `height` parameter to support historical queries.
|
||||
- rpc/client: new ABCIQueryWithOptions supports options like `trusted` (set false to get a proof) and `height` to query a historical height.
|
||||
|
||||
IMPROVEMENTS:
|
||||
- rpc: `/genesis` result includes `app_options`
|
||||
- rpc/lib/client: add jitter to reconnects.
|
||||
- rpc/lib/types: `RPCError` satisfies the `error` interface.
|
||||
|
||||
BUG FIXES:
|
||||
- rpc/client: fix ws deadlock after stopping
|
||||
- blockchain: fix panic on AddBlock when peer is nil
|
||||
- mempool: fix sending on TxsAvailable when a tx has been invalidated
|
||||
- consensus: dont run WAL catchup if we fast synced
|
||||
|
||||
## 0.11.1 (October 10, 2017)
|
||||
|
||||
IMPROVEMENTS:
|
||||
- blockchain/reactor: respondWithNoResponseMessage for missing height
|
||||
|
||||
BUG FIXES:
|
||||
- rpc: fixed client WebSocket timeout
|
||||
- rpc: client now resubscribes on reconnection
|
||||
- rpc: fix panics on missing params
|
||||
- rpc: fix `/dump_consensus_state` to have normal json output (NOTE: technically breaking, but worth a bug fix label)
|
||||
- types: fixed out of range error in VoteSet.addVote
|
||||
- consensus: fix wal autofile via https://github.com/tendermint/tmlibs/blob/master/CHANGELOG.md#032-october-2-2017
|
||||
|
||||
## 0.11.0 (September 22, 2017)
|
||||
|
||||
BREAKING:
|
||||
- genesis file: validator `amount` is now `power`
|
||||
- abci: Info, BeginBlock, InitChain all take structs
|
||||
- rpc: various changes to match JSONRPC spec (http://www.jsonrpc.org/specification), including breaking ones:
|
||||
- requests that previously returned HTTP code 4XX now return 200 with an error code in the JSONRPC.
|
||||
- `rpctypes.RPCResponse` uses new `RPCError` type instead of `string`.
|
||||
|
||||
- cmd: if there is no genesis, exit immediately instead of waiting around for one to show.
|
||||
- types: `Signer.Sign` returns an error.
|
||||
- state: every validator set change is persisted to disk, which required some changes to the `State` structure.
|
||||
- p2p: new `p2p.Peer` interface used for all reactor methods (instead of `*p2p.Peer` struct).
|
||||
|
||||
FEATURES:
|
||||
- rpc: `/validators?height=X` allows querying of validators at previous heights.
|
||||
- rpc: Leaving the `height` param empty for `/block`, `/validators`, and `/commit` will return the value for the latest height.
|
||||
|
||||
IMPROVEMENTS:
|
||||
- docs: Moved all docs from the website and tools repo in, converted to `.rst`, and cleaned up for presentation on `tendermint.readthedocs.io`
|
||||
|
||||
BUG FIXES:
|
||||
- fix WAL openning issue on Windows
|
||||
|
||||
## 0.10.4 (September 5, 2017)
|
||||
|
||||
IMPROVEMENTS:
|
||||
- docs: Added Slate docs to each rpc function (see rpc/core)
|
||||
- docs: Ported all website docs to Read The Docs
|
||||
- config: expose some p2p params to tweak performance: RecvRate, SendRate, and MaxMsgPacketPayloadSize
|
||||
- rpc: Upgrade the websocket client and server, including improved auto reconnect, and proper ping/pong
|
||||
|
||||
BUG FIXES:
|
||||
- consensus: fix panic on getVoteBitArray
|
||||
- consensus: hang instead of panicking on byzantine consensus failures
|
||||
- cmd: dont load config for version command
|
||||
|
||||
## 0.10.3 (August 10, 2017)
|
||||
|
||||
FEATURES:
|
||||
- control over empty block production:
|
||||
- new flag, `--consensus.create_empty_blocks`; when set to false, blocks are only created when there are txs or when the AppHash changes.
|
||||
- new config option, `consensus.create_empty_blocks_interval`; an empty block is created after this many seconds.
|
||||
- in normal operation, `create_empty_blocks = true` and `create_empty_blocks_interval = 0`, so blocks are being created all the time (as in all previous versions of tendermint). The number of empty blocks can be reduced by increasing `create_empty_blocks_interval` or by setting `create_empty_blocks = false`.
|
||||
- new `TxsAvailable()` method added to Mempool that returns a channel which fires when txs are available.
|
||||
- new heartbeat message added to consensus reactor to notify peers that a node is waiting for txs before entering propose step.
|
||||
- rpc: Add `syncing` field to response returned by `/status`. Is `true` while in fast-sync mode.
|
||||
|
||||
IMPROVEMENTS:
|
||||
- various improvements to documentation and code comments
|
||||
|
||||
BUG FIXES:
|
||||
- mempool: pass height into constructor so it doesn't always start at 0
|
||||
|
||||
## 0.10.2 (July 10, 2017)
|
||||
|
||||
FEATURES:
|
||||
- Enable lower latency block commits by adding consensus reactor sleep durations and p2p flush throttle timeout to the config
|
||||
|
||||
IMPROVEMENTS:
|
||||
- More detailed logging in the consensus reactor and state machine
|
||||
- More in-code documentation for many exposed functions, especially in consensus/reactor.go and p2p/switch.go
|
||||
- Improved readability for some function definitions and code blocks with long lines
|
||||
|
||||
## 0.10.1 (June 28, 2017)
|
||||
|
||||
FEATURES:
|
||||
- Use `--trace` to get stack traces for logged errors
|
||||
- types: GenesisDoc.ValidatorHash returns the hash of the genesis validator set
|
||||
- types: GenesisDocFromFile parses a GenesiDoc from a JSON file
|
||||
|
||||
IMPROVEMENTS:
|
||||
- Add a Code of Conduct
|
||||
- Variety of improvements as suggested by `megacheck` tool
|
||||
- rpc: deduplicate tests between rpc/client and rpc/tests
|
||||
- rpc: addresses without a protocol prefix default to `tcp://`. `http://` is also accepted as an alias for `tcp://`
|
||||
- cmd: commands are more easily reuseable from other tools
|
||||
- DOCKER: automate build/push
|
||||
|
||||
BUG FIXES:
|
||||
- Fix log statements using keys with spaces (logger does not currently support spaces)
|
||||
- rpc: set logger on websocket connection
|
||||
- rpc: fix ws connection stability by setting write deadline on pings
|
||||
|
||||
## 0.10.0 (June 2, 2017)
|
||||
|
||||
Includes major updates to configuration, logging, and json serialization.
|
||||
Also includes the Grand Repo-Merge of 2017.
|
||||
|
||||
BREAKING CHANGES:
|
||||
|
||||
- Config and Flags:
|
||||
- The `config` map is replaced with a [`Config` struct](https://github.com/tendermint/tendermint/blob/master/config/config.go#L11),
|
||||
containing substructs: `BaseConfig`, `P2PConfig`, `MempoolConfig`, `ConsensusConfig`, `RPCConfig`
|
||||
- This affects the following flags:
|
||||
- `--seeds` is now `--p2p.seeds`
|
||||
- `--node_laddr` is now `--p2p.laddr`
|
||||
- `--pex` is now `--p2p.pex`
|
||||
- `--skip_upnp` is now `--p2p.skip_upnp`
|
||||
- `--rpc_laddr` is now `--rpc.laddr`
|
||||
- `--grpc_laddr` is now `--rpc.grpc_laddr`
|
||||
- Any configuration option now within a substract must come under that heading in the `config.toml`, for instance:
|
||||
```
|
||||
[p2p]
|
||||
laddr="tcp://1.2.3.4:46656"
|
||||
|
||||
[consensus]
|
||||
timeout_propose=1000
|
||||
```
|
||||
- Use viper and `DefaultConfig() / TestConfig()` functions to handle defaults, and remove `config/tendermint` and `config/tendermint_test`
|
||||
- Change some function and method signatures to
|
||||
- Change some [function and method signatures](https://gist.github.com/ebuchman/640d5fc6c2605f73497992fe107ebe0b) accomodate new config
|
||||
|
||||
- Logger
|
||||
- Replace static `log15` logger with a simple interface, and provide a new implementation using `go-kit`.
|
||||
See our new [logging library](https://github.com/tendermint/tmlibs/log) and [blog post](https://tendermint.com/blog/abstracting-the-logger-interface-in-go) for more details
|
||||
- Levels `warn` and `notice` are removed (you may need to change them in your `config.toml`!)
|
||||
- Change some [function and method signatures](https://gist.github.com/ebuchman/640d5fc6c2605f73497992fe107ebe0b) to accept a logger
|
||||
|
||||
- JSON serialization:
|
||||
- Replace `[TypeByte, Xxx]` with `{"type": "some-type", "data": Xxx}` in RPC and all `.json` files by using `go-wire/data`. For instance, a public key is now:
|
||||
```
|
||||
"pub_key": {
|
||||
"type": "ed25519",
|
||||
"data": "83DDF8775937A4A12A2704269E2729FCFCD491B933C4B0A7FFE37FE41D7760D0"
|
||||
}
|
||||
```
|
||||
- Remove type information about RPC responses, so `[TypeByte, {"jsonrpc": "2.0", ... }]` is now just `{"jsonrpc": "2.0", ... }`
|
||||
- Change `[]byte` to `data.Bytes` in all serialized types (for hex encoding)
|
||||
- Lowercase the JSON tags in `ValidatorSet` fields
|
||||
- Introduce `EventDataInner` for serializing events
|
||||
|
||||
- Other:
|
||||
- Send InitChain message in handshake if `appBlockHeight == 0`
|
||||
- Do not include the `Accum` field when computing the validator hash. This makes the ValidatorSetHash unique for a given validator set, rather than changing with every block (as the Accum changes)
|
||||
- Unsafe RPC calls are not enabled by default. This includes `/dial_seeds`, and all calls prefixed with `unsafe`. Use the `--rpc.unsafe` flag to enable.
|
||||
|
||||
|
||||
FEATURES:
|
||||
|
||||
- Per-module log levels. For instance, the new default is `state:info,*:error`, which means the `state` package logs at `info` level, and everything else logs at `error` level
|
||||
- Log if a node is validator or not in every consensus round
|
||||
- Use ldflags to set git hash as part of the version
|
||||
- Ignore `address` and `pub_key` fields in `priv_validator.json` and overwrite them with the values derrived from the `priv_key`
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- Merge `tendermint/go-p2p -> tendermint/tendermint/p2p` and `tendermint/go-rpc -> tendermint/tendermint/rpc/lib`
|
||||
- Update paths for grand repo merge:
|
||||
- `go-common -> tmlibs/common`
|
||||
- `go-data -> go-wire/data`
|
||||
- All other `go-` libs, except `go-crypto` and `go-wire`, are merged under `tmlibs`
|
||||
- No global loggers (loggers are passed into constructors, or preferably set with a SetLogger method)
|
||||
- Return HTTP status codes with errors for RPC responses
|
||||
- Limit `/blockchain_info` call to return a maximum of 20 blocks
|
||||
- Use `.Wrap()` and `.Unwrap()` instead of eg. `PubKeyS` for `go-crypto` types
|
||||
- RPC JSON responses use pretty printing (via `json.MarshalIndent`)
|
||||
- Color code different instances of the consensus for tests
|
||||
- Isolate viper to `cmd/tendermint/commands` and do not read config from file for tests
|
||||
|
||||
|
||||
## 0.9.2 (April 26, 2017)
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fix bug in `ResetPrivValidator` where we were using the global config and log (causing external consumers, eg. basecoin, to fail).
|
||||
|
||||
## 0.9.1 (April 21, 2017)
|
||||
|
||||
FEATURES:
|
||||
|
||||
- Transaction indexing - txs are indexed by their hash using a simple key-value store; easily extended to more advanced indexers
|
||||
- New `/tx?hash=X` endpoint to query for transactions and their DeliverTx result by hash. Optionally returns a proof of the tx's inclusion in the block
|
||||
- `tendermint testnet` command initializes files for a testnet
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- CLI now uses Cobra framework
|
||||
- TMROOT is now TMHOME (TMROOT will stop working in 0.10.0)
|
||||
- `/broadcast_tx_XXX` also returns the Hash (can be used to query for the tx)
|
||||
- `/broadcast_tx_commit` also returns the height the block was committed in
|
||||
- ABCIResponses struct persisted to disk before calling Commit; makes handshake replay much cleaner
|
||||
- WAL uses #ENDHEIGHT instead of #HEIGHT (#HEIGHT will stop working in 0.10.0)
|
||||
- Peers included via `--seeds`, under `seeds` in the config, or in `/dial_seeds` are now persistent, and will be reconnected to if the connection breaks
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fix bug in fast-sync where we stop syncing after a peer is removed, even if they're re-added later
|
||||
- Fix handshake replay to handle validator set changes and results of DeliverTx when we crash after app.Commit but before state.Save()
|
||||
|
||||
## 0.9.0 (March 6, 2017)
|
||||
|
||||
BREAKING CHANGES:
|
||||
|
||||
- Update ABCI to v0.4.0, where Query is now `Query(RequestQuery) ResponseQuery`, enabling precise proofs at particular heights:
|
||||
|
||||
```
|
||||
message RequestQuery{
|
||||
bytes data = 1;
|
||||
string path = 2;
|
||||
uint64 height = 3;
|
||||
bool prove = 4;
|
||||
}
|
||||
|
||||
message ResponseQuery{
|
||||
CodeType code = 1;
|
||||
int64 index = 2;
|
||||
bytes key = 3;
|
||||
bytes value = 4;
|
||||
bytes proof = 5;
|
||||
uint64 height = 6;
|
||||
string log = 7;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
- `BlockMeta` data type unifies its Hash and PartSetHash under a `BlockID`:
|
||||
|
||||
```
|
||||
type BlockMeta struct {
|
||||
BlockID BlockID `json:"block_id"` // the block hash and partsethash
|
||||
Header *Header `json:"header"` // The block's Header
|
||||
}
|
||||
```
|
||||
|
||||
- `ValidatorSet.Proposer` is exposed as a field and persisted with the `State`. Use `GetProposer()` to initialize or update after validator-set changes.
|
||||
|
||||
- `tendermint gen_validator` command output is now pure JSON
|
||||
|
||||
FEATURES:
|
||||
|
||||
- New RPC endpoint `/commit?height=X` returns header and commit for block at height `X`
|
||||
- Client API for each endpoint, including mocks for testing
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- `Node` is now a `BaseService`
|
||||
- Simplified starting Tendermint in-process from another application
|
||||
- Better organized Makefile
|
||||
- Scripts for auto-building binaries across platforms
|
||||
- Docker image improved, slimmed down (using Alpine), and changed from tendermint/tmbase to tendermint/tendermint
|
||||
- New repo files: `CONTRIBUTING.md`, Github `ISSUE_TEMPLATE`, `CHANGELOG.md`
|
||||
- Improvements on CircleCI for managing build/test artifacts
|
||||
- Handshake replay is doen through the consensus package, possibly using a mockApp
|
||||
- Graceful shutdown of RPC listeners
|
||||
- Tests for the PEX reactor and DialSeeds
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Check peer.Send for failure before updating PeerState in consensus
|
||||
- Fix panic in `/dial_seeds` with invalid addresses
|
||||
- Fix proposer selection logic in ValidatorSet by taking the address into account in the `accumComparable`
|
||||
- Fix inconcistencies with `ValidatorSet.Proposer` across restarts by persisting it in the `State`
|
||||
|
||||
|
||||
## 0.8.0 (January 13, 2017)
|
||||
|
||||
BREAKING CHANGES:
|
||||
|
||||
- New data type `BlockID` to represent blocks:
|
||||
|
||||
```
|
||||
type BlockID struct {
|
||||
Hash []byte `json:"hash"`
|
||||
PartsHeader PartSetHeader `json:"parts"`
|
||||
}
|
||||
```
|
||||
|
||||
- `Vote` data type now includes validator address and index:
|
||||
|
||||
```
|
||||
type Vote struct {
|
||||
ValidatorAddress []byte `json:"validator_address"`
|
||||
ValidatorIndex int `json:"validator_index"`
|
||||
Height int `json:"height"`
|
||||
Round int `json:"round"`
|
||||
Type byte `json:"type"`
|
||||
BlockID BlockID `json:"block_id"` // zero if vote is nil.
|
||||
Signature crypto.Signature `json:"signature"`
|
||||
}
|
||||
```
|
||||
|
||||
- Update TMSP to v0.3.0, where it is now called ABCI and AppendTx is DeliverTx
|
||||
- Hex strings in the RPC are now "0x" prefixed
|
||||
|
||||
|
||||
FEATURES:
|
||||
|
||||
- New message type on the ConsensusReactor, `Maj23Msg`, for peers to alert others they've seen a Maj23,
|
||||
in order to track and handle conflicting votes intelligently to prevent Byzantine faults from causing halts:
|
||||
|
||||
```
|
||||
type VoteSetMaj23Message struct {
|
||||
Height int
|
||||
Round int
|
||||
Type byte
|
||||
BlockID types.BlockID
|
||||
}
|
||||
```
|
||||
|
||||
- Configurable block part set size
|
||||
- Validator set changes
|
||||
- Optionally skip TimeoutCommit if we have all the votes
|
||||
- Handshake between Tendermint and App on startup to sync latest state and ensure consistent recovery from crashes
|
||||
- GRPC server for BroadcastTx endpoint
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- Less verbose logging
|
||||
- Better test coverage (37% -> 49%)
|
||||
- Canonical SignBytes for signable types
|
||||
- Write-Ahead Log for Mempool and Consensus via tmlibs/autofile
|
||||
- Better in-process testing for the consensus reactor and byzantine faults
|
||||
- Better crash/restart testing for individual nodes at preset failure points, and of networks at arbitrary points
|
||||
- Better abstraction over timeout mechanics
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fix memory leak in mempool peer
|
||||
- Fix panic on POLRound=-1
|
||||
- Actually set the CommitTime
|
||||
- Actually send BeginBlock message
|
||||
- Fix a liveness issues caused by Byzantine proposals/votes. Uses the new `Maj23Msg`.
|
||||
|
||||
|
||||
## 0.7.4 (December 14, 2016)
|
||||
|
||||
FEATURES:
|
||||
|
||||
- Enable the Peer Exchange reactor with the `--pex` flag for more resilient gossip network (feature still in development, beware dragons)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- Remove restrictions on RPC endpoint `/dial_seeds` to enable manual network configuration
|
||||
|
||||
## 0.7.3 (October 20, 2016)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- Type safe FireEvent
|
||||
- More WAL/replay tests
|
||||
- Cleanup some docs
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Fix deadlock in mempool for synchronous apps
|
||||
- Replay handles non-empty blocks
|
||||
- Fix race condition in HeightVoteSet
|
||||
|
||||
## 0.7.2 (September 11, 2016)
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Set mustConnect=false so tendermint will retry connecting to the app
|
||||
|
||||
## 0.7.1 (September 10, 2016)
|
||||
|
||||
FEATURES:
|
||||
|
||||
- New TMSP connection for Query/Info
|
||||
- New RPC endpoints:
|
||||
- `tmsp_query`
|
||||
- `tmsp_info`
|
||||
- Allow application to filter peers through Query (off by default)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- TMSP connection type enforced at compile time
|
||||
- All listen/client urls use a "tcp://" or "unix://" prefix
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Save LastSignature/LastSignBytes to `priv_validator.json` for recovery
|
||||
- Fix event unsubscribe
|
||||
- Fix fastsync/blockchain reactor
|
||||
|
||||
## 0.7.0 (August 7, 2016)
|
||||
|
||||
BREAKING CHANGES:
|
||||
|
||||
- Strict SemVer starting now!
|
||||
- Update to ABCI v0.2.0
|
||||
- Validation types now called Commit
|
||||
- NewBlock event only returns the block header
|
||||
|
||||
|
||||
FEATURES:
|
||||
|
||||
- TMSP and RPC support TCP and UNIX sockets
|
||||
- Addition config options including block size and consensus parameters
|
||||
- New WAL mode `cswal_light`; logs only the validator's own votes
|
||||
- New RPC endpoints:
|
||||
- for starting/stopping profilers, and for updating config
|
||||
- `/broadcast_tx_commit`, returns when tx is included in a block, else an error
|
||||
- `/unsafe_flush_mempool`, empties the mempool
|
||||
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
- Various optimizations
|
||||
- Remove bad or invalidated transactions from the mempool cache (allows later duplicates)
|
||||
- More elaborate testing using CircleCI including benchmarking throughput on 4 digitalocean droplets
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
- Various fixes to WAL and replay logic
|
||||
- Various race conditions
|
||||
|
||||
## PreHistory
|
||||
|
||||
Strict versioning only began with the release of v0.7.0, in late summer 2016.
|
||||
The project itself began in early summer 2014 and was workable decentralized cryptocurrency software by the end of that year.
|
||||
Through the course of 2015, in collaboration with Eris Industries (now Monax Indsutries),
|
||||
many additional features were integrated, including an implementation from scratch of the Ethereum Virtual Machine.
|
||||
That implementation now forms the heart of [Burrow](https://github.com/hyperledger/burrow).
|
||||
In the later half of 2015, the consensus algorithm was upgraded with a more asynchronous design and a more deterministic and robust implementation.
|
||||
|
||||
By late 2015, frustration with the difficulty of forking a large monolithic stack to create alternative cryptocurrency designs led to the
|
||||
invention of the Application Blockchain Interface (ABCI), then called the Tendermint Socket Protocol (TMSP).
|
||||
The Ethereum Virtual Machine and various other transaction features were removed, and Tendermint was whittled down to a core consensus engine
|
||||
driving an application running in another process.
|
||||
The ABCI interface and implementation were iterated on and improved over the course of 2016,
|
||||
until versioned history kicked in with v0.7.0.
|
||||
56
CODE_OF_CONDUCT.md
Normal file
56
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# The Tendermint Code of Conduct
|
||||
This code of conduct applies to all projects run by the Tendermint/COSMOS team and hence to tendermint.
|
||||
|
||||
|
||||
----
|
||||
|
||||
|
||||
# Conduct
|
||||
## Contact: adrian@tendermint.com
|
||||
|
||||
* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic.
|
||||
|
||||
* On Slack, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all.
|
||||
|
||||
* Please be kind and courteous. There’s no need to be mean or rude.
|
||||
|
||||
* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.
|
||||
|
||||
* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.
|
||||
|
||||
* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behaviour. We interpret the term “harassment” as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don’t tolerate behavior that excludes people in socially marginalized groups.
|
||||
|
||||
* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel admins or the person mentioned above immediately. Whether you’re a regular contributor or a newcomer, we care about making this community a safe place for you and we’ve got your back.
|
||||
|
||||
* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behaviour is not welcome.
|
||||
|
||||
|
||||
----
|
||||
|
||||
|
||||
# Moderation
|
||||
These are the policies for upholding our community’s standards of conduct. If you feel that a thread needs moderation, please contact the above mentioned person.
|
||||
|
||||
1. Remarks that violate the Tendermint/COSMOS standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.)
|
||||
|
||||
2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed.
|
||||
|
||||
3. Moderators will first respond to such remarks with a warning.
|
||||
|
||||
4. If the warning is unheeded, the user will be “kicked,” i.e., kicked out of the communication channel to cool off.
|
||||
|
||||
5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded.
|
||||
|
||||
6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology.
|
||||
|
||||
7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, in private. Complaints about bans in-channel are not allowed.
|
||||
|
||||
8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others.
|
||||
|
||||
In the Tendermint/COSMOS community we strive to go the extra step to look out for each other. Don’t just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they’re off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely.
|
||||
|
||||
And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could’ve communicated better — remember that it’s your responsibility to make your fellow Cosmonauts comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust.
|
||||
|
||||
The enforcement policies listed above apply to all official Tendermint/COSMOS venues.For other projects adopting the Tendermint/COSMOS Code of Conduct, please contact the maintainers of those projects for enforcement. If you wish to use this code of conduct for your own project, consider explicitly mentioning your moderation policy or making a copy with your own moderation policy so as to avoid confusion.
|
||||
|
||||
*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling), the [Contributor Covenant v1.3.0](http://contributor-covenant.org/version/1/3/0/) and the [Rust Code of Conduct](https://www.rust-lang.org/en-US/conduct.html).
|
||||
117
CONTRIBUTING.md
Normal file
117
CONTRIBUTING.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# Contributing
|
||||
|
||||
Thank you for considering making contributions to Tendermint and related repositories! Start by taking a look at the [coding repo](https://github.com/tendermint/coding) for overall information on repository workflow and standards.
|
||||
|
||||
Please follow standard github best practices: fork the repo, branch from the tip of develop, make some commits, and submit a pull request to develop. See the [open issues](https://github.com/tendermint/tendermint/issues) for things we need help with!
|
||||
|
||||
Please make sure to use `gofmt` before every commit - the easiest way to do this is have your editor run it for you upon saving a file.
|
||||
|
||||
## Forking
|
||||
|
||||
Please note that Go requires code to live under absolute paths, which complicates forking.
|
||||
While my fork lives at `https://github.com/ebuchman/tendermint`,
|
||||
the code should never exist at `$GOPATH/src/github.com/ebuchman/tendermint`.
|
||||
Instead, we use `git remote` to add the fork as a new remote for the original repo,
|
||||
`$GOPATH/src/github.com/tendermint/tendermint `, and do all the work there.
|
||||
|
||||
For instance, to create a fork and work on a branch of it, I would:
|
||||
|
||||
* Create the fork on github, using the fork button.
|
||||
* Go to the original repo checked out locally (ie. `$GOPATH/src/github.com/tendermint/tendermint`)
|
||||
* `git remote rename origin upstream`
|
||||
* `git remote add origin git@github.com:ebuchman/basecoin.git`
|
||||
|
||||
Now `origin` refers to my fork and `upstream` refers to the tendermint version.
|
||||
So I can `git push -u origin master` to update my fork, and make pull requests to tendermint from there.
|
||||
Of course, replace `ebuchman` with your git handle.
|
||||
|
||||
To pull in updates from the origin repo, run
|
||||
|
||||
* `git fetch upstream`
|
||||
* `git rebase upstream/master` (or whatever branch you want)
|
||||
|
||||
Please don't make Pull Requests to `master`.
|
||||
|
||||
## Dependencies
|
||||
|
||||
We use [dep](https://github.com/golang/dep) to manage dependencies.
|
||||
|
||||
That said, the master branch of every Tendermint repository should just build
|
||||
with `go get`, which means they should be kept up-to-date with their
|
||||
dependencies so we can get away with telling people they can just `go get` our
|
||||
software.
|
||||
|
||||
Since some dependencies are not under our control, a third party may break our
|
||||
build, in which case we can fall back on `dep ensure` (or `make
|
||||
get_vendor_deps`). Even for dependencies under our control, dep helps us to
|
||||
keep multiple repos in sync as they evolve. Anything with an executable, such
|
||||
as apps, tools, and the core, should use dep.
|
||||
|
||||
Run `dep status` to get a list of vendored dependencies that may not be
|
||||
up-to-date.
|
||||
|
||||
## Vagrant
|
||||
|
||||
If you are a [Vagrant](https://www.vagrantup.com/) user, you can get started
|
||||
hacking Tendermint with the commands below.
|
||||
|
||||
NOTE: In case you installed Vagrant in 2017, you might need to run
|
||||
`vagrant box update` to upgrade to the latest `ubuntu/xenial64`.
|
||||
|
||||
```
|
||||
vagrant up
|
||||
vagrant ssh
|
||||
make test
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
All repos should be hooked up to [CircleCI](https://circleci.com/).
|
||||
|
||||
If they have `.go` files in the root directory, they will be automatically
|
||||
tested by circle using `go test -v -race ./...`. If not, they will need a
|
||||
`circle.yml`. Ideally, every repo has a `Makefile` that defines `make test` and
|
||||
includes its continuous integration status using a badge in the `README.md`.
|
||||
|
||||
## Branching Model and Release
|
||||
|
||||
User-facing repos should adhere to the branching model: http://nvie.com/posts/a-successful-git-branching-model/.
|
||||
That is, these repos should be well versioned, and any merge to master requires a version bump and tagged release.
|
||||
|
||||
Libraries need not follow the model strictly, but would be wise to,
|
||||
especially `go-p2p` and `go-rpc`, as their versions are referenced in tendermint core.
|
||||
|
||||
### Development Procedure:
|
||||
- the latest state of development is on `develop`
|
||||
- `develop` must never fail `make test`
|
||||
- no --force onto `develop` (except when reverting a broken commit, which should seldom happen)
|
||||
- create a development branch either on github.com/tendermint/tendermint, or your fork (using `git add origin`)
|
||||
- before submitting a pull request, begin `git rebase` on top of `develop`
|
||||
|
||||
### Pull Merge Procedure:
|
||||
- ensure pull branch is rebased on develop
|
||||
- run `make test` to ensure that all tests pass
|
||||
- merge pull request
|
||||
- the `unstable` branch may be used to aggregate pull merges before testing once
|
||||
- push master may request that pull requests be rebased on top of `unstable`
|
||||
|
||||
### Release Procedure:
|
||||
- start on `develop`
|
||||
- run integration tests (see `test_integrations` in Makefile)
|
||||
- prepare changelog/release issue
|
||||
- bump versions
|
||||
- push to release-vX.X.X to run the extended integration tests on the CI
|
||||
- merge to master
|
||||
- merge master back to develop
|
||||
|
||||
### Hotfix Procedure:
|
||||
- start on `master`
|
||||
- checkout a new branch named hotfix-vX.X.X
|
||||
- make the required changes
|
||||
- these changes should be small and an absolute necessity
|
||||
- add a note to CHANGELOG.md
|
||||
- bumb versions
|
||||
- push to hotfix-vX.X.X to run the extended integration tests on the CI
|
||||
- merge hotfix-vX.X.X to master
|
||||
- merge hotfix-vX.X.X to develop
|
||||
- delete the hotfix-vX.X.X branch
|
||||
@@ -1,41 +1,45 @@
|
||||
# Pull base image.
|
||||
FROM golang:1.4
|
||||
FROM alpine:3.7
|
||||
|
||||
ENV user tendermint
|
||||
ENV data_root /data/tendermint
|
||||
# This is the release of tendermint to pull in.
|
||||
ENV TM_VERSION 0.17.1
|
||||
ENV TM_SHA256SUM d57008c63d2d9176861137e38ed203da486febf20ae7d388fb810a75afff8f24
|
||||
|
||||
# set user right away for determinism
|
||||
RUN groupadd -r $user \
|
||||
&& useradd -r -s /bin/false -g $user $user
|
||||
# Tendermint will be looking for genesis file in /tendermint (unless you change
|
||||
# `genesis_file` in config.toml). You can put your config.toml and private
|
||||
# validator file into /tendermint.
|
||||
#
|
||||
# The /tendermint/data dir is used by tendermint to store state.
|
||||
ENV DATA_ROOT /tendermint
|
||||
ENV TMHOME $DATA_ROOT
|
||||
|
||||
# create directory for persistence and give our user ownership
|
||||
RUN mkdir -p $data_root \
|
||||
&& chown -R $user:$user $data_root
|
||||
# Set user right away for determinism
|
||||
RUN addgroup tmuser && \
|
||||
adduser -S -G tmuser tmuser
|
||||
|
||||
# Set the env variables to non-interactive
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
ENV DEBIAN_PRIORITY critical
|
||||
ENV DEBCONF_NOWARNINGS yes
|
||||
ENV TERM linux
|
||||
RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
|
||||
# Create directory for persistence and give our user ownership
|
||||
RUN mkdir -p $DATA_ROOT && \
|
||||
chown -R tmuser:tmuser $DATA_ROOT
|
||||
|
||||
# grab deps (gmp)
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
libgmp3-dev && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
# jq and curl used for extracting `pub_key` from private validator while
|
||||
# deploying tendermint with Kubernetes. It is nice to have bash so the users
|
||||
# could execute bash commands.
|
||||
RUN apk add --no-cache bash curl jq
|
||||
|
||||
# set the repo and install tendermint
|
||||
ENV repo /go/src/github.com/tendermint/tendermint
|
||||
ADD . $repo
|
||||
WORKDIR $repo
|
||||
RUN make
|
||||
RUN apk add --no-cache openssl && \
|
||||
wget https://github.com/tendermint/tendermint/releases/download/v${TM_VERSION}/tendermint_${TM_VERSION}_linux_amd64.zip && \
|
||||
echo "${TM_SHA256SUM} tendermint_${TM_VERSION}_linux_amd64.zip" | sha256sum -c && \
|
||||
unzip -d /bin tendermint_${TM_VERSION}_linux_amd64.zip && \
|
||||
apk del openssl && \
|
||||
rm -f tendermint_${TM_VERSION}_linux_amd64.zip
|
||||
|
||||
# persist data, set user
|
||||
VOLUME $data_root
|
||||
USER tendermint
|
||||
ENV TMROOT $data_root
|
||||
# Expose the data directory as a volume since there's mutable state in there
|
||||
VOLUME $DATA_ROOT
|
||||
|
||||
# run tendermint
|
||||
CMD ["./DOCKER/run.sh"]
|
||||
# p2p port
|
||||
EXPOSE 46656
|
||||
# rpc port
|
||||
EXPOSE 46657
|
||||
|
||||
ENTRYPOINT ["tendermint"]
|
||||
|
||||
CMD ["node", "--moniker=`hostname`"]
|
||||
|
||||
35
DOCKER/Dockerfile.develop
Normal file
35
DOCKER/Dockerfile.develop
Normal file
@@ -0,0 +1,35 @@
|
||||
FROM alpine:3.7
|
||||
|
||||
ENV DATA_ROOT /tendermint
|
||||
ENV TMHOME $DATA_ROOT
|
||||
|
||||
RUN addgroup tmuser && \
|
||||
adduser -S -G tmuser tmuser
|
||||
|
||||
RUN mkdir -p $DATA_ROOT && \
|
||||
chown -R tmuser:tmuser $DATA_ROOT
|
||||
|
||||
RUN apk add --no-cache bash curl jq
|
||||
|
||||
ENV GOPATH /go
|
||||
ENV PATH "$PATH:/go/bin"
|
||||
RUN mkdir -p /go/src/github.com/tendermint/tendermint && \
|
||||
apk add --no-cache go build-base git && \
|
||||
cd /go/src/github.com/tendermint/tendermint && \
|
||||
git clone https://github.com/tendermint/tendermint . && \
|
||||
git checkout develop && \
|
||||
make get_tools && \
|
||||
make get_vendor_deps && \
|
||||
make install && \
|
||||
cd - && \
|
||||
rm -rf /go/src/github.com/tendermint/tendermint && \
|
||||
apk del go build-base git
|
||||
|
||||
VOLUME $DATA_ROOT
|
||||
|
||||
EXPOSE 46656
|
||||
EXPOSE 46657
|
||||
|
||||
ENTRYPOINT ["tendermint"]
|
||||
|
||||
CMD ["node", "--moniker=`hostname`", "--proxy_app=kvstore"]
|
||||
13
DOCKER/Makefile
Normal file
13
DOCKER/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
build:
|
||||
@sh -c "'$(CURDIR)/build.sh'"
|
||||
|
||||
push:
|
||||
@sh -c "'$(CURDIR)/push.sh'"
|
||||
|
||||
build_develop:
|
||||
docker build -t "tendermint/tendermint:develop" -f Dockerfile.develop .
|
||||
|
||||
push_develop:
|
||||
docker push "tendermint/tendermint:develop"
|
||||
|
||||
.PHONY: build build_develop push push_develop
|
||||
@@ -1,33 +1,61 @@
|
||||
# Supported tags and respective `Dockerfile` links
|
||||
|
||||
# Persistence
|
||||
- `0.17.1`, `latest` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/208ac32fa266657bd6c304e84ec828aa252bb0b8/DOCKER/Dockerfile)
|
||||
- `0.15.0` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/170777300ea92dc21a8aec1abc16cb51812513a4/DOCKER/Dockerfile)
|
||||
- `0.13.0` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/a28b3fff49dce2fb31f90abb2fc693834e0029c2/DOCKER/Dockerfile)
|
||||
- `0.12.1` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/457c688346b565e90735431619ca3ca597ef9007/DOCKER/Dockerfile)
|
||||
- `0.12.0` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/70d8afa6e952e24c573ece345560a5971bf2cc0e/DOCKER/Dockerfile)
|
||||
- `0.11.0` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/9177cc1f64ca88a4a0243c5d1773d10fba67e201/DOCKER/Dockerfile)
|
||||
- `0.10.0` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/e5342f4054ab784b2cd6150e14f01053d7c8deb2/DOCKER/Dockerfile)
|
||||
- `0.9.1`, `0.9`, [(Dockerfile)](https://github.com/tendermint/tendermint/blob/809e0e8c5933604ba8b2d096803ada7c5ec4dfd3/DOCKER/Dockerfile)
|
||||
- `0.9.0` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/d474baeeea6c22b289e7402449572f7c89ee21da/DOCKER/Dockerfile)
|
||||
- `0.8.0`, `0.8` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/bf64dd21fdb193e54d8addaaaa2ecf7ac371de8c/DOCKER/Dockerfile)
|
||||
- `develop` [(Dockerfile)](https://github.com/tendermint/tendermint/blob/master/DOCKER/Dockerfile.develop)
|
||||
|
||||
It's good practice to use a data-only container, alongside the main application.
|
||||
The `docker.sh` script sets it all up for you, and provides the
|
||||
same functionality as `-v host_dir:image_dir` but by copying the data rather than
|
||||
mounting it.
|
||||
`develop` tag points to the [develop](https://github.com/tendermint/tendermint/tree/develop) branch.
|
||||
|
||||
# To Play
|
||||
# Quick reference
|
||||
|
||||
The commands should work from tendermint/tendermint or tendermint/tendermint/DOCKER,
|
||||
save the removal of DOCKER from the path.
|
||||
* **Where to get help:**
|
||||
https://tendermint.com/community
|
||||
|
||||
Get quickly caught up with the testnet: `FAST_SYNC=true ./DOCKER/docker.sh`
|
||||
* **Where to file issues:**
|
||||
https://github.com/tendermint/tendermint/issues
|
||||
|
||||
Use a pre-existing `~/.tendermint`: `VC=~/.tendermint NO_BUILD=true ./DOCKER/docker.sh`
|
||||
* **Supported Docker versions:**
|
||||
[the latest release](https://github.com/moby/moby/releases) (down to 1.6 on a best-effort basis)
|
||||
|
||||
This is like doing `-v ~/.tendermint:/data/tendermint`, but better.
|
||||
# Tendermint
|
||||
|
||||
Use `NO_BUILD` to avoid waiting if the image is already built.
|
||||
Tendermint Core is Byzantine Fault Tolerant (BFT) middleware that takes a state transition machine, written in any programming language, and securely replicates it on many machines.
|
||||
|
||||
Rerunning `docker.sh` will require you to delete the old containers:
|
||||
For more background, see the [introduction](https://tendermint.readthedocs.io/en/master/introduction.html).
|
||||
|
||||
`docker rm mint mintdata`
|
||||
To get started developing applications, see the [application developers guide](https://tendermint.readthedocs.io/en/master/getting-started.html).
|
||||
|
||||
However, if you remove the `mintdata` container, you delete the data (the blockchain).
|
||||
If you don't use the `VC` option, your key will be deleted too
|
||||
# How to use this image
|
||||
|
||||
To avoid deleting and recreating the data container, use
|
||||
## Start one instance of the Tendermint core with the `kvstore` app
|
||||
|
||||
`VD=true NO_BUILD=true ./DOCKER/docker.sh`
|
||||
A very simple example of a built-in app and Tendermint core in one container.
|
||||
|
||||
Of course, once running, you can just control the main container with `docker stop mint` and `docker start mint`
|
||||
```
|
||||
docker run -it --rm -v "/tmp:/tendermint" tendermint/tendermint init
|
||||
docker run -it --rm -v "/tmp:/tendermint" tendermint/tendermint node --proxy_app=kvstore
|
||||
```
|
||||
|
||||
## mintnet-kubernetes
|
||||
|
||||
If you want to see many containers talking to each other, consider using [mintnet-kubernetes](https://github.com/tendermint/tools/tree/master/mintnet-kubernetes), which is a tool for running Tendermint-based applications on a Kubernetes cluster.
|
||||
|
||||
# License
|
||||
|
||||
View [license information](https://raw.githubusercontent.com/tendermint/tendermint/master/LICENSE) for the software contained in this image.
|
||||
|
||||
# User Feedback
|
||||
|
||||
## Contributing
|
||||
|
||||
You are invited to contribute new features, fixes, or updates, large or small; we are always thrilled to receive pull requests, and do our best to process them as fast as we can.
|
||||
|
||||
Before you start to code, we recommend discussing your plans through a [GitHub](https://github.com/tendermint/tendermint/issues) issue, especially for more ambitious contributions. This gives other contributors a chance to point you in the right direction, give you feedback on your design, and help you find out if someone else is working on the same thing.
|
||||
|
||||
20
DOCKER/build.sh
Executable file
20
DOCKER/build.sh
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# Get the tag from the version, or try to figure it out.
|
||||
if [ -z "$TAG" ]; then
|
||||
TAG=$(awk -F\" '/Version =/ { print $2; exit }' < ../version/version.go)
|
||||
fi
|
||||
if [ -z "$TAG" ]; then
|
||||
echo "Please specify a tag."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TAG_NO_PATCH=${TAG%.*}
|
||||
|
||||
read -p "==> Build 3 docker images with the following tags (latest, $TAG, $TAG_NO_PATCH)? y/n" -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]
|
||||
then
|
||||
docker build -t "tendermint/tendermint" -t "tendermint/tendermint:$TAG" -t "tendermint/tendermint:$TAG_NO_PATCH" .
|
||||
fi
|
||||
@@ -1,21 +0,0 @@
|
||||
#! /bin/bash
|
||||
|
||||
# don't build if you're impatient
|
||||
if [[ ! $NO_BUILD ]]; then
|
||||
cd $GOPATH/src/github.com/tendermint/tendermint
|
||||
docker build -t mint -f DOCKER/Dockerfile .
|
||||
fi
|
||||
|
||||
# create the data-only container
|
||||
if [[ ! $VD ]]; then
|
||||
docker run --name mintdata --entrypoint /bin/echo mint Data-only container for mint
|
||||
fi
|
||||
|
||||
# copy a directory from host to data-only volume
|
||||
if [[ $VC ]]; then
|
||||
cd $VC
|
||||
tar cf - . | docker run -i --rm --volumes-from mintdata mint tar xvf - -C /data/tendermint
|
||||
fi
|
||||
|
||||
# run tendermint
|
||||
docker run --name mint --volumes-from mintdata -d -p 46656:46656 -p 46657:46657 -e FAST_SYNC=$FAST_SYNC mint
|
||||
22
DOCKER/push.sh
Executable file
22
DOCKER/push.sh
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# Get the tag from the version, or try to figure it out.
|
||||
if [ -z "$TAG" ]; then
|
||||
TAG=$(awk -F\" '/Version =/ { print $2; exit }' < ../version/version.go)
|
||||
fi
|
||||
if [ -z "$TAG" ]; then
|
||||
echo "Please specify a tag."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TAG_NO_PATCH=${TAG%.*}
|
||||
|
||||
read -p "==> Push 3 docker images with the following tags (latest, $TAG, $TAG_NO_PATCH)? y/n" -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]
|
||||
then
|
||||
docker push "tendermint/tendermint:latest"
|
||||
docker push "tendermint/tendermint:$TAG"
|
||||
docker push "tendermint/tendermint:$TAG_NO_PATCH"
|
||||
fi
|
||||
@@ -1,12 +0,0 @@
|
||||
#! /bin/bash
|
||||
|
||||
if [[ $BARAK_SEED ]]; then
|
||||
cat ./cmd/barak/$BARAK_SEED | ./build/barak &
|
||||
fi
|
||||
|
||||
if [ "$FAST_SYNC" = "true" ]; then
|
||||
tendermint node --fast_sync
|
||||
else
|
||||
tendermint node
|
||||
fi
|
||||
|
||||
108
Godeps/Godeps.json
generated
108
Godeps/Godeps.json
generated
@@ -1,108 +0,0 @@
|
||||
{
|
||||
"ImportPath": "github.com/tendermint/tendermint",
|
||||
"GoVersion": "go1.4.2",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "code.google.com/p/go.crypto/ripemd160",
|
||||
"Comment": "null-236",
|
||||
"Rev": "69e2a90ed92d03812364aeb947b7068dc42e561e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "code.google.com/p/mxk/go1/flowcontrol",
|
||||
"Comment": "null-12",
|
||||
"Rev": "5ff2502e25566863e8a0136c7aae8838e4c7de39"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/agl/ed25519/edwards25519",
|
||||
"Rev": "d2b94fd789ea21d12fac1a4443dd3a3f79cda72c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/codegangsta/cli",
|
||||
"Comment": "1.2.0-106-ga889873",
|
||||
"Rev": "a889873af50a499d060097216dcdbcc26ed09e7c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gorilla/websocket",
|
||||
"Rev": "1f87405cd9755fc388e111c4003caca4a2f52fa6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/inconshreveable/log15/stack",
|
||||
"Comment": "v2.3-38-g352fceb",
|
||||
"Rev": "352fceb48e895bd1dd0b9f5d3ae8f8516c49af0f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/inconshreveable/log15/term",
|
||||
"Comment": "v2.3-38-g352fceb",
|
||||
"Rev": "352fceb48e895bd1dd0b9f5d3ae8f8516c49af0f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mattn/go-colorable",
|
||||
"Rev": "043ae16291351db8465272edf465c9f388161627"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/naoina/go-stringutil",
|
||||
"Rev": "360db0db4b01d34e12a2ec042c09e7d37fece761"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/naoina/toml",
|
||||
"Rev": "7b2dffbeaee47506726f29e36d19cf4ee90d361b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/sfreiberg/gotwilio",
|
||||
"Rev": "b7230c284bd0c1614c94d00b9998c49f9a2737d8"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/spf13/pflag",
|
||||
"Rev": "5644820622454e71517561946e3d94b9f9db6842"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/syndtr/goleveldb/leveldb",
|
||||
"Rev": "63c9e642efad852f49e20a6f90194cae112fd2ac"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/syndtr/gosnappy/snappy",
|
||||
"Rev": "ce8acff4829e0c2458a67ead32390ac0a381c862"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/tendermint/ed25519",
|
||||
"Rev": "533fb6548e2071076888eda3c38749d707ba49bc"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/tendermint/log15",
|
||||
"Comment": "v2.3-34-gbec7415",
|
||||
"Rev": "bec7415fb62f05ac62298c2bc1a080d45ac3065c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/curve25519",
|
||||
"Rev": "02a186af8b62cb007f392270669b91be5527d39c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/nacl/box",
|
||||
"Rev": "02a186af8b62cb007f392270669b91be5527d39c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/nacl/secretbox",
|
||||
"Rev": "02a186af8b62cb007f392270669b91be5527d39c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/poly1305",
|
||||
"Rev": "02a186af8b62cb007f392270669b91be5527d39c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/ripemd160",
|
||||
"Rev": "02a186af8b62cb007f392270669b91be5527d39c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/salsa20/salsa",
|
||||
"Rev": "02a186af8b62cb007f392270669b91be5527d39c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/fatih/set.v0",
|
||||
"Comment": "v0.1.0-3-g27c4092",
|
||||
"Rev": "27c40922c40b43fe04554d8223a402af3ea333f3"
|
||||
}
|
||||
]
|
||||
}
|
||||
5
Godeps/Readme
generated
5
Godeps/Readme
generated
@@ -1,5 +0,0 @@
|
||||
This directory tree is generated automatically by godep.
|
||||
|
||||
Please do not edit.
|
||||
|
||||
See https://github.com/tools/godep for more information.
|
||||
2
Godeps/_workspace/.gitignore
generated
vendored
2
Godeps/_workspace/.gitignore
generated
vendored
@@ -1,2 +0,0 @@
|
||||
/pkg
|
||||
/bin
|
||||
120
Godeps/_workspace/src/code.google.com/p/go.crypto/ripemd160/ripemd160.go
generated
vendored
120
Godeps/_workspace/src/code.google.com/p/go.crypto/ripemd160/ripemd160.go
generated
vendored
@@ -1,120 +0,0 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package ripemd160 implements the RIPEMD-160 hash algorithm.
|
||||
package ripemd160
|
||||
|
||||
// RIPEMD-160 is designed by by Hans Dobbertin, Antoon Bosselaers, and Bart
|
||||
// Preneel with specifications available at:
|
||||
// http://homes.esat.kuleuven.be/~cosicart/pdf/AB-9601/AB-9601.pdf.
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"hash"
|
||||
)
|
||||
|
||||
func init() {
|
||||
crypto.RegisterHash(crypto.RIPEMD160, New)
|
||||
}
|
||||
|
||||
// The size of the checksum in bytes.
|
||||
const Size = 20
|
||||
|
||||
// The block size of the hash algorithm in bytes.
|
||||
const BlockSize = 64
|
||||
|
||||
const (
|
||||
_s0 = 0x67452301
|
||||
_s1 = 0xefcdab89
|
||||
_s2 = 0x98badcfe
|
||||
_s3 = 0x10325476
|
||||
_s4 = 0xc3d2e1f0
|
||||
)
|
||||
|
||||
// digest represents the partial evaluation of a checksum.
|
||||
type digest struct {
|
||||
s [5]uint32 // running context
|
||||
x [BlockSize]byte // temporary buffer
|
||||
nx int // index into x
|
||||
tc uint64 // total count of bytes processed
|
||||
}
|
||||
|
||||
func (d *digest) Reset() {
|
||||
d.s[0], d.s[1], d.s[2], d.s[3], d.s[4] = _s0, _s1, _s2, _s3, _s4
|
||||
d.nx = 0
|
||||
d.tc = 0
|
||||
}
|
||||
|
||||
// New returns a new hash.Hash computing the checksum.
|
||||
func New() hash.Hash {
|
||||
result := new(digest)
|
||||
result.Reset()
|
||||
return result
|
||||
}
|
||||
|
||||
func (d *digest) Size() int { return Size }
|
||||
|
||||
func (d *digest) BlockSize() int { return BlockSize }
|
||||
|
||||
func (d *digest) Write(p []byte) (nn int, err error) {
|
||||
nn = len(p)
|
||||
d.tc += uint64(nn)
|
||||
if d.nx > 0 {
|
||||
n := len(p)
|
||||
if n > BlockSize-d.nx {
|
||||
n = BlockSize - d.nx
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
d.x[d.nx+i] = p[i]
|
||||
}
|
||||
d.nx += n
|
||||
if d.nx == BlockSize {
|
||||
_Block(d, d.x[0:])
|
||||
d.nx = 0
|
||||
}
|
||||
p = p[n:]
|
||||
}
|
||||
n := _Block(d, p)
|
||||
p = p[n:]
|
||||
if len(p) > 0 {
|
||||
d.nx = copy(d.x[:], p)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (d0 *digest) Sum(in []byte) []byte {
|
||||
// Make a copy of d0 so that caller can keep writing and summing.
|
||||
d := *d0
|
||||
|
||||
// Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
|
||||
tc := d.tc
|
||||
var tmp [64]byte
|
||||
tmp[0] = 0x80
|
||||
if tc%64 < 56 {
|
||||
d.Write(tmp[0 : 56-tc%64])
|
||||
} else {
|
||||
d.Write(tmp[0 : 64+56-tc%64])
|
||||
}
|
||||
|
||||
// Length in bits.
|
||||
tc <<= 3
|
||||
for i := uint(0); i < 8; i++ {
|
||||
tmp[i] = byte(tc >> (8 * i))
|
||||
}
|
||||
d.Write(tmp[0:8])
|
||||
|
||||
if d.nx != 0 {
|
||||
panic("d.nx != 0")
|
||||
}
|
||||
|
||||
var digest [Size]byte
|
||||
for i, s := range d.s {
|
||||
digest[i*4] = byte(s)
|
||||
digest[i*4+1] = byte(s >> 8)
|
||||
digest[i*4+2] = byte(s >> 16)
|
||||
digest[i*4+3] = byte(s >> 24)
|
||||
}
|
||||
|
||||
return append(in, digest[:]...)
|
||||
}
|
||||
64
Godeps/_workspace/src/code.google.com/p/go.crypto/ripemd160/ripemd160_test.go
generated
vendored
64
Godeps/_workspace/src/code.google.com/p/go.crypto/ripemd160/ripemd160_test.go
generated
vendored
@@ -1,64 +0,0 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ripemd160
|
||||
|
||||
// Test vectors are from:
|
||||
// http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type mdTest struct {
|
||||
out string
|
||||
in string
|
||||
}
|
||||
|
||||
var vectors = [...]mdTest{
|
||||
{"9c1185a5c5e9fc54612808977ee8f548b2258d31", ""},
|
||||
{"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", "a"},
|
||||
{"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", "abc"},
|
||||
{"5d0689ef49d2fae572b881b123a85ffa21595f36", "message digest"},
|
||||
{"f71c27109c692c1b56bbdceb5b9d2865b3708dbc", "abcdefghijklmnopqrstuvwxyz"},
|
||||
{"12a053384a9c0c88e405a06c27dcf49ada62eb2b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"},
|
||||
{"b0e20b6e3116640286ed3a87a5713079b21f5189", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"},
|
||||
{"9b752e45573d4b39f4dbd3323cab82bf63326bfb", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"},
|
||||
}
|
||||
|
||||
func TestVectors(t *testing.T) {
|
||||
for i := 0; i < len(vectors); i++ {
|
||||
tv := vectors[i]
|
||||
md := New()
|
||||
for j := 0; j < 3; j++ {
|
||||
if j < 2 {
|
||||
io.WriteString(md, tv.in)
|
||||
} else {
|
||||
io.WriteString(md, tv.in[0:len(tv.in)/2])
|
||||
md.Sum(nil)
|
||||
io.WriteString(md, tv.in[len(tv.in)/2:])
|
||||
}
|
||||
s := fmt.Sprintf("%x", md.Sum(nil))
|
||||
if s != tv.out {
|
||||
t.Fatalf("RIPEMD-160[%d](%s) = %s, expected %s", j, tv.in, s, tv.out)
|
||||
}
|
||||
md.Reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMillionA(t *testing.T) {
|
||||
md := New()
|
||||
for i := 0; i < 100000; i++ {
|
||||
io.WriteString(md, "aaaaaaaaaa")
|
||||
}
|
||||
out := "52783243c1697bdbe16d37f97f68f08325dc1528"
|
||||
s := fmt.Sprintf("%x", md.Sum(nil))
|
||||
if s != out {
|
||||
t.Fatalf("RIPEMD-160 (1 million 'a') = %s, expected %s", s, out)
|
||||
}
|
||||
md.Reset()
|
||||
}
|
||||
161
Godeps/_workspace/src/code.google.com/p/go.crypto/ripemd160/ripemd160block.go
generated
vendored
161
Godeps/_workspace/src/code.google.com/p/go.crypto/ripemd160/ripemd160block.go
generated
vendored
@@ -1,161 +0,0 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// RIPEMD-160 block step.
|
||||
// In its own file so that a faster assembly or C version
|
||||
// can be substituted easily.
|
||||
|
||||
package ripemd160
|
||||
|
||||
// work buffer indices and roll amounts for one line
|
||||
var _n = [80]uint{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
|
||||
3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
|
||||
1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
|
||||
4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13,
|
||||
}
|
||||
|
||||
var _r = [80]uint{
|
||||
11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
|
||||
7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
|
||||
11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
|
||||
11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
|
||||
9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6,
|
||||
}
|
||||
|
||||
// same for the other parallel one
|
||||
var n_ = [80]uint{
|
||||
5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
|
||||
6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
|
||||
15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
|
||||
8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
|
||||
12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11,
|
||||
}
|
||||
|
||||
var r_ = [80]uint{
|
||||
8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
|
||||
9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
|
||||
9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
|
||||
15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
|
||||
8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11,
|
||||
}
|
||||
|
||||
func _Block(md *digest, p []byte) int {
|
||||
n := 0
|
||||
var x [16]uint32
|
||||
var alpha, beta uint32
|
||||
for len(p) >= BlockSize {
|
||||
a, b, c, d, e := md.s[0], md.s[1], md.s[2], md.s[3], md.s[4]
|
||||
aa, bb, cc, dd, ee := a, b, c, d, e
|
||||
j := 0
|
||||
for i := 0; i < 16; i++ {
|
||||
x[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
|
||||
j += 4
|
||||
}
|
||||
|
||||
// round 1
|
||||
i := 0
|
||||
for i < 16 {
|
||||
alpha = a + (b ^ c ^ d) + x[_n[i]]
|
||||
s := _r[i]
|
||||
alpha = (alpha<<s | alpha>>(32-s)) + e
|
||||
beta = c<<10 | c>>22
|
||||
a, b, c, d, e = e, alpha, b, beta, d
|
||||
|
||||
// parallel line
|
||||
alpha = aa + (bb ^ (cc | ^dd)) + x[n_[i]] + 0x50a28be6
|
||||
s = r_[i]
|
||||
alpha = (alpha<<s | alpha>>(32-s)) + ee
|
||||
beta = cc<<10 | cc>>22
|
||||
aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
// round 2
|
||||
for i < 32 {
|
||||
alpha = a + (b&c | ^b&d) + x[_n[i]] + 0x5a827999
|
||||
s := _r[i]
|
||||
alpha = (alpha<<s | alpha>>(32-s)) + e
|
||||
beta = c<<10 | c>>22
|
||||
a, b, c, d, e = e, alpha, b, beta, d
|
||||
|
||||
// parallel line
|
||||
alpha = aa + (bb&dd | cc&^dd) + x[n_[i]] + 0x5c4dd124
|
||||
s = r_[i]
|
||||
alpha = (alpha<<s | alpha>>(32-s)) + ee
|
||||
beta = cc<<10 | cc>>22
|
||||
aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
// round 3
|
||||
for i < 48 {
|
||||
alpha = a + (b | ^c ^ d) + x[_n[i]] + 0x6ed9eba1
|
||||
s := _r[i]
|
||||
alpha = (alpha<<s | alpha>>(32-s)) + e
|
||||
beta = c<<10 | c>>22
|
||||
a, b, c, d, e = e, alpha, b, beta, d
|
||||
|
||||
// parallel line
|
||||
alpha = aa + (bb | ^cc ^ dd) + x[n_[i]] + 0x6d703ef3
|
||||
s = r_[i]
|
||||
alpha = (alpha<<s | alpha>>(32-s)) + ee
|
||||
beta = cc<<10 | cc>>22
|
||||
aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
// round 4
|
||||
for i < 64 {
|
||||
alpha = a + (b&d | c&^d) + x[_n[i]] + 0x8f1bbcdc
|
||||
s := _r[i]
|
||||
alpha = (alpha<<s | alpha>>(32-s)) + e
|
||||
beta = c<<10 | c>>22
|
||||
a, b, c, d, e = e, alpha, b, beta, d
|
||||
|
||||
// parallel line
|
||||
alpha = aa + (bb&cc | ^bb&dd) + x[n_[i]] + 0x7a6d76e9
|
||||
s = r_[i]
|
||||
alpha = (alpha<<s | alpha>>(32-s)) + ee
|
||||
beta = cc<<10 | cc>>22
|
||||
aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
// round 5
|
||||
for i < 80 {
|
||||
alpha = a + (b ^ (c | ^d)) + x[_n[i]] + 0xa953fd4e
|
||||
s := _r[i]
|
||||
alpha = (alpha<<s | alpha>>(32-s)) + e
|
||||
beta = c<<10 | c>>22
|
||||
a, b, c, d, e = e, alpha, b, beta, d
|
||||
|
||||
// parallel line
|
||||
alpha = aa + (bb ^ cc ^ dd) + x[n_[i]]
|
||||
s = r_[i]
|
||||
alpha = (alpha<<s | alpha>>(32-s)) + ee
|
||||
beta = cc<<10 | cc>>22
|
||||
aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
// combine results
|
||||
dd += c + md.s[1]
|
||||
md.s[1] = md.s[2] + d + ee
|
||||
md.s[2] = md.s[3] + e + aa
|
||||
md.s[3] = md.s[4] + a + bb
|
||||
md.s[4] = md.s[0] + b + cc
|
||||
md.s[0] = dd
|
||||
|
||||
p = p[BlockSize:]
|
||||
n += BlockSize
|
||||
}
|
||||
return n
|
||||
}
|
||||
267
Godeps/_workspace/src/code.google.com/p/mxk/go1/flowcontrol/flowcontrol.go
generated
vendored
267
Godeps/_workspace/src/code.google.com/p/mxk/go1/flowcontrol/flowcontrol.go
generated
vendored
@@ -1,267 +0,0 @@
|
||||
//
|
||||
// Written by Maxim Khitrov (November 2012)
|
||||
//
|
||||
|
||||
// Package flowcontrol provides the tools for monitoring and limiting the
|
||||
// transfer rate of an arbitrary data stream.
|
||||
package flowcontrol
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Monitor monitors and limits the transfer rate of a data stream.
|
||||
type Monitor struct {
|
||||
mu sync.Mutex // Mutex guarding access to all internal fields
|
||||
active bool // Flag indicating an active transfer
|
||||
start time.Duration // Transfer start time (clock() value)
|
||||
bytes int64 // Total number of bytes transferred
|
||||
samples int64 // Total number of samples taken
|
||||
|
||||
rSample float64 // Most recent transfer rate sample (bytes per second)
|
||||
rEMA float64 // Exponential moving average of rSample
|
||||
rPeak float64 // Peak transfer rate (max of all rSamples)
|
||||
rWindow float64 // rEMA window (seconds)
|
||||
|
||||
sBytes int64 // Number of bytes transferred since sLast
|
||||
sLast time.Duration // Most recent sample time (stop time when inactive)
|
||||
sRate time.Duration // Sampling rate
|
||||
|
||||
tBytes int64 // Number of bytes expected in the current transfer
|
||||
tLast time.Duration // Time of the most recent transfer of at least 1 byte
|
||||
}
|
||||
|
||||
// New creates a new flow control monitor. Instantaneous transfer rate is
|
||||
// measured and updated for each sampleRate interval. windowSize determines the
|
||||
// weight of each sample in the exponential moving average (EMA) calculation.
|
||||
// The exact formulas are:
|
||||
//
|
||||
// sampleTime = currentTime - prevSampleTime
|
||||
// sampleRate = byteCount / sampleTime
|
||||
// weight = 1 - exp(-sampleTime/windowSize)
|
||||
// newRate = weight*sampleRate + (1-weight)*oldRate
|
||||
//
|
||||
// The default values for sampleRate and windowSize (if <= 0) are 100ms and 1s,
|
||||
// respectively.
|
||||
func New(sampleRate, windowSize time.Duration) *Monitor {
|
||||
if sampleRate = clockRound(sampleRate); sampleRate <= 0 {
|
||||
sampleRate = 5 * clockRate
|
||||
}
|
||||
if windowSize <= 0 {
|
||||
windowSize = 1 * time.Second
|
||||
}
|
||||
now := clock()
|
||||
return &Monitor{
|
||||
active: true,
|
||||
start: now,
|
||||
rWindow: windowSize.Seconds(),
|
||||
sLast: now,
|
||||
sRate: sampleRate,
|
||||
tLast: now,
|
||||
}
|
||||
}
|
||||
|
||||
// Update records the transfer of n bytes and returns n. It should be called
|
||||
// after each Read/Write operation, even if n is 0.
|
||||
func (m *Monitor) Update(n int) int {
|
||||
m.mu.Lock()
|
||||
m.update(n)
|
||||
m.mu.Unlock()
|
||||
return n
|
||||
}
|
||||
|
||||
// IO is a convenience method intended to wrap io.Reader and io.Writer method
|
||||
// execution. It calls m.Update(n) and then returns (n, err) unmodified.
|
||||
func (m *Monitor) IO(n int, err error) (int, error) {
|
||||
return m.Update(n), err
|
||||
}
|
||||
|
||||
// Done marks the transfer as finished and prevents any further updates or
|
||||
// limiting. Instantaneous and current transfer rates drop to 0. Update, IO, and
|
||||
// Limit methods become NOOPs. It returns the total number of bytes transferred.
|
||||
func (m *Monitor) Done() int64 {
|
||||
m.mu.Lock()
|
||||
if now := m.update(0); m.sBytes > 0 {
|
||||
m.reset(now)
|
||||
}
|
||||
m.active = false
|
||||
m.tLast = 0
|
||||
n := m.bytes
|
||||
m.mu.Unlock()
|
||||
return n
|
||||
}
|
||||
|
||||
// timeRemLimit is the maximum Status.TimeRem value.
|
||||
const timeRemLimit = 999*time.Hour + 59*time.Minute + 59*time.Second
|
||||
|
||||
// Status represents the current Monitor status. All transfer rates are in bytes
|
||||
// per second rounded to the nearest byte.
|
||||
type Status struct {
|
||||
Active bool // Flag indicating an active transfer
|
||||
Start time.Time // Transfer start time
|
||||
Duration time.Duration // Time period covered by the statistics
|
||||
Idle time.Duration // Time since the last transfer of at least 1 byte
|
||||
Bytes int64 // Total number of bytes transferred
|
||||
Samples int64 // Total number of samples taken
|
||||
InstRate int64 // Instantaneous transfer rate
|
||||
CurRate int64 // Current transfer rate (EMA of InstRate)
|
||||
AvgRate int64 // Average transfer rate (Bytes / Duration)
|
||||
PeakRate int64 // Maximum instantaneous transfer rate
|
||||
BytesRem int64 // Number of bytes remaining in the transfer
|
||||
TimeRem time.Duration // Estimated time to completion
|
||||
Progress Percent // Overall transfer progress
|
||||
}
|
||||
|
||||
// Status returns current transfer status information. The returned value
|
||||
// becomes static after a call to Done.
|
||||
func (m *Monitor) Status() Status {
|
||||
m.mu.Lock()
|
||||
now := m.update(0)
|
||||
s := Status{
|
||||
Active: m.active,
|
||||
Start: clockToTime(m.start),
|
||||
Duration: m.sLast - m.start,
|
||||
Idle: now - m.tLast,
|
||||
Bytes: m.bytes,
|
||||
Samples: m.samples,
|
||||
PeakRate: round(m.rPeak),
|
||||
BytesRem: m.tBytes - m.bytes,
|
||||
Progress: percentOf(float64(m.bytes), float64(m.tBytes)),
|
||||
}
|
||||
if s.BytesRem < 0 {
|
||||
s.BytesRem = 0
|
||||
}
|
||||
if s.Duration > 0 {
|
||||
rAvg := float64(s.Bytes) / s.Duration.Seconds()
|
||||
s.AvgRate = round(rAvg)
|
||||
if s.Active {
|
||||
s.InstRate = round(m.rSample)
|
||||
s.CurRate = round(m.rEMA)
|
||||
if s.BytesRem > 0 {
|
||||
if tRate := 0.8*m.rEMA + 0.2*rAvg; tRate > 0 {
|
||||
ns := float64(s.BytesRem) / tRate * 1e9
|
||||
if ns > float64(timeRemLimit) {
|
||||
ns = float64(timeRemLimit)
|
||||
}
|
||||
s.TimeRem = clockRound(time.Duration(ns))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m.mu.Unlock()
|
||||
return s
|
||||
}
|
||||
|
||||
// Limit restricts the instantaneous (per-sample) data flow to rate bytes per
|
||||
// second. It returns the maximum number of bytes (0 <= n <= want) that may be
|
||||
// transferred immediately without exceeding the limit. If block == true, the
|
||||
// call blocks until n > 0. want is returned unmodified if want < 1, rate < 1,
|
||||
// or the transfer is inactive (after a call to Done).
|
||||
//
|
||||
// At least one byte is always allowed to be transferred in any given sampling
|
||||
// period. Thus, if the sampling rate is 100ms, the lowest achievable flow rate
|
||||
// is 10 bytes per second.
|
||||
//
|
||||
// For usage examples, see the implementation of Reader and Writer in io.go.
|
||||
func (m *Monitor) Limit(want int, rate int64, block bool) (n int) {
|
||||
if want < 1 || rate < 1 {
|
||||
return want
|
||||
}
|
||||
m.mu.Lock()
|
||||
|
||||
// Determine the maximum number of bytes that can be sent in one sample
|
||||
limit := round(float64(rate) * m.sRate.Seconds())
|
||||
if limit <= 0 {
|
||||
limit = 1
|
||||
}
|
||||
|
||||
// If block == true, wait until m.sBytes < limit
|
||||
if now := m.update(0); block {
|
||||
for m.sBytes >= limit && m.active {
|
||||
now = m.waitNextSample(now)
|
||||
}
|
||||
}
|
||||
|
||||
// Make limit <= want (unlimited if the transfer is no longer active)
|
||||
if limit -= m.sBytes; limit > int64(want) || !m.active {
|
||||
limit = int64(want)
|
||||
}
|
||||
m.mu.Unlock()
|
||||
|
||||
if limit < 0 {
|
||||
limit = 0
|
||||
}
|
||||
return int(limit)
|
||||
}
|
||||
|
||||
// SetTransferSize specifies the total size of the data transfer, which allows
|
||||
// the Monitor to calculate the overall progress and time to completion.
|
||||
func (m *Monitor) SetTransferSize(bytes int64) {
|
||||
if bytes < 0 {
|
||||
bytes = 0
|
||||
}
|
||||
m.mu.Lock()
|
||||
m.tBytes = bytes
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// update accumulates the transferred byte count for the current sample until
|
||||
// clock() - m.sLast >= m.sRate. The monitor status is updated once the current
|
||||
// sample is done.
|
||||
func (m *Monitor) update(n int) (now time.Duration) {
|
||||
if !m.active {
|
||||
return
|
||||
}
|
||||
if now = clock(); n > 0 {
|
||||
m.tLast = now
|
||||
}
|
||||
m.sBytes += int64(n)
|
||||
if sTime := now - m.sLast; sTime >= m.sRate {
|
||||
t := sTime.Seconds()
|
||||
if m.rSample = float64(m.sBytes) / t; m.rSample > m.rPeak {
|
||||
m.rPeak = m.rSample
|
||||
}
|
||||
|
||||
// Exponential moving average using a method similar to *nix load
|
||||
// average calculation. Longer sampling periods carry greater weight.
|
||||
if m.samples > 0 {
|
||||
w := math.Exp(-t / m.rWindow)
|
||||
m.rEMA = m.rSample + w*(m.rEMA-m.rSample)
|
||||
} else {
|
||||
m.rEMA = m.rSample
|
||||
}
|
||||
m.reset(now)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// reset clears the current sample state in preparation for the next sample.
|
||||
func (m *Monitor) reset(sampleTime time.Duration) {
|
||||
m.bytes += m.sBytes
|
||||
m.samples++
|
||||
m.sBytes = 0
|
||||
m.sLast = sampleTime
|
||||
}
|
||||
|
||||
// waitNextSample sleeps for the remainder of the current sample. The lock is
|
||||
// released and reacquired during the actual sleep period, so it's possible for
|
||||
// the transfer to be inactive when this method returns.
|
||||
func (m *Monitor) waitNextSample(now time.Duration) time.Duration {
|
||||
const minWait = 5 * time.Millisecond
|
||||
current := m.sLast
|
||||
|
||||
// sleep until the last sample time changes (ideally, just one iteration)
|
||||
for m.sLast == current && m.active {
|
||||
d := current + m.sRate - now
|
||||
m.mu.Unlock()
|
||||
if d < minWait {
|
||||
d = minWait
|
||||
}
|
||||
time.Sleep(d)
|
||||
m.mu.Lock()
|
||||
now = m.update(0)
|
||||
}
|
||||
return now
|
||||
}
|
||||
133
Godeps/_workspace/src/code.google.com/p/mxk/go1/flowcontrol/io.go
generated
vendored
133
Godeps/_workspace/src/code.google.com/p/mxk/go1/flowcontrol/io.go
generated
vendored
@@ -1,133 +0,0 @@
|
||||
//
|
||||
// Written by Maxim Khitrov (November 2012)
|
||||
//
|
||||
|
||||
package flowcontrol
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
// ErrLimit is returned by the Writer when a non-blocking write is short due to
|
||||
// the transfer rate limit.
|
||||
var ErrLimit = errors.New("flowcontrol: transfer rate limit exceeded")
|
||||
|
||||
// Limiter is implemented by the Reader and Writer to provide a consistent
|
||||
// interface for monitoring and controlling data transfer.
|
||||
type Limiter interface {
|
||||
Done() int64
|
||||
Status() Status
|
||||
SetTransferSize(bytes int64)
|
||||
SetLimit(new int64) (old int64)
|
||||
SetBlocking(new bool) (old bool)
|
||||
}
|
||||
|
||||
// Reader implements io.ReadCloser with a restriction on the rate of data
|
||||
// transfer.
|
||||
type Reader struct {
|
||||
io.Reader // Data source
|
||||
*Monitor // Flow control monitor
|
||||
|
||||
limit int64 // Rate limit in bytes per second (unlimited when <= 0)
|
||||
block bool // What to do when no new bytes can be read due to the limit
|
||||
}
|
||||
|
||||
// NewReader restricts all Read operations on r to limit bytes per second.
|
||||
func NewReader(r io.Reader, limit int64) *Reader {
|
||||
return &Reader{r, New(0, 0), limit, true}
|
||||
}
|
||||
|
||||
// Read reads up to len(p) bytes into p without exceeding the current transfer
|
||||
// rate limit. It returns (0, nil) immediately if r is non-blocking and no new
|
||||
// bytes can be read at this time.
|
||||
func (r *Reader) Read(p []byte) (n int, err error) {
|
||||
p = p[:r.Limit(len(p), r.limit, r.block)]
|
||||
if len(p) > 0 {
|
||||
n, err = r.IO(r.Reader.Read(p))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SetLimit changes the transfer rate limit to new bytes per second and returns
|
||||
// the previous setting.
|
||||
func (r *Reader) SetLimit(new int64) (old int64) {
|
||||
old, r.limit = r.limit, new
|
||||
return
|
||||
}
|
||||
|
||||
// SetBlocking changes the blocking behavior and returns the previous setting. A
|
||||
// Read call on a non-blocking reader returns immediately if no additional bytes
|
||||
// may be read at this time due to the rate limit.
|
||||
func (r *Reader) SetBlocking(new bool) (old bool) {
|
||||
old, r.block = r.block, new
|
||||
return
|
||||
}
|
||||
|
||||
// Close closes the underlying reader if it implements the io.Closer interface.
|
||||
func (r *Reader) Close() error {
|
||||
defer r.Done()
|
||||
if c, ok := r.Reader.(io.Closer); ok {
|
||||
return c.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Writer implements io.WriteCloser with a restriction on the rate of data
|
||||
// transfer.
|
||||
type Writer struct {
|
||||
io.Writer // Data destination
|
||||
*Monitor // Flow control monitor
|
||||
|
||||
limit int64 // Rate limit in bytes per second (unlimited when <= 0)
|
||||
block bool // What to do when no new bytes can be written due to the limit
|
||||
}
|
||||
|
||||
// NewWriter restricts all Write operations on w to limit bytes per second. The
|
||||
// transfer rate and the default blocking behavior (true) can be changed
|
||||
// directly on the returned *Writer.
|
||||
func NewWriter(w io.Writer, limit int64) *Writer {
|
||||
return &Writer{w, New(0, 0), limit, true}
|
||||
}
|
||||
|
||||
// Write writes len(p) bytes from p to the underlying data stream without
|
||||
// exceeding the current transfer rate limit. It returns (n, ErrLimit) if w is
|
||||
// non-blocking and no additional bytes can be written at this time.
|
||||
func (w *Writer) Write(p []byte) (n int, err error) {
|
||||
var c int
|
||||
for len(p) > 0 && err == nil {
|
||||
s := p[:w.Limit(len(p), w.limit, w.block)]
|
||||
if len(s) > 0 {
|
||||
c, err = w.IO(w.Writer.Write(s))
|
||||
} else {
|
||||
return n, ErrLimit
|
||||
}
|
||||
p = p[c:]
|
||||
n += c
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SetLimit changes the transfer rate limit to new bytes per second and returns
|
||||
// the previous setting.
|
||||
func (w *Writer) SetLimit(new int64) (old int64) {
|
||||
old, w.limit = w.limit, new
|
||||
return
|
||||
}
|
||||
|
||||
// SetBlocking changes the blocking behavior and returns the previous setting. A
|
||||
// Write call on a non-blocking writer returns as soon as no additional bytes
|
||||
// may be written at this time due to the rate limit.
|
||||
func (w *Writer) SetBlocking(new bool) (old bool) {
|
||||
old, w.block = w.block, new
|
||||
return
|
||||
}
|
||||
|
||||
// Close closes the underlying writer if it implements the io.Closer interface.
|
||||
func (w *Writer) Close() error {
|
||||
defer w.Done()
|
||||
if c, ok := w.Writer.(io.Closer); ok {
|
||||
return c.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
146
Godeps/_workspace/src/code.google.com/p/mxk/go1/flowcontrol/io_test.go
generated
vendored
146
Godeps/_workspace/src/code.google.com/p/mxk/go1/flowcontrol/io_test.go
generated
vendored
@@ -1,146 +0,0 @@
|
||||
//
|
||||
// Written by Maxim Khitrov (November 2012)
|
||||
//
|
||||
|
||||
package flowcontrol
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
_50ms = 50 * time.Millisecond
|
||||
_100ms = 100 * time.Millisecond
|
||||
_200ms = 200 * time.Millisecond
|
||||
_300ms = 300 * time.Millisecond
|
||||
_400ms = 400 * time.Millisecond
|
||||
_500ms = 500 * time.Millisecond
|
||||
)
|
||||
|
||||
func nextStatus(m *Monitor) Status {
|
||||
samples := m.samples
|
||||
for i := 0; i < 30; i++ {
|
||||
if s := m.Status(); s.Samples != samples {
|
||||
return s
|
||||
}
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
}
|
||||
return m.Status()
|
||||
}
|
||||
|
||||
func TestReader(t *testing.T) {
|
||||
in := make([]byte, 100)
|
||||
for i := range in {
|
||||
in[i] = byte(i)
|
||||
}
|
||||
b := make([]byte, 100)
|
||||
r := NewReader(bytes.NewReader(in), 100)
|
||||
start := time.Now()
|
||||
|
||||
// Make sure r implements Limiter
|
||||
_ = Limiter(r)
|
||||
|
||||
// 1st read of 10 bytes is performed immediately
|
||||
if n, err := r.Read(b); n != 10 || err != nil {
|
||||
t.Fatalf("r.Read(b) expected 10 (<nil>); got %v (%v)", n, err)
|
||||
} else if rt := time.Since(start); rt > _50ms {
|
||||
t.Fatalf("r.Read(b) took too long (%v)", rt)
|
||||
}
|
||||
|
||||
// No new Reads allowed in the current sample
|
||||
r.SetBlocking(false)
|
||||
if n, err := r.Read(b); n != 0 || err != nil {
|
||||
t.Fatalf("r.Read(b) expected 0 (<nil>); got %v (%v)", n, err)
|
||||
} else if rt := time.Since(start); rt > _50ms {
|
||||
t.Fatalf("r.Read(b) took too long (%v)", rt)
|
||||
}
|
||||
|
||||
status := [6]Status{0: r.Status()} // No samples in the first status
|
||||
|
||||
// 2nd read of 10 bytes blocks until the next sample
|
||||
r.SetBlocking(true)
|
||||
if n, err := r.Read(b[10:]); n != 10 || err != nil {
|
||||
t.Fatalf("r.Read(b[10:]) expected 10 (<nil>); got %v (%v)", n, err)
|
||||
} else if rt := time.Since(start); rt < _100ms {
|
||||
t.Fatalf("r.Read(b[10:]) returned ahead of time (%v)", rt)
|
||||
}
|
||||
|
||||
status[1] = r.Status() // 1st sample
|
||||
status[2] = nextStatus(r.Monitor) // 2nd sample
|
||||
status[3] = nextStatus(r.Monitor) // No activity for the 3rd sample
|
||||
|
||||
if n := r.Done(); n != 20 {
|
||||
t.Fatalf("r.Done() expected 20; got %v", n)
|
||||
}
|
||||
|
||||
status[4] = r.Status()
|
||||
status[5] = nextStatus(r.Monitor) // Timeout
|
||||
start = status[0].Start
|
||||
|
||||
// Active, Start, Duration, Idle, Bytes, Samples, InstRate, CurRate, AvgRate, PeakRate, BytesRem, TimeRem, Progress
|
||||
want := []Status{
|
||||
Status{true, start, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
Status{true, start, _100ms, 0, 10, 1, 100, 100, 100, 100, 0, 0, 0},
|
||||
Status{true, start, _200ms, _100ms, 20, 2, 100, 100, 100, 100, 0, 0, 0},
|
||||
Status{true, start, _300ms, _200ms, 20, 3, 0, 90, 67, 100, 0, 0, 0},
|
||||
Status{false, start, _300ms, 0, 20, 3, 0, 0, 67, 100, 0, 0, 0},
|
||||
Status{false, start, _300ms, 0, 20, 3, 0, 0, 67, 100, 0, 0, 0},
|
||||
}
|
||||
for i, s := range status {
|
||||
if !reflect.DeepEqual(&s, &want[i]) {
|
||||
t.Errorf("r.Status(%v) expected %v; got %v", i, want[i], s)
|
||||
}
|
||||
}
|
||||
if !bytes.Equal(b[:20], in[:20]) {
|
||||
t.Errorf("r.Read() input doesn't match output")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriter(t *testing.T) {
|
||||
b := make([]byte, 100)
|
||||
for i := range b {
|
||||
b[i] = byte(i)
|
||||
}
|
||||
w := NewWriter(&bytes.Buffer{}, 200)
|
||||
start := time.Now()
|
||||
|
||||
// Make sure w implements Limiter
|
||||
_ = Limiter(w)
|
||||
|
||||
// Non-blocking 20-byte write for the first sample returns ErrLimit
|
||||
w.SetBlocking(false)
|
||||
if n, err := w.Write(b); n != 20 || err != ErrLimit {
|
||||
t.Fatalf("w.Write(b) expected 20 (ErrLimit); got %v (%v)", n, err)
|
||||
} else if rt := time.Since(start); rt > _50ms {
|
||||
t.Fatalf("w.Write(b) took too long (%v)", rt)
|
||||
}
|
||||
|
||||
// Blocking 80-byte write
|
||||
w.SetBlocking(true)
|
||||
if n, err := w.Write(b[20:]); n != 80 || err != nil {
|
||||
t.Fatalf("w.Write(b[20:]) expected 80 (<nil>); got %v (%v)", n, err)
|
||||
} else if rt := time.Since(start); rt < _400ms {
|
||||
t.Fatalf("w.Write(b[20:]) returned ahead of time (%v)", rt)
|
||||
}
|
||||
|
||||
w.SetTransferSize(100)
|
||||
status := []Status{w.Status(), nextStatus(w.Monitor)}
|
||||
start = status[0].Start
|
||||
|
||||
// Active, Start, Duration, Idle, Bytes, Samples, InstRate, CurRate, AvgRate, PeakRate, BytesRem, TimeRem, Progress
|
||||
want := []Status{
|
||||
Status{true, start, _400ms, 0, 80, 4, 200, 200, 200, 200, 20, _100ms, 80000},
|
||||
Status{true, start, _500ms, _100ms, 100, 5, 200, 200, 200, 200, 0, 0, 100000},
|
||||
}
|
||||
for i, s := range status {
|
||||
if !reflect.DeepEqual(&s, &want[i]) {
|
||||
t.Errorf("w.Status(%v) expected %v; got %v", i, want[i], s)
|
||||
}
|
||||
}
|
||||
if !bytes.Equal(b, w.Writer.(*bytes.Buffer).Bytes()) {
|
||||
t.Errorf("w.Write() input doesn't match output")
|
||||
}
|
||||
}
|
||||
67
Godeps/_workspace/src/code.google.com/p/mxk/go1/flowcontrol/util.go
generated
vendored
67
Godeps/_workspace/src/code.google.com/p/mxk/go1/flowcontrol/util.go
generated
vendored
@@ -1,67 +0,0 @@
|
||||
//
|
||||
// Written by Maxim Khitrov (November 2012)
|
||||
//
|
||||
|
||||
package flowcontrol
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// clockRate is the resolution and precision of clock().
|
||||
const clockRate = 20 * time.Millisecond
|
||||
|
||||
// czero is the process start time rounded down to the nearest clockRate
|
||||
// increment.
|
||||
var czero = time.Duration(time.Now().UnixNano()) / clockRate * clockRate
|
||||
|
||||
// clock returns a low resolution timestamp relative to the process start time.
|
||||
func clock() time.Duration {
|
||||
return time.Duration(time.Now().UnixNano())/clockRate*clockRate - czero
|
||||
}
|
||||
|
||||
// clockToTime converts a clock() timestamp to an absolute time.Time value.
|
||||
func clockToTime(c time.Duration) time.Time {
|
||||
return time.Unix(0, int64(czero+c))
|
||||
}
|
||||
|
||||
// clockRound returns d rounded to the nearest clockRate increment.
|
||||
func clockRound(d time.Duration) time.Duration {
|
||||
return (d + clockRate>>1) / clockRate * clockRate
|
||||
}
|
||||
|
||||
// round returns x rounded to the nearest int64 (non-negative values only).
|
||||
func round(x float64) int64 {
|
||||
if _, frac := math.Modf(x); frac >= 0.5 {
|
||||
return int64(math.Ceil(x))
|
||||
}
|
||||
return int64(math.Floor(x))
|
||||
}
|
||||
|
||||
// Percent represents a percentage in increments of 1/1000th of a percent.
|
||||
type Percent uint32
|
||||
|
||||
// percentOf calculates what percent of the total is x.
|
||||
func percentOf(x, total float64) Percent {
|
||||
if x < 0 || total <= 0 {
|
||||
return 0
|
||||
} else if p := round(x / total * 1e5); p <= math.MaxUint32 {
|
||||
return Percent(p)
|
||||
}
|
||||
return Percent(math.MaxUint32)
|
||||
}
|
||||
|
||||
func (p Percent) Float() float64 {
|
||||
return float64(p) * 1e-3
|
||||
}
|
||||
|
||||
func (p Percent) String() string {
|
||||
var buf [12]byte
|
||||
b := strconv.AppendUint(buf[:0], uint64(p)/1000, 10)
|
||||
n := len(b)
|
||||
b = strconv.AppendUint(b, 1000+uint64(p)%1000, 10)
|
||||
b[n] = '.'
|
||||
return string(append(b, '%'))
|
||||
}
|
||||
1411
Godeps/_workspace/src/github.com/agl/ed25519/edwards25519/const.go
generated
vendored
1411
Godeps/_workspace/src/github.com/agl/ed25519/edwards25519/const.go
generated
vendored
File diff suppressed because it is too large
Load Diff
2127
Godeps/_workspace/src/github.com/agl/ed25519/edwards25519/edwards25519.go
generated
vendored
2127
Godeps/_workspace/src/github.com/agl/ed25519/edwards25519/edwards25519.go
generated
vendored
File diff suppressed because it is too large
Load Diff
6
Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml
generated
vendored
6
Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml
generated
vendored
@@ -1,6 +0,0 @@
|
||||
language: go
|
||||
go: 1.1
|
||||
|
||||
script:
|
||||
- go vet ./...
|
||||
- go test -v ./...
|
||||
21
Godeps/_workspace/src/github.com/codegangsta/cli/LICENSE
generated
vendored
21
Godeps/_workspace/src/github.com/codegangsta/cli/LICENSE
generated
vendored
@@ -1,21 +0,0 @@
|
||||
Copyright (C) 2013 Jeremy Saenz
|
||||
All Rights Reserved.
|
||||
|
||||
MIT LICENSE
|
||||
|
||||
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 AUTHORS OR
|
||||
COPYRIGHT HOLDERS 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.
|
||||
298
Godeps/_workspace/src/github.com/codegangsta/cli/README.md
generated
vendored
298
Godeps/_workspace/src/github.com/codegangsta/cli/README.md
generated
vendored
@@ -1,298 +0,0 @@
|
||||
[](https://travis-ci.org/codegangsta/cli)
|
||||
|
||||
# cli.go
|
||||
cli.go is simple, fast, and fun package for building command line apps in Go. The goal is to enable developers to write fast and distributable command line applications in an expressive way.
|
||||
|
||||
You can view the API docs here:
|
||||
http://godoc.org/github.com/codegangsta/cli
|
||||
|
||||
## Overview
|
||||
Command line apps are usually so tiny that there is absolutely no reason why your code should *not* be self-documenting. Things like generating help text and parsing command flags/options should not hinder productivity when writing a command line app.
|
||||
|
||||
**This is where cli.go comes into play.** cli.go makes command line programming fun, organized, and expressive!
|
||||
|
||||
## Installation
|
||||
Make sure you have a working Go environment (go 1.1+ is *required*). [See the install instructions](http://golang.org/doc/install.html).
|
||||
|
||||
To install `cli.go`, simply run:
|
||||
```
|
||||
$ go get github.com/codegangsta/cli
|
||||
```
|
||||
|
||||
Make sure your `PATH` includes to the `$GOPATH/bin` directory so your commands can be easily used:
|
||||
```
|
||||
export PATH=$PATH:$GOPATH/bin
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
One of the philosophies behind cli.go is that an API should be playful and full of discovery. So a cli.go app can be as little as one line of code in `main()`.
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cli.NewApp().Run(os.Args)
|
||||
}
|
||||
```
|
||||
|
||||
This app will run and show help text, but is not very useful. Let's give an action to execute and some help documentation:
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := cli.NewApp()
|
||||
app.Name = "boom"
|
||||
app.Usage = "make an explosive entrance"
|
||||
app.Action = func(c *cli.Context) {
|
||||
println("boom! I say!")
|
||||
}
|
||||
|
||||
app.Run(os.Args)
|
||||
}
|
||||
```
|
||||
|
||||
Running this already gives you a ton of functionality, plus support for things like subcommands and flags, which are covered below.
|
||||
|
||||
## Example
|
||||
|
||||
Being a programmer can be a lonely job. Thankfully by the power of automation that is not the case! Let's create a greeter app to fend off our demons of loneliness!
|
||||
|
||||
Start by creating a directory named `greet`, and within it, add a file, `greet.go` with the following code in it:
|
||||
|
||||
``` go
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := cli.NewApp()
|
||||
app.Name = "greet"
|
||||
app.Usage = "fight the loneliness!"
|
||||
app.Action = func(c *cli.Context) {
|
||||
println("Hello friend!")
|
||||
}
|
||||
|
||||
app.Run(os.Args)
|
||||
}
|
||||
```
|
||||
|
||||
Install our command to the `$GOPATH/bin` directory:
|
||||
|
||||
```
|
||||
$ go install
|
||||
```
|
||||
|
||||
Finally run our new command:
|
||||
|
||||
```
|
||||
$ greet
|
||||
Hello friend!
|
||||
```
|
||||
|
||||
cli.go also generates some bitchass help text:
|
||||
```
|
||||
$ greet help
|
||||
NAME:
|
||||
greet - fight the loneliness!
|
||||
|
||||
USAGE:
|
||||
greet [global options] command [command options] [arguments...]
|
||||
|
||||
VERSION:
|
||||
0.0.0
|
||||
|
||||
COMMANDS:
|
||||
help, h Shows a list of commands or help for one command
|
||||
|
||||
GLOBAL OPTIONS
|
||||
--version Shows version information
|
||||
```
|
||||
|
||||
### Arguments
|
||||
You can lookup arguments by calling the `Args` function on `cli.Context`.
|
||||
|
||||
``` go
|
||||
...
|
||||
app.Action = func(c *cli.Context) {
|
||||
println("Hello", c.Args()[0])
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
### Flags
|
||||
Setting and querying flags is simple.
|
||||
``` go
|
||||
...
|
||||
app.Flags = []cli.Flag {
|
||||
cli.StringFlag{
|
||||
Name: "lang",
|
||||
Value: "english",
|
||||
Usage: "language for the greeting",
|
||||
},
|
||||
}
|
||||
app.Action = func(c *cli.Context) {
|
||||
name := "someone"
|
||||
if len(c.Args()) > 0 {
|
||||
name = c.Args()[0]
|
||||
}
|
||||
if c.String("lang") == "spanish" {
|
||||
println("Hola", name)
|
||||
} else {
|
||||
println("Hello", name)
|
||||
}
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
#### Alternate Names
|
||||
|
||||
You can set alternate (or short) names for flags by providing a comma-delimited list for the `Name`. e.g.
|
||||
|
||||
``` go
|
||||
app.Flags = []cli.Flag {
|
||||
cli.StringFlag{
|
||||
Name: "lang, l",
|
||||
Value: "english",
|
||||
Usage: "language for the greeting",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
That flag can then be set with `--lang spanish` or `-l spanish`. Note that giving two different forms of the same flag in the same command invocation is an error.
|
||||
|
||||
#### Values from the Environment
|
||||
|
||||
You can also have the default value set from the environment via `EnvVar`. e.g.
|
||||
|
||||
``` go
|
||||
app.Flags = []cli.Flag {
|
||||
cli.StringFlag{
|
||||
Name: "lang, l",
|
||||
Value: "english",
|
||||
Usage: "language for the greeting",
|
||||
EnvVar: "APP_LANG",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
The `EnvVar` may also be given as a comma-delimited "cascade", where the first environment variable that resolves is used as the default.
|
||||
|
||||
``` go
|
||||
app.Flags = []cli.Flag {
|
||||
cli.StringFlag{
|
||||
Name: "lang, l",
|
||||
Value: "english",
|
||||
Usage: "language for the greeting",
|
||||
EnvVar: "LEGACY_COMPAT_LANG,APP_LANG,LANG",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Subcommands
|
||||
|
||||
Subcommands can be defined for a more git-like command line app.
|
||||
```go
|
||||
...
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "add",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "add a task to the list",
|
||||
Action: func(c *cli.Context) {
|
||||
println("added task: ", c.Args().First())
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "complete",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "complete a task on the list",
|
||||
Action: func(c *cli.Context) {
|
||||
println("completed task: ", c.Args().First())
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "template",
|
||||
Aliases: []string{"r"},
|
||||
Usage: "options for task templates",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "add",
|
||||
Usage: "add a new template",
|
||||
Action: func(c *cli.Context) {
|
||||
println("new task template: ", c.Args().First())
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "remove",
|
||||
Usage: "remove an existing template",
|
||||
Action: func(c *cli.Context) {
|
||||
println("removed task template: ", c.Args().First())
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
### Bash Completion
|
||||
|
||||
You can enable completion commands by setting the `EnableBashCompletion`
|
||||
flag on the `App` object. By default, this setting will only auto-complete to
|
||||
show an app's subcommands, but you can write your own completion methods for
|
||||
the App or its subcommands.
|
||||
```go
|
||||
...
|
||||
var tasks = []string{"cook", "clean", "laundry", "eat", "sleep", "code"}
|
||||
app := cli.NewApp()
|
||||
app.EnableBashCompletion = true
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "complete",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "complete a task on the list",
|
||||
Action: func(c *cli.Context) {
|
||||
println("completed task: ", c.Args().First())
|
||||
},
|
||||
BashComplete: func(c *cli.Context) {
|
||||
// This will complete if no args are passed
|
||||
if len(c.Args()) > 0 {
|
||||
return
|
||||
}
|
||||
for _, t := range tasks {
|
||||
fmt.Println(t)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
#### To Enable
|
||||
|
||||
Source the `autocomplete/bash_autocomplete` file in your `.bashrc` file while
|
||||
setting the `PROG` variable to the name of your program:
|
||||
|
||||
`PROG=myprogram source /.../cli/autocomplete/bash_autocomplete`
|
||||
|
||||
|
||||
## Contribution Guidelines
|
||||
Feel free to put up a pull request to fix a bug or maybe add a feature. I will give it a code review and make sure that it does not break backwards compatibility. If I or any other collaborators agree that it is in line with the vision of the project, we will work with you to get the code into a mergeable state and merge it into the master branch.
|
||||
|
||||
If you have contributed something significant to the project, I will most likely add you as a collaborator. As a collaborator you are given the ability to merge others pull requests. It is very important that new code does not break existing code, so be careful about what code you do choose to merge. If you have any questions feel free to link @codegangsta to the issue in question and we can review it together.
|
||||
|
||||
If you feel like you have contributed to the project but have not yet been added as a collaborator, I probably forgot to add you. Hit @codegangsta up over email and we will get it figured out.
|
||||
298
Godeps/_workspace/src/github.com/codegangsta/cli/app.go
generated
vendored
298
Godeps/_workspace/src/github.com/codegangsta/cli/app.go
generated
vendored
@@ -1,298 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// App is the main structure of a cli application. It is recomended that
|
||||
// and app be created with the cli.NewApp() function
|
||||
type App struct {
|
||||
// The name of the program. Defaults to os.Args[0]
|
||||
Name string
|
||||
// Description of the program.
|
||||
Usage string
|
||||
// Version of the program
|
||||
Version string
|
||||
// List of commands to execute
|
||||
Commands []Command
|
||||
// List of flags to parse
|
||||
Flags []Flag
|
||||
// Boolean to enable bash completion commands
|
||||
EnableBashCompletion bool
|
||||
// Boolean to hide built-in help command
|
||||
HideHelp bool
|
||||
// Boolean to hide built-in version flag
|
||||
HideVersion bool
|
||||
// An action to execute when the bash-completion flag is set
|
||||
BashComplete func(context *Context)
|
||||
// An action to execute before any subcommands are run, but after the context is ready
|
||||
// If a non-nil error is returned, no subcommands are run
|
||||
Before func(context *Context) error
|
||||
// An action to execute after any subcommands are run, but after the subcommand has finished
|
||||
// It is run even if Action() panics
|
||||
After func(context *Context) error
|
||||
// The action to execute when no subcommands are specified
|
||||
Action func(context *Context)
|
||||
// Execute this function if the proper command cannot be found
|
||||
CommandNotFound func(context *Context, command string)
|
||||
// Compilation date
|
||||
Compiled time.Time
|
||||
// List of all authors who contributed
|
||||
Authors []Author
|
||||
// Name of Author (Note: Use App.Authors, this is deprecated)
|
||||
Author string
|
||||
// Email of Author (Note: Use App.Authors, this is deprecated)
|
||||
Email string
|
||||
// Writer writer to write output to
|
||||
Writer io.Writer
|
||||
}
|
||||
|
||||
// Tries to find out when this binary was compiled.
|
||||
// Returns the current time if it fails to find it.
|
||||
func compileTime() time.Time {
|
||||
info, err := os.Stat(os.Args[0])
|
||||
if err != nil {
|
||||
return time.Now()
|
||||
}
|
||||
return info.ModTime()
|
||||
}
|
||||
|
||||
// Creates a new cli Application with some reasonable defaults for Name, Usage, Version and Action.
|
||||
func NewApp() *App {
|
||||
return &App{
|
||||
Name: os.Args[0],
|
||||
Usage: "A new cli application",
|
||||
Version: "0.0.0",
|
||||
BashComplete: DefaultAppComplete,
|
||||
Action: helpCommand.Action,
|
||||
Compiled: compileTime(),
|
||||
Writer: os.Stdout,
|
||||
}
|
||||
}
|
||||
|
||||
// Entry point to the cli app. Parses the arguments slice and routes to the proper flag/args combination
|
||||
func (a *App) Run(arguments []string) (err error) {
|
||||
if a.Author != "" || a.Email != "" {
|
||||
a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email})
|
||||
}
|
||||
|
||||
// append help to commands
|
||||
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
|
||||
a.Commands = append(a.Commands, helpCommand)
|
||||
if (HelpFlag != BoolFlag{}) {
|
||||
a.appendFlag(HelpFlag)
|
||||
}
|
||||
}
|
||||
|
||||
//append version/help flags
|
||||
if a.EnableBashCompletion {
|
||||
a.appendFlag(BashCompletionFlag)
|
||||
}
|
||||
|
||||
if !a.HideVersion {
|
||||
a.appendFlag(VersionFlag)
|
||||
}
|
||||
|
||||
// parse flags
|
||||
set := flagSet(a.Name, a.Flags)
|
||||
set.SetOutput(ioutil.Discard)
|
||||
err = set.Parse(arguments[1:])
|
||||
nerr := normalizeFlags(a.Flags, set)
|
||||
if nerr != nil {
|
||||
fmt.Fprintln(a.Writer, nerr)
|
||||
context := NewContext(a, set, set)
|
||||
ShowAppHelp(context)
|
||||
fmt.Fprintln(a.Writer)
|
||||
return nerr
|
||||
}
|
||||
context := NewContext(a, set, set)
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintf(a.Writer, "Incorrect Usage.\n\n")
|
||||
ShowAppHelp(context)
|
||||
fmt.Fprintln(a.Writer)
|
||||
return err
|
||||
}
|
||||
|
||||
if checkCompletions(context) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if checkHelp(context) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if checkVersion(context) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if a.After != nil {
|
||||
defer func() {
|
||||
// err is always nil here.
|
||||
// There is a check to see if it is non-nil
|
||||
// just few lines before.
|
||||
err = a.After(context)
|
||||
}()
|
||||
}
|
||||
|
||||
if a.Before != nil {
|
||||
err := a.Before(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
args := context.Args()
|
||||
if args.Present() {
|
||||
name := args.First()
|
||||
c := a.Command(name)
|
||||
if c != nil {
|
||||
return c.Run(context)
|
||||
}
|
||||
}
|
||||
|
||||
// Run default Action
|
||||
a.Action(context)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Another entry point to the cli app, takes care of passing arguments and error handling
|
||||
func (a *App) RunAndExitOnError() {
|
||||
if err := a.Run(os.Args); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Invokes the subcommand given the context, parses ctx.Args() to generate command-specific flags
|
||||
func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
||||
// append help to commands
|
||||
if len(a.Commands) > 0 {
|
||||
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
|
||||
a.Commands = append(a.Commands, helpCommand)
|
||||
if (HelpFlag != BoolFlag{}) {
|
||||
a.appendFlag(HelpFlag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// append flags
|
||||
if a.EnableBashCompletion {
|
||||
a.appendFlag(BashCompletionFlag)
|
||||
}
|
||||
|
||||
// parse flags
|
||||
set := flagSet(a.Name, a.Flags)
|
||||
set.SetOutput(ioutil.Discard)
|
||||
err = set.Parse(ctx.Args().Tail())
|
||||
nerr := normalizeFlags(a.Flags, set)
|
||||
context := NewContext(a, set, ctx.globalSet)
|
||||
|
||||
if nerr != nil {
|
||||
fmt.Fprintln(a.Writer, nerr)
|
||||
if len(a.Commands) > 0 {
|
||||
ShowSubcommandHelp(context)
|
||||
} else {
|
||||
ShowCommandHelp(ctx, context.Args().First())
|
||||
}
|
||||
fmt.Fprintln(a.Writer)
|
||||
return nerr
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintf(a.Writer, "Incorrect Usage.\n\n")
|
||||
ShowSubcommandHelp(context)
|
||||
return err
|
||||
}
|
||||
|
||||
if checkCompletions(context) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(a.Commands) > 0 {
|
||||
if checkSubcommandHelp(context) {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
if checkCommandHelp(ctx, context.Args().First()) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if a.After != nil {
|
||||
defer func() {
|
||||
// err is always nil here.
|
||||
// There is a check to see if it is non-nil
|
||||
// just few lines before.
|
||||
err = a.After(context)
|
||||
}()
|
||||
}
|
||||
|
||||
if a.Before != nil {
|
||||
err := a.Before(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
args := context.Args()
|
||||
if args.Present() {
|
||||
name := args.First()
|
||||
c := a.Command(name)
|
||||
if c != nil {
|
||||
return c.Run(context)
|
||||
}
|
||||
}
|
||||
|
||||
// Run default Action
|
||||
a.Action(context)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns the named command on App. Returns nil if the command does not exist
|
||||
func (a *App) Command(name string) *Command {
|
||||
for _, c := range a.Commands {
|
||||
if c.HasName(name) {
|
||||
return &c
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) hasFlag(flag Flag) bool {
|
||||
for _, f := range a.Flags {
|
||||
if flag == f {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (a *App) appendFlag(flag Flag) {
|
||||
if !a.hasFlag(flag) {
|
||||
a.Flags = append(a.Flags, flag)
|
||||
}
|
||||
}
|
||||
|
||||
// Author represents someone who has contributed to a cli project.
|
||||
type Author struct {
|
||||
Name string // The Authors name
|
||||
Email string // The Authors email
|
||||
}
|
||||
|
||||
// String makes Author comply to the Stringer interface, to allow an easy print in the templating process
|
||||
func (a Author) String() string {
|
||||
e := ""
|
||||
if a.Email != "" {
|
||||
e = "<" + a.Email + "> "
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v %v", a.Name, e)
|
||||
}
|
||||
679
Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go
generated
vendored
679
Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go
generated
vendored
@@ -1,679 +0,0 @@
|
||||
package cli_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/tendermint/tendermint/Godeps/_workspace/src/github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
func ExampleApp() {
|
||||
// set args for examples sake
|
||||
os.Args = []string{"greet", "--name", "Jeremy"}
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Name = "greet"
|
||||
app.Flags = []cli.Flag{
|
||||
cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
|
||||
}
|
||||
app.Action = func(c *cli.Context) {
|
||||
fmt.Printf("Hello %v\n", c.String("name"))
|
||||
}
|
||||
app.Author = "Harrison"
|
||||
app.Email = "harrison@lolwut.com"
|
||||
app.Authors = []cli.Author{cli.Author{Name: "Oliver Allen", Email: "oliver@toyshop.com"}}
|
||||
app.Run(os.Args)
|
||||
// Output:
|
||||
// Hello Jeremy
|
||||
}
|
||||
|
||||
func ExampleAppSubcommand() {
|
||||
// set args for examples sake
|
||||
os.Args = []string{"say", "hi", "english", "--name", "Jeremy"}
|
||||
app := cli.NewApp()
|
||||
app.Name = "say"
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "hello",
|
||||
Aliases: []string{"hi"},
|
||||
Usage: "use it to see a description",
|
||||
Description: "This is how we describe hello the function",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "english",
|
||||
Aliases: []string{"en"},
|
||||
Usage: "sends a greeting in english",
|
||||
Description: "greets someone in english",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "name",
|
||||
Value: "Bob",
|
||||
Usage: "Name of the person to greet",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) {
|
||||
fmt.Println("Hello,", c.String("name"))
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Run(os.Args)
|
||||
// Output:
|
||||
// Hello, Jeremy
|
||||
}
|
||||
|
||||
func ExampleAppHelp() {
|
||||
// set args for examples sake
|
||||
os.Args = []string{"greet", "h", "describeit"}
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Name = "greet"
|
||||
app.Flags = []cli.Flag{
|
||||
cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
|
||||
}
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "describeit",
|
||||
Aliases: []string{"d"},
|
||||
Usage: "use it to see a description",
|
||||
Description: "This is how we describe describeit the function",
|
||||
Action: func(c *cli.Context) {
|
||||
fmt.Printf("i like to describe things")
|
||||
},
|
||||
},
|
||||
}
|
||||
app.Run(os.Args)
|
||||
// Output:
|
||||
// NAME:
|
||||
// describeit - use it to see a description
|
||||
//
|
||||
// USAGE:
|
||||
// command describeit [arguments...]
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// This is how we describe describeit the function
|
||||
}
|
||||
|
||||
func ExampleAppBashComplete() {
|
||||
// set args for examples sake
|
||||
os.Args = []string{"greet", "--generate-bash-completion"}
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Name = "greet"
|
||||
app.EnableBashCompletion = true
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "describeit",
|
||||
Aliases: []string{"d"},
|
||||
Usage: "use it to see a description",
|
||||
Description: "This is how we describe describeit the function",
|
||||
Action: func(c *cli.Context) {
|
||||
fmt.Printf("i like to describe things")
|
||||
},
|
||||
}, {
|
||||
Name: "next",
|
||||
Usage: "next example",
|
||||
Description: "more stuff to see when generating bash completion",
|
||||
Action: func(c *cli.Context) {
|
||||
fmt.Printf("the next example")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Run(os.Args)
|
||||
// Output:
|
||||
// describeit
|
||||
// d
|
||||
// next
|
||||
// help
|
||||
// h
|
||||
}
|
||||
|
||||
func TestApp_Run(t *testing.T) {
|
||||
s := ""
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Action = func(c *cli.Context) {
|
||||
s = s + c.Args().First()
|
||||
}
|
||||
|
||||
err := app.Run([]string{"command", "foo"})
|
||||
expect(t, err, nil)
|
||||
err = app.Run([]string{"command", "bar"})
|
||||
expect(t, err, nil)
|
||||
expect(t, s, "foobar")
|
||||
}
|
||||
|
||||
var commandAppTests = []struct {
|
||||
name string
|
||||
expected bool
|
||||
}{
|
||||
{"foobar", true},
|
||||
{"batbaz", true},
|
||||
{"b", true},
|
||||
{"f", true},
|
||||
{"bat", false},
|
||||
{"nothing", false},
|
||||
}
|
||||
|
||||
func TestApp_Command(t *testing.T) {
|
||||
app := cli.NewApp()
|
||||
fooCommand := cli.Command{Name: "foobar", Aliases: []string{"f"}}
|
||||
batCommand := cli.Command{Name: "batbaz", Aliases: []string{"b"}}
|
||||
app.Commands = []cli.Command{
|
||||
fooCommand,
|
||||
batCommand,
|
||||
}
|
||||
|
||||
for _, test := range commandAppTests {
|
||||
expect(t, app.Command(test.name) != nil, test.expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApp_CommandWithArgBeforeFlags(t *testing.T) {
|
||||
var parsedOption, firstArg string
|
||||
|
||||
app := cli.NewApp()
|
||||
command := cli.Command{
|
||||
Name: "cmd",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{Name: "option", Value: "", Usage: "some option"},
|
||||
},
|
||||
Action: func(c *cli.Context) {
|
||||
parsedOption = c.String("option")
|
||||
firstArg = c.Args().First()
|
||||
},
|
||||
}
|
||||
app.Commands = []cli.Command{command}
|
||||
|
||||
app.Run([]string{"", "cmd", "my-arg", "--option", "my-option"})
|
||||
|
||||
expect(t, parsedOption, "my-option")
|
||||
expect(t, firstArg, "my-arg")
|
||||
}
|
||||
|
||||
func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
|
||||
var context *cli.Context
|
||||
|
||||
a := cli.NewApp()
|
||||
a.Commands = []cli.Command{
|
||||
{
|
||||
Name: "foo",
|
||||
Action: func(c *cli.Context) {
|
||||
context = c
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "lang",
|
||||
Value: "english",
|
||||
Usage: "language for the greeting",
|
||||
},
|
||||
},
|
||||
Before: func(_ *cli.Context) error { return nil },
|
||||
},
|
||||
}
|
||||
a.Run([]string{"", "foo", "--lang", "spanish", "abcd"})
|
||||
|
||||
expect(t, context.Args().Get(0), "abcd")
|
||||
expect(t, context.String("lang"), "spanish")
|
||||
}
|
||||
|
||||
func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
|
||||
var parsedOption string
|
||||
var args []string
|
||||
|
||||
app := cli.NewApp()
|
||||
command := cli.Command{
|
||||
Name: "cmd",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{Name: "option", Value: "", Usage: "some option"},
|
||||
},
|
||||
Action: func(c *cli.Context) {
|
||||
parsedOption = c.String("option")
|
||||
args = c.Args()
|
||||
},
|
||||
}
|
||||
app.Commands = []cli.Command{command}
|
||||
|
||||
app.Run([]string{"", "cmd", "my-arg", "--option", "my-option", "--", "--notARealFlag"})
|
||||
|
||||
expect(t, parsedOption, "my-option")
|
||||
expect(t, args[0], "my-arg")
|
||||
expect(t, args[1], "--")
|
||||
expect(t, args[2], "--notARealFlag")
|
||||
}
|
||||
|
||||
func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) {
|
||||
var args []string
|
||||
|
||||
app := cli.NewApp()
|
||||
command := cli.Command{
|
||||
Name: "cmd",
|
||||
Action: func(c *cli.Context) {
|
||||
args = c.Args()
|
||||
},
|
||||
}
|
||||
app.Commands = []cli.Command{command}
|
||||
|
||||
app.Run([]string{"", "cmd", "my-arg", "--", "notAFlagAtAll"})
|
||||
|
||||
expect(t, args[0], "my-arg")
|
||||
expect(t, args[1], "--")
|
||||
expect(t, args[2], "notAFlagAtAll")
|
||||
}
|
||||
|
||||
func TestApp_Float64Flag(t *testing.T) {
|
||||
var meters float64
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Flags = []cli.Flag{
|
||||
cli.Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"},
|
||||
}
|
||||
app.Action = func(c *cli.Context) {
|
||||
meters = c.Float64("height")
|
||||
}
|
||||
|
||||
app.Run([]string{"", "--height", "1.93"})
|
||||
expect(t, meters, 1.93)
|
||||
}
|
||||
|
||||
func TestApp_ParseSliceFlags(t *testing.T) {
|
||||
var parsedOption, firstArg string
|
||||
var parsedIntSlice []int
|
||||
var parsedStringSlice []string
|
||||
|
||||
app := cli.NewApp()
|
||||
command := cli.Command{
|
||||
Name: "cmd",
|
||||
Flags: []cli.Flag{
|
||||
cli.IntSliceFlag{Name: "p", Value: &cli.IntSlice{}, Usage: "set one or more ip addr"},
|
||||
cli.StringSliceFlag{Name: "ip", Value: &cli.StringSlice{}, Usage: "set one or more ports to open"},
|
||||
},
|
||||
Action: func(c *cli.Context) {
|
||||
parsedIntSlice = c.IntSlice("p")
|
||||
parsedStringSlice = c.StringSlice("ip")
|
||||
parsedOption = c.String("option")
|
||||
firstArg = c.Args().First()
|
||||
},
|
||||
}
|
||||
app.Commands = []cli.Command{command}
|
||||
|
||||
app.Run([]string{"", "cmd", "my-arg", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4"})
|
||||
|
||||
IntsEquals := func(a, b []int) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, v := range a {
|
||||
if v != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
StrsEquals := func(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, v := range a {
|
||||
if v != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
var expectedIntSlice = []int{22, 80}
|
||||
var expectedStringSlice = []string{"8.8.8.8", "8.8.4.4"}
|
||||
|
||||
if !IntsEquals(parsedIntSlice, expectedIntSlice) {
|
||||
t.Errorf("%v does not match %v", parsedIntSlice, expectedIntSlice)
|
||||
}
|
||||
|
||||
if !StrsEquals(parsedStringSlice, expectedStringSlice) {
|
||||
t.Errorf("%v does not match %v", parsedStringSlice, expectedStringSlice)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApp_DefaultStdout(t *testing.T) {
|
||||
app := cli.NewApp()
|
||||
|
||||
if app.Writer != os.Stdout {
|
||||
t.Error("Default output writer not set.")
|
||||
}
|
||||
}
|
||||
|
||||
type mockWriter struct {
|
||||
written []byte
|
||||
}
|
||||
|
||||
func (fw *mockWriter) Write(p []byte) (n int, err error) {
|
||||
if fw.written == nil {
|
||||
fw.written = p
|
||||
} else {
|
||||
fw.written = append(fw.written, p...)
|
||||
}
|
||||
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (fw *mockWriter) GetWritten() (b []byte) {
|
||||
return fw.written
|
||||
}
|
||||
|
||||
func TestApp_SetStdout(t *testing.T) {
|
||||
w := &mockWriter{}
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Name = "test"
|
||||
app.Writer = w
|
||||
|
||||
err := app.Run([]string{"help"})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Run error: %s", err)
|
||||
}
|
||||
|
||||
if len(w.written) == 0 {
|
||||
t.Error("App did not write output to desired writer.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApp_BeforeFunc(t *testing.T) {
|
||||
beforeRun, subcommandRun := false, false
|
||||
beforeError := fmt.Errorf("fail")
|
||||
var err error
|
||||
|
||||
app := cli.NewApp()
|
||||
|
||||
app.Before = func(c *cli.Context) error {
|
||||
beforeRun = true
|
||||
s := c.String("opt")
|
||||
if s == "fail" {
|
||||
return beforeError
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
app.Commands = []cli.Command{
|
||||
cli.Command{
|
||||
Name: "sub",
|
||||
Action: func(c *cli.Context) {
|
||||
subcommandRun = true
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Flags = []cli.Flag{
|
||||
cli.StringFlag{Name: "opt"},
|
||||
}
|
||||
|
||||
// run with the Before() func succeeding
|
||||
err = app.Run([]string{"command", "--opt", "succeed", "sub"})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Run error: %s", err)
|
||||
}
|
||||
|
||||
if beforeRun == false {
|
||||
t.Errorf("Before() not executed when expected")
|
||||
}
|
||||
|
||||
if subcommandRun == false {
|
||||
t.Errorf("Subcommand not executed when expected")
|
||||
}
|
||||
|
||||
// reset
|
||||
beforeRun, subcommandRun = false, false
|
||||
|
||||
// run with the Before() func failing
|
||||
err = app.Run([]string{"command", "--opt", "fail", "sub"})
|
||||
|
||||
// should be the same error produced by the Before func
|
||||
if err != beforeError {
|
||||
t.Errorf("Run error expected, but not received")
|
||||
}
|
||||
|
||||
if beforeRun == false {
|
||||
t.Errorf("Before() not executed when expected")
|
||||
}
|
||||
|
||||
if subcommandRun == true {
|
||||
t.Errorf("Subcommand executed when NOT expected")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestApp_AfterFunc(t *testing.T) {
|
||||
afterRun, subcommandRun := false, false
|
||||
afterError := fmt.Errorf("fail")
|
||||
var err error
|
||||
|
||||
app := cli.NewApp()
|
||||
|
||||
app.After = func(c *cli.Context) error {
|
||||
afterRun = true
|
||||
s := c.String("opt")
|
||||
if s == "fail" {
|
||||
return afterError
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
app.Commands = []cli.Command{
|
||||
cli.Command{
|
||||
Name: "sub",
|
||||
Action: func(c *cli.Context) {
|
||||
subcommandRun = true
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Flags = []cli.Flag{
|
||||
cli.StringFlag{Name: "opt"},
|
||||
}
|
||||
|
||||
// run with the After() func succeeding
|
||||
err = app.Run([]string{"command", "--opt", "succeed", "sub"})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Run error: %s", err)
|
||||
}
|
||||
|
||||
if afterRun == false {
|
||||
t.Errorf("After() not executed when expected")
|
||||
}
|
||||
|
||||
if subcommandRun == false {
|
||||
t.Errorf("Subcommand not executed when expected")
|
||||
}
|
||||
|
||||
// reset
|
||||
afterRun, subcommandRun = false, false
|
||||
|
||||
// run with the Before() func failing
|
||||
err = app.Run([]string{"command", "--opt", "fail", "sub"})
|
||||
|
||||
// should be the same error produced by the Before func
|
||||
if err != afterError {
|
||||
t.Errorf("Run error expected, but not received")
|
||||
}
|
||||
|
||||
if afterRun == false {
|
||||
t.Errorf("After() not executed when expected")
|
||||
}
|
||||
|
||||
if subcommandRun == false {
|
||||
t.Errorf("Subcommand not executed when expected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppNoHelpFlag(t *testing.T) {
|
||||
oldFlag := cli.HelpFlag
|
||||
defer func() {
|
||||
cli.HelpFlag = oldFlag
|
||||
}()
|
||||
|
||||
cli.HelpFlag = cli.BoolFlag{}
|
||||
|
||||
app := cli.NewApp()
|
||||
err := app.Run([]string{"test", "-h"})
|
||||
|
||||
if err != flag.ErrHelp {
|
||||
t.Errorf("expected error about missing help flag, but got: %s (%T)", err, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppHelpPrinter(t *testing.T) {
|
||||
oldPrinter := cli.HelpPrinter
|
||||
defer func() {
|
||||
cli.HelpPrinter = oldPrinter
|
||||
}()
|
||||
|
||||
var wasCalled = false
|
||||
cli.HelpPrinter = func(w io.Writer, template string, data interface{}) {
|
||||
wasCalled = true
|
||||
}
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Run([]string{"-h"})
|
||||
|
||||
if wasCalled == false {
|
||||
t.Errorf("Help printer expected to be called, but was not")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppVersionPrinter(t *testing.T) {
|
||||
oldPrinter := cli.VersionPrinter
|
||||
defer func() {
|
||||
cli.VersionPrinter = oldPrinter
|
||||
}()
|
||||
|
||||
var wasCalled = false
|
||||
cli.VersionPrinter = func(c *cli.Context) {
|
||||
wasCalled = true
|
||||
}
|
||||
|
||||
app := cli.NewApp()
|
||||
ctx := cli.NewContext(app, nil, nil)
|
||||
cli.ShowVersion(ctx)
|
||||
|
||||
if wasCalled == false {
|
||||
t.Errorf("Version printer expected to be called, but was not")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppCommandNotFound(t *testing.T) {
|
||||
beforeRun, subcommandRun := false, false
|
||||
app := cli.NewApp()
|
||||
|
||||
app.CommandNotFound = func(c *cli.Context, command string) {
|
||||
beforeRun = true
|
||||
}
|
||||
|
||||
app.Commands = []cli.Command{
|
||||
cli.Command{
|
||||
Name: "bar",
|
||||
Action: func(c *cli.Context) {
|
||||
subcommandRun = true
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Run([]string{"command", "foo"})
|
||||
|
||||
expect(t, beforeRun, true)
|
||||
expect(t, subcommandRun, false)
|
||||
}
|
||||
|
||||
func TestGlobalFlagsInSubcommands(t *testing.T) {
|
||||
subcommandRun := false
|
||||
app := cli.NewApp()
|
||||
|
||||
app.Flags = []cli.Flag{
|
||||
cli.BoolFlag{Name: "debug, d", Usage: "Enable debugging"},
|
||||
}
|
||||
|
||||
app.Commands = []cli.Command{
|
||||
cli.Command{
|
||||
Name: "foo",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "bar",
|
||||
Action: func(c *cli.Context) {
|
||||
if c.GlobalBool("debug") {
|
||||
subcommandRun = true
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Run([]string{"command", "-d", "foo", "bar"})
|
||||
|
||||
expect(t, subcommandRun, true)
|
||||
}
|
||||
|
||||
func TestApp_Run_CommandWithSubcommandHasHelpTopic(t *testing.T) {
|
||||
var subcommandHelpTopics = [][]string{
|
||||
{"command", "foo", "--help"},
|
||||
{"command", "foo", "-h"},
|
||||
{"command", "foo", "help"},
|
||||
}
|
||||
|
||||
for _, flagSet := range subcommandHelpTopics {
|
||||
t.Logf("==> checking with flags %v", flagSet)
|
||||
|
||||
app := cli.NewApp()
|
||||
buf := new(bytes.Buffer)
|
||||
app.Writer = buf
|
||||
|
||||
subCmdBar := cli.Command{
|
||||
Name: "bar",
|
||||
Usage: "does bar things",
|
||||
}
|
||||
subCmdBaz := cli.Command{
|
||||
Name: "baz",
|
||||
Usage: "does baz things",
|
||||
}
|
||||
cmd := cli.Command{
|
||||
Name: "foo",
|
||||
Description: "descriptive wall of text about how it does foo things",
|
||||
Subcommands: []cli.Command{subCmdBar, subCmdBaz},
|
||||
}
|
||||
|
||||
app.Commands = []cli.Command{cmd}
|
||||
err := app.Run(flagSet)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
output := buf.String()
|
||||
t.Logf("output: %q\n", buf.Bytes())
|
||||
|
||||
if strings.Contains(output, "No help topic for") {
|
||||
t.Errorf("expect a help topic, got none: \n%q", output)
|
||||
}
|
||||
|
||||
for _, shouldContain := range []string{
|
||||
cmd.Name, cmd.Description,
|
||||
subCmdBar.Name, subCmdBar.Usage,
|
||||
subCmdBaz.Name, subCmdBaz.Usage,
|
||||
} {
|
||||
if !strings.Contains(output, shouldContain) {
|
||||
t.Errorf("want help to contain %q, did not: \n%q", shouldContain, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete
generated
vendored
13
Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete
generated
vendored
@@ -1,13 +0,0 @@
|
||||
#! /bin/bash
|
||||
|
||||
_cli_bash_autocomplete() {
|
||||
local cur prev opts base
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
}
|
||||
|
||||
complete -F _cli_bash_autocomplete $PROG
|
||||
5
Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/zsh_autocomplete
generated
vendored
5
Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/zsh_autocomplete
generated
vendored
@@ -1,5 +0,0 @@
|
||||
autoload -U compinit && compinit
|
||||
autoload -U bashcompinit && bashcompinit
|
||||
|
||||
script_dir=$(dirname $0)
|
||||
source ${script_dir}/bash_autocomplete
|
||||
19
Godeps/_workspace/src/github.com/codegangsta/cli/cli.go
generated
vendored
19
Godeps/_workspace/src/github.com/codegangsta/cli/cli.go
generated
vendored
@@ -1,19 +0,0 @@
|
||||
// Package cli provides a minimal framework for creating and organizing command line
|
||||
// Go applications. cli is designed to be easy to understand and write, the most simple
|
||||
// cli application can be written as follows:
|
||||
// func main() {
|
||||
// cli.NewApp().Run(os.Args)
|
||||
// }
|
||||
//
|
||||
// Of course this application does not do much, so let's make this an actual application:
|
||||
// func main() {
|
||||
// app := cli.NewApp()
|
||||
// app.Name = "greet"
|
||||
// app.Usage = "say a greeting"
|
||||
// app.Action = func(c *cli.Context) {
|
||||
// println("Greetings")
|
||||
// }
|
||||
//
|
||||
// app.Run(os.Args)
|
||||
// }
|
||||
package cli
|
||||
100
Godeps/_workspace/src/github.com/codegangsta/cli/cli_test.go
generated
vendored
100
Godeps/_workspace/src/github.com/codegangsta/cli/cli_test.go
generated
vendored
@@ -1,100 +0,0 @@
|
||||
package cli_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/tendermint/tendermint/Godeps/_workspace/src/github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
func Example() {
|
||||
app := cli.NewApp()
|
||||
app.Name = "todo"
|
||||
app.Usage = "task list on the command line"
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "add",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "add a task to the list",
|
||||
Action: func(c *cli.Context) {
|
||||
println("added task: ", c.Args().First())
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "complete",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "complete a task on the list",
|
||||
Action: func(c *cli.Context) {
|
||||
println("completed task: ", c.Args().First())
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Run(os.Args)
|
||||
}
|
||||
|
||||
func ExampleSubcommand() {
|
||||
app := cli.NewApp()
|
||||
app.Name = "say"
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "hello",
|
||||
Aliases: []string{"hi"},
|
||||
Usage: "use it to see a description",
|
||||
Description: "This is how we describe hello the function",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "english",
|
||||
Aliases: []string{"en"},
|
||||
Usage: "sends a greeting in english",
|
||||
Description: "greets someone in english",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "name",
|
||||
Value: "Bob",
|
||||
Usage: "Name of the person to greet",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) {
|
||||
println("Hello, ", c.String("name"))
|
||||
},
|
||||
}, {
|
||||
Name: "spanish",
|
||||
Aliases: []string{"sp"},
|
||||
Usage: "sends a greeting in spanish",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "surname",
|
||||
Value: "Jones",
|
||||
Usage: "Surname of the person to greet",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) {
|
||||
println("Hola, ", c.String("surname"))
|
||||
},
|
||||
}, {
|
||||
Name: "french",
|
||||
Aliases: []string{"fr"},
|
||||
Usage: "sends a greeting in french",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "nickname",
|
||||
Value: "Stevie",
|
||||
Usage: "Nickname of the person to greet",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) {
|
||||
println("Bonjour, ", c.String("nickname"))
|
||||
},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
Name: "bye",
|
||||
Usage: "says goodbye",
|
||||
Action: func(c *cli.Context) {
|
||||
println("bye")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app.Run(os.Args)
|
||||
}
|
||||
184
Godeps/_workspace/src/github.com/codegangsta/cli/command.go
generated
vendored
184
Godeps/_workspace/src/github.com/codegangsta/cli/command.go
generated
vendored
@@ -1,184 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Command is a subcommand for a cli.App.
|
||||
type Command struct {
|
||||
// The name of the command
|
||||
Name string
|
||||
// short name of the command. Typically one character (deprecated, use `Aliases`)
|
||||
ShortName string
|
||||
// A list of aliases for the command
|
||||
Aliases []string
|
||||
// A short description of the usage of this command
|
||||
Usage string
|
||||
// A longer explanation of how the command works
|
||||
Description string
|
||||
// The function to call when checking for bash command completions
|
||||
BashComplete func(context *Context)
|
||||
// An action to execute before any sub-subcommands are run, but after the context is ready
|
||||
// If a non-nil error is returned, no sub-subcommands are run
|
||||
Before func(context *Context) error
|
||||
// An action to execute after any subcommands are run, but after the subcommand has finished
|
||||
// It is run even if Action() panics
|
||||
After func(context *Context) error
|
||||
// The function to call when this command is invoked
|
||||
Action func(context *Context)
|
||||
// List of child commands
|
||||
Subcommands []Command
|
||||
// List of flags to parse
|
||||
Flags []Flag
|
||||
// Treat all flags as normal arguments if true
|
||||
SkipFlagParsing bool
|
||||
// Boolean to hide built-in help command
|
||||
HideHelp bool
|
||||
}
|
||||
|
||||
// Invokes the command given the context, parses ctx.Args() to generate command-specific flags
|
||||
func (c Command) Run(ctx *Context) error {
|
||||
|
||||
if len(c.Subcommands) > 0 || c.Before != nil || c.After != nil {
|
||||
return c.startApp(ctx)
|
||||
}
|
||||
|
||||
if !c.HideHelp && (HelpFlag != BoolFlag{}) {
|
||||
// append help to flags
|
||||
c.Flags = append(
|
||||
c.Flags,
|
||||
HelpFlag,
|
||||
)
|
||||
}
|
||||
|
||||
if ctx.App.EnableBashCompletion {
|
||||
c.Flags = append(c.Flags, BashCompletionFlag)
|
||||
}
|
||||
|
||||
set := flagSet(c.Name, c.Flags)
|
||||
set.SetOutput(ioutil.Discard)
|
||||
|
||||
firstFlagIndex := -1
|
||||
terminatorIndex := -1
|
||||
for index, arg := range ctx.Args() {
|
||||
if arg == "--" {
|
||||
terminatorIndex = index
|
||||
break
|
||||
} else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 {
|
||||
firstFlagIndex = index
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
if firstFlagIndex > -1 && !c.SkipFlagParsing {
|
||||
args := ctx.Args()
|
||||
regularArgs := make([]string, len(args[1:firstFlagIndex]))
|
||||
copy(regularArgs, args[1:firstFlagIndex])
|
||||
|
||||
var flagArgs []string
|
||||
if terminatorIndex > -1 {
|
||||
flagArgs = args[firstFlagIndex:terminatorIndex]
|
||||
regularArgs = append(regularArgs, args[terminatorIndex:]...)
|
||||
} else {
|
||||
flagArgs = args[firstFlagIndex:]
|
||||
}
|
||||
|
||||
err = set.Parse(append(flagArgs, regularArgs...))
|
||||
} else {
|
||||
err = set.Parse(ctx.Args().Tail())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprint(ctx.App.Writer, "Incorrect Usage.\n\n")
|
||||
ShowCommandHelp(ctx, c.Name)
|
||||
fmt.Fprintln(ctx.App.Writer)
|
||||
return err
|
||||
}
|
||||
|
||||
nerr := normalizeFlags(c.Flags, set)
|
||||
if nerr != nil {
|
||||
fmt.Fprintln(ctx.App.Writer, nerr)
|
||||
fmt.Fprintln(ctx.App.Writer)
|
||||
ShowCommandHelp(ctx, c.Name)
|
||||
fmt.Fprintln(ctx.App.Writer)
|
||||
return nerr
|
||||
}
|
||||
context := NewContext(ctx.App, set, ctx.globalSet)
|
||||
|
||||
if checkCommandCompletions(context, c.Name) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if checkCommandHelp(context, c.Name) {
|
||||
return nil
|
||||
}
|
||||
context.Command = c
|
||||
c.Action(context)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c Command) Names() []string {
|
||||
names := []string{c.Name}
|
||||
|
||||
if c.ShortName != "" {
|
||||
names = append(names, c.ShortName)
|
||||
}
|
||||
|
||||
return append(names, c.Aliases...)
|
||||
}
|
||||
|
||||
// Returns true if Command.Name or Command.ShortName matches given name
|
||||
func (c Command) HasName(name string) bool {
|
||||
for _, n := range c.Names() {
|
||||
if n == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c Command) startApp(ctx *Context) error {
|
||||
app := NewApp()
|
||||
|
||||
// set the name and usage
|
||||
app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
|
||||
if c.Description != "" {
|
||||
app.Usage = c.Description
|
||||
} else {
|
||||
app.Usage = c.Usage
|
||||
}
|
||||
|
||||
// set CommandNotFound
|
||||
app.CommandNotFound = ctx.App.CommandNotFound
|
||||
|
||||
// set the flags and commands
|
||||
app.Commands = c.Subcommands
|
||||
app.Flags = c.Flags
|
||||
app.HideHelp = c.HideHelp
|
||||
|
||||
app.Version = ctx.App.Version
|
||||
app.HideVersion = ctx.App.HideVersion
|
||||
app.Compiled = ctx.App.Compiled
|
||||
app.Author = ctx.App.Author
|
||||
app.Email = ctx.App.Email
|
||||
app.Writer = ctx.App.Writer
|
||||
|
||||
// bash completion
|
||||
app.EnableBashCompletion = ctx.App.EnableBashCompletion
|
||||
if c.BashComplete != nil {
|
||||
app.BashComplete = c.BashComplete
|
||||
}
|
||||
|
||||
// set the actions
|
||||
app.Before = c.Before
|
||||
app.After = c.After
|
||||
if c.Action != nil {
|
||||
app.Action = c.Action
|
||||
} else {
|
||||
app.Action = helpSubcommand.Action
|
||||
}
|
||||
|
||||
return app.RunAsSubcommand(ctx)
|
||||
}
|
||||
49
Godeps/_workspace/src/github.com/codegangsta/cli/command_test.go
generated
vendored
49
Godeps/_workspace/src/github.com/codegangsta/cli/command_test.go
generated
vendored
@@ -1,49 +0,0 @@
|
||||
package cli_test
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"testing"
|
||||
|
||||
"github.com/tendermint/tendermint/Godeps/_workspace/src/github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
func TestCommandDoNotIgnoreFlags(t *testing.T) {
|
||||
app := cli.NewApp()
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
test := []string{"blah", "blah", "-break"}
|
||||
set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, set)
|
||||
|
||||
command := cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(_ *cli.Context) {},
|
||||
}
|
||||
err := command.Run(c)
|
||||
|
||||
expect(t, err.Error(), "flag provided but not defined: -break")
|
||||
}
|
||||
|
||||
func TestCommandIgnoreFlags(t *testing.T) {
|
||||
app := cli.NewApp()
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
test := []string{"blah", "blah"}
|
||||
set.Parse(test)
|
||||
|
||||
c := cli.NewContext(app, set, set)
|
||||
|
||||
command := cli.Command{
|
||||
Name: "test-cmd",
|
||||
Aliases: []string{"tc"},
|
||||
Usage: "this is for testing",
|
||||
Description: "testing",
|
||||
Action: func(_ *cli.Context) {},
|
||||
SkipFlagParsing: true,
|
||||
}
|
||||
err := command.Run(c)
|
||||
|
||||
expect(t, err, nil)
|
||||
}
|
||||
344
Godeps/_workspace/src/github.com/codegangsta/cli/context.go
generated
vendored
344
Godeps/_workspace/src/github.com/codegangsta/cli/context.go
generated
vendored
@@ -1,344 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Context is a type that is passed through to
|
||||
// each Handler action in a cli application. Context
|
||||
// can be used to retrieve context-specific Args and
|
||||
// parsed command-line options.
|
||||
type Context struct {
|
||||
App *App
|
||||
Command Command
|
||||
flagSet *flag.FlagSet
|
||||
globalSet *flag.FlagSet
|
||||
setFlags map[string]bool
|
||||
globalSetFlags map[string]bool
|
||||
}
|
||||
|
||||
// Creates a new context. For use in when invoking an App or Command action.
|
||||
func NewContext(app *App, set *flag.FlagSet, globalSet *flag.FlagSet) *Context {
|
||||
return &Context{App: app, flagSet: set, globalSet: globalSet}
|
||||
}
|
||||
|
||||
// Looks up the value of a local int flag, returns 0 if no int flag exists
|
||||
func (c *Context) Int(name string) int {
|
||||
return lookupInt(name, c.flagSet)
|
||||
}
|
||||
|
||||
// Looks up the value of a local time.Duration flag, returns 0 if no time.Duration flag exists
|
||||
func (c *Context) Duration(name string) time.Duration {
|
||||
return lookupDuration(name, c.flagSet)
|
||||
}
|
||||
|
||||
// Looks up the value of a local float64 flag, returns 0 if no float64 flag exists
|
||||
func (c *Context) Float64(name string) float64 {
|
||||
return lookupFloat64(name, c.flagSet)
|
||||
}
|
||||
|
||||
// Looks up the value of a local bool flag, returns false if no bool flag exists
|
||||
func (c *Context) Bool(name string) bool {
|
||||
return lookupBool(name, c.flagSet)
|
||||
}
|
||||
|
||||
// Looks up the value of a local boolT flag, returns false if no bool flag exists
|
||||
func (c *Context) BoolT(name string) bool {
|
||||
return lookupBoolT(name, c.flagSet)
|
||||
}
|
||||
|
||||
// Looks up the value of a local string flag, returns "" if no string flag exists
|
||||
func (c *Context) String(name string) string {
|
||||
return lookupString(name, c.flagSet)
|
||||
}
|
||||
|
||||
// Looks up the value of a local string slice flag, returns nil if no string slice flag exists
|
||||
func (c *Context) StringSlice(name string) []string {
|
||||
return lookupStringSlice(name, c.flagSet)
|
||||
}
|
||||
|
||||
// Looks up the value of a local int slice flag, returns nil if no int slice flag exists
|
||||
func (c *Context) IntSlice(name string) []int {
|
||||
return lookupIntSlice(name, c.flagSet)
|
||||
}
|
||||
|
||||
// Looks up the value of a local generic flag, returns nil if no generic flag exists
|
||||
func (c *Context) Generic(name string) interface{} {
|
||||
return lookupGeneric(name, c.flagSet)
|
||||
}
|
||||
|
||||
// Looks up the value of a global int flag, returns 0 if no int flag exists
|
||||
func (c *Context) GlobalInt(name string) int {
|
||||
return lookupInt(name, c.globalSet)
|
||||
}
|
||||
|
||||
// Looks up the value of a global time.Duration flag, returns 0 if no time.Duration flag exists
|
||||
func (c *Context) GlobalDuration(name string) time.Duration {
|
||||
return lookupDuration(name, c.globalSet)
|
||||
}
|
||||
|
||||
// Looks up the value of a global bool flag, returns false if no bool flag exists
|
||||
func (c *Context) GlobalBool(name string) bool {
|
||||
return lookupBool(name, c.globalSet)
|
||||
}
|
||||
|
||||
// Looks up the value of a global string flag, returns "" if no string flag exists
|
||||
func (c *Context) GlobalString(name string) string {
|
||||
return lookupString(name, c.globalSet)
|
||||
}
|
||||
|
||||
// Looks up the value of a global string slice flag, returns nil if no string slice flag exists
|
||||
func (c *Context) GlobalStringSlice(name string) []string {
|
||||
return lookupStringSlice(name, c.globalSet)
|
||||
}
|
||||
|
||||
// Looks up the value of a global int slice flag, returns nil if no int slice flag exists
|
||||
func (c *Context) GlobalIntSlice(name string) []int {
|
||||
return lookupIntSlice(name, c.globalSet)
|
||||
}
|
||||
|
||||
// Looks up the value of a global generic flag, returns nil if no generic flag exists
|
||||
func (c *Context) GlobalGeneric(name string) interface{} {
|
||||
return lookupGeneric(name, c.globalSet)
|
||||
}
|
||||
|
||||
// Returns the number of flags set
|
||||
func (c *Context) NumFlags() int {
|
||||
return c.flagSet.NFlag()
|
||||
}
|
||||
|
||||
// Determines if the flag was actually set
|
||||
func (c *Context) IsSet(name string) bool {
|
||||
if c.setFlags == nil {
|
||||
c.setFlags = make(map[string]bool)
|
||||
c.flagSet.Visit(func(f *flag.Flag) {
|
||||
c.setFlags[f.Name] = true
|
||||
})
|
||||
}
|
||||
return c.setFlags[name] == true
|
||||
}
|
||||
|
||||
// Determines if the global flag was actually set
|
||||
func (c *Context) GlobalIsSet(name string) bool {
|
||||
if c.globalSetFlags == nil {
|
||||
c.globalSetFlags = make(map[string]bool)
|
||||
c.globalSet.Visit(func(f *flag.Flag) {
|
||||
c.globalSetFlags[f.Name] = true
|
||||
})
|
||||
}
|
||||
return c.globalSetFlags[name] == true
|
||||
}
|
||||
|
||||
// Returns a slice of flag names used in this context.
|
||||
func (c *Context) FlagNames() (names []string) {
|
||||
for _, flag := range c.Command.Flags {
|
||||
name := strings.Split(flag.getName(), ",")[0]
|
||||
if name == "help" {
|
||||
continue
|
||||
}
|
||||
names = append(names, name)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Returns a slice of global flag names used by the app.
|
||||
func (c *Context) GlobalFlagNames() (names []string) {
|
||||
for _, flag := range c.App.Flags {
|
||||
name := strings.Split(flag.getName(), ",")[0]
|
||||
if name == "help" || name == "version" {
|
||||
continue
|
||||
}
|
||||
names = append(names, name)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type Args []string
|
||||
|
||||
// Returns the command line arguments associated with the context.
|
||||
func (c *Context) Args() Args {
|
||||
args := Args(c.flagSet.Args())
|
||||
return args
|
||||
}
|
||||
|
||||
// Returns the nth argument, or else a blank string
|
||||
func (a Args) Get(n int) string {
|
||||
if len(a) > n {
|
||||
return a[n]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Returns the first argument, or else a blank string
|
||||
func (a Args) First() string {
|
||||
return a.Get(0)
|
||||
}
|
||||
|
||||
// Return the rest of the arguments (not the first one)
|
||||
// or else an empty string slice
|
||||
func (a Args) Tail() []string {
|
||||
if len(a) >= 2 {
|
||||
return []string(a)[1:]
|
||||
}
|
||||
return []string{}
|
||||
}
|
||||
|
||||
// Checks if there are any arguments present
|
||||
func (a Args) Present() bool {
|
||||
return len(a) != 0
|
||||
}
|
||||
|
||||
// Swaps arguments at the given indexes
|
||||
func (a Args) Swap(from, to int) error {
|
||||
if from >= len(a) || to >= len(a) {
|
||||
return errors.New("index out of range")
|
||||
}
|
||||
a[from], a[to] = a[to], a[from]
|
||||
return nil
|
||||
}
|
||||
|
||||
func lookupInt(name string, set *flag.FlagSet) int {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
val, err := strconv.Atoi(f.Value.String())
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func lookupDuration(name string, set *flag.FlagSet) time.Duration {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
val, err := time.ParseDuration(f.Value.String())
|
||||
if err == nil {
|
||||
return val
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func lookupFloat64(name string, set *flag.FlagSet) float64 {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
val, err := strconv.ParseFloat(f.Value.String(), 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func lookupString(name string, set *flag.FlagSet) string {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
return f.Value.String()
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func lookupStringSlice(name string, set *flag.FlagSet) []string {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
return (f.Value.(*StringSlice)).Value()
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func lookupIntSlice(name string, set *flag.FlagSet) []int {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
return (f.Value.(*IntSlice)).Value()
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func lookupGeneric(name string, set *flag.FlagSet) interface{} {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
return f.Value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func lookupBool(name string, set *flag.FlagSet) bool {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
val, err := strconv.ParseBool(f.Value.String())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func lookupBoolT(name string, set *flag.FlagSet) bool {
|
||||
f := set.Lookup(name)
|
||||
if f != nil {
|
||||
val, err := strconv.ParseBool(f.Value.String())
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) {
|
||||
switch ff.Value.(type) {
|
||||
case *StringSlice:
|
||||
default:
|
||||
set.Set(name, ff.Value.String())
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeFlags(flags []Flag, set *flag.FlagSet) error {
|
||||
visited := make(map[string]bool)
|
||||
set.Visit(func(f *flag.Flag) {
|
||||
visited[f.Name] = true
|
||||
})
|
||||
for _, f := range flags {
|
||||
parts := strings.Split(f.getName(), ",")
|
||||
if len(parts) == 1 {
|
||||
continue
|
||||
}
|
||||
var ff *flag.Flag
|
||||
for _, name := range parts {
|
||||
name = strings.Trim(name, " ")
|
||||
if visited[name] {
|
||||
if ff != nil {
|
||||
return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name)
|
||||
}
|
||||
ff = set.Lookup(name)
|
||||
}
|
||||
}
|
||||
if ff == nil {
|
||||
continue
|
||||
}
|
||||
for _, name := range parts {
|
||||
name = strings.Trim(name, " ")
|
||||
if !visited[name] {
|
||||
copyFlag(name, ff, set)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
111
Godeps/_workspace/src/github.com/codegangsta/cli/context_test.go
generated
vendored
111
Godeps/_workspace/src/github.com/codegangsta/cli/context_test.go
generated
vendored
@@ -1,111 +0,0 @@
|
||||
package cli_test
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/tendermint/tendermint/Godeps/_workspace/src/github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
func TestNewContext(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Int("myflag", 12, "doc")
|
||||
globalSet := flag.NewFlagSet("test", 0)
|
||||
globalSet.Int("myflag", 42, "doc")
|
||||
command := cli.Command{Name: "mycommand"}
|
||||
c := cli.NewContext(nil, set, globalSet)
|
||||
c.Command = command
|
||||
expect(t, c.Int("myflag"), 12)
|
||||
expect(t, c.GlobalInt("myflag"), 42)
|
||||
expect(t, c.Command.Name, "mycommand")
|
||||
}
|
||||
|
||||
func TestContext_Int(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Int("myflag", 12, "doc")
|
||||
c := cli.NewContext(nil, set, set)
|
||||
expect(t, c.Int("myflag"), 12)
|
||||
}
|
||||
|
||||
func TestContext_Duration(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Duration("myflag", time.Duration(12*time.Second), "doc")
|
||||
c := cli.NewContext(nil, set, set)
|
||||
expect(t, c.Duration("myflag"), time.Duration(12*time.Second))
|
||||
}
|
||||
|
||||
func TestContext_String(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String("myflag", "hello world", "doc")
|
||||
c := cli.NewContext(nil, set, set)
|
||||
expect(t, c.String("myflag"), "hello world")
|
||||
}
|
||||
|
||||
func TestContext_Bool(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Bool("myflag", false, "doc")
|
||||
c := cli.NewContext(nil, set, set)
|
||||
expect(t, c.Bool("myflag"), false)
|
||||
}
|
||||
|
||||
func TestContext_BoolT(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Bool("myflag", true, "doc")
|
||||
c := cli.NewContext(nil, set, set)
|
||||
expect(t, c.BoolT("myflag"), true)
|
||||
}
|
||||
|
||||
func TestContext_Args(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Bool("myflag", false, "doc")
|
||||
c := cli.NewContext(nil, set, set)
|
||||
set.Parse([]string{"--myflag", "bat", "baz"})
|
||||
expect(t, len(c.Args()), 2)
|
||||
expect(t, c.Bool("myflag"), true)
|
||||
}
|
||||
|
||||
func TestContext_IsSet(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Bool("myflag", false, "doc")
|
||||
set.String("otherflag", "hello world", "doc")
|
||||
globalSet := flag.NewFlagSet("test", 0)
|
||||
globalSet.Bool("myflagGlobal", true, "doc")
|
||||
c := cli.NewContext(nil, set, globalSet)
|
||||
set.Parse([]string{"--myflag", "bat", "baz"})
|
||||
globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"})
|
||||
expect(t, c.IsSet("myflag"), true)
|
||||
expect(t, c.IsSet("otherflag"), false)
|
||||
expect(t, c.IsSet("bogusflag"), false)
|
||||
expect(t, c.IsSet("myflagGlobal"), false)
|
||||
}
|
||||
|
||||
func TestContext_GlobalIsSet(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Bool("myflag", false, "doc")
|
||||
set.String("otherflag", "hello world", "doc")
|
||||
globalSet := flag.NewFlagSet("test", 0)
|
||||
globalSet.Bool("myflagGlobal", true, "doc")
|
||||
globalSet.Bool("myflagGlobalUnset", true, "doc")
|
||||
c := cli.NewContext(nil, set, globalSet)
|
||||
set.Parse([]string{"--myflag", "bat", "baz"})
|
||||
globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"})
|
||||
expect(t, c.GlobalIsSet("myflag"), false)
|
||||
expect(t, c.GlobalIsSet("otherflag"), false)
|
||||
expect(t, c.GlobalIsSet("bogusflag"), false)
|
||||
expect(t, c.GlobalIsSet("myflagGlobal"), true)
|
||||
expect(t, c.GlobalIsSet("myflagGlobalUnset"), false)
|
||||
expect(t, c.GlobalIsSet("bogusGlobal"), false)
|
||||
}
|
||||
|
||||
func TestContext_NumFlags(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.Bool("myflag", false, "doc")
|
||||
set.String("otherflag", "hello world", "doc")
|
||||
globalSet := flag.NewFlagSet("test", 0)
|
||||
globalSet.Bool("myflagGlobal", true, "doc")
|
||||
c := cli.NewContext(nil, set, globalSet)
|
||||
set.Parse([]string{"--myflag", "--otherflag=foo"})
|
||||
globalSet.Parse([]string{"--myflagGlobal"})
|
||||
expect(t, c.NumFlags(), 2)
|
||||
}
|
||||
454
Godeps/_workspace/src/github.com/codegangsta/cli/flag.go
generated
vendored
454
Godeps/_workspace/src/github.com/codegangsta/cli/flag.go
generated
vendored
@@ -1,454 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// This flag enables bash-completion for all commands and subcommands
|
||||
var BashCompletionFlag = BoolFlag{
|
||||
Name: "generate-bash-completion",
|
||||
}
|
||||
|
||||
// This flag prints the version for the application
|
||||
var VersionFlag = BoolFlag{
|
||||
Name: "version, v",
|
||||
Usage: "print the version",
|
||||
}
|
||||
|
||||
// This flag prints the help for all commands and subcommands
|
||||
// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand
|
||||
// unless HideHelp is set to true)
|
||||
var HelpFlag = BoolFlag{
|
||||
Name: "help, h",
|
||||
Usage: "show help",
|
||||
}
|
||||
|
||||
// Flag is a common interface related to parsing flags in cli.
|
||||
// For more advanced flag parsing techniques, it is recomended that
|
||||
// this interface be implemented.
|
||||
type Flag interface {
|
||||
fmt.Stringer
|
||||
// Apply Flag settings to the given flag set
|
||||
Apply(*flag.FlagSet)
|
||||
getName() string
|
||||
}
|
||||
|
||||
func flagSet(name string, flags []Flag) *flag.FlagSet {
|
||||
set := flag.NewFlagSet(name, flag.ContinueOnError)
|
||||
|
||||
for _, f := range flags {
|
||||
f.Apply(set)
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
func eachName(longName string, fn func(string)) {
|
||||
parts := strings.Split(longName, ",")
|
||||
for _, name := range parts {
|
||||
name = strings.Trim(name, " ")
|
||||
fn(name)
|
||||
}
|
||||
}
|
||||
|
||||
// Generic is a generic parseable type identified by a specific flag
|
||||
type Generic interface {
|
||||
Set(value string) error
|
||||
String() string
|
||||
}
|
||||
|
||||
// GenericFlag is the flag type for types implementing Generic
|
||||
type GenericFlag struct {
|
||||
Name string
|
||||
Value Generic
|
||||
Usage string
|
||||
EnvVar string
|
||||
}
|
||||
|
||||
// String returns the string representation of the generic flag to display the
|
||||
// help text to the user (uses the String() method of the generic flag to show
|
||||
// the value)
|
||||
func (f GenericFlag) String() string {
|
||||
return withEnvHint(f.EnvVar, fmt.Sprintf("%s%s \"%v\"\t%v", prefixFor(f.Name), f.Name, f.Value, f.Usage))
|
||||
}
|
||||
|
||||
// Apply takes the flagset and calls Set on the generic flag with the value
|
||||
// provided by the user for parsing by the flag
|
||||
func (f GenericFlag) Apply(set *flag.FlagSet) {
|
||||
val := f.Value
|
||||
if f.EnvVar != "" {
|
||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||
envVar = strings.TrimSpace(envVar)
|
||||
if envVal := os.Getenv(envVar); envVal != "" {
|
||||
val.Set(envVal)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
set.Var(f.Value, name, f.Usage)
|
||||
})
|
||||
}
|
||||
|
||||
func (f GenericFlag) getName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
type StringSlice []string
|
||||
|
||||
func (f *StringSlice) Set(value string) error {
|
||||
*f = append(*f, value)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *StringSlice) String() string {
|
||||
return fmt.Sprintf("%s", *f)
|
||||
}
|
||||
|
||||
func (f *StringSlice) Value() []string {
|
||||
return *f
|
||||
}
|
||||
|
||||
type StringSliceFlag struct {
|
||||
Name string
|
||||
Value *StringSlice
|
||||
Usage string
|
||||
EnvVar string
|
||||
}
|
||||
|
||||
func (f StringSliceFlag) String() string {
|
||||
firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
|
||||
pref := prefixFor(firstName)
|
||||
return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage))
|
||||
}
|
||||
|
||||
func (f StringSliceFlag) Apply(set *flag.FlagSet) {
|
||||
if f.EnvVar != "" {
|
||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||
envVar = strings.TrimSpace(envVar)
|
||||
if envVal := os.Getenv(envVar); envVal != "" {
|
||||
newVal := &StringSlice{}
|
||||
for _, s := range strings.Split(envVal, ",") {
|
||||
s = strings.TrimSpace(s)
|
||||
newVal.Set(s)
|
||||
}
|
||||
f.Value = newVal
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
set.Var(f.Value, name, f.Usage)
|
||||
})
|
||||
}
|
||||
|
||||
func (f StringSliceFlag) getName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
type IntSlice []int
|
||||
|
||||
func (f *IntSlice) Set(value string) error {
|
||||
|
||||
tmp, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
*f = append(*f, tmp)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *IntSlice) String() string {
|
||||
return fmt.Sprintf("%d", *f)
|
||||
}
|
||||
|
||||
func (f *IntSlice) Value() []int {
|
||||
return *f
|
||||
}
|
||||
|
||||
type IntSliceFlag struct {
|
||||
Name string
|
||||
Value *IntSlice
|
||||
Usage string
|
||||
EnvVar string
|
||||
}
|
||||
|
||||
func (f IntSliceFlag) String() string {
|
||||
firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
|
||||
pref := prefixFor(firstName)
|
||||
return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage))
|
||||
}
|
||||
|
||||
func (f IntSliceFlag) Apply(set *flag.FlagSet) {
|
||||
if f.EnvVar != "" {
|
||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||
envVar = strings.TrimSpace(envVar)
|
||||
if envVal := os.Getenv(envVar); envVal != "" {
|
||||
newVal := &IntSlice{}
|
||||
for _, s := range strings.Split(envVal, ",") {
|
||||
s = strings.TrimSpace(s)
|
||||
err := newVal.Set(s)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
}
|
||||
}
|
||||
f.Value = newVal
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
set.Var(f.Value, name, f.Usage)
|
||||
})
|
||||
}
|
||||
|
||||
func (f IntSliceFlag) getName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
type BoolFlag struct {
|
||||
Name string
|
||||
Usage string
|
||||
EnvVar string
|
||||
}
|
||||
|
||||
func (f BoolFlag) String() string {
|
||||
return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage))
|
||||
}
|
||||
|
||||
func (f BoolFlag) Apply(set *flag.FlagSet) {
|
||||
val := false
|
||||
if f.EnvVar != "" {
|
||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||
envVar = strings.TrimSpace(envVar)
|
||||
if envVal := os.Getenv(envVar); envVal != "" {
|
||||
envValBool, err := strconv.ParseBool(envVal)
|
||||
if err == nil {
|
||||
val = envValBool
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
set.Bool(name, val, f.Usage)
|
||||
})
|
||||
}
|
||||
|
||||
func (f BoolFlag) getName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
type BoolTFlag struct {
|
||||
Name string
|
||||
Usage string
|
||||
EnvVar string
|
||||
}
|
||||
|
||||
func (f BoolTFlag) String() string {
|
||||
return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage))
|
||||
}
|
||||
|
||||
func (f BoolTFlag) Apply(set *flag.FlagSet) {
|
||||
val := true
|
||||
if f.EnvVar != "" {
|
||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||
envVar = strings.TrimSpace(envVar)
|
||||
if envVal := os.Getenv(envVar); envVal != "" {
|
||||
envValBool, err := strconv.ParseBool(envVal)
|
||||
if err == nil {
|
||||
val = envValBool
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
set.Bool(name, val, f.Usage)
|
||||
})
|
||||
}
|
||||
|
||||
func (f BoolTFlag) getName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
type StringFlag struct {
|
||||
Name string
|
||||
Value string
|
||||
Usage string
|
||||
EnvVar string
|
||||
}
|
||||
|
||||
func (f StringFlag) String() string {
|
||||
var fmtString string
|
||||
fmtString = "%s %v\t%v"
|
||||
|
||||
if len(f.Value) > 0 {
|
||||
fmtString = "%s \"%v\"\t%v"
|
||||
} else {
|
||||
fmtString = "%s %v\t%v"
|
||||
}
|
||||
|
||||
return withEnvHint(f.EnvVar, fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage))
|
||||
}
|
||||
|
||||
func (f StringFlag) Apply(set *flag.FlagSet) {
|
||||
if f.EnvVar != "" {
|
||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||
envVar = strings.TrimSpace(envVar)
|
||||
if envVal := os.Getenv(envVar); envVal != "" {
|
||||
f.Value = envVal
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
set.String(name, f.Value, f.Usage)
|
||||
})
|
||||
}
|
||||
|
||||
func (f StringFlag) getName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
type IntFlag struct {
|
||||
Name string
|
||||
Value int
|
||||
Usage string
|
||||
EnvVar string
|
||||
}
|
||||
|
||||
func (f IntFlag) String() string {
|
||||
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
|
||||
}
|
||||
|
||||
func (f IntFlag) Apply(set *flag.FlagSet) {
|
||||
if f.EnvVar != "" {
|
||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||
envVar = strings.TrimSpace(envVar)
|
||||
if envVal := os.Getenv(envVar); envVal != "" {
|
||||
envValInt, err := strconv.ParseInt(envVal, 0, 64)
|
||||
if err == nil {
|
||||
f.Value = int(envValInt)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
set.Int(name, f.Value, f.Usage)
|
||||
})
|
||||
}
|
||||
|
||||
func (f IntFlag) getName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
type DurationFlag struct {
|
||||
Name string
|
||||
Value time.Duration
|
||||
Usage string
|
||||
EnvVar string
|
||||
}
|
||||
|
||||
func (f DurationFlag) String() string {
|
||||
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
|
||||
}
|
||||
|
||||
func (f DurationFlag) Apply(set *flag.FlagSet) {
|
||||
if f.EnvVar != "" {
|
||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||
envVar = strings.TrimSpace(envVar)
|
||||
if envVal := os.Getenv(envVar); envVal != "" {
|
||||
envValDuration, err := time.ParseDuration(envVal)
|
||||
if err == nil {
|
||||
f.Value = envValDuration
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
set.Duration(name, f.Value, f.Usage)
|
||||
})
|
||||
}
|
||||
|
||||
func (f DurationFlag) getName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
type Float64Flag struct {
|
||||
Name string
|
||||
Value float64
|
||||
Usage string
|
||||
EnvVar string
|
||||
}
|
||||
|
||||
func (f Float64Flag) String() string {
|
||||
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
|
||||
}
|
||||
|
||||
func (f Float64Flag) Apply(set *flag.FlagSet) {
|
||||
if f.EnvVar != "" {
|
||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
||||
envVar = strings.TrimSpace(envVar)
|
||||
if envVal := os.Getenv(envVar); envVal != "" {
|
||||
envValFloat, err := strconv.ParseFloat(envVal, 10)
|
||||
if err == nil {
|
||||
f.Value = float64(envValFloat)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eachName(f.Name, func(name string) {
|
||||
set.Float64(name, f.Value, f.Usage)
|
||||
})
|
||||
}
|
||||
|
||||
func (f Float64Flag) getName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
func prefixFor(name string) (prefix string) {
|
||||
if len(name) == 1 {
|
||||
prefix = "-"
|
||||
} else {
|
||||
prefix = "--"
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func prefixedNames(fullName string) (prefixed string) {
|
||||
parts := strings.Split(fullName, ",")
|
||||
for i, name := range parts {
|
||||
name = strings.Trim(name, " ")
|
||||
prefixed += prefixFor(name) + name
|
||||
if i < len(parts)-1 {
|
||||
prefixed += ", "
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func withEnvHint(envVar, str string) string {
|
||||
envText := ""
|
||||
if envVar != "" {
|
||||
envText = fmt.Sprintf(" [$%s]", strings.Join(strings.Split(envVar, ","), ", $"))
|
||||
}
|
||||
return str + envText
|
||||
}
|
||||
742
Godeps/_workspace/src/github.com/codegangsta/cli/flag_test.go
generated
vendored
742
Godeps/_workspace/src/github.com/codegangsta/cli/flag_test.go
generated
vendored
@@ -1,742 +0,0 @@
|
||||
package cli_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/tendermint/tendermint/Godeps/_workspace/src/github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
var boolFlagTests = []struct {
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"help", "--help\t"},
|
||||
{"h", "-h\t"},
|
||||
}
|
||||
|
||||
func TestBoolFlagHelpOutput(t *testing.T) {
|
||||
|
||||
for _, test := range boolFlagTests {
|
||||
flag := cli.BoolFlag{Name: test.name}
|
||||
output := flag.String()
|
||||
|
||||
if output != test.expected {
|
||||
t.Errorf("%s does not match %s", output, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var stringFlagTests = []struct {
|
||||
name string
|
||||
value string
|
||||
expected string
|
||||
}{
|
||||
{"help", "", "--help \t"},
|
||||
{"h", "", "-h \t"},
|
||||
{"h", "", "-h \t"},
|
||||
{"test", "Something", "--test \"Something\"\t"},
|
||||
}
|
||||
|
||||
func TestStringFlagHelpOutput(t *testing.T) {
|
||||
|
||||
for _, test := range stringFlagTests {
|
||||
flag := cli.StringFlag{Name: test.name, Value: test.value}
|
||||
output := flag.String()
|
||||
|
||||
if output != test.expected {
|
||||
t.Errorf("%s does not match %s", output, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringFlagWithEnvVarHelpOutput(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_FOO", "derp")
|
||||
for _, test := range stringFlagTests {
|
||||
flag := cli.StringFlag{Name: test.name, Value: test.value, EnvVar: "APP_FOO"}
|
||||
output := flag.String()
|
||||
|
||||
if !strings.HasSuffix(output, " [$APP_FOO]") {
|
||||
t.Errorf("%s does not end with [$APP_FOO]", output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var stringSliceFlagTests = []struct {
|
||||
name string
|
||||
value *cli.StringSlice
|
||||
expected string
|
||||
}{
|
||||
{"help", func() *cli.StringSlice {
|
||||
s := &cli.StringSlice{}
|
||||
s.Set("")
|
||||
return s
|
||||
}(), "--help [--help option --help option]\t"},
|
||||
{"h", func() *cli.StringSlice {
|
||||
s := &cli.StringSlice{}
|
||||
s.Set("")
|
||||
return s
|
||||
}(), "-h [-h option -h option]\t"},
|
||||
{"h", func() *cli.StringSlice {
|
||||
s := &cli.StringSlice{}
|
||||
s.Set("")
|
||||
return s
|
||||
}(), "-h [-h option -h option]\t"},
|
||||
{"test", func() *cli.StringSlice {
|
||||
s := &cli.StringSlice{}
|
||||
s.Set("Something")
|
||||
return s
|
||||
}(), "--test [--test option --test option]\t"},
|
||||
}
|
||||
|
||||
func TestStringSliceFlagHelpOutput(t *testing.T) {
|
||||
|
||||
for _, test := range stringSliceFlagTests {
|
||||
flag := cli.StringSliceFlag{Name: test.name, Value: test.value}
|
||||
output := flag.String()
|
||||
|
||||
if output != test.expected {
|
||||
t.Errorf("%q does not match %q", output, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_QWWX", "11,4")
|
||||
for _, test := range stringSliceFlagTests {
|
||||
flag := cli.StringSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_QWWX"}
|
||||
output := flag.String()
|
||||
|
||||
if !strings.HasSuffix(output, " [$APP_QWWX]") {
|
||||
t.Errorf("%q does not end with [$APP_QWWX]", output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var intFlagTests = []struct {
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"help", "--help \"0\"\t"},
|
||||
{"h", "-h \"0\"\t"},
|
||||
}
|
||||
|
||||
func TestIntFlagHelpOutput(t *testing.T) {
|
||||
|
||||
for _, test := range intFlagTests {
|
||||
flag := cli.IntFlag{Name: test.name}
|
||||
output := flag.String()
|
||||
|
||||
if output != test.expected {
|
||||
t.Errorf("%s does not match %s", output, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntFlagWithEnvVarHelpOutput(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_BAR", "2")
|
||||
for _, test := range intFlagTests {
|
||||
flag := cli.IntFlag{Name: test.name, EnvVar: "APP_BAR"}
|
||||
output := flag.String()
|
||||
|
||||
if !strings.HasSuffix(output, " [$APP_BAR]") {
|
||||
t.Errorf("%s does not end with [$APP_BAR]", output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var durationFlagTests = []struct {
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"help", "--help \"0\"\t"},
|
||||
{"h", "-h \"0\"\t"},
|
||||
}
|
||||
|
||||
func TestDurationFlagHelpOutput(t *testing.T) {
|
||||
|
||||
for _, test := range durationFlagTests {
|
||||
flag := cli.DurationFlag{Name: test.name}
|
||||
output := flag.String()
|
||||
|
||||
if output != test.expected {
|
||||
t.Errorf("%s does not match %s", output, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDurationFlagWithEnvVarHelpOutput(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_BAR", "2h3m6s")
|
||||
for _, test := range durationFlagTests {
|
||||
flag := cli.DurationFlag{Name: test.name, EnvVar: "APP_BAR"}
|
||||
output := flag.String()
|
||||
|
||||
if !strings.HasSuffix(output, " [$APP_BAR]") {
|
||||
t.Errorf("%s does not end with [$APP_BAR]", output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var intSliceFlagTests = []struct {
|
||||
name string
|
||||
value *cli.IntSlice
|
||||
expected string
|
||||
}{
|
||||
{"help", &cli.IntSlice{}, "--help [--help option --help option]\t"},
|
||||
{"h", &cli.IntSlice{}, "-h [-h option -h option]\t"},
|
||||
{"h", &cli.IntSlice{}, "-h [-h option -h option]\t"},
|
||||
{"test", func() *cli.IntSlice {
|
||||
i := &cli.IntSlice{}
|
||||
i.Set("9")
|
||||
return i
|
||||
}(), "--test [--test option --test option]\t"},
|
||||
}
|
||||
|
||||
func TestIntSliceFlagHelpOutput(t *testing.T) {
|
||||
|
||||
for _, test := range intSliceFlagTests {
|
||||
flag := cli.IntSliceFlag{Name: test.name, Value: test.value}
|
||||
output := flag.String()
|
||||
|
||||
if output != test.expected {
|
||||
t.Errorf("%q does not match %q", output, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_SMURF", "42,3")
|
||||
for _, test := range intSliceFlagTests {
|
||||
flag := cli.IntSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_SMURF"}
|
||||
output := flag.String()
|
||||
|
||||
if !strings.HasSuffix(output, " [$APP_SMURF]") {
|
||||
t.Errorf("%q does not end with [$APP_SMURF]", output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var float64FlagTests = []struct {
|
||||
name string
|
||||
expected string
|
||||
}{
|
||||
{"help", "--help \"0\"\t"},
|
||||
{"h", "-h \"0\"\t"},
|
||||
}
|
||||
|
||||
func TestFloat64FlagHelpOutput(t *testing.T) {
|
||||
|
||||
for _, test := range float64FlagTests {
|
||||
flag := cli.Float64Flag{Name: test.name}
|
||||
output := flag.String()
|
||||
|
||||
if output != test.expected {
|
||||
t.Errorf("%s does not match %s", output, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_BAZ", "99.4")
|
||||
for _, test := range float64FlagTests {
|
||||
flag := cli.Float64Flag{Name: test.name, EnvVar: "APP_BAZ"}
|
||||
output := flag.String()
|
||||
|
||||
if !strings.HasSuffix(output, " [$APP_BAZ]") {
|
||||
t.Errorf("%s does not end with [$APP_BAZ]", output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var genericFlagTests = []struct {
|
||||
name string
|
||||
value cli.Generic
|
||||
expected string
|
||||
}{
|
||||
{"test", &Parser{"abc", "def"}, "--test \"abc,def\"\ttest flag"},
|
||||
{"t", &Parser{"abc", "def"}, "-t \"abc,def\"\ttest flag"},
|
||||
}
|
||||
|
||||
func TestGenericFlagHelpOutput(t *testing.T) {
|
||||
|
||||
for _, test := range genericFlagTests {
|
||||
flag := cli.GenericFlag{Name: test.name, Value: test.value, Usage: "test flag"}
|
||||
output := flag.String()
|
||||
|
||||
if output != test.expected {
|
||||
t.Errorf("%q does not match %q", output, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_ZAP", "3")
|
||||
for _, test := range genericFlagTests {
|
||||
flag := cli.GenericFlag{Name: test.name, EnvVar: "APP_ZAP"}
|
||||
output := flag.String()
|
||||
|
||||
if !strings.HasSuffix(output, " [$APP_ZAP]") {
|
||||
t.Errorf("%s does not end with [$APP_ZAP]", output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseMultiString(t *testing.T) {
|
||||
(&cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{Name: "serve, s"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if ctx.String("serve") != "10" {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.String("s") != "10" {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}).Run([]string{"run", "-s", "10"})
|
||||
}
|
||||
|
||||
func TestParseMultiStringFromEnv(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_COUNT", "20")
|
||||
(&cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{Name: "count, c", EnvVar: "APP_COUNT"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if ctx.String("count") != "20" {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.String("c") != "20" {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}).Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiStringFromEnvCascade(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_COUNT", "20")
|
||||
(&cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{Name: "count, c", EnvVar: "COMPAT_COUNT,APP_COUNT"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if ctx.String("count") != "20" {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.String("c") != "20" {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}).Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiStringSlice(t *testing.T) {
|
||||
(&cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.StringSliceFlag{Name: "serve, s", Value: &cli.StringSlice{}},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if !reflect.DeepEqual(ctx.StringSlice("serve"), []string{"10", "20"}) {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if !reflect.DeepEqual(ctx.StringSlice("s"), []string{"10", "20"}) {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}).Run([]string{"run", "-s", "10", "-s", "20"})
|
||||
}
|
||||
|
||||
func TestParseMultiStringSliceFromEnv(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_INTERVALS", "20,30,40")
|
||||
|
||||
(&cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.StringSliceFlag{Name: "intervals, i", Value: &cli.StringSlice{}, EnvVar: "APP_INTERVALS"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
|
||||
t.Errorf("main name not set from env")
|
||||
}
|
||||
if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
|
||||
t.Errorf("short name not set from env")
|
||||
}
|
||||
},
|
||||
}).Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiStringSliceFromEnvCascade(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_INTERVALS", "20,30,40")
|
||||
|
||||
(&cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.StringSliceFlag{Name: "intervals, i", Value: &cli.StringSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
|
||||
t.Errorf("main name not set from env")
|
||||
}
|
||||
if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
|
||||
t.Errorf("short name not set from env")
|
||||
}
|
||||
},
|
||||
}).Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiInt(t *testing.T) {
|
||||
a := cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.IntFlag{Name: "serve, s"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if ctx.Int("serve") != 10 {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.Int("s") != 10 {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run", "-s", "10"})
|
||||
}
|
||||
|
||||
func TestParseMultiIntFromEnv(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_TIMEOUT_SECONDS", "10")
|
||||
a := cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.IntFlag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if ctx.Int("timeout") != 10 {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.Int("t") != 10 {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiIntFromEnvCascade(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_TIMEOUT_SECONDS", "10")
|
||||
a := cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.IntFlag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if ctx.Int("timeout") != 10 {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.Int("t") != 10 {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiIntSlice(t *testing.T) {
|
||||
(&cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.IntSliceFlag{Name: "serve, s", Value: &cli.IntSlice{}},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if !reflect.DeepEqual(ctx.IntSlice("s"), []int{10, 20}) {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}).Run([]string{"run", "-s", "10", "-s", "20"})
|
||||
}
|
||||
|
||||
func TestParseMultiIntSliceFromEnv(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_INTERVALS", "20,30,40")
|
||||
|
||||
(&cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.IntSliceFlag{Name: "intervals, i", Value: &cli.IntSlice{}, EnvVar: "APP_INTERVALS"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
|
||||
t.Errorf("main name not set from env")
|
||||
}
|
||||
if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
|
||||
t.Errorf("short name not set from env")
|
||||
}
|
||||
},
|
||||
}).Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiIntSliceFromEnvCascade(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_INTERVALS", "20,30,40")
|
||||
|
||||
(&cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.IntSliceFlag{Name: "intervals, i", Value: &cli.IntSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
|
||||
t.Errorf("main name not set from env")
|
||||
}
|
||||
if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
|
||||
t.Errorf("short name not set from env")
|
||||
}
|
||||
},
|
||||
}).Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiFloat64(t *testing.T) {
|
||||
a := cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.Float64Flag{Name: "serve, s"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if ctx.Float64("serve") != 10.2 {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.Float64("s") != 10.2 {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run", "-s", "10.2"})
|
||||
}
|
||||
|
||||
func TestParseMultiFloat64FromEnv(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
|
||||
a := cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if ctx.Float64("timeout") != 15.5 {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.Float64("t") != 15.5 {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiFloat64FromEnvCascade(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
|
||||
a := cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.Float64Flag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if ctx.Float64("timeout") != 15.5 {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.Float64("t") != 15.5 {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiBool(t *testing.T) {
|
||||
a := cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{Name: "serve, s"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if ctx.Bool("serve") != true {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.Bool("s") != true {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run", "--serve"})
|
||||
}
|
||||
|
||||
func TestParseMultiBoolFromEnv(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_DEBUG", "1")
|
||||
a := cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{Name: "debug, d", EnvVar: "APP_DEBUG"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if ctx.Bool("debug") != true {
|
||||
t.Errorf("main name not set from env")
|
||||
}
|
||||
if ctx.Bool("d") != true {
|
||||
t.Errorf("short name not set from env")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiBoolFromEnvCascade(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_DEBUG", "1")
|
||||
a := cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if ctx.Bool("debug") != true {
|
||||
t.Errorf("main name not set from env")
|
||||
}
|
||||
if ctx.Bool("d") != true {
|
||||
t.Errorf("short name not set from env")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiBoolT(t *testing.T) {
|
||||
a := cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolTFlag{Name: "serve, s"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if ctx.BoolT("serve") != true {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if ctx.BoolT("s") != true {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run", "--serve"})
|
||||
}
|
||||
|
||||
func TestParseMultiBoolTFromEnv(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_DEBUG", "0")
|
||||
a := cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolTFlag{Name: "debug, d", EnvVar: "APP_DEBUG"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if ctx.BoolT("debug") != false {
|
||||
t.Errorf("main name not set from env")
|
||||
}
|
||||
if ctx.BoolT("d") != false {
|
||||
t.Errorf("short name not set from env")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseMultiBoolTFromEnvCascade(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_DEBUG", "0")
|
||||
a := cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolTFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if ctx.BoolT("debug") != false {
|
||||
t.Errorf("main name not set from env")
|
||||
}
|
||||
if ctx.BoolT("d") != false {
|
||||
t.Errorf("short name not set from env")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run"})
|
||||
}
|
||||
|
||||
type Parser [2]string
|
||||
|
||||
func (p *Parser) Set(value string) error {
|
||||
parts := strings.Split(value, ",")
|
||||
if len(parts) != 2 {
|
||||
return fmt.Errorf("invalid format")
|
||||
}
|
||||
|
||||
(*p)[0] = parts[0]
|
||||
(*p)[1] = parts[1]
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Parser) String() string {
|
||||
return fmt.Sprintf("%s,%s", p[0], p[1])
|
||||
}
|
||||
|
||||
func TestParseGeneric(t *testing.T) {
|
||||
a := cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.GenericFlag{Name: "serve, s", Value: &Parser{}},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"10", "20"}) {
|
||||
t.Errorf("main name not set")
|
||||
}
|
||||
if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"10", "20"}) {
|
||||
t.Errorf("short name not set")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run", "-s", "10,20"})
|
||||
}
|
||||
|
||||
func TestParseGenericFromEnv(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_SERVE", "20,30")
|
||||
a := cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.GenericFlag{Name: "serve, s", Value: &Parser{}, EnvVar: "APP_SERVE"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"20", "30"}) {
|
||||
t.Errorf("main name not set from env")
|
||||
}
|
||||
if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"20", "30"}) {
|
||||
t.Errorf("short name not set from env")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run"})
|
||||
}
|
||||
|
||||
func TestParseGenericFromEnvCascade(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("APP_FOO", "99,2000")
|
||||
a := cli.App{
|
||||
Flags: []cli.Flag{
|
||||
cli.GenericFlag{Name: "foos", Value: &Parser{}, EnvVar: "COMPAT_FOO,APP_FOO"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) {
|
||||
if !reflect.DeepEqual(ctx.Generic("foos"), &Parser{"99", "2000"}) {
|
||||
t.Errorf("value not set from env")
|
||||
}
|
||||
},
|
||||
}
|
||||
a.Run([]string{"run"})
|
||||
}
|
||||
235
Godeps/_workspace/src/github.com/codegangsta/cli/help.go
generated
vendored
235
Godeps/_workspace/src/github.com/codegangsta/cli/help.go
generated
vendored
@@ -1,235 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// The text template for the Default help topic.
|
||||
// cli.go uses text/template to render templates. You can
|
||||
// render custom help text by setting this variable.
|
||||
var AppHelpTemplate = `NAME:
|
||||
{{.Name}} - {{.Usage}}
|
||||
|
||||
USAGE:
|
||||
{{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...]
|
||||
|
||||
VERSION:
|
||||
{{.Version}}{{if len .Authors}}
|
||||
|
||||
AUTHOR(S):
|
||||
{{range .Authors}}{{ . }}{{end}}{{end}}
|
||||
|
||||
COMMANDS:
|
||||
{{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
|
||||
{{end}}{{if .Flags}}
|
||||
GLOBAL OPTIONS:
|
||||
{{range .Flags}}{{.}}
|
||||
{{end}}{{end}}
|
||||
`
|
||||
|
||||
// The text template for the command help topic.
|
||||
// cli.go uses text/template to render templates. You can
|
||||
// render custom help text by setting this variable.
|
||||
var CommandHelpTemplate = `NAME:
|
||||
{{.Name}} - {{.Usage}}
|
||||
|
||||
USAGE:
|
||||
command {{.Name}}{{if .Flags}} [command options]{{end}} [arguments...]{{if .Description}}
|
||||
|
||||
DESCRIPTION:
|
||||
{{.Description}}{{end}}{{if .Flags}}
|
||||
|
||||
OPTIONS:
|
||||
{{range .Flags}}{{.}}
|
||||
{{end}}{{ end }}
|
||||
`
|
||||
|
||||
// The text template for the subcommand help topic.
|
||||
// cli.go uses text/template to render templates. You can
|
||||
// render custom help text by setting this variable.
|
||||
var SubcommandHelpTemplate = `NAME:
|
||||
{{.Name}} - {{.Usage}}
|
||||
|
||||
USAGE:
|
||||
{{.Name}} command{{if .Flags}} [command options]{{end}} [arguments...]
|
||||
|
||||
COMMANDS:
|
||||
{{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
|
||||
{{end}}{{if .Flags}}
|
||||
OPTIONS:
|
||||
{{range .Flags}}{{.}}
|
||||
{{end}}{{end}}
|
||||
`
|
||||
|
||||
var helpCommand = Command{
|
||||
Name: "help",
|
||||
Aliases: []string{"h"},
|
||||
Usage: "Shows a list of commands or help for one command",
|
||||
Action: func(c *Context) {
|
||||
args := c.Args()
|
||||
if args.Present() {
|
||||
ShowCommandHelp(c, args.First())
|
||||
} else {
|
||||
ShowAppHelp(c)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var helpSubcommand = Command{
|
||||
Name: "help",
|
||||
Aliases: []string{"h"},
|
||||
Usage: "Shows a list of commands or help for one command",
|
||||
Action: func(c *Context) {
|
||||
args := c.Args()
|
||||
if args.Present() {
|
||||
ShowCommandHelp(c, args.First())
|
||||
} else {
|
||||
ShowSubcommandHelp(c)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// Prints help for the App or Command
|
||||
type helpPrinter func(w io.Writer, templ string, data interface{})
|
||||
|
||||
var HelpPrinter helpPrinter = printHelp
|
||||
|
||||
// Prints version for the App
|
||||
var VersionPrinter = printVersion
|
||||
|
||||
func ShowAppHelp(c *Context) {
|
||||
HelpPrinter(c.App.Writer, AppHelpTemplate, c.App)
|
||||
}
|
||||
|
||||
// Prints the list of subcommands as the default app completion method
|
||||
func DefaultAppComplete(c *Context) {
|
||||
for _, command := range c.App.Commands {
|
||||
for _, name := range command.Names() {
|
||||
fmt.Fprintln(c.App.Writer, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prints help for the given command
|
||||
func ShowCommandHelp(ctx *Context, command string) {
|
||||
// show the subcommand help for a command with subcommands
|
||||
if command == "" {
|
||||
HelpPrinter(ctx.App.Writer, SubcommandHelpTemplate, ctx.App)
|
||||
return
|
||||
}
|
||||
|
||||
for _, c := range ctx.App.Commands {
|
||||
if c.HasName(command) {
|
||||
HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.App.CommandNotFound != nil {
|
||||
ctx.App.CommandNotFound(ctx, command)
|
||||
} else {
|
||||
fmt.Fprintf(ctx.App.Writer, "No help topic for '%v'\n", command)
|
||||
}
|
||||
}
|
||||
|
||||
// Prints help for the given subcommand
|
||||
func ShowSubcommandHelp(c *Context) {
|
||||
ShowCommandHelp(c, c.Command.Name)
|
||||
}
|
||||
|
||||
// Prints the version number of the App
|
||||
func ShowVersion(c *Context) {
|
||||
VersionPrinter(c)
|
||||
}
|
||||
|
||||
func printVersion(c *Context) {
|
||||
fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version)
|
||||
}
|
||||
|
||||
// Prints the lists of commands within a given context
|
||||
func ShowCompletions(c *Context) {
|
||||
a := c.App
|
||||
if a != nil && a.BashComplete != nil {
|
||||
a.BashComplete(c)
|
||||
}
|
||||
}
|
||||
|
||||
// Prints the custom completions for a given command
|
||||
func ShowCommandCompletions(ctx *Context, command string) {
|
||||
c := ctx.App.Command(command)
|
||||
if c != nil && c.BashComplete != nil {
|
||||
c.BashComplete(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func printHelp(out io.Writer, templ string, data interface{}) {
|
||||
funcMap := template.FuncMap{
|
||||
"join": strings.Join,
|
||||
}
|
||||
|
||||
w := tabwriter.NewWriter(out, 0, 8, 1, '\t', 0)
|
||||
t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
|
||||
err := t.Execute(w, data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
w.Flush()
|
||||
}
|
||||
|
||||
func checkVersion(c *Context) bool {
|
||||
if c.GlobalBool("version") {
|
||||
ShowVersion(c)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func checkHelp(c *Context) bool {
|
||||
if c.GlobalBool("h") || c.GlobalBool("help") {
|
||||
ShowAppHelp(c)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func checkCommandHelp(c *Context, name string) bool {
|
||||
if c.Bool("h") || c.Bool("help") {
|
||||
ShowCommandHelp(c, name)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func checkSubcommandHelp(c *Context) bool {
|
||||
if c.GlobalBool("h") || c.GlobalBool("help") {
|
||||
ShowSubcommandHelp(c)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func checkCompletions(c *Context) bool {
|
||||
if (c.GlobalBool(BashCompletionFlag.Name) || c.Bool(BashCompletionFlag.Name)) && c.App.EnableBashCompletion {
|
||||
ShowCompletions(c)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func checkCommandCompletions(c *Context, name string) bool {
|
||||
if c.Bool(BashCompletionFlag.Name) && c.App.EnableBashCompletion {
|
||||
ShowCommandCompletions(c, name)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
22
Godeps/_workspace/src/github.com/codegangsta/cli/help_test.go
generated
vendored
22
Godeps/_workspace/src/github.com/codegangsta/cli/help_test.go
generated
vendored
@@ -1,22 +0,0 @@
|
||||
package cli_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/tendermint/tendermint/Godeps/_workspace/src/github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
func Test_ShowAppHelp_NoAuthor(t *testing.T) {
|
||||
output := new(bytes.Buffer)
|
||||
app := cli.NewApp()
|
||||
app.Writer = output
|
||||
|
||||
c := cli.NewContext(app, nil, nil)
|
||||
|
||||
cli.ShowAppHelp(c)
|
||||
|
||||
if bytes.Index(output.Bytes(), []byte("AUTHOR(S):")) != -1 {
|
||||
t.Errorf("expected\n%snot to include %s", output.String(), "AUTHOR(S):")
|
||||
}
|
||||
}
|
||||
19
Godeps/_workspace/src/github.com/codegangsta/cli/helpers_test.go
generated
vendored
19
Godeps/_workspace/src/github.com/codegangsta/cli/helpers_test.go
generated
vendored
@@ -1,19 +0,0 @@
|
||||
package cli_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
/* Test Helpers */
|
||||
func expect(t *testing.T, a interface{}, b interface{}) {
|
||||
if a != b {
|
||||
t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
|
||||
}
|
||||
}
|
||||
|
||||
func refute(t *testing.T, a interface{}, b interface{}) {
|
||||
if a == b {
|
||||
t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
|
||||
}
|
||||
}
|
||||
22
Godeps/_workspace/src/github.com/gorilla/websocket/.gitignore
generated
vendored
22
Godeps/_workspace/src/github.com/gorilla/websocket/.gitignore
generated
vendored
@@ -1,22 +0,0 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
6
Godeps/_workspace/src/github.com/gorilla/websocket/.travis.yml
generated
vendored
6
Godeps/_workspace/src/github.com/gorilla/websocket/.travis.yml
generated
vendored
@@ -1,6 +0,0 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.1
|
||||
- 1.2
|
||||
- tip
|
||||
8
Godeps/_workspace/src/github.com/gorilla/websocket/AUTHORS
generated
vendored
8
Godeps/_workspace/src/github.com/gorilla/websocket/AUTHORS
generated
vendored
@@ -1,8 +0,0 @@
|
||||
# This is the official list of Gorilla WebSocket authors for copyright
|
||||
# purposes.
|
||||
#
|
||||
# Please keep the list sorted.
|
||||
|
||||
Gary Burd <gary@beagledreams.com>
|
||||
Joachim Bauch <mail@joachim-bauch.de>
|
||||
|
||||
22
Godeps/_workspace/src/github.com/gorilla/websocket/LICENSE
generated
vendored
22
Godeps/_workspace/src/github.com/gorilla/websocket/LICENSE
generated
vendored
@@ -1,22 +0,0 @@
|
||||
Copyright (c) 2013 The Gorilla WebSocket Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
59
Godeps/_workspace/src/github.com/gorilla/websocket/README.md
generated
vendored
59
Godeps/_workspace/src/github.com/gorilla/websocket/README.md
generated
vendored
@@ -1,59 +0,0 @@
|
||||
# Gorilla WebSocket
|
||||
|
||||
Gorilla WebSocket is a [Go](http://golang.org/) implementation of the
|
||||
[WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol.
|
||||
|
||||
### Documentation
|
||||
|
||||
* [API Reference](http://godoc.org/github.com/gorilla/websocket)
|
||||
* [Chat example](https://github.com/gorilla/websocket/tree/master/examples/chat)
|
||||
* [File watch example](https://github.com/gorilla/websocket/tree/master/examples/filewatch)
|
||||
|
||||
### Status
|
||||
|
||||
The Gorilla WebSocket package provides a complete and tested implementation of
|
||||
the [WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. The
|
||||
package API is stable.
|
||||
|
||||
### Installation
|
||||
|
||||
go get github.com/gorilla/websocket
|
||||
|
||||
### Protocol Compliance
|
||||
|
||||
The Gorilla WebSocket package passes the server tests in the [Autobahn Test
|
||||
Suite](http://autobahn.ws/testsuite) using the application in the [examples/autobahn
|
||||
subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn).
|
||||
|
||||
### Gorilla WebSocket compared with other packages
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th><a href="http://godoc.org/github.com/gorilla/websocket">github.com/gorilla</a></th>
|
||||
<th><a href="http://godoc.org/golang.org/x/net/websocket">golang.org/x/net</a></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr><td colspan="3"><a href="http://tools.ietf.org/html/rfc6455">RFC 6455</a> Features</td></tr>
|
||||
<tr><td>Passes <a href="http://autobahn.ws/testsuite/">Autobahn Test Suite</a></td><td><a href="https://github.com/gorilla/websocket/tree/master/examples/autobahn">Yes</a></td><td>No</td></tr>
|
||||
<tr><td>Receive <a href="https://tools.ietf.org/html/rfc6455#section-5.4">fragmented</a> message<td>Yes</td><td><a href="https://code.google.com/p/go/issues/detail?id=7632">No</a>, see note 1</td></tr>
|
||||
<tr><td>Send <a href="https://tools.ietf.org/html/rfc6455#section-5.5.1">close</a> message</td><td><a href="http://godoc.org/github.com/gorilla/websocket#hdr-Control_Messages">Yes</a></td><td><a href="https://code.google.com/p/go/issues/detail?id=4588">No</a></td></tr>
|
||||
<tr><td>Send <a href="https://tools.ietf.org/html/rfc6455#section-5.5.2">pings</a> and receive <a href="https://tools.ietf.org/html/rfc6455#section-5.5.3">pongs</a></td><td><a href="http://godoc.org/github.com/gorilla/websocket#hdr-Control_Messages">Yes</a></td><td>No</td></tr>
|
||||
<tr><td>Get the <a href="https://tools.ietf.org/html/rfc6455#section-5.6">type</a> of a received data message</td><td>Yes</td><td>Yes, see note 2</td></tr>
|
||||
<tr><td colspan="3">Other Features</tr></td>
|
||||
<tr><td>Limit size of received message</td><td><a href="http://godoc.org/github.com/gorilla/websocket#Conn.SetReadLimit">Yes</a></td><td><a href="https://code.google.com/p/go/issues/detail?id=5082">No</a></td></tr>
|
||||
<tr><td>Read message using io.Reader</td><td><a href="http://godoc.org/github.com/gorilla/websocket#Conn.NextReader">Yes</a></td><td>No, see note 3</td></tr>
|
||||
<tr><td>Write message using io.WriteCloser</td><td><a href="http://godoc.org/github.com/gorilla/websocket#Conn.NextWriter">Yes</a></td><td>No, see note 3</td></tr>
|
||||
</table>
|
||||
|
||||
Notes:
|
||||
|
||||
1. Large messages are fragmented in [Chrome's new WebSocket implementation](http://www.ietf.org/mail-archive/web/hybi/current/msg10503.html).
|
||||
2. The application can get the type of a received data message by implementing
|
||||
a [Codec marshal](http://godoc.org/golang.org/x/net/websocket#Codec.Marshal)
|
||||
function.
|
||||
3. The go.net io.Reader and io.Writer operate across WebSocket frame boundaries.
|
||||
Read returns when the input buffer is full or a frame boundary is
|
||||
encountered. Each call to Write sends a single frame message. The Gorilla
|
||||
io.Reader and io.WriteCloser operate on a single WebSocket message.
|
||||
|
||||
19
Godeps/_workspace/src/github.com/gorilla/websocket/bench_test.go
generated
vendored
19
Godeps/_workspace/src/github.com/gorilla/websocket/bench_test.go
generated
vendored
@@ -1,19 +0,0 @@
|
||||
// Copyright 2014 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkMaskBytes(b *testing.B) {
|
||||
var key [4]byte
|
||||
data := make([]byte, 1024)
|
||||
pos := 0
|
||||
for i := 0; i < b.N; i++ {
|
||||
pos = maskBytes(key, pos, data)
|
||||
}
|
||||
b.SetBytes(int64(len(data)))
|
||||
}
|
||||
235
Godeps/_workspace/src/github.com/gorilla/websocket/client.go
generated
vendored
235
Godeps/_workspace/src/github.com/gorilla/websocket/client.go
generated
vendored
@@ -1,235 +0,0 @@
|
||||
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ErrBadHandshake is returned when the server response to opening handshake is
|
||||
// invalid.
|
||||
var ErrBadHandshake = errors.New("websocket: bad handshake")
|
||||
|
||||
// NewClient creates a new client connection using the given net connection.
|
||||
// The URL u specifies the host and request URI. Use requestHeader to specify
|
||||
// the origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies
|
||||
// (Cookie). Use the response.Header to get the selected subprotocol
|
||||
// (Sec-WebSocket-Protocol) and cookies (Set-Cookie).
|
||||
//
|
||||
// If the WebSocket handshake fails, ErrBadHandshake is returned along with a
|
||||
// non-nil *http.Response so that callers can handle redirects, authentication,
|
||||
// etc.
|
||||
func NewClient(netConn net.Conn, u *url.URL, requestHeader http.Header, readBufSize, writeBufSize int) (c *Conn, response *http.Response, err error) {
|
||||
challengeKey, err := generateChallengeKey()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
acceptKey := computeAcceptKey(challengeKey)
|
||||
|
||||
c = newConn(netConn, false, readBufSize, writeBufSize)
|
||||
p := c.writeBuf[:0]
|
||||
p = append(p, "GET "...)
|
||||
p = append(p, u.RequestURI()...)
|
||||
p = append(p, " HTTP/1.1\r\nHost: "...)
|
||||
p = append(p, u.Host...)
|
||||
// "Upgrade" is capitalized for servers that do not use case insensitive
|
||||
// comparisons on header tokens.
|
||||
p = append(p, "\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: "...)
|
||||
p = append(p, challengeKey...)
|
||||
p = append(p, "\r\n"...)
|
||||
for k, vs := range requestHeader {
|
||||
for _, v := range vs {
|
||||
p = append(p, k...)
|
||||
p = append(p, ": "...)
|
||||
p = append(p, v...)
|
||||
p = append(p, "\r\n"...)
|
||||
}
|
||||
}
|
||||
p = append(p, "\r\n"...)
|
||||
|
||||
if _, err := netConn.Write(p); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
resp, err := http.ReadResponse(c.br, &http.Request{Method: "GET", URL: u})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if resp.StatusCode != 101 ||
|
||||
!strings.EqualFold(resp.Header.Get("Upgrade"), "websocket") ||
|
||||
!strings.EqualFold(resp.Header.Get("Connection"), "upgrade") ||
|
||||
resp.Header.Get("Sec-Websocket-Accept") != acceptKey {
|
||||
return nil, resp, ErrBadHandshake
|
||||
}
|
||||
c.subprotocol = resp.Header.Get("Sec-Websocket-Protocol")
|
||||
return c, resp, nil
|
||||
}
|
||||
|
||||
// A Dialer contains options for connecting to WebSocket server.
|
||||
type Dialer struct {
|
||||
// NetDial specifies the dial function for creating TCP connections. If
|
||||
// NetDial is nil, net.Dial is used.
|
||||
NetDial func(network, addr string) (net.Conn, error)
|
||||
|
||||
// TLSClientConfig specifies the TLS configuration to use with tls.Client.
|
||||
// If nil, the default configuration is used.
|
||||
TLSClientConfig *tls.Config
|
||||
|
||||
// HandshakeTimeout specifies the duration for the handshake to complete.
|
||||
HandshakeTimeout time.Duration
|
||||
|
||||
// Input and output buffer sizes. If the buffer size is zero, then a
|
||||
// default value of 4096 is used.
|
||||
ReadBufferSize, WriteBufferSize int
|
||||
|
||||
// Subprotocols specifies the client's requested subprotocols.
|
||||
Subprotocols []string
|
||||
}
|
||||
|
||||
var errMalformedURL = errors.New("malformed ws or wss URL")
|
||||
|
||||
// parseURL parses the URL. The url.Parse function is not used here because
|
||||
// url.Parse mangles the path.
|
||||
func parseURL(s string) (*url.URL, error) {
|
||||
// From the RFC:
|
||||
//
|
||||
// ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ]
|
||||
// wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ]
|
||||
//
|
||||
// We don't use the net/url parser here because the dialer interface does
|
||||
// not provide a way for applications to work around percent deocding in
|
||||
// the net/url parser.
|
||||
|
||||
var u url.URL
|
||||
switch {
|
||||
case strings.HasPrefix(s, "ws://"):
|
||||
u.Scheme = "ws"
|
||||
s = s[len("ws://"):]
|
||||
case strings.HasPrefix(s, "wss://"):
|
||||
u.Scheme = "wss"
|
||||
s = s[len("wss://"):]
|
||||
default:
|
||||
return nil, errMalformedURL
|
||||
}
|
||||
|
||||
u.Host = s
|
||||
u.Opaque = "/"
|
||||
if i := strings.Index(s, "/"); i >= 0 {
|
||||
u.Host = s[:i]
|
||||
u.Opaque = s[i:]
|
||||
}
|
||||
|
||||
return &u, nil
|
||||
}
|
||||
|
||||
func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) {
|
||||
hostPort = u.Host
|
||||
hostNoPort = u.Host
|
||||
if i := strings.LastIndex(u.Host, ":"); i > strings.LastIndex(u.Host, "]") {
|
||||
hostNoPort = hostNoPort[:i]
|
||||
} else {
|
||||
if u.Scheme == "wss" {
|
||||
hostPort += ":443"
|
||||
} else {
|
||||
hostPort += ":80"
|
||||
}
|
||||
}
|
||||
return hostPort, hostNoPort
|
||||
}
|
||||
|
||||
// DefaultDialer is a dialer with all fields set to the default zero values.
|
||||
var DefaultDialer *Dialer
|
||||
|
||||
// Dial creates a new client connection. Use requestHeader to specify the
|
||||
// origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies (Cookie).
|
||||
// Use the response.Header to get the selected subprotocol
|
||||
// (Sec-WebSocket-Protocol) and cookies (Set-Cookie).
|
||||
//
|
||||
// If the WebSocket handshake fails, ErrBadHandshake is returned along with a
|
||||
// non-nil *http.Response so that callers can handle redirects, authentication,
|
||||
// etc.
|
||||
func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) {
|
||||
u, err := parseURL(urlStr)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
hostPort, hostNoPort := hostPortNoPort(u)
|
||||
|
||||
if d == nil {
|
||||
d = &Dialer{}
|
||||
}
|
||||
|
||||
var deadline time.Time
|
||||
if d.HandshakeTimeout != 0 {
|
||||
deadline = time.Now().Add(d.HandshakeTimeout)
|
||||
}
|
||||
|
||||
netDial := d.NetDial
|
||||
if netDial == nil {
|
||||
netDialer := &net.Dialer{Deadline: deadline}
|
||||
netDial = netDialer.Dial
|
||||
}
|
||||
|
||||
netConn, err := netDial("tcp", hostPort)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if netConn != nil {
|
||||
netConn.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
if err := netConn.SetDeadline(deadline); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if u.Scheme == "wss" {
|
||||
cfg := d.TLSClientConfig
|
||||
if cfg == nil {
|
||||
cfg = &tls.Config{ServerName: hostNoPort}
|
||||
} else if cfg.ServerName == "" {
|
||||
shallowCopy := *cfg
|
||||
cfg = &shallowCopy
|
||||
cfg.ServerName = hostNoPort
|
||||
}
|
||||
tlsConn := tls.Client(netConn, cfg)
|
||||
netConn = tlsConn
|
||||
if err := tlsConn.Handshake(); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if !cfg.InsecureSkipVerify {
|
||||
if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(d.Subprotocols) > 0 {
|
||||
h := http.Header{}
|
||||
for k, v := range requestHeader {
|
||||
h[k] = v
|
||||
}
|
||||
h.Set("Sec-Websocket-Protocol", strings.Join(d.Subprotocols, ", "))
|
||||
requestHeader = h
|
||||
}
|
||||
|
||||
conn, resp, err := NewClient(netConn, u, requestHeader, d.ReadBufferSize, d.WriteBufferSize)
|
||||
if err != nil {
|
||||
return nil, resp, err
|
||||
}
|
||||
|
||||
netConn.SetDeadline(time.Time{})
|
||||
netConn = nil // to avoid close in defer.
|
||||
return conn, resp, nil
|
||||
}
|
||||
249
Godeps/_workspace/src/github.com/gorilla/websocket/client_server_test.go
generated
vendored
249
Godeps/_workspace/src/github.com/gorilla/websocket/client_server_test.go
generated
vendored
@@ -1,249 +0,0 @@
|
||||
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var cstUpgrader = Upgrader{
|
||||
Subprotocols: []string{"p0", "p1"},
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024,
|
||||
Error: func(w http.ResponseWriter, r *http.Request, status int, reason error) {
|
||||
http.Error(w, reason.Error(), status)
|
||||
},
|
||||
}
|
||||
|
||||
var cstDialer = Dialer{
|
||||
Subprotocols: []string{"p1", "p2"},
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024,
|
||||
}
|
||||
|
||||
type cstHandler struct{ *testing.T }
|
||||
|
||||
type Server struct {
|
||||
*httptest.Server
|
||||
URL string
|
||||
}
|
||||
|
||||
func newServer(t *testing.T) *Server {
|
||||
var s Server
|
||||
s.Server = httptest.NewServer(cstHandler{t})
|
||||
s.URL = "ws" + s.Server.URL[len("http"):]
|
||||
return &s
|
||||
}
|
||||
|
||||
func newTLSServer(t *testing.T) *Server {
|
||||
var s Server
|
||||
s.Server = httptest.NewTLSServer(cstHandler{t})
|
||||
s.URL = "ws" + s.Server.URL[len("http"):]
|
||||
return &s
|
||||
}
|
||||
|
||||
func (t cstHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
t.Logf("method %s not allowed", r.Method)
|
||||
http.Error(w, "method not allowed", 405)
|
||||
return
|
||||
}
|
||||
subprotos := Subprotocols(r)
|
||||
if !reflect.DeepEqual(subprotos, cstDialer.Subprotocols) {
|
||||
t.Logf("subprotols=%v, want %v", subprotos, cstDialer.Subprotocols)
|
||||
http.Error(w, "bad protocol", 400)
|
||||
return
|
||||
}
|
||||
ws, err := cstUpgrader.Upgrade(w, r, http.Header{"Set-Cookie": {"sessionID=1234"}})
|
||||
if err != nil {
|
||||
t.Logf("Upgrade: %v", err)
|
||||
return
|
||||
}
|
||||
defer ws.Close()
|
||||
|
||||
if ws.Subprotocol() != "p1" {
|
||||
t.Logf("Subprotocol() = %s, want p1", ws.Subprotocol())
|
||||
ws.Close()
|
||||
return
|
||||
}
|
||||
op, rd, err := ws.NextReader()
|
||||
if err != nil {
|
||||
t.Logf("NextReader: %v", err)
|
||||
return
|
||||
}
|
||||
wr, err := ws.NextWriter(op)
|
||||
if err != nil {
|
||||
t.Logf("NextWriter: %v", err)
|
||||
return
|
||||
}
|
||||
if _, err = io.Copy(wr, rd); err != nil {
|
||||
t.Logf("NextWriter: %v", err)
|
||||
return
|
||||
}
|
||||
if err := wr.Close(); err != nil {
|
||||
t.Logf("Close: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func sendRecv(t *testing.T, ws *Conn) {
|
||||
const message = "Hello World!"
|
||||
if err := ws.SetWriteDeadline(time.Now().Add(time.Second)); err != nil {
|
||||
t.Fatalf("SetWriteDeadline: %v", err)
|
||||
}
|
||||
if err := ws.WriteMessage(TextMessage, []byte(message)); err != nil {
|
||||
t.Fatalf("WriteMessage: %v", err)
|
||||
}
|
||||
if err := ws.SetReadDeadline(time.Now().Add(time.Second)); err != nil {
|
||||
t.Fatalf("SetReadDeadline: %v", err)
|
||||
}
|
||||
_, p, err := ws.ReadMessage()
|
||||
if err != nil {
|
||||
t.Fatalf("ReadMessage: %v", err)
|
||||
}
|
||||
if string(p) != message {
|
||||
t.Fatalf("message=%s, want %s", p, message)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDial(t *testing.T) {
|
||||
s := newServer(t)
|
||||
defer s.Close()
|
||||
|
||||
ws, _, err := cstDialer.Dial(s.URL, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Dial: %v", err)
|
||||
}
|
||||
defer ws.Close()
|
||||
sendRecv(t, ws)
|
||||
}
|
||||
|
||||
func TestDialTLS(t *testing.T) {
|
||||
s := newTLSServer(t)
|
||||
defer s.Close()
|
||||
|
||||
certs := x509.NewCertPool()
|
||||
for _, c := range s.TLS.Certificates {
|
||||
roots, err := x509.ParseCertificates(c.Certificate[len(c.Certificate)-1])
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing server's root cert: %v", err)
|
||||
}
|
||||
for _, root := range roots {
|
||||
certs.AddCert(root)
|
||||
}
|
||||
}
|
||||
|
||||
u, _ := url.Parse(s.URL)
|
||||
d := cstDialer
|
||||
d.NetDial = func(network, addr string) (net.Conn, error) { return net.Dial(network, u.Host) }
|
||||
d.TLSClientConfig = &tls.Config{RootCAs: certs}
|
||||
ws, _, err := d.Dial("wss://example.com/", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Dial: %v", err)
|
||||
}
|
||||
defer ws.Close()
|
||||
sendRecv(t, ws)
|
||||
}
|
||||
|
||||
func xTestDialTLSBadCert(t *testing.T) {
|
||||
s := newTLSServer(t)
|
||||
defer s.Close()
|
||||
|
||||
ws, _, err := cstDialer.Dial(s.URL, nil)
|
||||
if err == nil {
|
||||
ws.Close()
|
||||
t.Fatalf("Dial: nil")
|
||||
}
|
||||
}
|
||||
|
||||
func xTestDialTLSNoVerify(t *testing.T) {
|
||||
s := newTLSServer(t)
|
||||
defer s.Close()
|
||||
|
||||
d := cstDialer
|
||||
d.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
ws, _, err := d.Dial(s.URL, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Dial: %v", err)
|
||||
}
|
||||
defer ws.Close()
|
||||
sendRecv(t, ws)
|
||||
}
|
||||
|
||||
func TestDialTimeout(t *testing.T) {
|
||||
s := newServer(t)
|
||||
defer s.Close()
|
||||
|
||||
d := cstDialer
|
||||
d.HandshakeTimeout = -1
|
||||
ws, _, err := d.Dial(s.URL, nil)
|
||||
if err == nil {
|
||||
ws.Close()
|
||||
t.Fatalf("Dial: nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDialBadScheme(t *testing.T) {
|
||||
s := newServer(t)
|
||||
defer s.Close()
|
||||
|
||||
ws, _, err := cstDialer.Dial(s.Server.URL, nil)
|
||||
if err == nil {
|
||||
ws.Close()
|
||||
t.Fatalf("Dial: nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDialBadOrigin(t *testing.T) {
|
||||
s := newServer(t)
|
||||
defer s.Close()
|
||||
|
||||
ws, resp, err := cstDialer.Dial(s.URL, http.Header{"Origin": {"bad"}})
|
||||
if err == nil {
|
||||
ws.Close()
|
||||
t.Fatalf("Dial: nil")
|
||||
}
|
||||
if resp == nil {
|
||||
t.Fatalf("resp=nil, err=%v", err)
|
||||
}
|
||||
if resp.StatusCode != http.StatusForbidden {
|
||||
t.Fatalf("status=%d, want %d", resp.StatusCode, http.StatusForbidden)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandshake(t *testing.T) {
|
||||
s := newServer(t)
|
||||
defer s.Close()
|
||||
|
||||
ws, resp, err := cstDialer.Dial(s.URL, http.Header{"Origin": {s.URL}})
|
||||
if err != nil {
|
||||
t.Fatalf("Dial: %v", err)
|
||||
}
|
||||
defer ws.Close()
|
||||
|
||||
var sessionID string
|
||||
for _, c := range resp.Cookies() {
|
||||
if c.Name == "sessionID" {
|
||||
sessionID = c.Value
|
||||
}
|
||||
}
|
||||
if sessionID != "1234" {
|
||||
t.Error("Set-Cookie not received from the server.")
|
||||
}
|
||||
|
||||
if ws.Subprotocol() != "p1" {
|
||||
t.Errorf("ws.Subprotocol() = %s, want p1", ws.Subprotocol())
|
||||
}
|
||||
sendRecv(t, ws)
|
||||
}
|
||||
63
Godeps/_workspace/src/github.com/gorilla/websocket/client_test.go
generated
vendored
63
Godeps/_workspace/src/github.com/gorilla/websocket/client_test.go
generated
vendored
@@ -1,63 +0,0 @@
|
||||
// Copyright 2014 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var parseURLTests = []struct {
|
||||
s string
|
||||
u *url.URL
|
||||
}{
|
||||
{"ws://example.com/", &url.URL{Scheme: "ws", Host: "example.com", Opaque: "/"}},
|
||||
{"ws://example.com", &url.URL{Scheme: "ws", Host: "example.com", Opaque: "/"}},
|
||||
{"ws://example.com:7777/", &url.URL{Scheme: "ws", Host: "example.com:7777", Opaque: "/"}},
|
||||
{"wss://example.com/", &url.URL{Scheme: "wss", Host: "example.com", Opaque: "/"}},
|
||||
{"wss://example.com/a/b", &url.URL{Scheme: "wss", Host: "example.com", Opaque: "/a/b"}},
|
||||
{"ss://example.com/a/b", nil},
|
||||
}
|
||||
|
||||
func TestParseURL(t *testing.T) {
|
||||
for _, tt := range parseURLTests {
|
||||
u, err := parseURL(tt.s)
|
||||
if tt.u != nil && err != nil {
|
||||
t.Errorf("parseURL(%q) returned error %v", tt.s, err)
|
||||
continue
|
||||
}
|
||||
if tt.u == nil && err == nil {
|
||||
t.Errorf("parseURL(%q) did not return error", tt.s)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(u, tt.u) {
|
||||
t.Errorf("parseURL(%q) returned %v, want %v", tt.s, u, tt.u)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var hostPortNoPortTests = []struct {
|
||||
u *url.URL
|
||||
hostPort, hostNoPort string
|
||||
}{
|
||||
{&url.URL{Scheme: "ws", Host: "example.com"}, "example.com:80", "example.com"},
|
||||
{&url.URL{Scheme: "wss", Host: "example.com"}, "example.com:443", "example.com"},
|
||||
{&url.URL{Scheme: "ws", Host: "example.com:7777"}, "example.com:7777", "example.com"},
|
||||
{&url.URL{Scheme: "wss", Host: "example.com:7777"}, "example.com:7777", "example.com"},
|
||||
}
|
||||
|
||||
func TestHostPortNoPort(t *testing.T) {
|
||||
for _, tt := range hostPortNoPortTests {
|
||||
hostPort, hostNoPort := hostPortNoPort(tt.u)
|
||||
if hostPort != tt.hostPort {
|
||||
t.Errorf("hostPortNoPort(%v) returned hostPort %q, want %q", tt.u, hostPort, tt.hostPort)
|
||||
}
|
||||
if hostNoPort != tt.hostNoPort {
|
||||
t.Errorf("hostPortNoPort(%v) returned hostNoPort %q, want %q", tt.u, hostNoPort, tt.hostNoPort)
|
||||
}
|
||||
}
|
||||
}
|
||||
825
Godeps/_workspace/src/github.com/gorilla/websocket/conn.go
generated
vendored
825
Godeps/_workspace/src/github.com/gorilla/websocket/conn.go
generated
vendored
@@ -1,825 +0,0 @@
|
||||
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
maxFrameHeaderSize = 2 + 8 + 4 // Fixed header + length + mask
|
||||
maxControlFramePayloadSize = 125
|
||||
finalBit = 1 << 7
|
||||
maskBit = 1 << 7
|
||||
writeWait = time.Second
|
||||
|
||||
defaultReadBufferSize = 4096
|
||||
defaultWriteBufferSize = 4096
|
||||
|
||||
continuationFrame = 0
|
||||
noFrame = -1
|
||||
)
|
||||
|
||||
// Close codes defined in RFC 6455, section 11.7.
|
||||
const (
|
||||
CloseNormalClosure = 1000
|
||||
CloseGoingAway = 1001
|
||||
CloseProtocolError = 1002
|
||||
CloseUnsupportedData = 1003
|
||||
CloseNoStatusReceived = 1005
|
||||
CloseAbnormalClosure = 1006
|
||||
CloseInvalidFramePayloadData = 1007
|
||||
ClosePolicyViolation = 1008
|
||||
CloseMessageTooBig = 1009
|
||||
CloseMandatoryExtension = 1010
|
||||
CloseInternalServerErr = 1011
|
||||
CloseTLSHandshake = 1015
|
||||
)
|
||||
|
||||
// The message types are defined in RFC 6455, section 11.8.
|
||||
const (
|
||||
// TextMessage denotes a text data message. The text message payload is
|
||||
// interpreted as UTF-8 encoded text data.
|
||||
TextMessage = 1
|
||||
|
||||
// BinaryMessage denotes a binary data message.
|
||||
BinaryMessage = 2
|
||||
|
||||
// CloseMessage denotes a close control message. The optional message
|
||||
// payload contains a numeric code and text. Use the FormatCloseMessage
|
||||
// function to format a close message payload.
|
||||
CloseMessage = 8
|
||||
|
||||
// PingMessage denotes a ping control message. The optional message payload
|
||||
// is UTF-8 encoded text.
|
||||
PingMessage = 9
|
||||
|
||||
// PongMessage denotes a ping control message. The optional message payload
|
||||
// is UTF-8 encoded text.
|
||||
PongMessage = 10
|
||||
)
|
||||
|
||||
// ErrCloseSent is returned when the application writes a message to the
|
||||
// connection after sending a close message.
|
||||
var ErrCloseSent = errors.New("websocket: close sent")
|
||||
|
||||
// ErrReadLimit is returned when reading a message that is larger than the
|
||||
// read limit set for the connection.
|
||||
var ErrReadLimit = errors.New("websocket: read limit exceeded")
|
||||
|
||||
// netError satisfies the net Error interface.
|
||||
type netError struct {
|
||||
msg string
|
||||
temporary bool
|
||||
timeout bool
|
||||
}
|
||||
|
||||
func (e *netError) Error() string { return e.msg }
|
||||
func (e *netError) Temporary() bool { return e.temporary }
|
||||
func (e *netError) Timeout() bool { return e.timeout }
|
||||
|
||||
// closeError represents close frame.
|
||||
type closeError struct {
|
||||
code int
|
||||
text string
|
||||
}
|
||||
|
||||
func (e *closeError) Error() string {
|
||||
return "websocket: close " + strconv.Itoa(e.code) + " " + e.text
|
||||
}
|
||||
|
||||
var (
|
||||
errWriteTimeout = &netError{msg: "websocket: write timeout", timeout: true}
|
||||
errUnexpectedEOF = &closeError{code: CloseAbnormalClosure, text: io.ErrUnexpectedEOF.Error()}
|
||||
errBadWriteOpCode = errors.New("websocket: bad write message type")
|
||||
errWriteClosed = errors.New("websocket: write closed")
|
||||
errInvalidControlFrame = errors.New("websocket: invalid control frame")
|
||||
)
|
||||
|
||||
func hideTempErr(err error) error {
|
||||
if e, ok := err.(net.Error); ok && e.Temporary() {
|
||||
err = &netError{msg: e.Error(), timeout: e.Timeout()}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func isControl(frameType int) bool {
|
||||
return frameType == CloseMessage || frameType == PingMessage || frameType == PongMessage
|
||||
}
|
||||
|
||||
func isData(frameType int) bool {
|
||||
return frameType == TextMessage || frameType == BinaryMessage
|
||||
}
|
||||
|
||||
func maskBytes(key [4]byte, pos int, b []byte) int {
|
||||
for i := range b {
|
||||
b[i] ^= key[pos&3]
|
||||
pos++
|
||||
}
|
||||
return pos & 3
|
||||
}
|
||||
|
||||
func newMaskKey() [4]byte {
|
||||
n := rand.Uint32()
|
||||
return [4]byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)}
|
||||
}
|
||||
|
||||
// Conn represents a WebSocket connection.
|
||||
type Conn struct {
|
||||
conn net.Conn
|
||||
isServer bool
|
||||
subprotocol string
|
||||
|
||||
// Write fields
|
||||
mu chan bool // used as mutex to protect write to conn and closeSent
|
||||
closeSent bool // true if close message was sent
|
||||
|
||||
// Message writer fields.
|
||||
writeErr error
|
||||
writeBuf []byte // frame is constructed in this buffer.
|
||||
writePos int // end of data in writeBuf.
|
||||
writeFrameType int // type of the current frame.
|
||||
writeSeq int // incremented to invalidate message writers.
|
||||
writeDeadline time.Time
|
||||
|
||||
// Read fields
|
||||
readErr error
|
||||
br *bufio.Reader
|
||||
readRemaining int64 // bytes remaining in current frame.
|
||||
readFinal bool // true the current message has more frames.
|
||||
readSeq int // incremented to invalidate message readers.
|
||||
readLength int64 // Message size.
|
||||
readLimit int64 // Maximum message size.
|
||||
readMaskPos int
|
||||
readMaskKey [4]byte
|
||||
handlePong func(string) error
|
||||
handlePing func(string) error
|
||||
}
|
||||
|
||||
func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int) *Conn {
|
||||
mu := make(chan bool, 1)
|
||||
mu <- true
|
||||
|
||||
if readBufferSize == 0 {
|
||||
readBufferSize = defaultReadBufferSize
|
||||
}
|
||||
if writeBufferSize == 0 {
|
||||
writeBufferSize = defaultWriteBufferSize
|
||||
}
|
||||
|
||||
c := &Conn{
|
||||
isServer: isServer,
|
||||
br: bufio.NewReaderSize(conn, readBufferSize),
|
||||
conn: conn,
|
||||
mu: mu,
|
||||
readFinal: true,
|
||||
writeBuf: make([]byte, writeBufferSize+maxFrameHeaderSize),
|
||||
writeFrameType: noFrame,
|
||||
writePos: maxFrameHeaderSize,
|
||||
}
|
||||
c.SetPingHandler(nil)
|
||||
c.SetPongHandler(nil)
|
||||
return c
|
||||
}
|
||||
|
||||
// Subprotocol returns the negotiated protocol for the connection.
|
||||
func (c *Conn) Subprotocol() string {
|
||||
return c.subprotocol
|
||||
}
|
||||
|
||||
// Close closes the underlying network connection without sending or waiting for a close frame.
|
||||
func (c *Conn) Close() error {
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
// LocalAddr returns the local network address.
|
||||
func (c *Conn) LocalAddr() net.Addr {
|
||||
return c.conn.LocalAddr()
|
||||
}
|
||||
|
||||
// RemoteAddr returns the remote network address.
|
||||
func (c *Conn) RemoteAddr() net.Addr {
|
||||
return c.conn.RemoteAddr()
|
||||
}
|
||||
|
||||
// Write methods
|
||||
|
||||
func (c *Conn) write(frameType int, deadline time.Time, bufs ...[]byte) error {
|
||||
<-c.mu
|
||||
defer func() { c.mu <- true }()
|
||||
|
||||
if c.closeSent {
|
||||
return ErrCloseSent
|
||||
} else if frameType == CloseMessage {
|
||||
c.closeSent = true
|
||||
}
|
||||
|
||||
c.conn.SetWriteDeadline(deadline)
|
||||
for _, buf := range bufs {
|
||||
if len(buf) > 0 {
|
||||
n, err := c.conn.Write(buf)
|
||||
if n != len(buf) {
|
||||
// Close on partial write.
|
||||
c.conn.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteControl writes a control message with the given deadline. The allowed
|
||||
// message types are CloseMessage, PingMessage and PongMessage.
|
||||
func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) error {
|
||||
if !isControl(messageType) {
|
||||
return errBadWriteOpCode
|
||||
}
|
||||
if len(data) > maxControlFramePayloadSize {
|
||||
return errInvalidControlFrame
|
||||
}
|
||||
|
||||
b0 := byte(messageType) | finalBit
|
||||
b1 := byte(len(data))
|
||||
if !c.isServer {
|
||||
b1 |= maskBit
|
||||
}
|
||||
|
||||
buf := make([]byte, 0, maxFrameHeaderSize+maxControlFramePayloadSize)
|
||||
buf = append(buf, b0, b1)
|
||||
|
||||
if c.isServer {
|
||||
buf = append(buf, data...)
|
||||
} else {
|
||||
key := newMaskKey()
|
||||
buf = append(buf, key[:]...)
|
||||
buf = append(buf, data...)
|
||||
maskBytes(key, 0, buf[6:])
|
||||
}
|
||||
|
||||
d := time.Hour * 1000
|
||||
if !deadline.IsZero() {
|
||||
d = deadline.Sub(time.Now())
|
||||
if d < 0 {
|
||||
return errWriteTimeout
|
||||
}
|
||||
}
|
||||
|
||||
timer := time.NewTimer(d)
|
||||
select {
|
||||
case <-c.mu:
|
||||
timer.Stop()
|
||||
case <-timer.C:
|
||||
return errWriteTimeout
|
||||
}
|
||||
defer func() { c.mu <- true }()
|
||||
|
||||
if c.closeSent {
|
||||
return ErrCloseSent
|
||||
} else if messageType == CloseMessage {
|
||||
c.closeSent = true
|
||||
}
|
||||
|
||||
c.conn.SetWriteDeadline(deadline)
|
||||
n, err := c.conn.Write(buf)
|
||||
if n != 0 && n != len(buf) {
|
||||
c.conn.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// NextWriter returns a writer for the next message to send. The writer's
|
||||
// Close method flushes the complete message to the network.
|
||||
//
|
||||
// There can be at most one open writer on a connection. NextWriter closes the
|
||||
// previous writer if the application has not already done so.
|
||||
//
|
||||
// The NextWriter method and the writers returned from the method cannot be
|
||||
// accessed by more than one goroutine at a time.
|
||||
func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) {
|
||||
if c.writeErr != nil {
|
||||
return nil, c.writeErr
|
||||
}
|
||||
|
||||
if c.writeFrameType != noFrame {
|
||||
if err := c.flushFrame(true, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if !isControl(messageType) && !isData(messageType) {
|
||||
return nil, errBadWriteOpCode
|
||||
}
|
||||
|
||||
c.writeFrameType = messageType
|
||||
return messageWriter{c, c.writeSeq}, nil
|
||||
}
|
||||
|
||||
func (c *Conn) flushFrame(final bool, extra []byte) error {
|
||||
length := c.writePos - maxFrameHeaderSize + len(extra)
|
||||
|
||||
// Check for invalid control frames.
|
||||
if isControl(c.writeFrameType) &&
|
||||
(!final || length > maxControlFramePayloadSize) {
|
||||
c.writeSeq++
|
||||
c.writeFrameType = noFrame
|
||||
c.writePos = maxFrameHeaderSize
|
||||
return errInvalidControlFrame
|
||||
}
|
||||
|
||||
b0 := byte(c.writeFrameType)
|
||||
if final {
|
||||
b0 |= finalBit
|
||||
}
|
||||
b1 := byte(0)
|
||||
if !c.isServer {
|
||||
b1 |= maskBit
|
||||
}
|
||||
|
||||
// Assume that the frame starts at beginning of c.writeBuf.
|
||||
framePos := 0
|
||||
if c.isServer {
|
||||
// Adjust up if mask not included in the header.
|
||||
framePos = 4
|
||||
}
|
||||
|
||||
switch {
|
||||
case length >= 65536:
|
||||
c.writeBuf[framePos] = b0
|
||||
c.writeBuf[framePos+1] = b1 | 127
|
||||
binary.BigEndian.PutUint64(c.writeBuf[framePos+2:], uint64(length))
|
||||
case length > 125:
|
||||
framePos += 6
|
||||
c.writeBuf[framePos] = b0
|
||||
c.writeBuf[framePos+1] = b1 | 126
|
||||
binary.BigEndian.PutUint16(c.writeBuf[framePos+2:], uint16(length))
|
||||
default:
|
||||
framePos += 8
|
||||
c.writeBuf[framePos] = b0
|
||||
c.writeBuf[framePos+1] = b1 | byte(length)
|
||||
}
|
||||
|
||||
if !c.isServer {
|
||||
key := newMaskKey()
|
||||
copy(c.writeBuf[maxFrameHeaderSize-4:], key[:])
|
||||
maskBytes(key, 0, c.writeBuf[maxFrameHeaderSize:c.writePos])
|
||||
if len(extra) > 0 {
|
||||
c.writeErr = errors.New("websocket: internal error, extra used in client mode")
|
||||
return c.writeErr
|
||||
}
|
||||
}
|
||||
|
||||
// Write the buffers to the connection.
|
||||
c.writeErr = c.write(c.writeFrameType, c.writeDeadline, c.writeBuf[framePos:c.writePos], extra)
|
||||
|
||||
// Setup for next frame.
|
||||
c.writePos = maxFrameHeaderSize
|
||||
c.writeFrameType = continuationFrame
|
||||
if final {
|
||||
c.writeSeq++
|
||||
c.writeFrameType = noFrame
|
||||
}
|
||||
return c.writeErr
|
||||
}
|
||||
|
||||
type messageWriter struct {
|
||||
c *Conn
|
||||
seq int
|
||||
}
|
||||
|
||||
func (w messageWriter) err() error {
|
||||
c := w.c
|
||||
if c.writeSeq != w.seq {
|
||||
return errWriteClosed
|
||||
}
|
||||
if c.writeErr != nil {
|
||||
return c.writeErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w messageWriter) ncopy(max int) (int, error) {
|
||||
n := len(w.c.writeBuf) - w.c.writePos
|
||||
if n <= 0 {
|
||||
if err := w.c.flushFrame(false, nil); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
n = len(w.c.writeBuf) - w.c.writePos
|
||||
}
|
||||
if n > max {
|
||||
n = max
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (w messageWriter) write(final bool, p []byte) (int, error) {
|
||||
if err := w.err(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if len(p) > 2*len(w.c.writeBuf) && w.c.isServer {
|
||||
// Don't buffer large messages.
|
||||
err := w.c.flushFrame(final, p)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
nn := len(p)
|
||||
for len(p) > 0 {
|
||||
n, err := w.ncopy(len(p))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
copy(w.c.writeBuf[w.c.writePos:], p[:n])
|
||||
w.c.writePos += n
|
||||
p = p[n:]
|
||||
}
|
||||
return nn, nil
|
||||
}
|
||||
|
||||
func (w messageWriter) Write(p []byte) (int, error) {
|
||||
return w.write(false, p)
|
||||
}
|
||||
|
||||
func (w messageWriter) WriteString(p string) (int, error) {
|
||||
if err := w.err(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
nn := len(p)
|
||||
for len(p) > 0 {
|
||||
n, err := w.ncopy(len(p))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
copy(w.c.writeBuf[w.c.writePos:], p[:n])
|
||||
w.c.writePos += n
|
||||
p = p[n:]
|
||||
}
|
||||
return nn, nil
|
||||
}
|
||||
|
||||
func (w messageWriter) ReadFrom(r io.Reader) (nn int64, err error) {
|
||||
if err := w.err(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
for {
|
||||
if w.c.writePos == len(w.c.writeBuf) {
|
||||
err = w.c.flushFrame(false, nil)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
var n int
|
||||
n, err = r.Read(w.c.writeBuf[w.c.writePos:])
|
||||
w.c.writePos += n
|
||||
nn += int64(n)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return nn, err
|
||||
}
|
||||
|
||||
func (w messageWriter) Close() error {
|
||||
if err := w.err(); err != nil {
|
||||
return err
|
||||
}
|
||||
return w.c.flushFrame(true, nil)
|
||||
}
|
||||
|
||||
// WriteMessage is a helper method for getting a writer using NextWriter,
|
||||
// writing the message and closing the writer.
|
||||
func (c *Conn) WriteMessage(messageType int, data []byte) error {
|
||||
wr, err := c.NextWriter(messageType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w := wr.(messageWriter)
|
||||
if _, err := w.write(true, data); err != nil {
|
||||
return err
|
||||
}
|
||||
if c.writeSeq == w.seq {
|
||||
if err := c.flushFrame(true, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetWriteDeadline sets the write deadline on the underlying network
|
||||
// connection. After a write has timed out, the websocket state is corrupt and
|
||||
// all future writes will return an error. A zero value for t means writes will
|
||||
// not time out.
|
||||
func (c *Conn) SetWriteDeadline(t time.Time) error {
|
||||
c.writeDeadline = t
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read methods
|
||||
|
||||
// readFull is like io.ReadFull except that io.EOF is never returned.
|
||||
func (c *Conn) readFull(p []byte) (err error) {
|
||||
var n int
|
||||
for n < len(p) && err == nil {
|
||||
var nn int
|
||||
nn, err = c.br.Read(p[n:])
|
||||
n += nn
|
||||
}
|
||||
if n == len(p) {
|
||||
err = nil
|
||||
} else if err == io.EOF {
|
||||
err = errUnexpectedEOF
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Conn) advanceFrame() (int, error) {
|
||||
|
||||
// 1. Skip remainder of previous frame.
|
||||
|
||||
if c.readRemaining > 0 {
|
||||
if _, err := io.CopyN(ioutil.Discard, c.br, c.readRemaining); err != nil {
|
||||
return noFrame, err
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Read and parse first two bytes of frame header.
|
||||
|
||||
var b [8]byte
|
||||
if err := c.readFull(b[:2]); err != nil {
|
||||
return noFrame, err
|
||||
}
|
||||
|
||||
final := b[0]&finalBit != 0
|
||||
frameType := int(b[0] & 0xf)
|
||||
reserved := int((b[0] >> 4) & 0x7)
|
||||
mask := b[1]&maskBit != 0
|
||||
c.readRemaining = int64(b[1] & 0x7f)
|
||||
|
||||
if reserved != 0 {
|
||||
return noFrame, c.handleProtocolError("unexpected reserved bits " + strconv.Itoa(reserved))
|
||||
}
|
||||
|
||||
switch frameType {
|
||||
case CloseMessage, PingMessage, PongMessage:
|
||||
if c.readRemaining > maxControlFramePayloadSize {
|
||||
return noFrame, c.handleProtocolError("control frame length > 125")
|
||||
}
|
||||
if !final {
|
||||
return noFrame, c.handleProtocolError("control frame not final")
|
||||
}
|
||||
case TextMessage, BinaryMessage:
|
||||
if !c.readFinal {
|
||||
return noFrame, c.handleProtocolError("message start before final message frame")
|
||||
}
|
||||
c.readFinal = final
|
||||
case continuationFrame:
|
||||
if c.readFinal {
|
||||
return noFrame, c.handleProtocolError("continuation after final message frame")
|
||||
}
|
||||
c.readFinal = final
|
||||
default:
|
||||
return noFrame, c.handleProtocolError("unknown opcode " + strconv.Itoa(frameType))
|
||||
}
|
||||
|
||||
// 3. Read and parse frame length.
|
||||
|
||||
switch c.readRemaining {
|
||||
case 126:
|
||||
if err := c.readFull(b[:2]); err != nil {
|
||||
return noFrame, err
|
||||
}
|
||||
c.readRemaining = int64(binary.BigEndian.Uint16(b[:2]))
|
||||
case 127:
|
||||
if err := c.readFull(b[:8]); err != nil {
|
||||
return noFrame, err
|
||||
}
|
||||
c.readRemaining = int64(binary.BigEndian.Uint64(b[:8]))
|
||||
}
|
||||
|
||||
// 4. Handle frame masking.
|
||||
|
||||
if mask != c.isServer {
|
||||
return noFrame, c.handleProtocolError("incorrect mask flag")
|
||||
}
|
||||
|
||||
if mask {
|
||||
c.readMaskPos = 0
|
||||
if err := c.readFull(c.readMaskKey[:]); err != nil {
|
||||
return noFrame, err
|
||||
}
|
||||
}
|
||||
|
||||
// 5. For text and binary messages, enforce read limit and return.
|
||||
|
||||
if frameType == continuationFrame || frameType == TextMessage || frameType == BinaryMessage {
|
||||
|
||||
c.readLength += c.readRemaining
|
||||
if c.readLimit > 0 && c.readLength > c.readLimit {
|
||||
c.WriteControl(CloseMessage, FormatCloseMessage(CloseMessageTooBig, ""), time.Now().Add(writeWait))
|
||||
return noFrame, ErrReadLimit
|
||||
}
|
||||
|
||||
return frameType, nil
|
||||
}
|
||||
|
||||
// 6. Read control frame payload.
|
||||
|
||||
var payload []byte
|
||||
if c.readRemaining > 0 {
|
||||
payload = make([]byte, c.readRemaining)
|
||||
c.readRemaining = 0
|
||||
if err := c.readFull(payload); err != nil {
|
||||
return noFrame, err
|
||||
}
|
||||
if c.isServer {
|
||||
maskBytes(c.readMaskKey, 0, payload)
|
||||
}
|
||||
}
|
||||
|
||||
// 7. Process control frame payload.
|
||||
|
||||
switch frameType {
|
||||
case PongMessage:
|
||||
if err := c.handlePong(string(payload)); err != nil {
|
||||
return noFrame, err
|
||||
}
|
||||
case PingMessage:
|
||||
if err := c.handlePing(string(payload)); err != nil {
|
||||
return noFrame, err
|
||||
}
|
||||
case CloseMessage:
|
||||
c.WriteControl(CloseMessage, []byte{}, time.Now().Add(writeWait))
|
||||
closeCode := CloseNoStatusReceived
|
||||
closeText := ""
|
||||
if len(payload) >= 2 {
|
||||
closeCode = int(binary.BigEndian.Uint16(payload))
|
||||
closeText = string(payload[2:])
|
||||
}
|
||||
switch closeCode {
|
||||
case CloseNormalClosure, CloseGoingAway:
|
||||
return noFrame, io.EOF
|
||||
default:
|
||||
return noFrame, &closeError{code: closeCode, text: closeText}
|
||||
}
|
||||
}
|
||||
|
||||
return frameType, nil
|
||||
}
|
||||
|
||||
func (c *Conn) handleProtocolError(message string) error {
|
||||
c.WriteControl(CloseMessage, FormatCloseMessage(CloseProtocolError, message), time.Now().Add(writeWait))
|
||||
return errors.New("websocket: " + message)
|
||||
}
|
||||
|
||||
// NextReader returns the next data message received from the peer. The
|
||||
// returned messageType is either TextMessage or BinaryMessage.
|
||||
//
|
||||
// There can be at most one open reader on a connection. NextReader discards
|
||||
// the previous message if the application has not already consumed it.
|
||||
//
|
||||
// The NextReader method and the readers returned from the method cannot be
|
||||
// accessed by more than one goroutine at a time.
|
||||
func (c *Conn) NextReader() (messageType int, r io.Reader, err error) {
|
||||
|
||||
c.readSeq++
|
||||
c.readLength = 0
|
||||
|
||||
for c.readErr == nil {
|
||||
frameType, err := c.advanceFrame()
|
||||
if err != nil {
|
||||
c.readErr = hideTempErr(err)
|
||||
break
|
||||
}
|
||||
if frameType == TextMessage || frameType == BinaryMessage {
|
||||
return frameType, messageReader{c, c.readSeq}, nil
|
||||
}
|
||||
}
|
||||
return noFrame, nil, c.readErr
|
||||
}
|
||||
|
||||
type messageReader struct {
|
||||
c *Conn
|
||||
seq int
|
||||
}
|
||||
|
||||
func (r messageReader) Read(b []byte) (int, error) {
|
||||
|
||||
if r.seq != r.c.readSeq {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
for r.c.readErr == nil {
|
||||
|
||||
if r.c.readRemaining > 0 {
|
||||
if int64(len(b)) > r.c.readRemaining {
|
||||
b = b[:r.c.readRemaining]
|
||||
}
|
||||
n, err := r.c.br.Read(b)
|
||||
r.c.readErr = hideTempErr(err)
|
||||
if r.c.isServer {
|
||||
r.c.readMaskPos = maskBytes(r.c.readMaskKey, r.c.readMaskPos, b[:n])
|
||||
}
|
||||
r.c.readRemaining -= int64(n)
|
||||
return n, r.c.readErr
|
||||
}
|
||||
|
||||
if r.c.readFinal {
|
||||
r.c.readSeq++
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
frameType, err := r.c.advanceFrame()
|
||||
switch {
|
||||
case err != nil:
|
||||
r.c.readErr = hideTempErr(err)
|
||||
case frameType == TextMessage || frameType == BinaryMessage:
|
||||
r.c.readErr = errors.New("websocket: internal error, unexpected text or binary in Reader")
|
||||
}
|
||||
}
|
||||
|
||||
err := r.c.readErr
|
||||
if err == io.EOF && r.seq == r.c.readSeq {
|
||||
err = errUnexpectedEOF
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// ReadMessage is a helper method for getting a reader using NextReader and
|
||||
// reading from that reader to a buffer.
|
||||
func (c *Conn) ReadMessage() (messageType int, p []byte, err error) {
|
||||
var r io.Reader
|
||||
messageType, r, err = c.NextReader()
|
||||
if err != nil {
|
||||
return messageType, nil, err
|
||||
}
|
||||
p, err = ioutil.ReadAll(r)
|
||||
return messageType, p, err
|
||||
}
|
||||
|
||||
// SetReadDeadline sets the read deadline on the underlying network connection.
|
||||
// After a read has timed out, the websocket connection state is corrupt and
|
||||
// all future reads will return an error. A zero value for t means reads will
|
||||
// not time out.
|
||||
func (c *Conn) SetReadDeadline(t time.Time) error {
|
||||
return c.conn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
// SetReadLimit sets the maximum size for a message read from the peer. If a
|
||||
// message exceeds the limit, the connection sends a close frame to the peer
|
||||
// and returns ErrReadLimit to the application.
|
||||
func (c *Conn) SetReadLimit(limit int64) {
|
||||
c.readLimit = limit
|
||||
}
|
||||
|
||||
// SetPingHandler sets the handler for ping messages received from the peer.
|
||||
// The default ping handler sends a pong to the peer.
|
||||
func (c *Conn) SetPingHandler(h func(string) error) {
|
||||
if h == nil {
|
||||
h = func(message string) error {
|
||||
c.WriteControl(PongMessage, []byte(message), time.Now().Add(writeWait))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
c.handlePing = h
|
||||
}
|
||||
|
||||
// SetPongHandler sets then handler for pong messages received from the peer.
|
||||
// The default pong handler does nothing.
|
||||
func (c *Conn) SetPongHandler(h func(string) error) {
|
||||
if h == nil {
|
||||
h = func(string) error { return nil }
|
||||
}
|
||||
c.handlePong = h
|
||||
}
|
||||
|
||||
// UnderlyingConn returns the internal net.Conn. This can be used to further
|
||||
// modifications to connection specific flags.
|
||||
func (c *Conn) UnderlyingConn() net.Conn {
|
||||
return c.conn
|
||||
}
|
||||
|
||||
// FormatCloseMessage formats closeCode and text as a WebSocket close message.
|
||||
func FormatCloseMessage(closeCode int, text string) []byte {
|
||||
buf := make([]byte, 2+len(text))
|
||||
binary.BigEndian.PutUint16(buf, uint16(closeCode))
|
||||
copy(buf[2:], text)
|
||||
return buf
|
||||
}
|
||||
238
Godeps/_workspace/src/github.com/gorilla/websocket/conn_test.go
generated
vendored
238
Godeps/_workspace/src/github.com/gorilla/websocket/conn_test.go
generated
vendored
@@ -1,238 +0,0 @@
|
||||
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"testing"
|
||||
"testing/iotest"
|
||||
"time"
|
||||
)
|
||||
|
||||
var _ net.Error = errWriteTimeout
|
||||
|
||||
type fakeNetConn struct {
|
||||
io.Reader
|
||||
io.Writer
|
||||
}
|
||||
|
||||
func (c fakeNetConn) Close() error { return nil }
|
||||
func (c fakeNetConn) LocalAddr() net.Addr { return nil }
|
||||
func (c fakeNetConn) RemoteAddr() net.Addr { return nil }
|
||||
func (c fakeNetConn) SetDeadline(t time.Time) error { return nil }
|
||||
func (c fakeNetConn) SetReadDeadline(t time.Time) error { return nil }
|
||||
func (c fakeNetConn) SetWriteDeadline(t time.Time) error { return nil }
|
||||
|
||||
func TestFraming(t *testing.T) {
|
||||
frameSizes := []int{0, 1, 2, 124, 125, 126, 127, 128, 129, 65534, 65535, 65536, 65537}
|
||||
var readChunkers = []struct {
|
||||
name string
|
||||
f func(io.Reader) io.Reader
|
||||
}{
|
||||
{"half", iotest.HalfReader},
|
||||
{"one", iotest.OneByteReader},
|
||||
{"asis", func(r io.Reader) io.Reader { return r }},
|
||||
}
|
||||
|
||||
writeBuf := make([]byte, 65537)
|
||||
for i := range writeBuf {
|
||||
writeBuf[i] = byte(i)
|
||||
}
|
||||
|
||||
for _, isServer := range []bool{true, false} {
|
||||
for _, chunker := range readChunkers {
|
||||
|
||||
var connBuf bytes.Buffer
|
||||
wc := newConn(fakeNetConn{Reader: nil, Writer: &connBuf}, isServer, 1024, 1024)
|
||||
rc := newConn(fakeNetConn{Reader: chunker.f(&connBuf), Writer: nil}, !isServer, 1024, 1024)
|
||||
|
||||
for _, n := range frameSizes {
|
||||
for _, iocopy := range []bool{true, false} {
|
||||
name := fmt.Sprintf("s:%v, r:%s, n:%d c:%v", isServer, chunker.name, n, iocopy)
|
||||
|
||||
w, err := wc.NextWriter(TextMessage)
|
||||
if err != nil {
|
||||
t.Errorf("%s: wc.NextWriter() returned %v", name, err)
|
||||
continue
|
||||
}
|
||||
var nn int
|
||||
if iocopy {
|
||||
var n64 int64
|
||||
n64, err = io.Copy(w, bytes.NewReader(writeBuf[:n]))
|
||||
nn = int(n64)
|
||||
} else {
|
||||
nn, err = w.Write(writeBuf[:n])
|
||||
}
|
||||
if err != nil || nn != n {
|
||||
t.Errorf("%s: w.Write(writeBuf[:n]) returned %d, %v", name, nn, err)
|
||||
continue
|
||||
}
|
||||
err = w.Close()
|
||||
if err != nil {
|
||||
t.Errorf("%s: w.Close() returned %v", name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
opCode, r, err := rc.NextReader()
|
||||
if err != nil || opCode != TextMessage {
|
||||
t.Errorf("%s: NextReader() returned %d, r, %v", name, opCode, err)
|
||||
continue
|
||||
}
|
||||
rbuf, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
t.Errorf("%s: ReadFull() returned rbuf, %v", name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(rbuf) != n {
|
||||
t.Errorf("%s: len(rbuf) is %d, want %d", name, len(rbuf), n)
|
||||
continue
|
||||
}
|
||||
|
||||
for i, b := range rbuf {
|
||||
if byte(i) != b {
|
||||
t.Errorf("%s: bad byte at offset %d", name, i)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestControl(t *testing.T) {
|
||||
const message = "this is a ping/pong messsage"
|
||||
for _, isServer := range []bool{true, false} {
|
||||
for _, isWriteControl := range []bool{true, false} {
|
||||
name := fmt.Sprintf("s:%v, wc:%v", isServer, isWriteControl)
|
||||
var connBuf bytes.Buffer
|
||||
wc := newConn(fakeNetConn{Reader: nil, Writer: &connBuf}, isServer, 1024, 1024)
|
||||
rc := newConn(fakeNetConn{Reader: &connBuf, Writer: nil}, !isServer, 1024, 1024)
|
||||
if isWriteControl {
|
||||
wc.WriteControl(PongMessage, []byte(message), time.Now().Add(time.Second))
|
||||
} else {
|
||||
w, err := wc.NextWriter(PongMessage)
|
||||
if err != nil {
|
||||
t.Errorf("%s: wc.NextWriter() returned %v", name, err)
|
||||
continue
|
||||
}
|
||||
if _, err := w.Write([]byte(message)); err != nil {
|
||||
t.Errorf("%s: w.Write() returned %v", name, err)
|
||||
continue
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
t.Errorf("%s: w.Close() returned %v", name, err)
|
||||
continue
|
||||
}
|
||||
var actualMessage string
|
||||
rc.SetPongHandler(func(s string) error { actualMessage = s; return nil })
|
||||
rc.NextReader()
|
||||
if actualMessage != message {
|
||||
t.Errorf("%s: pong=%q, want %q", name, actualMessage, message)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloseBeforeFinalFrame(t *testing.T) {
|
||||
const bufSize = 512
|
||||
|
||||
var b1, b2 bytes.Buffer
|
||||
wc := newConn(fakeNetConn{Reader: nil, Writer: &b1}, false, 1024, bufSize)
|
||||
rc := newConn(fakeNetConn{Reader: &b1, Writer: &b2}, true, 1024, 1024)
|
||||
|
||||
w, _ := wc.NextWriter(BinaryMessage)
|
||||
w.Write(make([]byte, bufSize+bufSize/2))
|
||||
wc.WriteControl(CloseMessage, FormatCloseMessage(CloseNormalClosure, ""), time.Now().Add(10*time.Second))
|
||||
w.Close()
|
||||
|
||||
op, r, err := rc.NextReader()
|
||||
if op != BinaryMessage || err != nil {
|
||||
t.Fatalf("NextReader() returned %d, %v", op, err)
|
||||
}
|
||||
_, err = io.Copy(ioutil.Discard, r)
|
||||
if err != errUnexpectedEOF {
|
||||
t.Fatalf("io.Copy() returned %v, want %v", err, errUnexpectedEOF)
|
||||
}
|
||||
_, _, err = rc.NextReader()
|
||||
if err != io.EOF {
|
||||
t.Fatalf("NextReader() returned %v, want %v", err, io.EOF)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEOFBeforeFinalFrame(t *testing.T) {
|
||||
const bufSize = 512
|
||||
|
||||
var b1, b2 bytes.Buffer
|
||||
wc := newConn(fakeNetConn{Reader: nil, Writer: &b1}, false, 1024, bufSize)
|
||||
rc := newConn(fakeNetConn{Reader: &b1, Writer: &b2}, true, 1024, 1024)
|
||||
|
||||
w, _ := wc.NextWriter(BinaryMessage)
|
||||
w.Write(make([]byte, bufSize+bufSize/2))
|
||||
|
||||
op, r, err := rc.NextReader()
|
||||
if op != BinaryMessage || err != nil {
|
||||
t.Fatalf("NextReader() returned %d, %v", op, err)
|
||||
}
|
||||
_, err = io.Copy(ioutil.Discard, r)
|
||||
if err != errUnexpectedEOF {
|
||||
t.Fatalf("io.Copy() returned %v, want %v", err, errUnexpectedEOF)
|
||||
}
|
||||
_, _, err = rc.NextReader()
|
||||
if err != errUnexpectedEOF {
|
||||
t.Fatalf("NextReader() returned %v, want %v", err, errUnexpectedEOF)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadLimit(t *testing.T) {
|
||||
|
||||
const readLimit = 512
|
||||
message := make([]byte, readLimit+1)
|
||||
|
||||
var b1, b2 bytes.Buffer
|
||||
wc := newConn(fakeNetConn{Reader: nil, Writer: &b1}, false, 1024, readLimit-2)
|
||||
rc := newConn(fakeNetConn{Reader: &b1, Writer: &b2}, true, 1024, 1024)
|
||||
rc.SetReadLimit(readLimit)
|
||||
|
||||
// Send message at the limit with interleaved pong.
|
||||
w, _ := wc.NextWriter(BinaryMessage)
|
||||
w.Write(message[:readLimit-1])
|
||||
wc.WriteControl(PongMessage, []byte("this is a pong"), time.Now().Add(10*time.Second))
|
||||
w.Write(message[:1])
|
||||
w.Close()
|
||||
|
||||
// Send message larger than the limit.
|
||||
wc.WriteMessage(BinaryMessage, message[:readLimit+1])
|
||||
|
||||
op, _, err := rc.NextReader()
|
||||
if op != BinaryMessage || err != nil {
|
||||
t.Fatalf("1: NextReader() returned %d, %v", op, err)
|
||||
}
|
||||
op, r, err := rc.NextReader()
|
||||
if op != BinaryMessage || err != nil {
|
||||
t.Fatalf("2: NextReader() returned %d, %v", op, err)
|
||||
}
|
||||
_, err = io.Copy(ioutil.Discard, r)
|
||||
if err != ErrReadLimit {
|
||||
t.Fatalf("io.Copy() returned %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnderlyingConn(t *testing.T) {
|
||||
var b1, b2 bytes.Buffer
|
||||
fc := fakeNetConn{Reader: &b1, Writer: &b2}
|
||||
c := newConn(fc, true, 1024, 1024)
|
||||
ul := c.UnderlyingConn()
|
||||
if ul != fc {
|
||||
t.Fatalf("Underlying conn is not what it should be.")
|
||||
}
|
||||
}
|
||||
148
Godeps/_workspace/src/github.com/gorilla/websocket/doc.go
generated
vendored
148
Godeps/_workspace/src/github.com/gorilla/websocket/doc.go
generated
vendored
@@ -1,148 +0,0 @@
|
||||
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package websocket implements the WebSocket protocol defined in RFC 6455.
|
||||
//
|
||||
// Overview
|
||||
//
|
||||
// The Conn type represents a WebSocket connection. A server application uses
|
||||
// the Upgrade function from an Upgrader object with a HTTP request handler
|
||||
// to get a pointer to a Conn:
|
||||
//
|
||||
// var upgrader = websocket.Upgrader{
|
||||
// ReadBufferSize: 1024,
|
||||
// WriteBufferSize: 1024,
|
||||
// }
|
||||
//
|
||||
// func handler(w http.ResponseWriter, r *http.Request) {
|
||||
// conn, err := upgrader.Upgrade(w, r, nil)
|
||||
// if err != nil {
|
||||
// log.Println(err)
|
||||
// return
|
||||
// }
|
||||
// ... Use conn to send and receive messages.
|
||||
// }
|
||||
//
|
||||
// Call the connection WriteMessage and ReadMessages methods to send and
|
||||
// receive messages as a slice of bytes. This snippet of code shows how to echo
|
||||
// messages using these methods:
|
||||
//
|
||||
// for {
|
||||
// messageType, p, err := conn.ReadMessage()
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// if err = conn.WriteMessage(messageType, p); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// In above snippet of code, p is a []byte and messageType is an int with value
|
||||
// websocket.BinaryMessage or websocket.TextMessage.
|
||||
//
|
||||
// An application can also send and receive messages using the io.WriteCloser
|
||||
// and io.Reader interfaces. To send a message, call the connection NextWriter
|
||||
// method to get an io.WriteCloser, write the message to the writer and close
|
||||
// the writer when done. To receive a message, call the connection NextReader
|
||||
// method to get an io.Reader and read until io.EOF is returned. This snippet
|
||||
// snippet shows how to echo messages using the NextWriter and NextReader
|
||||
// methods:
|
||||
//
|
||||
// for {
|
||||
// messageType, r, err := conn.NextReader()
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// w, err := conn.NextWriter(messageType)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// if _, err := io.Copy(w, r); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// if err := w.Close(); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Data Messages
|
||||
//
|
||||
// The WebSocket protocol distinguishes between text and binary data messages.
|
||||
// Text messages are interpreted as UTF-8 encoded text. The interpretation of
|
||||
// binary messages is left to the application.
|
||||
//
|
||||
// This package uses the TextMessage and BinaryMessage integer constants to
|
||||
// identify the two data message types. The ReadMessage and NextReader methods
|
||||
// return the type of the received message. The messageType argument to the
|
||||
// WriteMessage and NextWriter methods specifies the type of a sent message.
|
||||
//
|
||||
// It is the application's responsibility to ensure that text messages are
|
||||
// valid UTF-8 encoded text.
|
||||
//
|
||||
// Control Messages
|
||||
//
|
||||
// The WebSocket protocol defines three types of control messages: close, ping
|
||||
// and pong. Call the connection WriteControl, WriteMessage or NextWriter
|
||||
// methods to send a control message to the peer.
|
||||
//
|
||||
// Connections handle received ping and pong messages by invoking a callback
|
||||
// function set with SetPingHandler and SetPongHandler methods. These callback
|
||||
// functions can be invoked from the ReadMessage method, the NextReader method
|
||||
// or from a call to the data message reader returned from NextReader.
|
||||
//
|
||||
// Connections handle received close messages by returning an error from the
|
||||
// ReadMessage method, the NextReader method or from a call to the data message
|
||||
// reader returned from NextReader.
|
||||
//
|
||||
// Concurrency
|
||||
//
|
||||
// Connections do not support concurrent calls to the write methods
|
||||
// (NextWriter, SetWriteDeadline, WriteMessage) or concurrent calls to the read
|
||||
// methods methods (NextReader, SetReadDeadline, ReadMessage). Connections do
|
||||
// support a concurrent reader and writer.
|
||||
//
|
||||
// The Close and WriteControl methods can be called concurrently with all other
|
||||
// methods.
|
||||
//
|
||||
// Read is Required
|
||||
//
|
||||
// The application must read the connection to process ping and close messages
|
||||
// sent from the peer. If the application is not otherwise interested in
|
||||
// messages from the peer, then the application should start a goroutine to read
|
||||
// and discard messages from the peer. A simple example is:
|
||||
//
|
||||
// func readLoop(c *websocket.Conn) {
|
||||
// for {
|
||||
// if _, _, err := c.NextReader(); err != nil {
|
||||
// c.Close()
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Origin Considerations
|
||||
//
|
||||
// Web browsers allow Javascript applications to open a WebSocket connection to
|
||||
// any host. It's up to the server to enforce an origin policy using the Origin
|
||||
// request header sent by the browser.
|
||||
//
|
||||
// The Upgrader calls the function specified in the CheckOrigin field to check
|
||||
// the origin. If the CheckOrigin function returns false, then the Upgrade
|
||||
// method fails the WebSocket handshake with HTTP status 403.
|
||||
//
|
||||
// If the CheckOrigin field is nil, then the Upgrader uses a safe default: fail
|
||||
// the handshake if the Origin request header is present and not equal to the
|
||||
// Host request header.
|
||||
//
|
||||
// An application can allow connections from any origin by specifying a
|
||||
// function that always returns true:
|
||||
//
|
||||
// var upgrader = websocket.Upgrader{
|
||||
// CheckOrigin: func(r *http.Request) bool { return true },
|
||||
// }
|
||||
//
|
||||
// The deprecated Upgrade function does not enforce an origin policy. It's the
|
||||
// application's responsibility to check the Origin header before calling
|
||||
// Upgrade.
|
||||
package websocket
|
||||
13
Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md
generated
vendored
13
Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md
generated
vendored
@@ -1,13 +0,0 @@
|
||||
# Test Server
|
||||
|
||||
This package contains a server for the [Autobahn WebSockets Test Suite](http://autobahn.ws/testsuite).
|
||||
|
||||
To test the server, run
|
||||
|
||||
go run server.go
|
||||
|
||||
and start the client test driver
|
||||
|
||||
wstest -m fuzzingclient -s fuzzingclient.json
|
||||
|
||||
When the client completes, it writes a report to reports/clients/index.html.
|
||||
14
Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json
generated
vendored
14
Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json
generated
vendored
@@ -1,14 +0,0 @@
|
||||
|
||||
{
|
||||
"options": {"failByDrop": false},
|
||||
"outdir": "./reports/clients",
|
||||
"servers": [
|
||||
{"agent": "ReadAllWriteMessage", "url": "ws://localhost:9000/m", "options": {"version": 18}},
|
||||
{"agent": "ReadAllWrite", "url": "ws://localhost:9000/r", "options": {"version": 18}},
|
||||
{"agent": "CopyFull", "url": "ws://localhost:9000/f", "options": {"version": 18}},
|
||||
{"agent": "CopyWriterOnly", "url": "ws://localhost:9000/c", "options": {"version": 18}}
|
||||
],
|
||||
"cases": ["*"],
|
||||
"exclude-cases": [],
|
||||
"exclude-agent-cases": {}
|
||||
}
|
||||
246
Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/server.go
generated
vendored
246
Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/server.go
generated
vendored
@@ -1,246 +0,0 @@
|
||||
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Command server is a test server for the Autobahn WebSockets Test Suite.
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"github.com/tendermint/tendermint/Godeps/_workspace/src/github.com/gorilla/websocket"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
ReadBufferSize: 4096,
|
||||
WriteBufferSize: 4096,
|
||||
CheckOrigin: func(r *http.Request) bool {
|
||||
return true
|
||||
},
|
||||
}
|
||||
|
||||
// echoCopy echoes messages from the client using io.Copy.
|
||||
func echoCopy(w http.ResponseWriter, r *http.Request, writerOnly bool) {
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
log.Println("Upgrade:", err)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
for {
|
||||
mt, r, err := conn.NextReader()
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
log.Println("NextReader:", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if mt == websocket.TextMessage {
|
||||
r = &validator{r: r}
|
||||
}
|
||||
w, err := conn.NextWriter(mt)
|
||||
if err != nil {
|
||||
log.Println("NextWriter:", err)
|
||||
return
|
||||
}
|
||||
if mt == websocket.TextMessage {
|
||||
r = &validator{r: r}
|
||||
}
|
||||
if writerOnly {
|
||||
_, err = io.Copy(struct{ io.Writer }{w}, r)
|
||||
} else {
|
||||
_, err = io.Copy(w, r)
|
||||
}
|
||||
if err != nil {
|
||||
if err == errInvalidUTF8 {
|
||||
conn.WriteControl(websocket.CloseMessage,
|
||||
websocket.FormatCloseMessage(websocket.CloseInvalidFramePayloadData, ""),
|
||||
time.Time{})
|
||||
}
|
||||
log.Println("Copy:", err)
|
||||
return
|
||||
}
|
||||
err = w.Close()
|
||||
if err != nil {
|
||||
log.Println("Close:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func echoCopyWriterOnly(w http.ResponseWriter, r *http.Request) {
|
||||
echoCopy(w, r, true)
|
||||
}
|
||||
|
||||
func echoCopyFull(w http.ResponseWriter, r *http.Request) {
|
||||
echoCopy(w, r, false)
|
||||
}
|
||||
|
||||
// echoReadAll echoes messages from the client by reading the entire message
|
||||
// with ioutil.ReadAll.
|
||||
func echoReadAll(w http.ResponseWriter, r *http.Request, writeMessage bool) {
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
log.Println("Upgrade:", err)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
for {
|
||||
mt, b, err := conn.ReadMessage()
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
log.Println("NextReader:", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if mt == websocket.TextMessage {
|
||||
if !utf8.Valid(b) {
|
||||
conn.WriteControl(websocket.CloseMessage,
|
||||
websocket.FormatCloseMessage(websocket.CloseInvalidFramePayloadData, ""),
|
||||
time.Time{})
|
||||
log.Println("ReadAll: invalid utf8")
|
||||
}
|
||||
}
|
||||
if writeMessage {
|
||||
err = conn.WriteMessage(mt, b)
|
||||
if err != nil {
|
||||
log.Println("WriteMessage:", err)
|
||||
}
|
||||
} else {
|
||||
w, err := conn.NextWriter(mt)
|
||||
if err != nil {
|
||||
log.Println("NextWriter:", err)
|
||||
return
|
||||
}
|
||||
if _, err := w.Write(b); err != nil {
|
||||
log.Println("Writer:", err)
|
||||
return
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
log.Println("Close:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func echoReadAllWriter(w http.ResponseWriter, r *http.Request) {
|
||||
echoReadAll(w, r, false)
|
||||
}
|
||||
|
||||
func echoReadAllWriteMessage(w http.ResponseWriter, r *http.Request) {
|
||||
echoReadAll(w, r, true)
|
||||
}
|
||||
|
||||
func serveHome(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/" {
|
||||
http.Error(w, "Not found.", 404)
|
||||
return
|
||||
}
|
||||
if r.Method != "GET" {
|
||||
http.Error(w, "Method not allowed", 405)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
io.WriteString(w, "<html><body>Echo Server</body></html>")
|
||||
}
|
||||
|
||||
var addr = flag.String("addr", ":9000", "http service address")
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
http.HandleFunc("/", serveHome)
|
||||
http.HandleFunc("/c", echoCopyWriterOnly)
|
||||
http.HandleFunc("/f", echoCopyFull)
|
||||
http.HandleFunc("/r", echoReadAllWriter)
|
||||
http.HandleFunc("/m", echoReadAllWriteMessage)
|
||||
err := http.ListenAndServe(*addr, nil)
|
||||
if err != nil {
|
||||
log.Fatal("ListenAndServe: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
type validator struct {
|
||||
state int
|
||||
x rune
|
||||
r io.Reader
|
||||
}
|
||||
|
||||
var errInvalidUTF8 = errors.New("invalid utf8")
|
||||
|
||||
func (r *validator) Read(p []byte) (int, error) {
|
||||
n, err := r.r.Read(p)
|
||||
state := r.state
|
||||
x := r.x
|
||||
for _, b := range p[:n] {
|
||||
state, x = decode(state, x, b)
|
||||
if state == utf8Reject {
|
||||
break
|
||||
}
|
||||
}
|
||||
r.state = state
|
||||
r.x = x
|
||||
if state == utf8Reject || (err == io.EOF && state != utf8Accept) {
|
||||
return n, errInvalidUTF8
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
// UTF-8 decoder from http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
|
||||
//
|
||||
// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
|
||||
//
|
||||
// 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
|
||||
// AUTHORS OR COPYRIGHT HOLDERS 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.
|
||||
var utf8d = [...]byte{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1f
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3f
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5f
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7f
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9f
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // a0..bf
|
||||
8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c0..df
|
||||
0xa, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // e0..ef
|
||||
0xb, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // f0..ff
|
||||
0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2
|
||||
1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4
|
||||
1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6
|
||||
1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // s7..s8
|
||||
}
|
||||
|
||||
const (
|
||||
utf8Accept = 0
|
||||
utf8Reject = 1
|
||||
)
|
||||
|
||||
func decode(state int, x rune, b byte) (int, rune) {
|
||||
t := utf8d[b]
|
||||
if state != utf8Accept {
|
||||
x = rune(b&0x3f) | (x << 6)
|
||||
} else {
|
||||
x = rune((0xff >> t) & b)
|
||||
}
|
||||
state = int(utf8d[256+state*16+int(t)])
|
||||
return state, x
|
||||
}
|
||||
19
Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md
generated
vendored
19
Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md
generated
vendored
@@ -1,19 +0,0 @@
|
||||
# Chat Example
|
||||
|
||||
This application shows how to use use the
|
||||
[websocket](https://github.com/gorilla/websocket) package and
|
||||
[jQuery](http://jquery.com) to implement a simple web chat application.
|
||||
|
||||
## Running the example
|
||||
|
||||
The example requires a working Go development environment. The [Getting
|
||||
Started](http://golang.org/doc/install) page describes how to install the
|
||||
development environment.
|
||||
|
||||
Once you have Go up and running, you can download, build and run the example
|
||||
using the following commands.
|
||||
|
||||
$ go get github.com/gorilla/websocket
|
||||
$ cd `go list -f '{{.Dir}}' github.com/gorilla/websocket/examples/chat`
|
||||
$ go run *.go
|
||||
|
||||
106
Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/conn.go
generated
vendored
106
Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/conn.go
generated
vendored
@@ -1,106 +0,0 @@
|
||||
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/tendermint/tendermint/Godeps/_workspace/src/github.com/gorilla/websocket"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// Time allowed to write a message to the peer.
|
||||
writeWait = 10 * time.Second
|
||||
|
||||
// Time allowed to read the next pong message from the peer.
|
||||
pongWait = 60 * time.Second
|
||||
|
||||
// Send pings to peer with this period. Must be less than pongWait.
|
||||
pingPeriod = (pongWait * 9) / 10
|
||||
|
||||
// Maximum message size allowed from peer.
|
||||
maxMessageSize = 512
|
||||
)
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024,
|
||||
}
|
||||
|
||||
// connection is an middleman between the websocket connection and the hub.
|
||||
type connection struct {
|
||||
// The websocket connection.
|
||||
ws *websocket.Conn
|
||||
|
||||
// Buffered channel of outbound messages.
|
||||
send chan []byte
|
||||
}
|
||||
|
||||
// readPump pumps messages from the websocket connection to the hub.
|
||||
func (c *connection) readPump() {
|
||||
defer func() {
|
||||
h.unregister <- c
|
||||
c.ws.Close()
|
||||
}()
|
||||
c.ws.SetReadLimit(maxMessageSize)
|
||||
c.ws.SetReadDeadline(time.Now().Add(pongWait))
|
||||
c.ws.SetPongHandler(func(string) error { c.ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
|
||||
for {
|
||||
_, message, err := c.ws.ReadMessage()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
h.broadcast <- message
|
||||
}
|
||||
}
|
||||
|
||||
// write writes a message with the given message type and payload.
|
||||
func (c *connection) write(mt int, payload []byte) error {
|
||||
c.ws.SetWriteDeadline(time.Now().Add(writeWait))
|
||||
return c.ws.WriteMessage(mt, payload)
|
||||
}
|
||||
|
||||
// writePump pumps messages from the hub to the websocket connection.
|
||||
func (c *connection) writePump() {
|
||||
ticker := time.NewTicker(pingPeriod)
|
||||
defer func() {
|
||||
ticker.Stop()
|
||||
c.ws.Close()
|
||||
}()
|
||||
for {
|
||||
select {
|
||||
case message, ok := <-c.send:
|
||||
if !ok {
|
||||
c.write(websocket.CloseMessage, []byte{})
|
||||
return
|
||||
}
|
||||
if err := c.write(websocket.TextMessage, message); err != nil {
|
||||
return
|
||||
}
|
||||
case <-ticker.C:
|
||||
if err := c.write(websocket.PingMessage, []byte{}); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// serverWs handles websocket requests from the peer.
|
||||
func serveWs(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
http.Error(w, "Method not allowed", 405)
|
||||
return
|
||||
}
|
||||
ws, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
c := &connection{send: make(chan []byte, 256), ws: ws}
|
||||
h.register <- c
|
||||
go c.writePump()
|
||||
c.readPump()
|
||||
}
|
||||
92
Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/home.html
generated
vendored
92
Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/home.html
generated
vendored
@@ -1,92 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Chat Example</title>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
|
||||
var conn;
|
||||
var msg = $("#msg");
|
||||
var log = $("#log");
|
||||
|
||||
function appendLog(msg) {
|
||||
var d = log[0]
|
||||
var doScroll = d.scrollTop == d.scrollHeight - d.clientHeight;
|
||||
msg.appendTo(log)
|
||||
if (doScroll) {
|
||||
d.scrollTop = d.scrollHeight - d.clientHeight;
|
||||
}
|
||||
}
|
||||
|
||||
$("#form").submit(function() {
|
||||
if (!conn) {
|
||||
return false;
|
||||
}
|
||||
if (!msg.val()) {
|
||||
return false;
|
||||
}
|
||||
conn.send(msg.val());
|
||||
msg.val("");
|
||||
return false
|
||||
});
|
||||
|
||||
if (window["WebSocket"]) {
|
||||
conn = new WebSocket("ws://{{$}}/ws");
|
||||
conn.onclose = function(evt) {
|
||||
appendLog($("<div><b>Connection closed.</b></div>"))
|
||||
}
|
||||
conn.onmessage = function(evt) {
|
||||
appendLog($("<div/>").text(evt.data))
|
||||
}
|
||||
} else {
|
||||
appendLog($("<div><b>Your browser does not support WebSockets.</b></div>"))
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style type="text/css">
|
||||
html {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: gray;
|
||||
}
|
||||
|
||||
#log {
|
||||
background: white;
|
||||
margin: 0;
|
||||
padding: 0.5em 0.5em 0.5em 0.5em;
|
||||
position: absolute;
|
||||
top: 0.5em;
|
||||
left: 0.5em;
|
||||
right: 0.5em;
|
||||
bottom: 3em;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#form {
|
||||
padding: 0 0.5em 0 0.5em;
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
bottom: 1em;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="log"></div>
|
||||
<form id="form">
|
||||
<input type="submit" value="Send" />
|
||||
<input type="text" id="msg" size="64"/>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
51
Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go
generated
vendored
51
Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go
generated
vendored
@@ -1,51 +0,0 @@
|
||||
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
// hub maintains the set of active connections and broadcasts messages to the
|
||||
// connections.
|
||||
type hub struct {
|
||||
// Registered connections.
|
||||
connections map[*connection]bool
|
||||
|
||||
// Inbound messages from the connections.
|
||||
broadcast chan []byte
|
||||
|
||||
// Register requests from the connections.
|
||||
register chan *connection
|
||||
|
||||
// Unregister requests from connections.
|
||||
unregister chan *connection
|
||||
}
|
||||
|
||||
var h = hub{
|
||||
broadcast: make(chan []byte),
|
||||
register: make(chan *connection),
|
||||
unregister: make(chan *connection),
|
||||
connections: make(map[*connection]bool),
|
||||
}
|
||||
|
||||
func (h *hub) run() {
|
||||
for {
|
||||
select {
|
||||
case c := <-h.register:
|
||||
h.connections[c] = true
|
||||
case c := <-h.unregister:
|
||||
if _, ok := h.connections[c]; ok {
|
||||
delete(h.connections, c)
|
||||
close(c.send)
|
||||
}
|
||||
case m := <-h.broadcast:
|
||||
for c := range h.connections {
|
||||
select {
|
||||
case c.send <- m:
|
||||
default:
|
||||
close(c.send)
|
||||
delete(h.connections, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
39
Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go
generated
vendored
39
Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go
generated
vendored
@@ -1,39 +0,0 @@
|
||||
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"net/http"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
var addr = flag.String("addr", ":8080", "http service address")
|
||||
var homeTempl = template.Must(template.ParseFiles("home.html"))
|
||||
|
||||
func serveHome(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/" {
|
||||
http.Error(w, "Not found", 404)
|
||||
return
|
||||
}
|
||||
if r.Method != "GET" {
|
||||
http.Error(w, "Method not allowed", 405)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
homeTempl.Execute(w, r.Host)
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
go h.run()
|
||||
http.HandleFunc("/", serveHome)
|
||||
http.HandleFunc("/ws", serveWs)
|
||||
err := http.ListenAndServe(*addr, nil)
|
||||
if err != nil {
|
||||
log.Fatal("ListenAndServe: ", err)
|
||||
}
|
||||
}
|
||||
9
Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md
generated
vendored
9
Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md
generated
vendored
@@ -1,9 +0,0 @@
|
||||
# File Watch example.
|
||||
|
||||
This example sends a file to the browser client for display whenever the file is modified.
|
||||
|
||||
$ go get github.com/gorilla/websocket
|
||||
$ cd `go list -f '{{.Dir}}' github.com/gorilla/websocket/examples/filewatch`
|
||||
$ go run main.go <name of file to watch>
|
||||
# Open http://localhost:8080/ .
|
||||
# Modify the file to see it update in the browser.
|
||||
193
Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/main.go
generated
vendored
193
Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/main.go
generated
vendored
@@ -1,193 +0,0 @@
|
||||
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/tendermint/tendermint/Godeps/_workspace/src/github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
const (
|
||||
// Time allowed to write the file to the client.
|
||||
writeWait = 10 * time.Second
|
||||
|
||||
// Time allowed to read the next pong message from the client.
|
||||
pongWait = 60 * time.Second
|
||||
|
||||
// Send pings to client with this period. Must be less than pongWait.
|
||||
pingPeriod = (pongWait * 9) / 10
|
||||
|
||||
// Poll file for changes with this period.
|
||||
filePeriod = 10 * time.Second
|
||||
)
|
||||
|
||||
var (
|
||||
addr = flag.String("addr", ":8080", "http service address")
|
||||
homeTempl = template.Must(template.New("").Parse(homeHTML))
|
||||
filename string
|
||||
upgrader = websocket.Upgrader{
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024,
|
||||
}
|
||||
)
|
||||
|
||||
func readFileIfModified(lastMod time.Time) ([]byte, time.Time, error) {
|
||||
fi, err := os.Stat(filename)
|
||||
if err != nil {
|
||||
return nil, lastMod, err
|
||||
}
|
||||
if !fi.ModTime().After(lastMod) {
|
||||
return nil, lastMod, nil
|
||||
}
|
||||
p, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, fi.ModTime(), err
|
||||
}
|
||||
return p, fi.ModTime(), nil
|
||||
}
|
||||
|
||||
func reader(ws *websocket.Conn) {
|
||||
defer ws.Close()
|
||||
ws.SetReadLimit(512)
|
||||
ws.SetReadDeadline(time.Now().Add(pongWait))
|
||||
ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
|
||||
for {
|
||||
_, _, err := ws.ReadMessage()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func writer(ws *websocket.Conn, lastMod time.Time) {
|
||||
lastError := ""
|
||||
pingTicker := time.NewTicker(pingPeriod)
|
||||
fileTicker := time.NewTicker(filePeriod)
|
||||
defer func() {
|
||||
pingTicker.Stop()
|
||||
fileTicker.Stop()
|
||||
ws.Close()
|
||||
}()
|
||||
for {
|
||||
select {
|
||||
case <-fileTicker.C:
|
||||
var p []byte
|
||||
var err error
|
||||
|
||||
p, lastMod, err = readFileIfModified(lastMod)
|
||||
|
||||
if err != nil {
|
||||
if s := err.Error(); s != lastError {
|
||||
lastError = s
|
||||
p = []byte(lastError)
|
||||
}
|
||||
} else {
|
||||
lastError = ""
|
||||
}
|
||||
|
||||
if p != nil {
|
||||
ws.SetWriteDeadline(time.Now().Add(writeWait))
|
||||
if err := ws.WriteMessage(websocket.TextMessage, p); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
case <-pingTicker.C:
|
||||
ws.SetWriteDeadline(time.Now().Add(writeWait))
|
||||
if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func serveWs(w http.ResponseWriter, r *http.Request) {
|
||||
ws, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
if _, ok := err.(websocket.HandshakeError); !ok {
|
||||
log.Println(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var lastMod time.Time
|
||||
if n, err := strconv.ParseInt(r.FormValue("lastMod"), 16, 64); err != nil {
|
||||
lastMod = time.Unix(0, n)
|
||||
}
|
||||
|
||||
go writer(ws, lastMod)
|
||||
reader(ws)
|
||||
}
|
||||
|
||||
func serveHome(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/" {
|
||||
http.Error(w, "Not found", 404)
|
||||
return
|
||||
}
|
||||
if r.Method != "GET" {
|
||||
http.Error(w, "Method not allowed", 405)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
p, lastMod, err := readFileIfModified(time.Time{})
|
||||
if err != nil {
|
||||
p = []byte(err.Error())
|
||||
lastMod = time.Unix(0, 0)
|
||||
}
|
||||
var v = struct {
|
||||
Host string
|
||||
Data string
|
||||
LastMod string
|
||||
}{
|
||||
r.Host,
|
||||
string(p),
|
||||
strconv.FormatInt(lastMod.UnixNano(), 16),
|
||||
}
|
||||
homeTempl.Execute(w, &v)
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
if flag.NArg() != 1 {
|
||||
log.Fatal("filename not specified")
|
||||
}
|
||||
filename = flag.Args()[0]
|
||||
http.HandleFunc("/", serveHome)
|
||||
http.HandleFunc("/ws", serveWs)
|
||||
if err := http.ListenAndServe(*addr, nil); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
const homeHTML = `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>WebSocket Example</title>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="fileData">{{.Data}}</pre>
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
var data = document.getElementById("fileData");
|
||||
var conn = new WebSocket("ws://{{.Host}}/ws?lastMod={{.LastMod}}");
|
||||
conn.onclose = function(evt) {
|
||||
data.textContent = 'Connection closed';
|
||||
}
|
||||
conn.onmessage = function(evt) {
|
||||
console.log('file updated');
|
||||
data.textContent = evt.data;
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
49
Godeps/_workspace/src/github.com/gorilla/websocket/json.go
generated
vendored
49
Godeps/_workspace/src/github.com/gorilla/websocket/json.go
generated
vendored
@@ -1,49 +0,0 @@
|
||||
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// WriteJSON is deprecated, use c.WriteJSON instead.
|
||||
func WriteJSON(c *Conn, v interface{}) error {
|
||||
return c.WriteJSON(v)
|
||||
}
|
||||
|
||||
// WriteJSON writes the JSON encoding of v to the connection.
|
||||
//
|
||||
// See the documentation for encoding/json Marshal for details about the
|
||||
// conversion of Go values to JSON.
|
||||
func (c *Conn) WriteJSON(v interface{}) error {
|
||||
w, err := c.NextWriter(TextMessage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err1 := json.NewEncoder(w).Encode(v)
|
||||
err2 := w.Close()
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
return err2
|
||||
}
|
||||
|
||||
// ReadJSON is deprecated, use c.ReadJSON instead.
|
||||
func ReadJSON(c *Conn, v interface{}) error {
|
||||
return c.ReadJSON(v)
|
||||
}
|
||||
|
||||
// ReadJSON reads the next JSON-encoded message from the connection and stores
|
||||
// it in the value pointed to by v.
|
||||
//
|
||||
// See the documentation for the encoding/json Unmarshal function for details
|
||||
// about the conversion of JSON to a Go value.
|
||||
func (c *Conn) ReadJSON(v interface{}) error {
|
||||
_, r, err := c.NextReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.NewDecoder(r).Decode(v)
|
||||
}
|
||||
63
Godeps/_workspace/src/github.com/gorilla/websocket/json_test.go
generated
vendored
63
Godeps/_workspace/src/github.com/gorilla/websocket/json_test.go
generated
vendored
@@ -1,63 +0,0 @@
|
||||
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestJSON(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
c := fakeNetConn{&buf, &buf}
|
||||
wc := newConn(c, true, 1024, 1024)
|
||||
rc := newConn(c, false, 1024, 1024)
|
||||
|
||||
var actual, expect struct {
|
||||
A int
|
||||
B string
|
||||
}
|
||||
expect.A = 1
|
||||
expect.B = "hello"
|
||||
|
||||
if err := wc.WriteJSON(&expect); err != nil {
|
||||
t.Fatal("write", err)
|
||||
}
|
||||
|
||||
if err := rc.ReadJSON(&actual); err != nil {
|
||||
t.Fatal("read", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(&actual, &expect) {
|
||||
t.Fatal("equal", actual, expect)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeprecatedJSON(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
c := fakeNetConn{&buf, &buf}
|
||||
wc := newConn(c, true, 1024, 1024)
|
||||
rc := newConn(c, false, 1024, 1024)
|
||||
|
||||
var actual, expect struct {
|
||||
A int
|
||||
B string
|
||||
}
|
||||
expect.A = 1
|
||||
expect.B = "hello"
|
||||
|
||||
if err := WriteJSON(wc, &expect); err != nil {
|
||||
t.Fatal("write", err)
|
||||
}
|
||||
|
||||
if err := ReadJSON(rc, &actual); err != nil {
|
||||
t.Fatal("read", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(&actual, &expect) {
|
||||
t.Fatal("equal", actual, expect)
|
||||
}
|
||||
}
|
||||
247
Godeps/_workspace/src/github.com/gorilla/websocket/server.go
generated
vendored
247
Godeps/_workspace/src/github.com/gorilla/websocket/server.go
generated
vendored
@@ -1,247 +0,0 @@
|
||||
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// HandshakeError describes an error with the handshake from the peer.
|
||||
type HandshakeError struct {
|
||||
message string
|
||||
}
|
||||
|
||||
func (e HandshakeError) Error() string { return e.message }
|
||||
|
||||
// Upgrader specifies parameters for upgrading an HTTP connection to a
|
||||
// WebSocket connection.
|
||||
type Upgrader struct {
|
||||
// HandshakeTimeout specifies the duration for the handshake to complete.
|
||||
HandshakeTimeout time.Duration
|
||||
|
||||
// ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer
|
||||
// size is zero, then a default value of 4096 is used. The I/O buffer sizes
|
||||
// do not limit the size of the messages that can be sent or received.
|
||||
ReadBufferSize, WriteBufferSize int
|
||||
|
||||
// Subprotocols specifies the server's supported protocols in order of
|
||||
// preference. If this field is set, then the Upgrade method negotiates a
|
||||
// subprotocol by selecting the first match in this list with a protocol
|
||||
// requested by the client.
|
||||
Subprotocols []string
|
||||
|
||||
// Error specifies the function for generating HTTP error responses. If Error
|
||||
// is nil, then http.Error is used to generate the HTTP response.
|
||||
Error func(w http.ResponseWriter, r *http.Request, status int, reason error)
|
||||
|
||||
// CheckOrigin returns true if the request Origin header is acceptable. If
|
||||
// CheckOrigin is nil, the host in the Origin header must not be set or
|
||||
// must match the host of the request.
|
||||
CheckOrigin func(r *http.Request) bool
|
||||
}
|
||||
|
||||
func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status int, reason string) (*Conn, error) {
|
||||
err := HandshakeError{reason}
|
||||
if u.Error != nil {
|
||||
u.Error(w, r, status, err)
|
||||
} else {
|
||||
http.Error(w, http.StatusText(status), status)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// checkSameOrigin returns true if the origin is not set or is equal to the request host.
|
||||
func checkSameOrigin(r *http.Request) bool {
|
||||
origin := r.Header["Origin"]
|
||||
if len(origin) == 0 {
|
||||
return true
|
||||
}
|
||||
u, err := url.Parse(origin[0])
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return u.Host == r.Host
|
||||
}
|
||||
|
||||
func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header) string {
|
||||
if u.Subprotocols != nil {
|
||||
clientProtocols := Subprotocols(r)
|
||||
for _, serverProtocol := range u.Subprotocols {
|
||||
for _, clientProtocol := range clientProtocols {
|
||||
if clientProtocol == serverProtocol {
|
||||
return clientProtocol
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if responseHeader != nil {
|
||||
return responseHeader.Get("Sec-Websocket-Protocol")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
|
||||
//
|
||||
// The responseHeader is included in the response to the client's upgrade
|
||||
// request. Use the responseHeader to specify cookies (Set-Cookie) and the
|
||||
// application negotiated subprotocol (Sec-Websocket-Protocol).
|
||||
func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) {
|
||||
if values := r.Header["Sec-Websocket-Version"]; len(values) == 0 || values[0] != "13" {
|
||||
return u.returnError(w, r, http.StatusBadRequest, "websocket: version != 13")
|
||||
}
|
||||
|
||||
if !tokenListContainsValue(r.Header, "Connection", "upgrade") {
|
||||
return u.returnError(w, r, http.StatusBadRequest, "websocket: connection header != upgrade")
|
||||
}
|
||||
|
||||
if !tokenListContainsValue(r.Header, "Upgrade", "websocket") {
|
||||
return u.returnError(w, r, http.StatusBadRequest, "websocket: upgrade != websocket")
|
||||
}
|
||||
|
||||
checkOrigin := u.CheckOrigin
|
||||
if checkOrigin == nil {
|
||||
checkOrigin = checkSameOrigin
|
||||
}
|
||||
if !checkOrigin(r) {
|
||||
return u.returnError(w, r, http.StatusForbidden, "websocket: origin not allowed")
|
||||
}
|
||||
|
||||
challengeKey := r.Header.Get("Sec-Websocket-Key")
|
||||
if challengeKey == "" {
|
||||
return u.returnError(w, r, http.StatusBadRequest, "websocket: key missing or blank")
|
||||
}
|
||||
|
||||
subprotocol := u.selectSubprotocol(r, responseHeader)
|
||||
|
||||
var (
|
||||
netConn net.Conn
|
||||
br *bufio.Reader
|
||||
err error
|
||||
)
|
||||
|
||||
h, ok := w.(http.Hijacker)
|
||||
if !ok {
|
||||
return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker")
|
||||
}
|
||||
var rw *bufio.ReadWriter
|
||||
netConn, rw, err = h.Hijack()
|
||||
if err != nil {
|
||||
return u.returnError(w, r, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
br = rw.Reader
|
||||
|
||||
if br.Buffered() > 0 {
|
||||
netConn.Close()
|
||||
return nil, errors.New("websocket: client sent data before handshake is complete")
|
||||
}
|
||||
|
||||
c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize)
|
||||
c.subprotocol = subprotocol
|
||||
|
||||
p := c.writeBuf[:0]
|
||||
p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...)
|
||||
p = append(p, computeAcceptKey(challengeKey)...)
|
||||
p = append(p, "\r\n"...)
|
||||
if c.subprotocol != "" {
|
||||
p = append(p, "Sec-Websocket-Protocol: "...)
|
||||
p = append(p, c.subprotocol...)
|
||||
p = append(p, "\r\n"...)
|
||||
}
|
||||
for k, vs := range responseHeader {
|
||||
if k == "Sec-Websocket-Protocol" {
|
||||
continue
|
||||
}
|
||||
for _, v := range vs {
|
||||
p = append(p, k...)
|
||||
p = append(p, ": "...)
|
||||
for i := 0; i < len(v); i++ {
|
||||
b := v[i]
|
||||
if b <= 31 {
|
||||
// prevent response splitting.
|
||||
b = ' '
|
||||
}
|
||||
p = append(p, b)
|
||||
}
|
||||
p = append(p, "\r\n"...)
|
||||
}
|
||||
}
|
||||
p = append(p, "\r\n"...)
|
||||
|
||||
// Clear deadlines set by HTTP server.
|
||||
netConn.SetDeadline(time.Time{})
|
||||
|
||||
if u.HandshakeTimeout > 0 {
|
||||
netConn.SetWriteDeadline(time.Now().Add(u.HandshakeTimeout))
|
||||
}
|
||||
if _, err = netConn.Write(p); err != nil {
|
||||
netConn.Close()
|
||||
return nil, err
|
||||
}
|
||||
if u.HandshakeTimeout > 0 {
|
||||
netConn.SetWriteDeadline(time.Time{})
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
|
||||
//
|
||||
// This function is deprecated, use websocket.Upgrader instead.
|
||||
//
|
||||
// The application is responsible for checking the request origin before
|
||||
// calling Upgrade. An example implementation of the same origin policy is:
|
||||
//
|
||||
// if req.Header.Get("Origin") != "http://"+req.Host {
|
||||
// http.Error(w, "Origin not allowed", 403)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// If the endpoint supports subprotocols, then the application is responsible
|
||||
// for negotiating the protocol used on the connection. Use the Subprotocols()
|
||||
// function to get the subprotocols requested by the client. Use the
|
||||
// Sec-Websocket-Protocol response header to specify the subprotocol selected
|
||||
// by the application.
|
||||
//
|
||||
// The responseHeader is included in the response to the client's upgrade
|
||||
// request. Use the responseHeader to specify cookies (Set-Cookie) and the
|
||||
// negotiated subprotocol (Sec-Websocket-Protocol).
|
||||
//
|
||||
// The connection buffers IO to the underlying network connection. The
|
||||
// readBufSize and writeBufSize parameters specify the size of the buffers to
|
||||
// use. Messages can be larger than the buffers.
|
||||
//
|
||||
// If the request is not a valid WebSocket handshake, then Upgrade returns an
|
||||
// error of type HandshakeError. Applications should handle this error by
|
||||
// replying to the client with an HTTP error response.
|
||||
func Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header, readBufSize, writeBufSize int) (*Conn, error) {
|
||||
u := Upgrader{ReadBufferSize: readBufSize, WriteBufferSize: writeBufSize}
|
||||
u.Error = func(w http.ResponseWriter, r *http.Request, status int, reason error) {
|
||||
// don't return errors to maintain backwards compatibility
|
||||
}
|
||||
u.CheckOrigin = func(r *http.Request) bool {
|
||||
// allow all connections by default
|
||||
return true
|
||||
}
|
||||
return u.Upgrade(w, r, responseHeader)
|
||||
}
|
||||
|
||||
// Subprotocols returns the subprotocols requested by the client in the
|
||||
// Sec-Websocket-Protocol header.
|
||||
func Subprotocols(r *http.Request) []string {
|
||||
h := strings.TrimSpace(r.Header.Get("Sec-Websocket-Protocol"))
|
||||
if h == "" {
|
||||
return nil
|
||||
}
|
||||
protocols := strings.Split(h, ",")
|
||||
for i := range protocols {
|
||||
protocols[i] = strings.TrimSpace(protocols[i])
|
||||
}
|
||||
return protocols
|
||||
}
|
||||
33
Godeps/_workspace/src/github.com/gorilla/websocket/server_test.go
generated
vendored
33
Godeps/_workspace/src/github.com/gorilla/websocket/server_test.go
generated
vendored
@@ -1,33 +0,0 @@
|
||||
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var subprotocolTests = []struct {
|
||||
h string
|
||||
protocols []string
|
||||
}{
|
||||
{"", nil},
|
||||
{"foo", []string{"foo"}},
|
||||
{"foo,bar", []string{"foo", "bar"}},
|
||||
{"foo, bar", []string{"foo", "bar"}},
|
||||
{" foo, bar", []string{"foo", "bar"}},
|
||||
{" foo, bar ", []string{"foo", "bar"}},
|
||||
}
|
||||
|
||||
func TestSubprotocols(t *testing.T) {
|
||||
for _, st := range subprotocolTests {
|
||||
r := http.Request{Header: http.Header{"Sec-Websocket-Protocol": {st.h}}}
|
||||
protocols := Subprotocols(&r)
|
||||
if !reflect.DeepEqual(st.protocols, protocols) {
|
||||
t.Errorf("SubProtocols(%q) returned %#v, want %#v", st.h, protocols, st.protocols)
|
||||
}
|
||||
}
|
||||
}
|
||||
44
Godeps/_workspace/src/github.com/gorilla/websocket/util.go
generated
vendored
44
Godeps/_workspace/src/github.com/gorilla/websocket/util.go
generated
vendored
@@ -1,44 +0,0 @@
|
||||
// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// tokenListContainsValue returns true if the 1#token header with the given
|
||||
// name contains token.
|
||||
func tokenListContainsValue(header http.Header, name string, value string) bool {
|
||||
for _, v := range header[name] {
|
||||
for _, s := range strings.Split(v, ",") {
|
||||
if strings.EqualFold(value, strings.TrimSpace(s)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
|
||||
|
||||
func computeAcceptKey(challengeKey string) string {
|
||||
h := sha1.New()
|
||||
h.Write([]byte(challengeKey))
|
||||
h.Write(keyGUID)
|
||||
return base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
func generateChallengeKey() (string, error) {
|
||||
p := make([]byte, 16)
|
||||
if _, err := io.ReadFull(rand.Reader, p); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(p), nil
|
||||
}
|
||||
34
Godeps/_workspace/src/github.com/gorilla/websocket/util_test.go
generated
vendored
34
Godeps/_workspace/src/github.com/gorilla/websocket/util_test.go
generated
vendored
@@ -1,34 +0,0 @@
|
||||
// Copyright 2014 The Gorilla WebSocket Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var tokenListContainsValueTests = []struct {
|
||||
value string
|
||||
ok bool
|
||||
}{
|
||||
{"WebSocket", true},
|
||||
{"WEBSOCKET", true},
|
||||
{"websocket", true},
|
||||
{"websockets", false},
|
||||
{"x websocket", false},
|
||||
{"websocket x", false},
|
||||
{"other,websocket,more", true},
|
||||
{"other, websocket, more", true},
|
||||
}
|
||||
|
||||
func TestTokenListContainsValue(t *testing.T) {
|
||||
for _, tt := range tokenListContainsValueTests {
|
||||
h := http.Header{"Upgrade": {tt.value}}
|
||||
ok := tokenListContainsValue(h, "Upgrade", "websocket")
|
||||
if ok != tt.ok {
|
||||
t.Errorf("tokenListContainsValue(h, n, %q) = %v, want %v", tt.value, ok, tt.ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
225
Godeps/_workspace/src/github.com/inconshreveable/log15/stack/stack.go
generated
vendored
225
Godeps/_workspace/src/github.com/inconshreveable/log15/stack/stack.go
generated
vendored
@@ -1,225 +0,0 @@
|
||||
// Package stack implements utilities to capture, manipulate, and format call
|
||||
// stacks.
|
||||
package stack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Call records a single function invocation from a goroutine stack. It is a
|
||||
// wrapper for the program counter values returned by runtime.Caller and
|
||||
// runtime.Callers and consumed by runtime.FuncForPC.
|
||||
type Call uintptr
|
||||
|
||||
// Format implements fmt.Formatter with support for the following verbs.
|
||||
//
|
||||
// %s source file
|
||||
// %d line number
|
||||
// %n function name
|
||||
// %v equivalent to %s:%d
|
||||
//
|
||||
// It accepts the '+' and '#' flags for most of the verbs as follows.
|
||||
//
|
||||
// %+s path of source file relative to the compile time GOPATH
|
||||
// %#s full path of source file
|
||||
// %+n import path qualified function name
|
||||
// %+v equivalent to %+s:%d
|
||||
// %#v equivalent to %#s:%d
|
||||
func (pc Call) Format(s fmt.State, c rune) {
|
||||
// BUG(ChrisHines): Subtracting one from pc is a work around for
|
||||
// https://code.google.com/p/go/issues/detail?id=7690. The idea for this
|
||||
// work around comes from rsc's initial patch at
|
||||
// https://codereview.appspot.com/84100043/#ps20001, but as noted in the
|
||||
// issue discussion, it is not a complete fix since it doesn't handle some
|
||||
// cases involving signals. Just the same, it handles all of the other
|
||||
// cases I have tested.
|
||||
pcFix := uintptr(pc) - 1
|
||||
fn := runtime.FuncForPC(pcFix)
|
||||
if fn == nil {
|
||||
fmt.Fprintf(s, "%%!%c(NOFUNC)", c)
|
||||
return
|
||||
}
|
||||
|
||||
switch c {
|
||||
case 's', 'v':
|
||||
file, line := fn.FileLine(pcFix)
|
||||
switch {
|
||||
case s.Flag('#'):
|
||||
// done
|
||||
case s.Flag('+'):
|
||||
// Here we want to get the source file path relative to the
|
||||
// compile time GOPATH. As of Go 1.3.x there is no direct way to
|
||||
// know the compiled GOPATH at runtime, but we can infer the
|
||||
// number of path segments in the GOPATH. We note that fn.Name()
|
||||
// returns the function name qualified by the import path, which
|
||||
// does not include the GOPATH. Thus we can trim segments from the
|
||||
// beginning of the file path until the number of path separators
|
||||
// remaining is one more than the number of path separators in the
|
||||
// function name. For example, given:
|
||||
//
|
||||
// GOPATH /home/user
|
||||
// file /home/user/src/pkg/sub/file.go
|
||||
// fn.Name() pkg/sub.Type.Method
|
||||
//
|
||||
// We want to produce:
|
||||
//
|
||||
// pkg/sub/file.go
|
||||
//
|
||||
// From this we can easily see that fn.Name() has one less path
|
||||
// separator than our desired output.
|
||||
const sep = "/"
|
||||
impCnt := strings.Count(fn.Name(), sep) + 1
|
||||
pathCnt := strings.Count(file, sep)
|
||||
for pathCnt > impCnt {
|
||||
i := strings.Index(file, sep)
|
||||
if i == -1 {
|
||||
break
|
||||
}
|
||||
file = file[i+len(sep):]
|
||||
pathCnt--
|
||||
}
|
||||
default:
|
||||
const sep = "/"
|
||||
if i := strings.LastIndex(file, sep); i != -1 {
|
||||
file = file[i+len(sep):]
|
||||
}
|
||||
}
|
||||
fmt.Fprint(s, file)
|
||||
if c == 'v' {
|
||||
fmt.Fprint(s, ":", line)
|
||||
}
|
||||
|
||||
case 'd':
|
||||
_, line := fn.FileLine(pcFix)
|
||||
fmt.Fprint(s, line)
|
||||
|
||||
case 'n':
|
||||
name := fn.Name()
|
||||
if !s.Flag('+') {
|
||||
const pathSep = "/"
|
||||
if i := strings.LastIndex(name, pathSep); i != -1 {
|
||||
name = name[i+len(pathSep):]
|
||||
}
|
||||
const pkgSep = "."
|
||||
if i := strings.Index(name, pkgSep); i != -1 {
|
||||
name = name[i+len(pkgSep):]
|
||||
}
|
||||
}
|
||||
fmt.Fprint(s, name)
|
||||
}
|
||||
}
|
||||
|
||||
// Callers returns a Trace for the current goroutine with element 0
|
||||
// identifying the calling function.
|
||||
func Callers() Trace {
|
||||
pcs := poolBuf()
|
||||
pcs = pcs[:cap(pcs)]
|
||||
n := runtime.Callers(2, pcs)
|
||||
cs := make([]Call, n)
|
||||
for i, pc := range pcs[:n] {
|
||||
cs[i] = Call(pc)
|
||||
}
|
||||
putPoolBuf(pcs)
|
||||
return cs
|
||||
}
|
||||
|
||||
// name returns the import path qualified name of the function containing the
|
||||
// call.
|
||||
func (pc Call) name() string {
|
||||
pcFix := uintptr(pc) - 1 // work around for go issue #7690
|
||||
fn := runtime.FuncForPC(pcFix)
|
||||
if fn == nil {
|
||||
return "???"
|
||||
}
|
||||
return fn.Name()
|
||||
}
|
||||
|
||||
func (pc Call) file() string {
|
||||
pcFix := uintptr(pc) - 1 // work around for go issue #7690
|
||||
fn := runtime.FuncForPC(pcFix)
|
||||
if fn == nil {
|
||||
return "???"
|
||||
}
|
||||
file, _ := fn.FileLine(pcFix)
|
||||
return file
|
||||
}
|
||||
|
||||
// Trace records a sequence of function invocations from a goroutine stack.
|
||||
type Trace []Call
|
||||
|
||||
// Format implements fmt.Formatter by printing the Trace as square brackes ([,
|
||||
// ]) surrounding a space separated list of Calls each formatted with the
|
||||
// supplied verb and options.
|
||||
func (pcs Trace) Format(s fmt.State, c rune) {
|
||||
s.Write([]byte("["))
|
||||
for i, pc := range pcs {
|
||||
if i > 0 {
|
||||
s.Write([]byte(" "))
|
||||
}
|
||||
pc.Format(s, c)
|
||||
}
|
||||
s.Write([]byte("]"))
|
||||
}
|
||||
|
||||
// TrimBelow returns a slice of the Trace with all entries below pc removed.
|
||||
func (pcs Trace) TrimBelow(pc Call) Trace {
|
||||
for len(pcs) > 0 && pcs[0] != pc {
|
||||
pcs = pcs[1:]
|
||||
}
|
||||
return pcs
|
||||
}
|
||||
|
||||
// TrimAbove returns a slice of the Trace with all entries above pc removed.
|
||||
func (pcs Trace) TrimAbove(pc Call) Trace {
|
||||
for len(pcs) > 0 && pcs[len(pcs)-1] != pc {
|
||||
pcs = pcs[:len(pcs)-1]
|
||||
}
|
||||
return pcs
|
||||
}
|
||||
|
||||
// TrimBelowName returns a slice of the Trace with all entries below the
|
||||
// lowest with function name name removed.
|
||||
func (pcs Trace) TrimBelowName(name string) Trace {
|
||||
for len(pcs) > 0 && pcs[0].name() != name {
|
||||
pcs = pcs[1:]
|
||||
}
|
||||
return pcs
|
||||
}
|
||||
|
||||
// TrimAboveName returns a slice of the Trace with all entries above the
|
||||
// highest with function name name removed.
|
||||
func (pcs Trace) TrimAboveName(name string) Trace {
|
||||
for len(pcs) > 0 && pcs[len(pcs)-1].name() != name {
|
||||
pcs = pcs[:len(pcs)-1]
|
||||
}
|
||||
return pcs
|
||||
}
|
||||
|
||||
var goroot string
|
||||
|
||||
func init() {
|
||||
goroot = filepath.ToSlash(runtime.GOROOT())
|
||||
if runtime.GOOS == "windows" {
|
||||
goroot = strings.ToLower(goroot)
|
||||
}
|
||||
}
|
||||
|
||||
func inGoroot(path string) bool {
|
||||
if runtime.GOOS == "windows" {
|
||||
path = strings.ToLower(path)
|
||||
}
|
||||
return strings.HasPrefix(path, goroot)
|
||||
}
|
||||
|
||||
// TrimRuntime returns a slice of the Trace with the topmost entries from the
|
||||
// go runtime removed. It considers any calls originating from files under
|
||||
// GOROOT as part of the runtime.
|
||||
func (pcs Trace) TrimRuntime() Trace {
|
||||
for len(pcs) > 0 && inGoroot(pcs[len(pcs)-1].file()) {
|
||||
pcs = pcs[:len(pcs)-1]
|
||||
}
|
||||
return pcs
|
||||
}
|
||||
19
Godeps/_workspace/src/github.com/inconshreveable/log15/stack/stack_pool.go
generated
vendored
19
Godeps/_workspace/src/github.com/inconshreveable/log15/stack/stack_pool.go
generated
vendored
@@ -1,19 +0,0 @@
|
||||
// +build go1.3
|
||||
|
||||
package stack
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var pcStackPool = sync.Pool{
|
||||
New: func() interface{} { return make([]uintptr, 1000) },
|
||||
}
|
||||
|
||||
func poolBuf() []uintptr {
|
||||
return pcStackPool.Get().([]uintptr)
|
||||
}
|
||||
|
||||
func putPoolBuf(p []uintptr) {
|
||||
pcStackPool.Put(p)
|
||||
}
|
||||
27
Godeps/_workspace/src/github.com/inconshreveable/log15/stack/stack_pool_chan.go
generated
vendored
27
Godeps/_workspace/src/github.com/inconshreveable/log15/stack/stack_pool_chan.go
generated
vendored
@@ -1,27 +0,0 @@
|
||||
// +build !go1.3 appengine
|
||||
|
||||
package stack
|
||||
|
||||
const (
|
||||
stackPoolSize = 64
|
||||
)
|
||||
|
||||
var (
|
||||
pcStackPool = make(chan []uintptr, stackPoolSize)
|
||||
)
|
||||
|
||||
func poolBuf() []uintptr {
|
||||
select {
|
||||
case p := <-pcStackPool:
|
||||
return p
|
||||
default:
|
||||
return make([]uintptr, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
func putPoolBuf(p []uintptr) {
|
||||
select {
|
||||
case pcStackPool <- p:
|
||||
default:
|
||||
}
|
||||
}
|
||||
231
Godeps/_workspace/src/github.com/inconshreveable/log15/stack/stack_test.go
generated
vendored
231
Godeps/_workspace/src/github.com/inconshreveable/log15/stack/stack_test.go
generated
vendored
@@ -1,231 +0,0 @@
|
||||
package stack_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/tendermint/tendermint/Godeps/_workspace/src/github.com/inconshreveable/log15/stack"
|
||||
)
|
||||
|
||||
type testType struct{}
|
||||
|
||||
func (tt testType) testMethod() (pc uintptr, file string, line int, ok bool) {
|
||||
return runtime.Caller(0)
|
||||
}
|
||||
|
||||
func TestCallFormat(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pc, file, line, ok := runtime.Caller(0)
|
||||
if !ok {
|
||||
t.Fatal("runtime.Caller(0) failed")
|
||||
}
|
||||
|
||||
gopathSrc := filepath.Join(os.Getenv("GOPATH"), "src")
|
||||
relFile, err := filepath.Rel(gopathSrc, file)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to determine path relative to GOPATH: %v", err)
|
||||
}
|
||||
relFile = filepath.ToSlash(relFile)
|
||||
|
||||
pc2, file2, line2, ok2 := testType{}.testMethod()
|
||||
if !ok2 {
|
||||
t.Fatal("runtime.Caller(0) failed")
|
||||
}
|
||||
relFile2, err := filepath.Rel(gopathSrc, file)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to determine path relative to GOPATH: %v", err)
|
||||
}
|
||||
relFile2 = filepath.ToSlash(relFile2)
|
||||
|
||||
data := []struct {
|
||||
pc uintptr
|
||||
desc string
|
||||
fmt string
|
||||
out string
|
||||
}{
|
||||
{0, "error", "%s", "%!s(NOFUNC)"},
|
||||
|
||||
{pc, "func", "%s", path.Base(file)},
|
||||
{pc, "func", "%+s", relFile},
|
||||
{pc, "func", "%#s", file},
|
||||
{pc, "func", "%d", fmt.Sprint(line)},
|
||||
{pc, "func", "%n", "TestCallFormat"},
|
||||
{pc, "func", "%+n", runtime.FuncForPC(pc).Name()},
|
||||
{pc, "func", "%v", fmt.Sprint(path.Base(file), ":", line)},
|
||||
{pc, "func", "%+v", fmt.Sprint(relFile, ":", line)},
|
||||
{pc, "func", "%#v", fmt.Sprint(file, ":", line)},
|
||||
{pc, "func", "%v|%[1]n()", fmt.Sprint(path.Base(file), ":", line, "|", "TestCallFormat()")},
|
||||
|
||||
{pc2, "meth", "%s", path.Base(file2)},
|
||||
{pc2, "meth", "%+s", relFile2},
|
||||
{pc2, "meth", "%#s", file2},
|
||||
{pc2, "meth", "%d", fmt.Sprint(line2)},
|
||||
{pc2, "meth", "%n", "testType.testMethod"},
|
||||
{pc2, "meth", "%+n", runtime.FuncForPC(pc2).Name()},
|
||||
{pc2, "meth", "%v", fmt.Sprint(path.Base(file2), ":", line2)},
|
||||
{pc2, "meth", "%+v", fmt.Sprint(relFile2, ":", line2)},
|
||||
{pc2, "meth", "%#v", fmt.Sprint(file2, ":", line2)},
|
||||
{pc2, "meth", "%v|%[1]n()", fmt.Sprint(path.Base(file2), ":", line2, "|", "testType.testMethod()")},
|
||||
}
|
||||
|
||||
for _, d := range data {
|
||||
got := fmt.Sprintf(d.fmt, stack.Call(d.pc))
|
||||
if got != d.out {
|
||||
t.Errorf("fmt.Sprintf(%q, Call(%s)) = %s, want %s", d.fmt, d.desc, got, d.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCallVFmt(b *testing.B) {
|
||||
pc, _, _, ok := runtime.Caller(0)
|
||||
if !ok {
|
||||
b.Fatal("runtime.Caller(0) failed")
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
fmt.Fprint(ioutil.Discard, stack.Call(pc))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCallPlusVFmt(b *testing.B) {
|
||||
pc, _, _, ok := runtime.Caller(0)
|
||||
if !ok {
|
||||
b.Fatal("runtime.Caller(0) failed")
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
fmt.Fprintf(ioutil.Discard, "%+v", stack.Call(pc))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCallSharpVFmt(b *testing.B) {
|
||||
pc, _, _, ok := runtime.Caller(0)
|
||||
if !ok {
|
||||
b.Fatal("runtime.Caller(0) failed")
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
fmt.Fprintf(ioutil.Discard, "%#v", stack.Call(pc))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCallSFmt(b *testing.B) {
|
||||
pc, _, _, ok := runtime.Caller(0)
|
||||
if !ok {
|
||||
b.Fatal("runtime.Caller(0) failed")
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
fmt.Fprintf(ioutil.Discard, "%s", stack.Call(pc))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCallPlusSFmt(b *testing.B) {
|
||||
pc, _, _, ok := runtime.Caller(0)
|
||||
if !ok {
|
||||
b.Fatal("runtime.Caller(0) failed")
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
fmt.Fprintf(ioutil.Discard, "%+s", stack.Call(pc))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCallSharpSFmt(b *testing.B) {
|
||||
pc, _, _, ok := runtime.Caller(0)
|
||||
if !ok {
|
||||
b.Fatal("runtime.Caller(0) failed")
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
fmt.Fprintf(ioutil.Discard, "%#s", stack.Call(pc))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCallDFmt(b *testing.B) {
|
||||
pc, _, _, ok := runtime.Caller(0)
|
||||
if !ok {
|
||||
b.Fatal("runtime.Caller(0) failed")
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
fmt.Fprintf(ioutil.Discard, "%d", stack.Call(pc))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCallNFmt(b *testing.B) {
|
||||
pc, _, _, ok := runtime.Caller(0)
|
||||
if !ok {
|
||||
b.Fatal("runtime.Caller(0) failed")
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
fmt.Fprintf(ioutil.Discard, "%n", stack.Call(pc))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCallPlusNFmt(b *testing.B) {
|
||||
pc, _, _, ok := runtime.Caller(0)
|
||||
if !ok {
|
||||
b.Fatal("runtime.Caller(0) failed")
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
fmt.Fprintf(ioutil.Discard, "%+n", stack.Call(pc))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCallers(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
stack.Callers()
|
||||
}
|
||||
}
|
||||
|
||||
func deepStack(depth int, b *testing.B) stack.Trace {
|
||||
if depth > 0 {
|
||||
return deepStack(depth-1, b)
|
||||
}
|
||||
b.StartTimer()
|
||||
s := stack.Callers()
|
||||
b.StopTimer()
|
||||
return s
|
||||
}
|
||||
|
||||
func BenchmarkCallers10(b *testing.B) {
|
||||
b.StopTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
deepStack(10, b)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCallers50(b *testing.B) {
|
||||
b.StopTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
deepStack(50, b)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCallers100(b *testing.B) {
|
||||
b.StopTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
deepStack(100, b)
|
||||
}
|
||||
}
|
||||
21
Godeps/_workspace/src/github.com/inconshreveable/log15/term/LICENSE
generated
vendored
21
Godeps/_workspace/src/github.com/inconshreveable/log15/term/LICENSE
generated
vendored
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Simon Eskildsen
|
||||
|
||||
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
|
||||
AUTHORS OR COPYRIGHT HOLDERS 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.
|
||||
13
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_appengine.go
generated
vendored
13
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_appengine.go
generated
vendored
@@ -1,13 +0,0 @@
|
||||
// Based on ssh/terminal:
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build appengine
|
||||
|
||||
package term
|
||||
|
||||
// IsTty always returns false on AppEngine.
|
||||
func IsTty(fd uintptr) bool {
|
||||
return false
|
||||
}
|
||||
12
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_darwin.go
generated
vendored
12
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_darwin.go
generated
vendored
@@ -1,12 +0,0 @@
|
||||
// Based on ssh/terminal:
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package term
|
||||
|
||||
import "syscall"
|
||||
|
||||
const ioctlReadTermios = syscall.TIOCGETA
|
||||
|
||||
type Termios syscall.Termios
|
||||
18
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_freebsd.go
generated
vendored
18
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_freebsd.go
generated
vendored
@@ -1,18 +0,0 @@
|
||||
package term
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const ioctlReadTermios = syscall.TIOCGETA
|
||||
|
||||
// Go 1.2 doesn't include Termios for FreeBSD. This should be added in 1.3 and this could be merged with terminal_darwin.
|
||||
type Termios struct {
|
||||
Iflag uint32
|
||||
Oflag uint32
|
||||
Cflag uint32
|
||||
Lflag uint32
|
||||
Cc [20]uint8
|
||||
Ispeed uint32
|
||||
Ospeed uint32
|
||||
}
|
||||
14
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_linux.go
generated
vendored
14
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_linux.go
generated
vendored
@@ -1,14 +0,0 @@
|
||||
// Based on ssh/terminal:
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !appengine
|
||||
|
||||
package term
|
||||
|
||||
import "syscall"
|
||||
|
||||
const ioctlReadTermios = syscall.TCGETS
|
||||
|
||||
type Termios syscall.Termios
|
||||
20
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_notwindows.go
generated
vendored
20
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_notwindows.go
generated
vendored
@@ -1,20 +0,0 @@
|
||||
// Based on ssh/terminal:
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux,!appengine darwin freebsd
|
||||
|
||||
package term
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// IsTty returns true if the given file descriptor is a terminal.
|
||||
func IsTty(fd uintptr) bool {
|
||||
var termios Termios
|
||||
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
||||
return err == 0
|
||||
}
|
||||
26
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_windows.go
generated
vendored
26
Godeps/_workspace/src/github.com/inconshreveable/log15/term/terminal_windows.go
generated
vendored
@@ -1,26 +0,0 @@
|
||||
// Based on ssh/terminal:
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows
|
||||
|
||||
package term
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
|
||||
var (
|
||||
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
||||
)
|
||||
|
||||
// IsTty returns true if the given file descriptor is a terminal.
|
||||
func IsTty(fd uintptr) bool {
|
||||
var st uint32
|
||||
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
|
||||
return r != 0 && e == 0
|
||||
}
|
||||
42
Godeps/_workspace/src/github.com/mattn/go-colorable/README.md
generated
vendored
42
Godeps/_workspace/src/github.com/mattn/go-colorable/README.md
generated
vendored
@@ -1,42 +0,0 @@
|
||||
# go-colorable
|
||||
|
||||
Colorable writer for windows.
|
||||
|
||||
For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.)
|
||||
This package is possible to handle escape sequence for ansi color on windows.
|
||||
|
||||
## Too Bad!
|
||||
|
||||

|
||||
|
||||
|
||||
## So Good!
|
||||
|
||||

|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
logrus.SetOutput(colorable.NewColorableStdout())
|
||||
|
||||
logrus.Info("succeeded")
|
||||
logrus.Warn("not correct")
|
||||
logrus.Error("something error")
|
||||
logrus.Fatal("panic")
|
||||
```
|
||||
|
||||
You can compile above code on non-windows OSs.
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
$ go get github.com/mattn/go-colorable
|
||||
```
|
||||
|
||||
# License
|
||||
|
||||
MIT
|
||||
|
||||
# Author
|
||||
|
||||
Yasuhiro Matsumoto (a.k.a mattn)
|
||||
16
Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_others.go
generated
vendored
16
Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_others.go
generated
vendored
@@ -1,16 +0,0 @@
|
||||
// +build !windows
|
||||
|
||||
package colorable
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
func NewColorableStdout() io.Writer {
|
||||
return os.Stdout
|
||||
}
|
||||
|
||||
func NewColorableStderr() io.Writer {
|
||||
return os.Stderr
|
||||
}
|
||||
594
Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_windows.go
generated
vendored
594
Godeps/_workspace/src/github.com/mattn/go-colorable/colorable_windows.go
generated
vendored
@@ -1,594 +0,0 @@
|
||||
package colorable
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
const (
|
||||
foregroundBlue = 0x1
|
||||
foregroundGreen = 0x2
|
||||
foregroundRed = 0x4
|
||||
foregroundIntensity = 0x8
|
||||
foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity)
|
||||
backgroundBlue = 0x10
|
||||
backgroundGreen = 0x20
|
||||
backgroundRed = 0x40
|
||||
backgroundIntensity = 0x80
|
||||
backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
|
||||
)
|
||||
|
||||
type wchar uint16
|
||||
type short int16
|
||||
type dword uint32
|
||||
type word uint16
|
||||
|
||||
type coord struct {
|
||||
x short
|
||||
y short
|
||||
}
|
||||
|
||||
type smallRect struct {
|
||||
left short
|
||||
top short
|
||||
right short
|
||||
bottom short
|
||||
}
|
||||
|
||||
type consoleScreenBufferInfo struct {
|
||||
size coord
|
||||
cursorPosition coord
|
||||
attributes word
|
||||
window smallRect
|
||||
maximumWindowSize coord
|
||||
}
|
||||
|
||||
var (
|
||||
kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
|
||||
procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
|
||||
)
|
||||
|
||||
type Writer struct {
|
||||
out io.Writer
|
||||
handle syscall.Handle
|
||||
lastbuf bytes.Buffer
|
||||
oldattr word
|
||||
}
|
||||
|
||||
func NewColorableStdout() io.Writer {
|
||||
var csbi consoleScreenBufferInfo
|
||||
out := os.Stdout
|
||||
if !isatty.IsTerminal(out.Fd()) {
|
||||
return out
|
||||
}
|
||||
handle := syscall.Handle(out.Fd())
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
return &Writer{out: out, handle: handle, oldattr: csbi.attributes}
|
||||
}
|
||||
|
||||
func NewColorableStderr() io.Writer {
|
||||
var csbi consoleScreenBufferInfo
|
||||
out := os.Stderr
|
||||
if !isatty.IsTerminal(out.Fd()) {
|
||||
return out
|
||||
}
|
||||
handle := syscall.Handle(out.Fd())
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
return &Writer{out: out, handle: handle, oldattr: csbi.attributes}
|
||||
}
|
||||
|
||||
var color256 = map[int]int{
|
||||
0: 0x000000,
|
||||
1: 0x800000,
|
||||
2: 0x008000,
|
||||
3: 0x808000,
|
||||
4: 0x000080,
|
||||
5: 0x800080,
|
||||
6: 0x008080,
|
||||
7: 0xc0c0c0,
|
||||
8: 0x808080,
|
||||
9: 0xff0000,
|
||||
10: 0x00ff00,
|
||||
11: 0xffff00,
|
||||
12: 0x0000ff,
|
||||
13: 0xff00ff,
|
||||
14: 0x00ffff,
|
||||
15: 0xffffff,
|
||||
16: 0x000000,
|
||||
17: 0x00005f,
|
||||
18: 0x000087,
|
||||
19: 0x0000af,
|
||||
20: 0x0000d7,
|
||||
21: 0x0000ff,
|
||||
22: 0x005f00,
|
||||
23: 0x005f5f,
|
||||
24: 0x005f87,
|
||||
25: 0x005faf,
|
||||
26: 0x005fd7,
|
||||
27: 0x005fff,
|
||||
28: 0x008700,
|
||||
29: 0x00875f,
|
||||
30: 0x008787,
|
||||
31: 0x0087af,
|
||||
32: 0x0087d7,
|
||||
33: 0x0087ff,
|
||||
34: 0x00af00,
|
||||
35: 0x00af5f,
|
||||
36: 0x00af87,
|
||||
37: 0x00afaf,
|
||||
38: 0x00afd7,
|
||||
39: 0x00afff,
|
||||
40: 0x00d700,
|
||||
41: 0x00d75f,
|
||||
42: 0x00d787,
|
||||
43: 0x00d7af,
|
||||
44: 0x00d7d7,
|
||||
45: 0x00d7ff,
|
||||
46: 0x00ff00,
|
||||
47: 0x00ff5f,
|
||||
48: 0x00ff87,
|
||||
49: 0x00ffaf,
|
||||
50: 0x00ffd7,
|
||||
51: 0x00ffff,
|
||||
52: 0x5f0000,
|
||||
53: 0x5f005f,
|
||||
54: 0x5f0087,
|
||||
55: 0x5f00af,
|
||||
56: 0x5f00d7,
|
||||
57: 0x5f00ff,
|
||||
58: 0x5f5f00,
|
||||
59: 0x5f5f5f,
|
||||
60: 0x5f5f87,
|
||||
61: 0x5f5faf,
|
||||
62: 0x5f5fd7,
|
||||
63: 0x5f5fff,
|
||||
64: 0x5f8700,
|
||||
65: 0x5f875f,
|
||||
66: 0x5f8787,
|
||||
67: 0x5f87af,
|
||||
68: 0x5f87d7,
|
||||
69: 0x5f87ff,
|
||||
70: 0x5faf00,
|
||||
71: 0x5faf5f,
|
||||
72: 0x5faf87,
|
||||
73: 0x5fafaf,
|
||||
74: 0x5fafd7,
|
||||
75: 0x5fafff,
|
||||
76: 0x5fd700,
|
||||
77: 0x5fd75f,
|
||||
78: 0x5fd787,
|
||||
79: 0x5fd7af,
|
||||
80: 0x5fd7d7,
|
||||
81: 0x5fd7ff,
|
||||
82: 0x5fff00,
|
||||
83: 0x5fff5f,
|
||||
84: 0x5fff87,
|
||||
85: 0x5fffaf,
|
||||
86: 0x5fffd7,
|
||||
87: 0x5fffff,
|
||||
88: 0x870000,
|
||||
89: 0x87005f,
|
||||
90: 0x870087,
|
||||
91: 0x8700af,
|
||||
92: 0x8700d7,
|
||||
93: 0x8700ff,
|
||||
94: 0x875f00,
|
||||
95: 0x875f5f,
|
||||
96: 0x875f87,
|
||||
97: 0x875faf,
|
||||
98: 0x875fd7,
|
||||
99: 0x875fff,
|
||||
100: 0x878700,
|
||||
101: 0x87875f,
|
||||
102: 0x878787,
|
||||
103: 0x8787af,
|
||||
104: 0x8787d7,
|
||||
105: 0x8787ff,
|
||||
106: 0x87af00,
|
||||
107: 0x87af5f,
|
||||
108: 0x87af87,
|
||||
109: 0x87afaf,
|
||||
110: 0x87afd7,
|
||||
111: 0x87afff,
|
||||
112: 0x87d700,
|
||||
113: 0x87d75f,
|
||||
114: 0x87d787,
|
||||
115: 0x87d7af,
|
||||
116: 0x87d7d7,
|
||||
117: 0x87d7ff,
|
||||
118: 0x87ff00,
|
||||
119: 0x87ff5f,
|
||||
120: 0x87ff87,
|
||||
121: 0x87ffaf,
|
||||
122: 0x87ffd7,
|
||||
123: 0x87ffff,
|
||||
124: 0xaf0000,
|
||||
125: 0xaf005f,
|
||||
126: 0xaf0087,
|
||||
127: 0xaf00af,
|
||||
128: 0xaf00d7,
|
||||
129: 0xaf00ff,
|
||||
130: 0xaf5f00,
|
||||
131: 0xaf5f5f,
|
||||
132: 0xaf5f87,
|
||||
133: 0xaf5faf,
|
||||
134: 0xaf5fd7,
|
||||
135: 0xaf5fff,
|
||||
136: 0xaf8700,
|
||||
137: 0xaf875f,
|
||||
138: 0xaf8787,
|
||||
139: 0xaf87af,
|
||||
140: 0xaf87d7,
|
||||
141: 0xaf87ff,
|
||||
142: 0xafaf00,
|
||||
143: 0xafaf5f,
|
||||
144: 0xafaf87,
|
||||
145: 0xafafaf,
|
||||
146: 0xafafd7,
|
||||
147: 0xafafff,
|
||||
148: 0xafd700,
|
||||
149: 0xafd75f,
|
||||
150: 0xafd787,
|
||||
151: 0xafd7af,
|
||||
152: 0xafd7d7,
|
||||
153: 0xafd7ff,
|
||||
154: 0xafff00,
|
||||
155: 0xafff5f,
|
||||
156: 0xafff87,
|
||||
157: 0xafffaf,
|
||||
158: 0xafffd7,
|
||||
159: 0xafffff,
|
||||
160: 0xd70000,
|
||||
161: 0xd7005f,
|
||||
162: 0xd70087,
|
||||
163: 0xd700af,
|
||||
164: 0xd700d7,
|
||||
165: 0xd700ff,
|
||||
166: 0xd75f00,
|
||||
167: 0xd75f5f,
|
||||
168: 0xd75f87,
|
||||
169: 0xd75faf,
|
||||
170: 0xd75fd7,
|
||||
171: 0xd75fff,
|
||||
172: 0xd78700,
|
||||
173: 0xd7875f,
|
||||
174: 0xd78787,
|
||||
175: 0xd787af,
|
||||
176: 0xd787d7,
|
||||
177: 0xd787ff,
|
||||
178: 0xd7af00,
|
||||
179: 0xd7af5f,
|
||||
180: 0xd7af87,
|
||||
181: 0xd7afaf,
|
||||
182: 0xd7afd7,
|
||||
183: 0xd7afff,
|
||||
184: 0xd7d700,
|
||||
185: 0xd7d75f,
|
||||
186: 0xd7d787,
|
||||
187: 0xd7d7af,
|
||||
188: 0xd7d7d7,
|
||||
189: 0xd7d7ff,
|
||||
190: 0xd7ff00,
|
||||
191: 0xd7ff5f,
|
||||
192: 0xd7ff87,
|
||||
193: 0xd7ffaf,
|
||||
194: 0xd7ffd7,
|
||||
195: 0xd7ffff,
|
||||
196: 0xff0000,
|
||||
197: 0xff005f,
|
||||
198: 0xff0087,
|
||||
199: 0xff00af,
|
||||
200: 0xff00d7,
|
||||
201: 0xff00ff,
|
||||
202: 0xff5f00,
|
||||
203: 0xff5f5f,
|
||||
204: 0xff5f87,
|
||||
205: 0xff5faf,
|
||||
206: 0xff5fd7,
|
||||
207: 0xff5fff,
|
||||
208: 0xff8700,
|
||||
209: 0xff875f,
|
||||
210: 0xff8787,
|
||||
211: 0xff87af,
|
||||
212: 0xff87d7,
|
||||
213: 0xff87ff,
|
||||
214: 0xffaf00,
|
||||
215: 0xffaf5f,
|
||||
216: 0xffaf87,
|
||||
217: 0xffafaf,
|
||||
218: 0xffafd7,
|
||||
219: 0xffafff,
|
||||
220: 0xffd700,
|
||||
221: 0xffd75f,
|
||||
222: 0xffd787,
|
||||
223: 0xffd7af,
|
||||
224: 0xffd7d7,
|
||||
225: 0xffd7ff,
|
||||
226: 0xffff00,
|
||||
227: 0xffff5f,
|
||||
228: 0xffff87,
|
||||
229: 0xffffaf,
|
||||
230: 0xffffd7,
|
||||
231: 0xffffff,
|
||||
232: 0x080808,
|
||||
233: 0x121212,
|
||||
234: 0x1c1c1c,
|
||||
235: 0x262626,
|
||||
236: 0x303030,
|
||||
237: 0x3a3a3a,
|
||||
238: 0x444444,
|
||||
239: 0x4e4e4e,
|
||||
240: 0x585858,
|
||||
241: 0x626262,
|
||||
242: 0x6c6c6c,
|
||||
243: 0x767676,
|
||||
244: 0x808080,
|
||||
245: 0x8a8a8a,
|
||||
246: 0x949494,
|
||||
247: 0x9e9e9e,
|
||||
248: 0xa8a8a8,
|
||||
249: 0xb2b2b2,
|
||||
250: 0xbcbcbc,
|
||||
251: 0xc6c6c6,
|
||||
252: 0xd0d0d0,
|
||||
253: 0xdadada,
|
||||
254: 0xe4e4e4,
|
||||
255: 0xeeeeee,
|
||||
}
|
||||
|
||||
func (w *Writer) Write(data []byte) (n int, err error) {
|
||||
var csbi consoleScreenBufferInfo
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
|
||||
er := bytes.NewBuffer(data)
|
||||
loop:
|
||||
for {
|
||||
r1, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
if r1 == 0 {
|
||||
break loop
|
||||
}
|
||||
|
||||
c1, _, err := er.ReadRune()
|
||||
if err != nil {
|
||||
break loop
|
||||
}
|
||||
if c1 != 0x1b {
|
||||
fmt.Fprint(w.out, string(c1))
|
||||
continue
|
||||
}
|
||||
c2, _, err := er.ReadRune()
|
||||
if err != nil {
|
||||
w.lastbuf.WriteRune(c1)
|
||||
break loop
|
||||
}
|
||||
if c2 != 0x5b {
|
||||
w.lastbuf.WriteRune(c1)
|
||||
w.lastbuf.WriteRune(c2)
|
||||
continue
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
var m rune
|
||||
for {
|
||||
c, _, err := er.ReadRune()
|
||||
if err != nil {
|
||||
w.lastbuf.WriteRune(c1)
|
||||
w.lastbuf.WriteRune(c2)
|
||||
w.lastbuf.Write(buf.Bytes())
|
||||
break loop
|
||||
}
|
||||
if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
|
||||
m = c
|
||||
break
|
||||
}
|
||||
buf.Write([]byte(string(c)))
|
||||
}
|
||||
|
||||
switch m {
|
||||
case 'm':
|
||||
attr := csbi.attributes
|
||||
cs := buf.String()
|
||||
if cs == "" {
|
||||
procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr))
|
||||
continue
|
||||
}
|
||||
token := strings.Split(cs, ";")
|
||||
for i, ns := range token {
|
||||
if n, err = strconv.Atoi(ns); err == nil {
|
||||
switch {
|
||||
case n == 0 || n == 100:
|
||||
attr = w.oldattr
|
||||
case 1 <= n && n <= 5:
|
||||
attr |= foregroundIntensity
|
||||
case n == 7:
|
||||
attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
|
||||
case 22 == n || n == 25 || n == 25:
|
||||
attr |= foregroundIntensity
|
||||
case n == 27:
|
||||
attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
|
||||
case 30 <= n && n <= 37:
|
||||
attr = (attr & backgroundMask)
|
||||
if (n-30)&1 != 0 {
|
||||
attr |= foregroundRed
|
||||
}
|
||||
if (n-30)&2 != 0 {
|
||||
attr |= foregroundGreen
|
||||
}
|
||||
if (n-30)&4 != 0 {
|
||||
attr |= foregroundBlue
|
||||
}
|
||||
case n == 38: // set foreground color.
|
||||
if i < len(token)-2 && token[i+1] == "5" {
|
||||
if n256, err := strconv.Atoi(token[i+2]); err == nil {
|
||||
if n256foreAttr == nil {
|
||||
n256setup()
|
||||
}
|
||||
attr &= backgroundMask
|
||||
attr |= n256foreAttr[n256]
|
||||
i += 2
|
||||
}
|
||||
} else {
|
||||
attr = attr & (w.oldattr & backgroundMask)
|
||||
}
|
||||
case n == 39: // reset foreground color.
|
||||
attr &= backgroundMask
|
||||
attr |= w.oldattr & foregroundMask
|
||||
case 40 <= n && n <= 47:
|
||||
attr = (attr & foregroundMask)
|
||||
if (n-40)&1 != 0 {
|
||||
attr |= backgroundRed
|
||||
}
|
||||
if (n-40)&2 != 0 {
|
||||
attr |= backgroundGreen
|
||||
}
|
||||
if (n-40)&4 != 0 {
|
||||
attr |= backgroundBlue
|
||||
}
|
||||
case n == 48: // set background color.
|
||||
if i < len(token)-2 && token[i+1] == "5" {
|
||||
if n256, err := strconv.Atoi(token[i+2]); err == nil {
|
||||
if n256backAttr == nil {
|
||||
n256setup()
|
||||
}
|
||||
attr &= foregroundMask
|
||||
attr |= n256backAttr[n256]
|
||||
i += 2
|
||||
}
|
||||
} else {
|
||||
attr = attr & (w.oldattr & foregroundMask)
|
||||
}
|
||||
case n == 49: // reset foreground color.
|
||||
attr &= foregroundMask
|
||||
attr |= w.oldattr & backgroundMask
|
||||
}
|
||||
procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return len(data) - w.lastbuf.Len(), nil
|
||||
}
|
||||
|
||||
type consoleColor struct {
|
||||
red bool
|
||||
green bool
|
||||
blue bool
|
||||
intensity bool
|
||||
}
|
||||
|
||||
func minmax3(a, b, c int) (min, max int) {
|
||||
if a < b {
|
||||
if b < c {
|
||||
return a, c
|
||||
} else if a < c {
|
||||
return a, b
|
||||
} else {
|
||||
return c, b
|
||||
}
|
||||
} else {
|
||||
if a < c {
|
||||
return b, c
|
||||
} else if b < c {
|
||||
return b, a
|
||||
} else {
|
||||
return c, a
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func toConsoleColor(rgb int) (c consoleColor) {
|
||||
r, g, b := (rgb&0xFF0000)>>16, (rgb&0x00FF00)>>8, rgb&0x0000FF
|
||||
min, max := minmax3(r, g, b)
|
||||
a := (min + max) / 2
|
||||
if r < 128 && g < 128 && b < 128 {
|
||||
if r >= a {
|
||||
c.red = true
|
||||
}
|
||||
if g >= a {
|
||||
c.green = true
|
||||
}
|
||||
if b >= a {
|
||||
c.blue = true
|
||||
}
|
||||
// non-intensed white is lighter than intensed black, so swap those.
|
||||
if c.red && c.green && c.blue {
|
||||
c.red, c.green, c.blue = false, false, false
|
||||
c.intensity = true
|
||||
}
|
||||
} else {
|
||||
if min < 128 {
|
||||
min = 128
|
||||
a = (min + max) / 2
|
||||
}
|
||||
if r >= a {
|
||||
c.red = true
|
||||
}
|
||||
if g >= a {
|
||||
c.green = true
|
||||
}
|
||||
if b >= a {
|
||||
c.blue = true
|
||||
}
|
||||
c.intensity = true
|
||||
// intensed black is darker than non-intensed white, so swap those.
|
||||
if !c.red && !c.green && !c.blue {
|
||||
c.red, c.green, c.blue = true, true, true
|
||||
c.intensity = false
|
||||
}
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (c consoleColor) foregroundAttr() (attr word) {
|
||||
if c.red {
|
||||
attr |= foregroundRed
|
||||
}
|
||||
if c.green {
|
||||
attr |= foregroundGreen
|
||||
}
|
||||
if c.blue {
|
||||
attr |= foregroundBlue
|
||||
}
|
||||
if c.intensity {
|
||||
attr |= foregroundIntensity
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c consoleColor) backgroundAttr() (attr word) {
|
||||
if c.red {
|
||||
attr |= backgroundRed
|
||||
}
|
||||
if c.green {
|
||||
attr |= backgroundGreen
|
||||
}
|
||||
if c.blue {
|
||||
attr |= backgroundBlue
|
||||
}
|
||||
if c.intensity {
|
||||
attr |= backgroundIntensity
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var n256foreAttr []word
|
||||
var n256backAttr []word
|
||||
|
||||
func n256setup() {
|
||||
n256foreAttr = make([]word, 256)
|
||||
n256backAttr = make([]word, 256)
|
||||
for i, rgb := range color256 {
|
||||
c := toConsoleColor(rgb)
|
||||
n256foreAttr[i] = c.foregroundAttr()
|
||||
n256backAttr[i] = c.backgroundAttr()
|
||||
}
|
||||
}
|
||||
9
Godeps/_workspace/src/github.com/naoina/go-stringutil/.travis.yml
generated
vendored
9
Godeps/_workspace/src/github.com/naoina/go-stringutil/.travis.yml
generated
vendored
@@ -1,9 +0,0 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.3
|
||||
- 1.4
|
||||
- tip
|
||||
install:
|
||||
- go get -v github.com/naoina/go-stringutil
|
||||
script:
|
||||
- go test -v ./... -bench . -benchmem
|
||||
19
Godeps/_workspace/src/github.com/naoina/go-stringutil/LICENSE
generated
vendored
19
Godeps/_workspace/src/github.com/naoina/go-stringutil/LICENSE
generated
vendored
@@ -1,19 +0,0 @@
|
||||
Copyright (c) 2015 Naoya Inada <naoina@kuune.org>
|
||||
|
||||
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
|
||||
AUTHORS OR COPYRIGHT HOLDERS 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.
|
||||
13
Godeps/_workspace/src/github.com/naoina/go-stringutil/README.md
generated
vendored
13
Godeps/_workspace/src/github.com/naoina/go-stringutil/README.md
generated
vendored
@@ -1,13 +0,0 @@
|
||||
# stringutil [](https://travis-ci.org/naoina/go-stringutil)
|
||||
|
||||
## Installation
|
||||
|
||||
go get -u github.com/naoina/go-stringutil
|
||||
|
||||
## Documentation
|
||||
|
||||
See https://godoc.org/github.com/naoina/go-stringutil
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
120
Godeps/_workspace/src/github.com/naoina/go-stringutil/strings.go
generated
vendored
120
Godeps/_workspace/src/github.com/naoina/go-stringutil/strings.go
generated
vendored
@@ -1,120 +0,0 @@
|
||||
package stringutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// ToUpperCamelCase returns a copy of the string s with all Unicode letters mapped to their camel case.
|
||||
// It will convert to upper case previous letter of '_' and first letter, and remove letter of '_'.
|
||||
func ToUpperCamelCase(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
upper := true
|
||||
var result bytes.Buffer
|
||||
for _, c := range s {
|
||||
if c == '_' {
|
||||
upper = true
|
||||
continue
|
||||
}
|
||||
if upper {
|
||||
result.WriteRune(unicode.ToUpper(c))
|
||||
upper = false
|
||||
continue
|
||||
}
|
||||
result.WriteRune(c)
|
||||
}
|
||||
return result.String()
|
||||
}
|
||||
|
||||
// ToUpperCamelCaseASCII is similar to ToUpperCamelCase, but optimized for
|
||||
// only the ASCII characters.
|
||||
// ToUpperCamelCaseASCII is faster than ToUpperCamelCase, but doesn't work if
|
||||
// contains non-ASCII characters.
|
||||
func ToUpperCamelCaseASCII(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
upper := true
|
||||
result := make([]byte, 0, len(s))
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if c == '_' {
|
||||
upper = true
|
||||
continue
|
||||
}
|
||||
if upper {
|
||||
result = append(result, toUpperASCII(c))
|
||||
upper = false
|
||||
continue
|
||||
}
|
||||
result = append(result, c)
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
// ToSnakeCase returns a copy of the string s with all Unicode letters mapped to their snake case.
|
||||
// It will insert letter of '_' at position of previous letter of uppercase and all
|
||||
// letters convert to lower case.
|
||||
func ToSnakeCase(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
var result bytes.Buffer
|
||||
for _, c := range s {
|
||||
if unicode.IsUpper(c) {
|
||||
result.WriteByte('_')
|
||||
}
|
||||
result.WriteRune(unicode.ToLower(c))
|
||||
}
|
||||
s = result.String()
|
||||
if s[0] == '_' {
|
||||
return s[1:]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ToSnakeCaseASCII is similar to ToSnakeCase, but optimized for only the ASCII
|
||||
// characters.
|
||||
// ToSnakeCaseASCII is faster than ToSnakeCase, but doesn't work correctly if
|
||||
// contains non-ASCII characters.
|
||||
func ToSnakeCaseASCII(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
result := make([]byte, 0, len(s))
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if isUpperASCII(c) {
|
||||
result = append(result, '_')
|
||||
}
|
||||
result = append(result, toLowerASCII(c))
|
||||
}
|
||||
if result[0] == '_' {
|
||||
return string(result[1:])
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
func isUpperASCII(c byte) bool {
|
||||
return 'A' <= c && c <= 'Z'
|
||||
}
|
||||
|
||||
func isLowerASCII(c byte) bool {
|
||||
return 'a' <= c && c <= 'z'
|
||||
}
|
||||
|
||||
func toUpperASCII(c byte) byte {
|
||||
if isLowerASCII(c) {
|
||||
return c - ('a' - 'A')
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func toLowerASCII(c byte) byte {
|
||||
if isUpperASCII(c) {
|
||||
return c + 'a' - 'A'
|
||||
}
|
||||
return c
|
||||
}
|
||||
35
Godeps/_workspace/src/github.com/naoina/go-stringutil/strings_bench_test.go
generated
vendored
35
Godeps/_workspace/src/github.com/naoina/go-stringutil/strings_bench_test.go
generated
vendored
@@ -1,35 +0,0 @@
|
||||
package stringutil_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/tendermint/tendermint/Godeps/_workspace/src/github.com/naoina/go-stringutil"
|
||||
)
|
||||
|
||||
var benchcaseForCamelCase = "the_quick_brown_fox_jumps_over_the_lazy_dog"
|
||||
|
||||
func BenchmarkToUpperCamelCase(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
stringutil.ToUpperCamelCase(benchcaseForCamelCase)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkToUpperCamelCaseASCII(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
stringutil.ToUpperCamelCaseASCII(benchcaseForCamelCase)
|
||||
}
|
||||
}
|
||||
|
||||
var benchcaseForSnakeCase = "TheQuickBrownFoxJumpsOverTheLazyDog"
|
||||
|
||||
func BenchmarkToSnakeCase(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
stringutil.ToSnakeCase(benchcaseForSnakeCase)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkToSnakeCaseASCII(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
stringutil.ToSnakeCaseASCII(benchcaseForSnakeCase)
|
||||
}
|
||||
}
|
||||
88
Godeps/_workspace/src/github.com/naoina/go-stringutil/strings_test.go
generated
vendored
88
Godeps/_workspace/src/github.com/naoina/go-stringutil/strings_test.go
generated
vendored
@@ -1,88 +0,0 @@
|
||||
package stringutil_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/tendermint/tendermint/Godeps/_workspace/src/github.com/naoina/go-stringutil"
|
||||
)
|
||||
|
||||
func TestToUpperCamelCase(t *testing.T) {
|
||||
for _, v := range []struct {
|
||||
input, expect string
|
||||
}{
|
||||
{"", ""},
|
||||
{"thequickbrownfoxoverthelazydog", "Thequickbrownfoxoverthelazydog"},
|
||||
{"thequickbrownfoxoverthelazydoG", "ThequickbrownfoxoverthelazydoG"},
|
||||
{"thequickbrownfoxoverthelazydo_g", "ThequickbrownfoxoverthelazydoG"},
|
||||
{"TheQuickBrownFoxJumpsOverTheLazyDog", "TheQuickBrownFoxJumpsOverTheLazyDog"},
|
||||
{"the_quick_brown_fox_jumps_over_the_lazy_dog", "TheQuickBrownFoxJumpsOverTheLazyDog"},
|
||||
{"the_Quick_Brown_Fox_Jumps_Over_The_Lazy_Dog", "TheQuickBrownFoxJumpsOverTheLazyDog"},
|
||||
{"the_quick_brown_fox_over_the_lazy_dog", "TheQuickBrownFoxOverTheLazyDog"},
|
||||
} {
|
||||
actual := stringutil.ToUpperCamelCase(v.input)
|
||||
expect := v.expect
|
||||
if !reflect.DeepEqual(actual, expect) {
|
||||
t.Errorf(`stringutil.ToUpperCamelCase(%#v) => %#v; want %#v`, v.input, actual, expect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestToUpperCamelCaseASCII(t *testing.T) {
|
||||
for _, v := range []struct {
|
||||
input, expect string
|
||||
}{
|
||||
{"", ""},
|
||||
{"thequickbrownfoxoverthelazydog", "Thequickbrownfoxoverthelazydog"},
|
||||
{"thequickbrownfoxoverthelazydoG", "ThequickbrownfoxoverthelazydoG"},
|
||||
{"thequickbrownfoxoverthelazydo_g", "ThequickbrownfoxoverthelazydoG"},
|
||||
{"TheQuickBrownFoxJumpsOverTheLazyDog", "TheQuickBrownFoxJumpsOverTheLazyDog"},
|
||||
{"the_quick_brown_fox_jumps_over_the_lazy_dog", "TheQuickBrownFoxJumpsOverTheLazyDog"},
|
||||
{"the_Quick_Brown_Fox_Jumps_Over_The_Lazy_Dog", "TheQuickBrownFoxJumpsOverTheLazyDog"},
|
||||
} {
|
||||
actual := stringutil.ToUpperCamelCaseASCII(v.input)
|
||||
expect := v.expect
|
||||
if !reflect.DeepEqual(actual, expect) {
|
||||
t.Errorf(`stringutil.ToUpperCamelCaseASCII(%#v) => %#v; want %#v`, v.input, actual, expect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestToSnakeCase(t *testing.T) {
|
||||
for _, v := range []struct {
|
||||
input, expect string
|
||||
}{
|
||||
{"", ""},
|
||||
{"thequickbrownfoxjumpsoverthelazydog", "thequickbrownfoxjumpsoverthelazydog"},
|
||||
{"Thequickbrownfoxjumpsoverthelazydog", "thequickbrownfoxjumpsoverthelazydog"},
|
||||
{"ThequickbrownfoxjumpsoverthelazydoG", "thequickbrownfoxjumpsoverthelazydo_g"},
|
||||
{"TheQuickBrownFoxJumpsOverTheLazyDog", "the_quick_brown_fox_jumps_over_the_lazy_dog"},
|
||||
{"the_quick_brown_fox_jumps_over_the_lazy_dog", "the_quick_brown_fox_jumps_over_the_lazy_dog"},
|
||||
{"TheQuickBrownFoxOverTheLazyDog", "the_quick_brown_fox_over_the_lazy_dog"},
|
||||
} {
|
||||
actual := stringutil.ToSnakeCase(v.input)
|
||||
expect := v.expect
|
||||
if !reflect.DeepEqual(actual, expect) {
|
||||
t.Errorf(`stringutil.ToSnakeCase(%#v) => %#v; want %#v`, v.input, actual, expect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestToSnakeCaseASCII(t *testing.T) {
|
||||
for _, v := range []struct {
|
||||
input, expect string
|
||||
}{
|
||||
{"", ""},
|
||||
{"thequickbrownfoxjumpsoverthelazydog", "thequickbrownfoxjumpsoverthelazydog"},
|
||||
{"Thequickbrownfoxjumpsoverthelazydog", "thequickbrownfoxjumpsoverthelazydog"},
|
||||
{"ThequickbrownfoxjumpsoverthelazydoG", "thequickbrownfoxjumpsoverthelazydo_g"},
|
||||
{"TheQuickBrownFoxJumpsOverTheLazyDog", "the_quick_brown_fox_jumps_over_the_lazy_dog"},
|
||||
{"the_quick_brown_fox_jumps_over_the_lazy_dog", "the_quick_brown_fox_jumps_over_the_lazy_dog"},
|
||||
} {
|
||||
actual := stringutil.ToSnakeCaseASCII(v.input)
|
||||
expect := v.expect
|
||||
if !reflect.DeepEqual(actual, expect) {
|
||||
t.Errorf(`stringutil.ToSnakeCaseASCII(%#v) => %#v; want %#v`, v.input, actual, expect)
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Godeps/_workspace/src/github.com/naoina/toml/.travis.yml
generated
vendored
11
Godeps/_workspace/src/github.com/naoina/toml/.travis.yml
generated
vendored
@@ -1,11 +0,0 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.3
|
||||
- tip
|
||||
|
||||
install:
|
||||
- go get -v ./...
|
||||
|
||||
script:
|
||||
- go test ./...
|
||||
19
Godeps/_workspace/src/github.com/naoina/toml/LICENSE
generated
vendored
19
Godeps/_workspace/src/github.com/naoina/toml/LICENSE
generated
vendored
@@ -1,19 +0,0 @@
|
||||
Copyright (c) 2014 Naoya Inada <naoina@kuune.org>
|
||||
|
||||
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
|
||||
AUTHORS OR COPYRIGHT HOLDERS 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.
|
||||
16
Godeps/_workspace/src/github.com/naoina/toml/Makefile
generated
vendored
16
Godeps/_workspace/src/github.com/naoina/toml/Makefile
generated
vendored
@@ -1,16 +0,0 @@
|
||||
GO = go
|
||||
PEG = peg
|
||||
|
||||
.SUFFIXES: .peg .peg.go
|
||||
|
||||
.PHONY: all test clean
|
||||
all: parse.peg.go
|
||||
|
||||
.peg.peg.go:
|
||||
$(PEG) -switch -inline $<
|
||||
|
||||
test: all
|
||||
$(GO) test ./...
|
||||
|
||||
clean:
|
||||
$(RM) *.peg.go
|
||||
364
Godeps/_workspace/src/github.com/naoina/toml/README.md
generated
vendored
364
Godeps/_workspace/src/github.com/naoina/toml/README.md
generated
vendored
@@ -1,364 +0,0 @@
|
||||
# TOML parser and encoder library for Golang [](https://travis-ci.org/naoina/toml)
|
||||
|
||||
[TOML](https://github.com/toml-lang/toml) parser and encoder library for [Golang](http://golang.org/).
|
||||
|
||||
This library is compatible with TOML version [v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md).
|
||||
|
||||
## Installation
|
||||
|
||||
go get -u github.com/naoina/toml
|
||||
|
||||
## Usage
|
||||
|
||||
The following TOML save as `example.toml`.
|
||||
|
||||
```toml
|
||||
# This is a TOML document. Boom.
|
||||
|
||||
title = "TOML Example"
|
||||
|
||||
[owner]
|
||||
name = "Lance Uppercut"
|
||||
dob = 1979-05-27T07:32:00-08:00 # First class dates? Why not?
|
||||
|
||||
[database]
|
||||
server = "192.168.1.1"
|
||||
ports = [ 8001, 8001, 8002 ]
|
||||
connection_max = 5000
|
||||
enabled = true
|
||||
|
||||
[servers]
|
||||
|
||||
# You can indent as you please. Tabs or spaces. TOML don't care.
|
||||
[servers.alpha]
|
||||
ip = "10.0.0.1"
|
||||
dc = "eqdc10"
|
||||
|
||||
[servers.beta]
|
||||
ip = "10.0.0.2"
|
||||
dc = "eqdc10"
|
||||
|
||||
[clients]
|
||||
data = [ ["gamma", "delta"], [1, 2] ]
|
||||
|
||||
# Line breaks are OK when inside arrays
|
||||
hosts = [
|
||||
"alpha",
|
||||
"omega"
|
||||
]
|
||||
```
|
||||
|
||||
Then above TOML will mapping to `tomlConfig` struct using `toml.Unmarshal`.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/naoina/toml"
|
||||
)
|
||||
|
||||
type tomlConfig struct {
|
||||
Title string
|
||||
Owner struct {
|
||||
Name string
|
||||
Dob time.Time
|
||||
}
|
||||
Database struct {
|
||||
Server string
|
||||
Ports []int
|
||||
ConnectionMax uint
|
||||
Enabled bool
|
||||
}
|
||||
Servers map[string]Server
|
||||
Clients struct {
|
||||
Data [][]interface{}
|
||||
Hosts []string
|
||||
}
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
IP string
|
||||
DC string
|
||||
}
|
||||
|
||||
func main() {
|
||||
f, err := os.Open("example.toml")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f.Close()
|
||||
buf, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var config tomlConfig
|
||||
if err := toml.Unmarshal(buf, &config); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// then to use the unmarshaled config...
|
||||
}
|
||||
```
|
||||
|
||||
## Mappings
|
||||
|
||||
A key and value of TOML will map to the corresponding field.
|
||||
The fields of struct for mapping must be exported.
|
||||
|
||||
The rules of the mapping of key are following:
|
||||
|
||||
#### Exact matching
|
||||
|
||||
```toml
|
||||
timeout_seconds = 256
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Timeout_seconds int
|
||||
}
|
||||
```
|
||||
|
||||
#### Camelcase matching
|
||||
|
||||
```toml
|
||||
server_name = "srv1"
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
ServerName string
|
||||
}
|
||||
```
|
||||
|
||||
#### Uppercase matching
|
||||
|
||||
```toml
|
||||
ip = "10.0.0.1"
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
IP string
|
||||
}
|
||||
```
|
||||
|
||||
See the following examples for the value mappings.
|
||||
|
||||
### String
|
||||
|
||||
```toml
|
||||
val = "string"
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Val string
|
||||
}
|
||||
```
|
||||
|
||||
### Integer
|
||||
|
||||
```toml
|
||||
val = 100
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Val int
|
||||
}
|
||||
```
|
||||
|
||||
All types that can be used are following:
|
||||
|
||||
* int8 (from `-128` to `127`)
|
||||
* int16 (from `-32768` to `32767`)
|
||||
* int32 (from `-2147483648` to `2147483647`)
|
||||
* int64 (from `-9223372036854775808` to `9223372036854775807`)
|
||||
* int (same as `int32` on 32bit environment, or `int64` on 64bit environment)
|
||||
* uint8 (from `0` to `255`)
|
||||
* uint16 (from `0` to `65535`)
|
||||
* uint32 (from `0` to `4294967295`)
|
||||
* uint64 (from `0` to `18446744073709551615`)
|
||||
* uint (same as `uint` on 32bit environment, or `uint64` on 64bit environment)
|
||||
|
||||
### Float
|
||||
|
||||
```toml
|
||||
val = 3.1415
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Val float32
|
||||
}
|
||||
```
|
||||
|
||||
All types that can be used are following:
|
||||
|
||||
* float32
|
||||
* float64
|
||||
|
||||
### Boolean
|
||||
|
||||
```toml
|
||||
val = true
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Val bool
|
||||
}
|
||||
```
|
||||
|
||||
### Datetime
|
||||
|
||||
```toml
|
||||
val = 2014-09-28T21:27:39Z
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Val time.Time
|
||||
}
|
||||
```
|
||||
|
||||
### Array
|
||||
|
||||
```toml
|
||||
val = ["a", "b", "c"]
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Val []string
|
||||
}
|
||||
```
|
||||
|
||||
Also following examples all can be mapped:
|
||||
|
||||
```toml
|
||||
val1 = [1, 2, 3]
|
||||
val2 = [["a", "b"], ["c", "d"]]
|
||||
val3 = [[1, 2, 3], ["a", "b", "c"]]
|
||||
val4 = [[1, 2, 3], [["a", "b"], [true, false]]]
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Val1 []int
|
||||
Val2 [][]string
|
||||
Val3 [][]interface{}
|
||||
Val4 [][]interface{}
|
||||
}
|
||||
```
|
||||
|
||||
### Table
|
||||
|
||||
```toml
|
||||
[server]
|
||||
type = "app"
|
||||
|
||||
[server.development]
|
||||
ip = "10.0.0.1"
|
||||
|
||||
[server.production]
|
||||
ip = "10.0.0.2"
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Server map[string]Server
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
IP string
|
||||
}
|
||||
```
|
||||
|
||||
You can also use the following struct instead of map of struct.
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Server struct {
|
||||
Development Server
|
||||
Production Server
|
||||
}
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
IP string
|
||||
}
|
||||
```
|
||||
|
||||
### Array of Tables
|
||||
|
||||
```toml
|
||||
[[fruit]]
|
||||
name = "apple"
|
||||
|
||||
[fruit.physical]
|
||||
color = "red"
|
||||
shape = "round"
|
||||
|
||||
[[fruit.variety]]
|
||||
name = "red delicious"
|
||||
|
||||
[[fruit.variety]]
|
||||
name = "granny smith"
|
||||
|
||||
[[fruit]]
|
||||
name = "banana"
|
||||
|
||||
[[fruit.variety]]
|
||||
name = "plantain"
|
||||
```
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Fruit []struct {
|
||||
Name string
|
||||
Physical struct {
|
||||
Color string
|
||||
Shape string
|
||||
}
|
||||
Variety []struct {
|
||||
Name string
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Using `toml.UnmarshalTOML` interface
|
||||
|
||||
```toml
|
||||
duration = "10s"
|
||||
```
|
||||
|
||||
```go
|
||||
import time
|
||||
|
||||
type Config struct {
|
||||
Duration Duration
|
||||
}
|
||||
|
||||
type Duration struct {
|
||||
time.Duration
|
||||
}
|
||||
|
||||
func (d *Duration) UnmarshalTOML(data []byte) error {
|
||||
d.Duration, err := time.ParseDuration(string(data))
|
||||
return err
|
||||
}
|
||||
```
|
||||
|
||||
## API documentation
|
||||
|
||||
See [Godoc](http://godoc.org/github.com/naoina/toml).
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
184
Godeps/_workspace/src/github.com/naoina/toml/ast/ast.go
generated
vendored
184
Godeps/_workspace/src/github.com/naoina/toml/ast/ast.go
generated
vendored
@@ -1,184 +0,0 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Position struct {
|
||||
Begin int
|
||||
End int
|
||||
}
|
||||
|
||||
type Value interface {
|
||||
Pos() int
|
||||
End() int
|
||||
Source() string
|
||||
}
|
||||
|
||||
type String struct {
|
||||
Position Position
|
||||
Value string
|
||||
Data []rune
|
||||
}
|
||||
|
||||
func (s *String) Pos() int {
|
||||
return s.Position.Begin
|
||||
}
|
||||
|
||||
func (s *String) End() int {
|
||||
return s.Position.End
|
||||
}
|
||||
|
||||
func (s *String) Source() string {
|
||||
return string(s.Data)
|
||||
}
|
||||
|
||||
type Integer struct {
|
||||
Position Position
|
||||
Value string
|
||||
Data []rune
|
||||
}
|
||||
|
||||
func (i *Integer) Pos() int {
|
||||
return i.Position.Begin
|
||||
}
|
||||
|
||||
func (i *Integer) End() int {
|
||||
return i.Position.End
|
||||
}
|
||||
|
||||
func (i *Integer) Source() string {
|
||||
return string(i.Data)
|
||||
}
|
||||
|
||||
func (i *Integer) Int() (int64, error) {
|
||||
return strconv.ParseInt(i.Value, 10, 64)
|
||||
}
|
||||
|
||||
type Float struct {
|
||||
Position Position
|
||||
Value string
|
||||
Data []rune
|
||||
}
|
||||
|
||||
func (f *Float) Pos() int {
|
||||
return f.Position.Begin
|
||||
}
|
||||
|
||||
func (f *Float) End() int {
|
||||
return f.Position.End
|
||||
}
|
||||
|
||||
func (f *Float) Source() string {
|
||||
return string(f.Data)
|
||||
}
|
||||
|
||||
func (f *Float) Float() (float64, error) {
|
||||
return strconv.ParseFloat(f.Value, 64)
|
||||
}
|
||||
|
||||
type Boolean struct {
|
||||
Position Position
|
||||
Value string
|
||||
Data []rune
|
||||
}
|
||||
|
||||
func (b *Boolean) Pos() int {
|
||||
return b.Position.Begin
|
||||
}
|
||||
|
||||
func (b *Boolean) End() int {
|
||||
return b.Position.End
|
||||
}
|
||||
|
||||
func (b *Boolean) Source() string {
|
||||
return string(b.Data)
|
||||
}
|
||||
|
||||
func (b *Boolean) Boolean() (bool, error) {
|
||||
return strconv.ParseBool(b.Value)
|
||||
}
|
||||
|
||||
type Datetime struct {
|
||||
Position Position
|
||||
Value string
|
||||
Data []rune
|
||||
}
|
||||
|
||||
func (d *Datetime) Pos() int {
|
||||
return d.Position.Begin
|
||||
}
|
||||
|
||||
func (d *Datetime) End() int {
|
||||
return d.Position.End
|
||||
}
|
||||
|
||||
func (d *Datetime) Source() string {
|
||||
return string(d.Data)
|
||||
}
|
||||
|
||||
func (d *Datetime) Time() (time.Time, error) {
|
||||
return time.Parse(time.RFC3339Nano, d.Value)
|
||||
}
|
||||
|
||||
type Array struct {
|
||||
Position Position
|
||||
Value []Value
|
||||
Data []rune
|
||||
}
|
||||
|
||||
func (a *Array) Pos() int {
|
||||
return a.Position.Begin
|
||||
}
|
||||
|
||||
func (a *Array) End() int {
|
||||
return a.Position.End
|
||||
}
|
||||
|
||||
func (a *Array) Source() string {
|
||||
return string(a.Data)
|
||||
}
|
||||
|
||||
type TableType uint8
|
||||
|
||||
const (
|
||||
TableTypeNormal TableType = iota
|
||||
TableTypeArray
|
||||
)
|
||||
|
||||
var tableTypes = [...]string{
|
||||
"normal",
|
||||
"array",
|
||||
}
|
||||
|
||||
func (t TableType) String() string {
|
||||
return tableTypes[t]
|
||||
}
|
||||
|
||||
type Table struct {
|
||||
Position Position
|
||||
Line int
|
||||
Name string
|
||||
Fields map[string]interface{}
|
||||
Type TableType
|
||||
Data []rune
|
||||
}
|
||||
|
||||
func (t *Table) Pos() int {
|
||||
return t.Position.Begin
|
||||
}
|
||||
|
||||
func (t *Table) End() int {
|
||||
return t.Position.End
|
||||
}
|
||||
|
||||
func (t *Table) Source() string {
|
||||
return string(t.Data)
|
||||
}
|
||||
|
||||
type KeyValue struct {
|
||||
Key string
|
||||
Value Value
|
||||
Line int
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user