mirror of
https://github.com/zulip/zulip.git
synced 2025-11-01 04:23:46 +00:00
Compare commits
973 Commits
enterprise
...
1.3.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bec3c0943a | ||
|
|
7352f31c4b | ||
|
|
dafe69761e | ||
|
|
956fd7c420 | ||
|
|
f819c1e901 | ||
|
|
3b00029c52 | ||
|
|
1482a386c2 | ||
|
|
92aebe595b | ||
|
|
5ad84fd997 | ||
|
|
40ec59b93e | ||
|
|
5bf66e04fc | ||
|
|
3efdb7ebf3 | ||
|
|
80fa5006f8 | ||
|
|
bda9d78092 | ||
|
|
6bb9b129f7 | ||
|
|
d93d4c7216 | ||
|
|
852ac66f8e | ||
|
|
e20bc9f9b3 | ||
|
|
1f2f497cab | ||
|
|
578f769f60 | ||
|
|
54fd321941 | ||
|
|
b6c1f1d162 | ||
|
|
d2f5937d89 | ||
|
|
ed742fa847 | ||
|
|
a625ca49ec | ||
|
|
96bd1c38dc | ||
|
|
9748780192 | ||
|
|
bc3f096918 | ||
|
|
af4aac6836 | ||
|
|
e5f7000a23 | ||
|
|
00bf7b25b5 | ||
|
|
2c6bfe136a | ||
|
|
db51a1c547 | ||
|
|
3f76745235 | ||
|
|
b59b5cac35 | ||
|
|
5dd330e769 | ||
|
|
140e598a89 | ||
|
|
8159c03205 | ||
|
|
0d12dfd06f | ||
|
|
6888826d5b | ||
|
|
f0add4638c | ||
|
|
974a9bd0f3 | ||
|
|
aeb6a5df7c | ||
|
|
94c35d8fb0 | ||
|
|
1d40b2291c | ||
|
|
d6a41b4fe3 | ||
|
|
5bf6f05f60 | ||
|
|
b69c6228af | ||
|
|
f4be74dafc | ||
|
|
abb1a13e31 | ||
|
|
3c3238d8e1 | ||
|
|
5accdf6d69 | ||
|
|
1156a82297 | ||
|
|
81fe34d011 | ||
|
|
3caa743951 | ||
|
|
45a8b050ac | ||
|
|
b21a105a99 | ||
|
|
8967029729 | ||
|
|
9c0c5c57a7 | ||
|
|
f31816072d | ||
|
|
0ace7fe502 | ||
|
|
3770142635 | ||
|
|
441fa8ed9d | ||
|
|
11a51cf943 | ||
|
|
cc33b68d73 | ||
|
|
fcf4731ed9 | ||
|
|
8269b4dc76 | ||
|
|
2348a83678 | ||
|
|
ae4cb6df35 | ||
|
|
a0006d5faf | ||
|
|
6540807761 | ||
|
|
2fb9560476 | ||
|
|
d7618ff8dc | ||
|
|
be844b628d | ||
|
|
ce5e9093e6 | ||
|
|
3e5e40a3ed | ||
|
|
da5fe944e1 | ||
|
|
ca4db5ac4b | ||
|
|
95056c6681 | ||
|
|
c0bf02b4c2 | ||
|
|
49cf7abaed | ||
|
|
827e7ad19c | ||
|
|
a3c122eb41 | ||
|
|
1be909a450 | ||
|
|
3c1c14a7cc | ||
|
|
ac8167062b | ||
|
|
485c907721 | ||
|
|
53f74ef06a | ||
|
|
b6e2fd6e83 | ||
|
|
cf17168c9f | ||
|
|
78a9b301d0 | ||
|
|
99fd2924cf | ||
|
|
efa7a90ecc | ||
|
|
38ca08b18f | ||
|
|
4a858d7d1b | ||
|
|
c5b44dc921 | ||
|
|
32878e8343 | ||
|
|
ade363f3af | ||
|
|
b68d116e3a | ||
|
|
858d0a984b | ||
|
|
bfcae58cac | ||
|
|
80a8725a03 | ||
|
|
36a9dc2cf7 | ||
|
|
5e0b6b809a | ||
|
|
602077f75b | ||
|
|
94d7ed006f | ||
|
|
e29c473077 | ||
|
|
23a81af8ad | ||
|
|
7fc7e5ee8c | ||
|
|
232de3015a | ||
|
|
eff0d31dcd | ||
|
|
176e3f4a54 | ||
|
|
f340778798 | ||
|
|
3ac95ddc1a | ||
|
|
a59e41b5ee | ||
|
|
9590d988c5 | ||
|
|
21ac93ae9c | ||
|
|
fcec80461b | ||
|
|
25a9ccccf1 | ||
|
|
b7bb55932a | ||
|
|
3b84a9a010 | ||
|
|
a5c1fc6d76 | ||
|
|
b3dfacae19 | ||
|
|
c0ec9e985a | ||
|
|
eca3c3bfaa | ||
|
|
87d2d543a5 | ||
|
|
155958871d | ||
|
|
166192fb57 | ||
|
|
24dfa10556 | ||
|
|
36445d1576 | ||
|
|
7f8ef32704 | ||
|
|
394a0aa774 | ||
|
|
a8643e44b4 | ||
|
|
9f0a6272fa | ||
|
|
cf1aff661c | ||
|
|
5be0c2902e | ||
|
|
73264ab530 | ||
|
|
0a3bdc20e9 | ||
|
|
942e97d886 | ||
|
|
d8b44606a3 | ||
|
|
4e61c06903 | ||
|
|
3239ca6728 | ||
|
|
1f07cbed1e | ||
|
|
36716fe518 | ||
|
|
5768fd7f49 | ||
|
|
bf8cc35edc | ||
|
|
1f2aa2fcab | ||
|
|
51841d5bcb | ||
|
|
1d2efb46c1 | ||
|
|
f1bf5ba24f | ||
|
|
827a825c06 | ||
|
|
17fd248f23 | ||
|
|
930c64df8a | ||
|
|
3e87c82d56 | ||
|
|
50ccbc4230 | ||
|
|
8549606eb3 | ||
|
|
da84aa3412 | ||
|
|
ab5e04ef36 | ||
|
|
e130884c6a | ||
|
|
c17e50e0c4 | ||
|
|
a9cf471239 | ||
|
|
33b7b2d021 | ||
|
|
1a3bc517d9 | ||
|
|
2e5c82203d | ||
|
|
cecbab3609 | ||
|
|
9eee250720 | ||
|
|
a3d85f501b | ||
|
|
3649c7be73 | ||
|
|
f25f935c02 | ||
|
|
3cfebbd9c0 | ||
|
|
6f50a2703e | ||
|
|
e78361f985 | ||
|
|
83a653efce | ||
|
|
a8261dd6ac | ||
|
|
16e0f21687 | ||
|
|
d0afb75619 | ||
|
|
d281fc75fd | ||
|
|
e3f38acbce | ||
|
|
3f7cb34b00 | ||
|
|
edf7e732a2 | ||
|
|
f9f1fdc4d7 | ||
|
|
f79adf830f | ||
|
|
d702ddb3cf | ||
|
|
63e576b811 | ||
|
|
8778c4726a | ||
|
|
24f6743288 | ||
|
|
59b94a901c | ||
|
|
80651c99cd | ||
|
|
78277b5ee5 | ||
|
|
3e61714035 | ||
|
|
90bfc39d55 | ||
|
|
ab9539cffe | ||
|
|
e7dc77426a | ||
|
|
ae0ae3dde8 | ||
|
|
ecc07333af | ||
|
|
15fe02b618 | ||
|
|
d88efef74b | ||
|
|
0aab583bb1 | ||
|
|
9db521a931 | ||
|
|
5ea3bf85de | ||
|
|
e65d508907 | ||
|
|
362f9c6c5f | ||
|
|
dfdc34603e | ||
|
|
9ded218950 | ||
|
|
599742536b | ||
|
|
64cccb2267 | ||
|
|
15abf9ed31 | ||
|
|
bd5fc484f0 | ||
|
|
4b3874988f | ||
|
|
ef320c6e95 | ||
|
|
e41c00107d | ||
|
|
32f6d1055d | ||
|
|
d34d44e1d4 | ||
|
|
ec5ed87ca0 | ||
|
|
2cab113035 | ||
|
|
d9f111ec28 | ||
|
|
e95dfd78ed | ||
|
|
58e5c654fa | ||
|
|
13f3b448e5 | ||
|
|
95afea9006 | ||
|
|
bded0d9d54 | ||
|
|
cb88147ca9 | ||
|
|
1b5f9e4374 | ||
|
|
5c6cd40fe7 | ||
|
|
36c6f1e731 | ||
|
|
3515a69e43 | ||
|
|
d2979ab5d4 | ||
|
|
222ea05a3a | ||
|
|
1880e96a22 | ||
|
|
b58867451d | ||
|
|
4d0f7c7ea4 | ||
|
|
9734d1ab3f | ||
|
|
bfa70675cb | ||
|
|
def426aa34 | ||
|
|
6176dfd039 | ||
|
|
9000d27f12 | ||
|
|
e79447131f | ||
|
|
0a6bb975c3 | ||
|
|
53c2b3f6f4 | ||
|
|
748f931999 | ||
|
|
dd8eda4edc | ||
|
|
bd66b2139b | ||
|
|
664db6b622 | ||
|
|
8cb7b759c6 | ||
|
|
086d8eee22 | ||
|
|
5b7f3466ba | ||
|
|
809efc4f2b | ||
|
|
e5cb2a468f | ||
|
|
90e2f5053f | ||
|
|
6a63303736 | ||
|
|
f78abd2dcc | ||
|
|
4a6e132a44 | ||
|
|
1e3249c94e | ||
|
|
a1237aa2b2 | ||
|
|
bb45f8d8e3 | ||
|
|
5a747ab690 | ||
|
|
dfb1601aed | ||
|
|
62973fce0f | ||
|
|
3043859700 | ||
|
|
7cd1d9665d | ||
|
|
0a20f168a7 | ||
|
|
86278804c9 | ||
|
|
dc5a5ce1de | ||
|
|
4bd93325de | ||
|
|
a9023935e4 | ||
|
|
dedc83e5dd | ||
|
|
472898cfc6 | ||
|
|
32783ebbfb | ||
|
|
902edf5200 | ||
|
|
580cdb55be | ||
|
|
795f191fb3 | ||
|
|
1e7d7c0b71 | ||
|
|
7e78dc4ca1 | ||
|
|
75d0146d33 | ||
|
|
0d7f749ad8 | ||
|
|
e2d416ad8b | ||
|
|
04d3eb33b1 | ||
|
|
6f77e68622 | ||
|
|
be23e6d189 | ||
|
|
6e55b4df8a | ||
|
|
1629e77174 | ||
|
|
127cdf63c6 | ||
|
|
5f74e6e76d | ||
|
|
54adbb1737 | ||
|
|
7cffb41e13 | ||
|
|
5b8894cd25 | ||
|
|
05b0cbb36a | ||
|
|
dcc3b3fe37 | ||
|
|
2de3e2ebdd | ||
|
|
8c88746912 | ||
|
|
43c7ff64d1 | ||
|
|
0dae10eab4 | ||
|
|
e61de3e052 | ||
|
|
2ffd022a5f | ||
|
|
78f32dcbd8 | ||
|
|
f792b67098 | ||
|
|
46e224997e | ||
|
|
ef50e74873 | ||
|
|
7b9e027e77 | ||
|
|
8461048a11 | ||
|
|
c25d9679a5 | ||
|
|
16e462d9d2 | ||
|
|
ac63d942ce | ||
|
|
29ed28af00 | ||
|
|
81d0f7c172 | ||
|
|
147304c676 | ||
|
|
9c310c6cdd | ||
|
|
c6ca60d6dc | ||
|
|
01d3c0c6aa | ||
|
|
f38aa4ca39 | ||
|
|
dd71771a82 | ||
|
|
e8ea761fbe | ||
|
|
4702d8e9b3 | ||
|
|
f5089e535d | ||
|
|
2fb2300d1b | ||
|
|
48f1a84d6e | ||
|
|
494d02cc35 | ||
|
|
81a2a20bbf | ||
|
|
8ea139c772 | ||
|
|
cf7ea9bef9 | ||
|
|
e4fce10f46 | ||
|
|
2f88b7dcd0 | ||
|
|
c545a42a67 | ||
|
|
466a678c2c | ||
|
|
4d3f0cdc74 | ||
|
|
802a3dd357 | ||
|
|
d3822c5d7b | ||
|
|
0b7ef24a34 | ||
|
|
4eaf88e8d1 | ||
|
|
0ae8e28635 | ||
|
|
d865732e0d | ||
|
|
1c22b48bb1 | ||
|
|
910429f365 | ||
|
|
64a0b86917 | ||
|
|
2bb268476e | ||
|
|
3ad140e5a7 | ||
|
|
179bf06940 | ||
|
|
15713964a5 | ||
|
|
a0a537e0ce | ||
|
|
2c1ef7d89e | ||
|
|
f4239d60ca | ||
|
|
53b02a694a | ||
|
|
1eebcb472d | ||
|
|
2c760ae735 | ||
|
|
a901677be1 | ||
|
|
6ba5271824 | ||
|
|
517703ab47 | ||
|
|
b9baf049e6 | ||
|
|
8ecb555a98 | ||
|
|
db0cec8d70 | ||
|
|
83dafb662a | ||
|
|
3c76c3fe54 | ||
|
|
fc828ed116 | ||
|
|
9738f2fa17 | ||
|
|
a3de75bf8b | ||
|
|
d3ebfbd042 | ||
|
|
bb9ced6e57 | ||
|
|
7b82db214c | ||
|
|
01d018ba31 | ||
|
|
35d22949ed | ||
|
|
7e9c121ad3 | ||
|
|
439b86fe3b | ||
|
|
3f68c56554 | ||
|
|
b3461ac3b5 | ||
|
|
4f1388706c | ||
|
|
1dbe00f164 | ||
|
|
e241e6e833 | ||
|
|
acccd2d5be | ||
|
|
e8f63e2041 | ||
|
|
8a8356221e | ||
|
|
0f27554423 | ||
|
|
a5063cf046 | ||
|
|
693857a1f8 | ||
|
|
eb1631f78d | ||
|
|
7e786d5426 | ||
|
|
d401d1cb47 | ||
|
|
87d1809657 | ||
|
|
f2e7f4cb67 | ||
|
|
f63ee86730 | ||
|
|
9c4764fe68 | ||
|
|
187469ea86 | ||
|
|
50c43b45ee | ||
|
|
6b1adf11f7 | ||
|
|
b2688bcf43 | ||
|
|
fe0a1c2643 | ||
|
|
0ca76e8cd8 | ||
|
|
d515f92d20 | ||
|
|
2a5826242d | ||
|
|
718a6ea697 | ||
|
|
a2c1fca488 | ||
|
|
30e4729254 | ||
|
|
23ef278d29 | ||
|
|
0726ec5931 | ||
|
|
0bc2f43e32 | ||
|
|
2a5ec20295 | ||
|
|
52944622f8 | ||
|
|
7411ce9092 | ||
|
|
569abda653 | ||
|
|
12cb8ceae0 | ||
|
|
752ff34f8f | ||
|
|
748fb9afe5 | ||
|
|
94ec1f3741 | ||
|
|
6ff3070c8e | ||
|
|
e4db196032 | ||
|
|
6b13f4a3c9 | ||
|
|
5147b52267 | ||
|
|
a54d50ab2d | ||
|
|
47873c181b | ||
|
|
c90b76444d | ||
|
|
307d367346 | ||
|
|
710a802f49 | ||
|
|
6c424e8446 | ||
|
|
70ac98b860 | ||
|
|
58429a617b | ||
|
|
203c04fdb8 | ||
|
|
0ea54a043e | ||
|
|
6ac6fd5e56 | ||
|
|
f62b9a199c | ||
|
|
3cf0d40436 | ||
|
|
27217fddb3 | ||
|
|
5507575b7e | ||
|
|
0b9884ce5b | ||
|
|
23c108a05c | ||
|
|
cb153967ec | ||
|
|
8c72eddb72 | ||
|
|
298e008cc2 | ||
|
|
8e9c019b35 | ||
|
|
4e1d86f775 | ||
|
|
b5f7ed037c | ||
|
|
b383884019 | ||
|
|
e4dbe57c10 | ||
|
|
ffc75cb074 | ||
|
|
667a3a06cd | ||
|
|
410e557bad | ||
|
|
8b1199ee35 | ||
|
|
148959f1b7 | ||
|
|
8f8b2519ea | ||
|
|
ef8b6e5a42 | ||
|
|
8b74a3e052 | ||
|
|
f7535a0a1b | ||
|
|
d2d9d9cb01 | ||
|
|
ddbb3a37fb | ||
|
|
672603d6cd | ||
|
|
1a47683d32 | ||
|
|
0494e40c39 | ||
|
|
5219851de4 | ||
|
|
6d43b22ebe | ||
|
|
1e7994d97d | ||
|
|
a9e439d9e0 | ||
|
|
0224fe2db6 | ||
|
|
7053fd2a24 | ||
|
|
7ed182c08f | ||
|
|
768b3b5011 | ||
|
|
b190a24f40 | ||
|
|
08a6969f48 | ||
|
|
50b763b12b | ||
|
|
0b44b7eb4c | ||
|
|
2fbb13be0a | ||
|
|
52424cd67a | ||
|
|
caef3f8bf3 | ||
|
|
3498a04613 | ||
|
|
5b080bd0cf | ||
|
|
2f7af69091 | ||
|
|
bd3f1c6a9e | ||
|
|
bd20b295e1 | ||
|
|
04f211bbff | ||
|
|
2e1d5ffd1c | ||
|
|
2cfeef606c | ||
|
|
6759a78d07 | ||
|
|
3fc779278b | ||
|
|
9114715030 | ||
|
|
8518801601 | ||
|
|
80db1b9feb | ||
|
|
56789e55b4 | ||
|
|
55e762b069 | ||
|
|
1e9efe441a | ||
|
|
c147daa312 | ||
|
|
94279c0522 | ||
|
|
536449c6a4 | ||
|
|
456e735725 | ||
|
|
0a1d142d69 | ||
|
|
3158075405 | ||
|
|
7bc98d1634 | ||
|
|
28245ce4e4 | ||
|
|
c3ded56a7e | ||
|
|
e60f76487f | ||
|
|
1613cad6f6 | ||
|
|
c39e657a3b | ||
|
|
61c16a20b4 | ||
|
|
35fe8bf81b | ||
|
|
e6bb683922 | ||
|
|
286bd3005d | ||
|
|
c38c9cf894 | ||
|
|
441688b41e | ||
|
|
c69f1dae3f | ||
|
|
e5467d3268 | ||
|
|
a9235a74f4 | ||
|
|
4f6ee6744d | ||
|
|
16faed0a83 | ||
|
|
fa440d0be2 | ||
|
|
c5993c2d2d | ||
|
|
405c3d7626 | ||
|
|
f8b71fa497 | ||
|
|
af3411cab8 | ||
|
|
9162ef3e0f | ||
|
|
bba2eb7622 | ||
|
|
5bb4a74ec0 | ||
|
|
6850835273 | ||
|
|
9aa3de0664 | ||
|
|
400e355a2f | ||
|
|
84b59d4335 | ||
|
|
be2a1c2893 | ||
|
|
f760567b96 | ||
|
|
7fce920522 | ||
|
|
77e7947f61 | ||
|
|
23e791a3b9 | ||
|
|
a8d61fa930 | ||
|
|
d52e5e551d | ||
|
|
84fc8f16dd | ||
|
|
b12b44579c | ||
|
|
91e83731f0 | ||
|
|
3889edd824 | ||
|
|
0e129614cf | ||
|
|
50bc5401a4 | ||
|
|
a1538b4bab | ||
|
|
c09b6914ba | ||
|
|
86ff8cdd8c | ||
|
|
9cefe46a1f | ||
|
|
202ac0fe10 | ||
|
|
4eded59dbe | ||
|
|
c832543168 | ||
|
|
ef81999f3f | ||
|
|
163d93c15b | ||
|
|
6d2c6f269d | ||
|
|
8f7542f34d | ||
|
|
8b1f0223fe | ||
|
|
7f3ea34dc5 | ||
|
|
26690adc47 | ||
|
|
1c06e37245 | ||
|
|
e7c8c322c0 | ||
|
|
fa1333c026 | ||
|
|
fa461e86fd | ||
|
|
3dc9ee182f | ||
|
|
6ec72a290d | ||
|
|
cbb5878477 | ||
|
|
065fcf1a1b | ||
|
|
7cd814d92c | ||
|
|
86d310a984 | ||
|
|
f7b64827e4 | ||
|
|
44bb9d58d1 | ||
|
|
0d0c427f2b | ||
|
|
080f7229fc | ||
|
|
f1db96143a | ||
|
|
72964a2194 | ||
|
|
d2f773a99d | ||
|
|
d445386adc | ||
|
|
1653541e83 | ||
|
|
fa37ac1d73 | ||
|
|
9a5289b96c | ||
|
|
b8de1dd13f | ||
|
|
45002aa03f | ||
|
|
d4fa917c49 | ||
|
|
0376d26c79 | ||
|
|
65e9d0bead | ||
|
|
63097f32e5 | ||
|
|
da66220524 | ||
|
|
9648fd1f9a | ||
|
|
7a509af38b | ||
|
|
ff44fb6fcf | ||
|
|
dfc34eb074 | ||
|
|
d6617a991c | ||
|
|
12309c61b6 | ||
|
|
24c23c2290 | ||
|
|
fcca1549b0 | ||
|
|
8b3b33c182 | ||
|
|
f4196ed6ef | ||
|
|
9ea3198ddf | ||
|
|
40164f4398 | ||
|
|
fd7dd0bc2c | ||
|
|
bd20a756f9 | ||
|
|
4397c25976 | ||
|
|
bdee9721ec | ||
|
|
f45f0b1df6 | ||
|
|
dfa45a3689 | ||
|
|
d6f01ed7b9 | ||
|
|
917a4363e7 | ||
|
|
0fbfbf488b | ||
|
|
e9acdd147f | ||
|
|
2f01e9c51d | ||
|
|
719d551de6 | ||
|
|
d3f14ae860 | ||
|
|
9d04b3d643 | ||
|
|
5fd58cf249 | ||
|
|
39f632134d | ||
|
|
0ccb794007 | ||
|
|
80ca037747 | ||
|
|
c7586a7135 | ||
|
|
6071a11419 | ||
|
|
1c7918495c | ||
|
|
72c9deb59e | ||
|
|
43d866dd71 | ||
|
|
c23028ec7a | ||
|
|
ef23a4efe4 | ||
|
|
2d3a7e5418 | ||
|
|
105c742e92 | ||
|
|
e993b8fc40 | ||
|
|
3d7c3a6de3 | ||
|
|
c3543b06f0 | ||
|
|
bc9a9db9b3 | ||
|
|
af16f6730e | ||
|
|
0eda5cbfec | ||
|
|
52478d684c | ||
|
|
97511067df | ||
|
|
e7ef654b45 | ||
|
|
9d8758557b | ||
|
|
65b6c80f07 | ||
|
|
246a5737e7 | ||
|
|
eda05d23bf | ||
|
|
2090d6ee27 | ||
|
|
27aaa3b1bf | ||
|
|
cc9fe19a9f | ||
|
|
3a8b663eb1 | ||
|
|
b5ec6c9958 | ||
|
|
c359499386 | ||
|
|
b80af20541 | ||
|
|
96f6939284 | ||
|
|
d8108f944c | ||
|
|
fb00ee79a0 | ||
|
|
8f37c3f5fd | ||
|
|
91fb286b0d | ||
|
|
ae326c066f | ||
|
|
a9f01e382a | ||
|
|
66ecc7a6f2 | ||
|
|
2429ed6eeb | ||
|
|
095c82ecc4 | ||
|
|
82dfc7b109 | ||
|
|
23155bbbae | ||
|
|
a983a62ad2 | ||
|
|
6ef234ba80 | ||
|
|
b343d322fe | ||
|
|
05d911b913 | ||
|
|
957486cc95 | ||
|
|
e7769d9004 | ||
|
|
aa9c98ef10 | ||
|
|
30f89f4669 | ||
|
|
fa37e91e5c | ||
|
|
3f6e53db6e | ||
|
|
86175e8627 | ||
|
|
0165da405f | ||
|
|
f66d864f45 | ||
|
|
b5ca2631e6 | ||
|
|
3772344e2d | ||
|
|
280575aff0 | ||
|
|
c0d104c110 | ||
|
|
64ba85aa19 | ||
|
|
b161f4cff9 | ||
|
|
c17ed8dc8c | ||
|
|
494868d21d | ||
|
|
f82cbe855f | ||
|
|
eebbf0d4ee | ||
|
|
eb1032c9c2 | ||
|
|
17b579911e | ||
|
|
538d76e6ed | ||
|
|
846dfd5105 | ||
|
|
50db83508b | ||
|
|
f3180b774b | ||
|
|
de545d5fa0 | ||
|
|
8efa04437d | ||
|
|
54ae946061 | ||
|
|
8efe4c0a1b | ||
|
|
82a935080d | ||
|
|
25a9eae74b | ||
|
|
58c44fee3e | ||
|
|
1b9752e10e | ||
|
|
89f10d7e7a | ||
|
|
e5e0ba9e7c | ||
|
|
30f9fed766 | ||
|
|
f495f79c90 | ||
|
|
4721a9093c | ||
|
|
9f4bc9fb72 | ||
|
|
f999440cc6 | ||
|
|
2a3a98228e | ||
|
|
d069ad0bc7 | ||
|
|
137f5e5980 | ||
|
|
11fef6b627 | ||
|
|
6b4fe69227 | ||
|
|
9b41b30487 | ||
|
|
868b071eb2 | ||
|
|
5f7df38b8a | ||
|
|
f445202ba5 | ||
|
|
a4a47db9e0 | ||
|
|
55fef4d60e | ||
|
|
09dfc9a89b | ||
|
|
eabd9341b6 | ||
|
|
2da547efc6 | ||
|
|
46d9f581ab | ||
|
|
12c04151e9 | ||
|
|
60d4c620b9 | ||
|
|
eec12ff268 | ||
|
|
16df239f39 | ||
|
|
c753dfc9a8 | ||
|
|
f2e8929b8a | ||
|
|
ca031304b9 | ||
|
|
1af7a9db1f | ||
|
|
bdaf8b2cfe | ||
|
|
6f67d94fc4 | ||
|
|
28a6644384 | ||
|
|
66734d46cf | ||
|
|
4fbe78d037 | ||
|
|
dfed7f0b7e | ||
|
|
47f96dc2dd | ||
|
|
38212f83fc | ||
|
|
b21dc34eed | ||
|
|
9634fccda7 | ||
|
|
814aed7cbe | ||
|
|
5c44fa9a29 | ||
|
|
64b0550f58 | ||
|
|
9c52818b93 | ||
|
|
b23dc256e4 | ||
|
|
204e7e7e90 | ||
|
|
0e3af9b238 | ||
|
|
3fbdfeee88 | ||
|
|
406e3025fb | ||
|
|
8155b8ea04 | ||
|
|
2850800e48 | ||
|
|
0dd209c813 | ||
|
|
802bd6448c | ||
|
|
577d8d33e1 | ||
|
|
2ca49c3735 | ||
|
|
40dd0c677e | ||
|
|
bf17ea0ee4 | ||
|
|
cd1e07fed3 | ||
|
|
e8843be3d0 | ||
|
|
8a16ea4cc6 | ||
|
|
4d47f487cb | ||
|
|
5ba0b6b633 | ||
|
|
213c0b49bc | ||
|
|
5696ff5ce6 | ||
|
|
fbe67f5d84 | ||
|
|
8bb359d194 | ||
|
|
52d6973191 | ||
|
|
f6cec22e6d | ||
|
|
2aeb5dde67 | ||
|
|
151370277c | ||
|
|
adcec427b6 | ||
|
|
f7518ea853 | ||
|
|
2ac428ad7d | ||
|
|
df7f85d3c3 | ||
|
|
2761f1338d | ||
|
|
fae92685ae | ||
|
|
816c0a4393 | ||
|
|
4e24b432c4 | ||
|
|
66edc784f9 | ||
|
|
87635b9e32 | ||
|
|
c96ceeaea4 | ||
|
|
88c8472a31 | ||
|
|
8a8efdc537 | ||
|
|
07bb7b2fee | ||
|
|
e0bd15669a | ||
|
|
7829e809c7 | ||
|
|
d89696291f | ||
|
|
dfc462c24d | ||
|
|
b07f4efc13 | ||
|
|
53021bf7d3 | ||
|
|
600786983c | ||
|
|
c673b3b0b1 | ||
|
|
df39a7bde2 | ||
|
|
d75412764e | ||
|
|
2d0b9e2aa2 | ||
|
|
db4770a577 | ||
|
|
0f96f5064e | ||
|
|
0b29a2f53a | ||
|
|
230802ee22 | ||
|
|
7a97d01719 | ||
|
|
3450d05858 | ||
|
|
de9d26126a | ||
|
|
ba0d3605ae | ||
|
|
0983809e6f | ||
|
|
6b200b3088 | ||
|
|
5807a44aee | ||
|
|
dda8bf6d8a | ||
|
|
a27610f560 | ||
|
|
dc15546ba3 | ||
|
|
99036efa06 | ||
|
|
a2d2438f03 | ||
|
|
8ea941e783 | ||
|
|
1eae686443 | ||
|
|
f4764e58c6 | ||
|
|
5d0abd6f3f | ||
|
|
98bc0b04c5 | ||
|
|
a07299f1d6 | ||
|
|
9da693c371 | ||
|
|
1788f5c576 | ||
|
|
6a803a88c8 | ||
|
|
f30a62e33c | ||
|
|
0ac73e4d73 | ||
|
|
61611a2dac | ||
|
|
4bc50c3560 | ||
|
|
bf5ebf1d2d | ||
|
|
f22665e710 | ||
|
|
7e49396fc5 | ||
|
|
c7a9e08105 | ||
|
|
c9140a6def | ||
|
|
5bb922200a | ||
|
|
b822c83b02 | ||
|
|
fab6b0f7ae | ||
|
|
9d21787cd7 | ||
|
|
f47a3c62e8 | ||
|
|
630187d91b | ||
|
|
243c327d0a | ||
|
|
b80293c80d | ||
|
|
e80c4f13b9 | ||
|
|
3fb3b564ae | ||
|
|
f605a7df22 | ||
|
|
63bcf98e71 | ||
|
|
9275901277 | ||
|
|
840ba90512 | ||
|
|
b51ea69db0 | ||
|
|
7658886b02 | ||
|
|
a547043831 | ||
|
|
865c57fa72 | ||
|
|
409bc7b657 | ||
|
|
5aef8b8fad | ||
|
|
4a58241b17 | ||
|
|
240050093b | ||
|
|
f93ccd4df1 | ||
|
|
5dfd6eee2d | ||
|
|
ccfaee8412 | ||
|
|
efe8fe4650 | ||
|
|
f304b93b91 | ||
|
|
7ebb3ec05d | ||
|
|
09958cbf66 | ||
|
|
7fe74a9d2e | ||
|
|
15f5884247 | ||
|
|
dbb3bf6a4d | ||
|
|
0e55e54bec | ||
|
|
ffdfa203e8 | ||
|
|
13045f953f | ||
|
|
3cd33c0fea | ||
|
|
7390b6ec53 | ||
|
|
1d601134ed | ||
|
|
5d013b78eb | ||
|
|
cd16eb952c | ||
|
|
54e8bb872c | ||
|
|
8ec1d9b552 | ||
|
|
71de0ac565 | ||
|
|
7f2f1ad533 | ||
|
|
f9d5a02710 | ||
|
|
5ad256fee7 | ||
|
|
fe826cdf2b | ||
|
|
0dbcdb94af | ||
|
|
d9bfef4848 | ||
|
|
1686d27633 | ||
|
|
f22885223f | ||
|
|
305cf30c50 | ||
|
|
b4e4a98de6 | ||
|
|
7ebe3bf824 | ||
|
|
568c33f294 | ||
|
|
748e5b6da6 | ||
|
|
f128ff6d53 | ||
|
|
174a62eb7c | ||
|
|
22e6ab4028 | ||
|
|
94db0466a7 | ||
|
|
ca92292550 | ||
|
|
e16da5db45 | ||
|
|
666252d749 | ||
|
|
ef92c345ea | ||
|
|
75c3e91a15 | ||
|
|
8075c6e5a8 | ||
|
|
2ca0015c0a | ||
|
|
55a862cc23 | ||
|
|
c729965b69 | ||
|
|
b67d976809 | ||
|
|
3a9bdec149 | ||
|
|
47b877357d | ||
|
|
1c4dcda639 | ||
|
|
187796c3d4 | ||
|
|
38a4011a52 | ||
|
|
5631e7e624 | ||
|
|
2a5dd139c8 | ||
|
|
2dd3776bc1 | ||
|
|
da874f8ec6 | ||
|
|
07140e7f11 | ||
|
|
2ce57fa5b9 | ||
|
|
1a6929d9ae | ||
|
|
8ce5404777 | ||
|
|
8611cc3977 | ||
|
|
e645574b14 | ||
|
|
44564274a1 | ||
|
|
f0c20d8acb | ||
|
|
0244b50f0b | ||
|
|
d177f49a96 | ||
|
|
9d973ff106 | ||
|
|
7822be5cd9 | ||
|
|
d0572f50fb | ||
|
|
b00ebd1bdf | ||
|
|
cff698d210 | ||
|
|
56f1c023ab | ||
|
|
cdd43baf5d | ||
|
|
b0d768b16b | ||
|
|
01a04c3169 | ||
|
|
8af170a3c3 | ||
|
|
320c2b8eaf | ||
|
|
de8509e40d | ||
|
|
dc71961dd9 | ||
|
|
de65bb8194 | ||
|
|
4c4cd1ed8e | ||
|
|
da3ac9ae1b | ||
|
|
48476fcbc5 | ||
|
|
2c56e692a2 | ||
|
|
235baf5187 | ||
|
|
9dd8779a3a | ||
|
|
9d68048d1d | ||
|
|
78a3da7fbe | ||
|
|
25331d8bb2 | ||
|
|
ee3cb60e3c | ||
|
|
8f90baf1eb | ||
|
|
34f9cf3aa6 | ||
|
|
dbdc0a9721 | ||
|
|
e7e2f3a79c | ||
|
|
29250a6692 | ||
|
|
8bae4d746d | ||
|
|
4bc76b2d6d | ||
|
|
6edb758136 | ||
|
|
f1ee2c6503 | ||
|
|
bbfd33185c | ||
|
|
580b6949cc | ||
|
|
64ff916ca2 | ||
|
|
14281de262 | ||
|
|
2c6d7e8e18 | ||
|
|
2d09036466 | ||
|
|
ebce82b136 | ||
|
|
3d04f5f738 | ||
|
|
8b58d8574b | ||
|
|
6c4295ed5b | ||
|
|
fa285fd1a9 | ||
|
|
54e24a5765 | ||
|
|
0b0b9b9379 | ||
|
|
c33eeeee23 | ||
|
|
89eef10d44 | ||
|
|
4ebc4a4ef1 | ||
|
|
d7e4429bb7 | ||
|
|
36e2929ee2 | ||
|
|
acec697fe7 | ||
|
|
91445035bc | ||
|
|
fb27cbcd01 | ||
|
|
11ba6a17ab | ||
|
|
aa90e265c2 | ||
|
|
76ff3a526c | ||
|
|
2fb7c0059d | ||
|
|
41e3a89398 | ||
|
|
98737a012e | ||
|
|
044e3ced4f | ||
|
|
e0efae4d59 | ||
|
|
cf13874c9d | ||
|
|
f4db89c7e9 | ||
|
|
90bb689e13 | ||
|
|
dd345bdece | ||
|
|
3a6df13360 | ||
|
|
25d461c8f5 | ||
|
|
2efaf75b25 | ||
|
|
19dcc3f385 | ||
|
|
bd9cccffce | ||
|
|
fcb8c106b1 | ||
|
|
f4c514fbf3 | ||
|
|
eaa777b612 | ||
|
|
2530009123 | ||
|
|
15da5628a9 | ||
|
|
97d4f2b009 | ||
|
|
f31b61ea5b | ||
|
|
502852541b | ||
|
|
addfcbfc30 | ||
|
|
c63f881518 |
10
.gitignore
vendored
10
.gitignore
vendored
@@ -7,12 +7,13 @@
|
|||||||
/prod-static
|
/prod-static
|
||||||
/errors/*
|
/errors/*
|
||||||
*.sw[po]
|
*.sw[po]
|
||||||
.DS_Store
|
*.DS_Store
|
||||||
event_queues.pickle
|
event_queues.pickle
|
||||||
stats/
|
stats/
|
||||||
zerver/fixtures/available-migrations
|
zerver/fixtures/available-migrations
|
||||||
zerver/fixtures/migration-status
|
zerver/fixtures/migration-status
|
||||||
zerver/fixtures/test_data1.json
|
zerver/fixtures/test_data1.json
|
||||||
|
zerver/tests/frontend/test_credentials.js
|
||||||
.kdev4
|
.kdev4
|
||||||
zulip.kdev4
|
zulip.kdev4
|
||||||
memcached_prefix
|
memcached_prefix
|
||||||
@@ -26,3 +27,10 @@ manage.log
|
|||||||
.kateproject.d/
|
.kateproject.d/
|
||||||
.kateproject
|
.kateproject
|
||||||
*.kate-swp
|
*.kate-swp
|
||||||
|
event_queues.json
|
||||||
|
.vagrant
|
||||||
|
/zproject/dev-secrets.conf
|
||||||
|
static/third/gemoji/
|
||||||
|
static/third/zxcvbn/
|
||||||
|
tools/emoji_dump/bitmaps/
|
||||||
|
tools/emoji_dump/*.ttx
|
||||||
|
|||||||
15
.travis.yml
Normal file
15
.travis.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
install:
|
||||||
|
- pip install pbs
|
||||||
|
- python provision.py --travis
|
||||||
|
cache: apt
|
||||||
|
language: python
|
||||||
|
python:
|
||||||
|
- "2.7"
|
||||||
|
# command to run tests
|
||||||
|
script:
|
||||||
|
- source /srv/zulip-venv/bin/activate && env PATH=$PATH:/srv/zulip-venv/bin ./tools/test-all
|
||||||
|
sudo: required
|
||||||
|
services:
|
||||||
|
- docker
|
||||||
|
addons:
|
||||||
|
postgresql: "9.3"
|
||||||
203
LICENSE
203
LICENSE
@@ -1,5 +1,202 @@
|
|||||||
Copyright <20> 2012-2013 Zulip, Inc.
|
|
||||||
|
|
||||||
This software is licensed under the Zulip Enterprise License Agreement.
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
Zulip can be reached at support@zulip.com.
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|||||||
239
README.md
Normal file
239
README.md
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
Zulip
|
||||||
|
=====
|
||||||
|
|
||||||
|
Zulip is a powerful, open source group chat application. Written in
|
||||||
|
Python and using the Django framework, Zulip supports both private
|
||||||
|
messaging and group chats via conversation streams.
|
||||||
|
|
||||||
|
Zulip also supports fast search, drag-and-drop file uploads, image
|
||||||
|
previews, group private messages, audible notifications,
|
||||||
|
missed-message emails, desktop apps, and much more.
|
||||||
|
|
||||||
|
Further information on the Zulip project and its features can be found
|
||||||
|
at https://www.zulip.org
|
||||||
|
|
||||||
|
Contributing to Zulip
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Zulip welcomes all forms of contributions!
|
||||||
|
|
||||||
|
Before a pull request can be merged, you need to to sign the [Dropbox
|
||||||
|
Contributor License Agreement](https://opensource.dropbox.com/cla/).
|
||||||
|
|
||||||
|
Please run the tests (tools/test-all) before submitting your pull
|
||||||
|
request and read our [commit message style
|
||||||
|
guidelines](http://zulip.readthedocs.org/en/latest/code-style.html#commit-messages).
|
||||||
|
|
||||||
|
Zulip has a growing collection of developer documentation including
|
||||||
|
detailed documentation on coding style available on [Read The
|
||||||
|
Docs](https://zulip.readthedocs.org/).
|
||||||
|
|
||||||
|
Zulip also has a [development discussion mailing list](https://groups.google.com/forum/#!forum/zulip-devel)
|
||||||
|
|
||||||
|
Feel free to send any questions or suggestions of areas where you'd
|
||||||
|
love to see more documentation to the list!
|
||||||
|
|
||||||
|
We recommend sending proposals for large features or refactorings to
|
||||||
|
the zulip-devel list for discussion and advice before getting too deep
|
||||||
|
into implementation.
|
||||||
|
|
||||||
|
Please report any security issues you discover to support@zulip.com.
|
||||||
|
|
||||||
|
Running Zulip in production
|
||||||
|
===========================
|
||||||
|
|
||||||
|
This is documented in https://zulip.org/server.html and README.prod.md.
|
||||||
|
|
||||||
|
Installing the Zulip Development environment
|
||||||
|
============================================
|
||||||
|
|
||||||
|
You will need a machine with at least 2GB of RAM available (see
|
||||||
|
https://github.com/zulip/zulip/issues/32 for a plan for how to
|
||||||
|
dramatically reduce this requirement).
|
||||||
|
|
||||||
|
Using Vagrant
|
||||||
|
-------------
|
||||||
|
|
||||||
|
This is the recommended approach, and is tested on OS X 10.10 as well as Ubuntu 14.04.
|
||||||
|
|
||||||
|
* The best performing way to run the Zulip development environment is
|
||||||
|
using an LXC container. If your host is Ubuntu 14.04 (or newer;
|
||||||
|
what matters is having support for LXC containers), you'll want to
|
||||||
|
install and configure the LXC Vagrant provider like this:
|
||||||
|
`sudo apt-get install vagrant lxc lxc-templates cgroup-lite redir && vagrant plugin install vagrant-lxc`
|
||||||
|
|
||||||
|
* If your host is OS X, download VirtualBox from
|
||||||
|
<http://download.virtualbox.org/virtualbox/4.3.30/VirtualBox-4.3.30-101610-OSX.dmg>
|
||||||
|
and install it.
|
||||||
|
|
||||||
|
Once that's done, simply change to your zulip directory and run
|
||||||
|
`vagrant up` in your terminal. That will install the development
|
||||||
|
server inside a Vagrant guest.
|
||||||
|
|
||||||
|
Once that finishes, you can run the development server as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
vagrant ssh -- -L9991:localhost:9991
|
||||||
|
# Now inside the container
|
||||||
|
cd /srv/zulip
|
||||||
|
source /srv/zulip-venv/bin/activate
|
||||||
|
./tools/run-dev.py --interface=''
|
||||||
|
```
|
||||||
|
|
||||||
|
You can now visit <http://localhost:9991/> in your browser. To get
|
||||||
|
shell access to the virtual machine running the server, use `vagrant ssh`.
|
||||||
|
|
||||||
|
(A small note on tools/run-dev.py: the `--interface=''` option will make
|
||||||
|
the development server listen on all network interfaces. While this
|
||||||
|
is correct for the Vagrant guest sitting behind a NAT, you probably
|
||||||
|
don't want to use that option when using run-dev.py in other environments).
|
||||||
|
|
||||||
|
The run-dev.py console output will show any errors your Zulip
|
||||||
|
development server encounters. It runs on top of Django's "manage.py
|
||||||
|
runserver" tool, which will automatically restart the Zulip server
|
||||||
|
whenever you save changes to Python code.
|
||||||
|
|
||||||
|
Using provision.py without Vagrant
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
If you'd like to install a Zulip development environment on a server
|
||||||
|
that's already running Ubuntu 14.04 Trusty, you can do that by just
|
||||||
|
running:
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y python-pbs
|
||||||
|
python /srv/zulip/provision.py
|
||||||
|
|
||||||
|
cd /srv/zulip
|
||||||
|
source /srv/zulip-venv/bin/activate
|
||||||
|
./tools/run-dev.py
|
||||||
|
```
|
||||||
|
|
||||||
|
By hand
|
||||||
|
-------
|
||||||
|
If you really want to install everything by hand, the below
|
||||||
|
instructions should work.
|
||||||
|
|
||||||
|
Install the following non-Python dependencies:
|
||||||
|
* libffi-dev — needed for some Python extensions
|
||||||
|
* postgresql 9.1 or later — our database (also install development headers)
|
||||||
|
* memcached (and headers)
|
||||||
|
* rabbitmq-server
|
||||||
|
* libldap2-dev
|
||||||
|
* python-dev
|
||||||
|
* redis-server — rate limiting
|
||||||
|
* tsearch-extras — better text search
|
||||||
|
|
||||||
|
On Debian or Ubuntu systems:
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo apt-get install libffi-dev memcached rabbitmq-server libldap2-dev python-dev redis-server postgresql-server-dev-all libmemcached-dev
|
||||||
|
|
||||||
|
# If on 12.04 or wheezy:
|
||||||
|
sudo apt-get install postgresql-9.1
|
||||||
|
wget https://dl.dropboxusercontent.com/u/283158365/zuliposs/postgresql-9.1-tsearch-extras_0.1.2_amd64.deb
|
||||||
|
sudo dpkg -i postgresql-9.1-tsearch-extras_0.1.2_amd64.deb
|
||||||
|
|
||||||
|
# If on 14.04:
|
||||||
|
sudo apt-get install postgresql-9.3
|
||||||
|
wget https://dl.dropboxusercontent.com/u/283158365/zuliposs/postgresql-9.3-tsearch-extras_0.1.2_amd64.deb
|
||||||
|
sudo dpkg -i postgresql-9.3-tsearch-extras_0.1.2_amd64.deb
|
||||||
|
|
||||||
|
# If on 15.04 or jessie:
|
||||||
|
sudo apt-get install postgresql-9.4
|
||||||
|
wget https://dl.dropboxusercontent.com/u/283158365/zuliposs/postgresql-9.4-tsearch-extras_0.1_amd64.deb
|
||||||
|
sudo dpkg -i postgresql-9.4-tsearch-extras_0.1_amd64.deb
|
||||||
|
|
||||||
|
# Then, all versions:
|
||||||
|
pip install -r requirements.txt
|
||||||
|
tools/download-zxcvbn
|
||||||
|
./tools/emoji_dump/build_emoji
|
||||||
|
generate_secrets.py -d
|
||||||
|
./scripts/setup/configure-rabbitmq
|
||||||
|
./tools/postgres-init-db
|
||||||
|
./tools/do-destroy-rebuild-database
|
||||||
|
./tools/postgres-init-test-db
|
||||||
|
./tools/do_destroy_rebuild_test_database
|
||||||
|
```
|
||||||
|
|
||||||
|
To start the development server:
|
||||||
|
|
||||||
|
```
|
||||||
|
./tools/run-dev.py
|
||||||
|
```
|
||||||
|
|
||||||
|
… and visit http://localhost:9991/.
|
||||||
|
|
||||||
|
|
||||||
|
Running the test suite
|
||||||
|
======================
|
||||||
|
|
||||||
|
Run all tests:
|
||||||
|
|
||||||
|
```
|
||||||
|
./tools/test-all
|
||||||
|
```
|
||||||
|
|
||||||
|
This runs the linter plus all of our test suites; they can all be run
|
||||||
|
separately (just read `tools/test-all` to see them). You can also run
|
||||||
|
individual tests, e.g.:
|
||||||
|
|
||||||
|
```
|
||||||
|
./tools/test-backend zerver.test_bugdown.BugdownTest.test_inline_youtube
|
||||||
|
./tools/test-js-with-casper 10-navigation.js
|
||||||
|
```
|
||||||
|
|
||||||
|
The above instructions include the first-time setup of test databases,
|
||||||
|
but you may need to rebuild the test database occasionally if you're
|
||||||
|
working on new database migrations. To do this, run:
|
||||||
|
|
||||||
|
```
|
||||||
|
./tools/postgres-init-test-db
|
||||||
|
./tools/do-destroy-rebuild-test-database
|
||||||
|
```
|
||||||
|
|
||||||
|
Possible testing issues
|
||||||
|
=======================
|
||||||
|
|
||||||
|
- The Casper tests are flaky on the Virtualbox environment (probably
|
||||||
|
due to some performance-sensitive races; they work reliably in
|
||||||
|
Travis CI). Until this issue is debugged, you may need to rerun
|
||||||
|
them to get them to pass.
|
||||||
|
|
||||||
|
- When running the test suite, if you get an error like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
sqlalchemy.exc.ProgrammingError: (ProgrammingError) function ts_match_locs_array(unknown, text, tsquery) does not exist
|
||||||
|
LINE 2: ...ECT message_id, flags, subject, rendered_content, ts_match_l...
|
||||||
|
^
|
||||||
|
```
|
||||||
|
|
||||||
|
… then you need to install tsearch-extras, described
|
||||||
|
above. Afterwards, re-run the `init*-db` and the
|
||||||
|
`do-destroy-rebuild*-database` scripts.
|
||||||
|
|
||||||
|
- When building the development environment using Vagrant and the LXC provider, if you encounter permissions errors, you may need to `chown -R 1000:$(whoami) /path/to/zulip` on the host before running `vagrant up` in order to ensure that the synced directory has the correct owner during provision. This issue will arise if you run `id username` on the host where `username` is the user running Vagrant and the output is anything but 1000.
|
||||||
|
This seems to be caused by Vagrant behavior; more information can be found here https://github.com/fgrehm/vagrant-lxc/wiki/FAQ#help-my-shared-folders-have-the-wrong-owner
|
||||||
|
|
||||||
|
License
|
||||||
|
=======
|
||||||
|
|
||||||
|
Copyright 2011-2015 Dropbox, Inc.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
The software includes some works released by third parties under other
|
||||||
|
free and open source licenses. Those works are redistributed under the
|
||||||
|
license terms under which the works were received. For more details,
|
||||||
|
see the ``THIRDPARTY`` file included with this distribution.
|
||||||
380
README.prod.md
Normal file
380
README.prod.md
Normal file
@@ -0,0 +1,380 @@
|
|||||||
|
Zulip in production
|
||||||
|
===================
|
||||||
|
|
||||||
|
This documents the process for installing Zulip in a production environment.
|
||||||
|
|
||||||
|
Note that if you just want to play around with Zulip and see what it
|
||||||
|
looks like, it is easier to install it in a development environment
|
||||||
|
following the instructions in README.dev, since then you don't need to
|
||||||
|
worry about setting up SSL certificates and an authentication mechanism.
|
||||||
|
|
||||||
|
Recommended requirements:
|
||||||
|
|
||||||
|
* Server running Ubuntu Precise or Debian Wheezy
|
||||||
|
* At least 2 CPUs for production use with 100+ users
|
||||||
|
* At least 4GB of RAM for production use with 100+ users. We strongly
|
||||||
|
recommend against installing with less than 2GB of RAM, as you will
|
||||||
|
likely experience OOM issues. In the future we expect Zulip's RAM
|
||||||
|
requirements to decrease to support smaller installations (see
|
||||||
|
https://github.com/zulip/zulip/issues/32).
|
||||||
|
* At least 10GB of free disk for production use (more may be required
|
||||||
|
if you intend to store uploaded files locally rather than in S3
|
||||||
|
and your team uses that feature extensively)
|
||||||
|
* Outgoing HTTP(S) access to the public Internet.
|
||||||
|
* SSL Certificate for the host you're putting this on
|
||||||
|
(e.g. zulip.example.com). If you just want to see what
|
||||||
|
Zulip looks like, we recommend installing the development
|
||||||
|
environment detailed in README.md as that is easier to setup.
|
||||||
|
* Email credentials Zulip can use to send outgoing emails to users
|
||||||
|
(e.g. email address confirmation emails during the signup process,
|
||||||
|
missed message notifications, password reminders if you're not using
|
||||||
|
SSO, etc.).
|
||||||
|
|
||||||
|
|
||||||
|
Installing Zulip in production
|
||||||
|
==============================
|
||||||
|
|
||||||
|
These instructions should be followed as root.
|
||||||
|
|
||||||
|
(1) Install the SSL certificates for your machine to
|
||||||
|
/etc/ssl/private/zulip.key
|
||||||
|
and
|
||||||
|
/etc/ssl/certs/zulip.combined-chain.crt
|
||||||
|
|
||||||
|
(2) download zulip-server.tar.gz, and unpack to it /root/zulip, e.g.
|
||||||
|
tar -xf zulip-server-1.1.3.tar.gz
|
||||||
|
mv zulip-server-1.1.3 /root/zulip
|
||||||
|
|
||||||
|
(3) run /root/zulip/scripts/setup/install
|
||||||
|
|
||||||
|
This may take a while to run, since it will install a large number of
|
||||||
|
packages via apt.
|
||||||
|
|
||||||
|
(4) Configure the Zulip server instance by filling in the settings in
|
||||||
|
/etc/zulip/settings.py
|
||||||
|
|
||||||
|
(5) su zulip -c /home/zulip/deployments/current/scripts/setup/initialize-database
|
||||||
|
|
||||||
|
This will report an error if you did not fill in all the mandatory
|
||||||
|
settings from /etc/zulip/settings.py. Once this completes
|
||||||
|
successfully, the main installation process will be complete, and if
|
||||||
|
you are planning on using password authentication, you should be able
|
||||||
|
to visit the URL for your server and register for an account.
|
||||||
|
|
||||||
|
(6) Subscribe to
|
||||||
|
https://groups.google.com/forum/#!forum/zulip-announce to get
|
||||||
|
announcements about new releases, security issues, etc.
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
Authentication and logging into Zulip the first time
|
||||||
|
====================================================
|
||||||
|
|
||||||
|
(As you read and follow the instructions in this section, if you run
|
||||||
|
into trouble, check out the troubleshooting advice in the next major
|
||||||
|
section.)
|
||||||
|
|
||||||
|
Once you've finished installing Zulip, configuring your settings.py
|
||||||
|
file, and initializing the database, it's time to login to your new
|
||||||
|
installation. By default, initialize-database creates 1 realm that
|
||||||
|
you can join, the ADMIN_DOMAIN realm (defined in
|
||||||
|
/etc/zulip/settings.py).
|
||||||
|
|
||||||
|
The ADMIN_DOMAIN realm is by default configured with the following settings:
|
||||||
|
* restricted_to_domain=True: Only people with emails ending with @ADMIN_DOMAIN can join.
|
||||||
|
* invite_required=False: An invitation is not required to join the realm.
|
||||||
|
* invite_by_admin_only=False: You don't need to be an admin user to invite other users.
|
||||||
|
* mandatory_topics=False: Users are not required to specify a topic when sending messages.
|
||||||
|
|
||||||
|
If you would like to change these settings, you can do so using the
|
||||||
|
following process as the zulip user:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd /home/zulip/deployments/current
|
||||||
|
./manage.py shell
|
||||||
|
from zerver.models import *
|
||||||
|
r = get_realm(settings.ADMIN_DOMAIN)
|
||||||
|
r.restricted_to_domain=False # Now anyone anywhere can login
|
||||||
|
r.save() # save to the database
|
||||||
|
```
|
||||||
|
|
||||||
|
If you realize you set ADMIN_DOMAIN wrong, in addition to fixing the
|
||||||
|
value in settings.py, you will also want to do a similar manage.py
|
||||||
|
process to set `r.domain = newexample.com`.
|
||||||
|
|
||||||
|
Depending what authentication backend you're planning to use, you will
|
||||||
|
need to do some additional setup documented in the settings.py template:
|
||||||
|
|
||||||
|
* For Google authentication, you need to follow the configuration
|
||||||
|
instructions around GOOGLE_OAUTH2_CLIENT_ID and GOOGLE_CLIENT_ID.
|
||||||
|
* For Email authentication, you will need to follow the configuration
|
||||||
|
instructions around outgoing SMTP from Django.
|
||||||
|
|
||||||
|
You should be able to login now. If you get an error, check
|
||||||
|
/var/log/zulip/errors.log for a traceback, and consult the next
|
||||||
|
section for advice on how to debug. If you aren't able to figure it
|
||||||
|
out, email zulip-devel@googlegroups.com with the traceback and we'll
|
||||||
|
try to help you out!
|
||||||
|
|
||||||
|
You will likely want to make your own user account an admin user,
|
||||||
|
which you can do via the following management command:
|
||||||
|
|
||||||
|
```
|
||||||
|
./manage.py knight username@example.com -f
|
||||||
|
```
|
||||||
|
|
||||||
|
Now that you are an administrator, you will have a special
|
||||||
|
"Administration" tab linked to from the upper-right gear menu in the
|
||||||
|
Zulip app that lets you deactivate other users, manage streams, change
|
||||||
|
the Realm settings you may have edited using manage.py shell above,
|
||||||
|
etc.
|
||||||
|
|
||||||
|
You can also use `manage.py knight` with the
|
||||||
|
`--permission=api_super_user` argument to create API super users,
|
||||||
|
which are needed to mirror messages to streams from other users for
|
||||||
|
the IRC and Jabber mirroring integrations (see
|
||||||
|
`bots/irc-mirror.py` and `bots/jabber_mirror.py` for some detail on these).
|
||||||
|
|
||||||
|
There are a large number of useful management commands under
|
||||||
|
zerver/manangement/commands/; you can also see them listed using
|
||||||
|
`./manage.py` with no arguments.
|
||||||
|
|
||||||
|
One such command worth highlighting because it's a valuable feature
|
||||||
|
with no UI in the Administration page is `./manage.py realm_filters`,
|
||||||
|
which allows you to configure certain pattens in messages to be
|
||||||
|
automatically linkified, e.g. whenever someone mentions "T1234" it
|
||||||
|
could be auto-linkified to ticket 1234 in your team's Trac instance.
|
||||||
|
|
||||||
|
Checking Zulip is healthy and debugging the services it depends on
|
||||||
|
==================================================================
|
||||||
|
|
||||||
|
You can check if the zulip application is running using:
|
||||||
|
|
||||||
|
supervisorctl status
|
||||||
|
|
||||||
|
And checking for errors in the Zulip errors logs under
|
||||||
|
/var/log/zulip/. That contains one log file for each service, plus
|
||||||
|
errors.log (has all errors), server.log (logs from the Django and
|
||||||
|
Tornado servers), and workers.log (combined logs from the queue
|
||||||
|
workers).
|
||||||
|
|
||||||
|
After you change configuration in /etc/zulip/settings.py or fix a
|
||||||
|
misconfigurtion, you will often want to restart the Zulip application.
|
||||||
|
You can restart Zulip using:
|
||||||
|
|
||||||
|
supervisorctl restart all
|
||||||
|
|
||||||
|
Similarly, you can stop Zulip using:
|
||||||
|
|
||||||
|
supervisorctl stop all
|
||||||
|
|
||||||
|
The Zulip application uses several major services to store and cache
|
||||||
|
data, queue messages, and otherwise support the Zulip application:
|
||||||
|
|
||||||
|
* postgresql
|
||||||
|
* rabbitmq-server
|
||||||
|
* nginx
|
||||||
|
* redis
|
||||||
|
* memcached
|
||||||
|
|
||||||
|
If one of these services is not installed or functioning correctly,
|
||||||
|
Zulip will not work. Below we detail some common configuration
|
||||||
|
problems and how to resolve them:
|
||||||
|
|
||||||
|
* An AMQPConnectionError traceback or error running rabbitmqctl
|
||||||
|
usually means that RabbitMQ is not running; to fix this, try:
|
||||||
|
|
||||||
|
service rabbitmq-server restart
|
||||||
|
|
||||||
|
If RabbitMQ fails to start, the problem is often that you are using
|
||||||
|
a virtual machine with broken DNS configuration; you can often
|
||||||
|
correct this by configuring /etc/hosts properly.
|
||||||
|
|
||||||
|
* If your browser reports no webserver is running, that is likely
|
||||||
|
because nginx is not configured properly and thus failed to start.
|
||||||
|
nginx will fail to start if you configured SSL incorrectly or did
|
||||||
|
not provide SSL certificates. To fix this, configure them properly
|
||||||
|
and then run:
|
||||||
|
|
||||||
|
service nginx restart
|
||||||
|
|
||||||
|
If you run into additional problems, please report them so that we can
|
||||||
|
update these lists!
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
Making your Zulip instance awesome
|
||||||
|
==================================
|
||||||
|
|
||||||
|
Once you've got Zulip setup, you'll likely want to configure it the
|
||||||
|
way you like. There are four big things to focus on:
|
||||||
|
|
||||||
|
(1) Integrations. We recommend setting up integrations for the major
|
||||||
|
tools that your team works with. For example, if you're a software
|
||||||
|
development team, you may want to start with integrations for your
|
||||||
|
version control, issue tracker, CI system, and monitoring tools.
|
||||||
|
|
||||||
|
Spend time configuring these integrations to be how you like them --
|
||||||
|
if an integration is spammy, you may want to change it to not send
|
||||||
|
messages that nobody cares about (E.g. for the zulip.com trac
|
||||||
|
integration, some teams find they only want notifications when new
|
||||||
|
tickets are opened, commented on, or closed, and not every time
|
||||||
|
someone edits the metadata).
|
||||||
|
|
||||||
|
If Zulip doesn't have an integration you want, you can add your own!
|
||||||
|
Most integrations are very easy to write, and even more complex
|
||||||
|
integrations usually take less than a day's work to build. We very
|
||||||
|
much appreciate contributions of new integrations; there is a brief
|
||||||
|
draft integration writing guide here:
|
||||||
|
https://github.com/zulip/zulip/issues/70
|
||||||
|
|
||||||
|
It can often be valuable to integrate your own internal processes to
|
||||||
|
send notifications into Zulip; e.g. notifications of new customer
|
||||||
|
signups, new error reports, or daily reports on the team's key
|
||||||
|
metrics; this can often spawn discussions in response to the data.
|
||||||
|
|
||||||
|
(2) Streams and Topics. If it feels like a stream has too much
|
||||||
|
traffic about a topic only of interest to some of the subscribers,
|
||||||
|
consider adding or renaming streams until you feel like your team is
|
||||||
|
working productively.
|
||||||
|
|
||||||
|
Second, most users are not used to topics. It can require a bit of
|
||||||
|
time for everyone to get used to topics and start benefitting from
|
||||||
|
them, but usually once a team is using them well, everyone ends up
|
||||||
|
enthusiastic about how much topics make life easier. Some tips on
|
||||||
|
using topics:
|
||||||
|
|
||||||
|
* When replying to an existing conversation thread, just click on the
|
||||||
|
message, or navigate to it with the arrow keys and hit "r" or
|
||||||
|
"enter" to reply on the same topic
|
||||||
|
* When you start a new conversation topic, even if it's related to the
|
||||||
|
previous conversation, type a new topic in the compose box
|
||||||
|
* You can edit topics to fix a thread that's already been started,
|
||||||
|
which can be helpful when onboarding new batches of users to the platform.
|
||||||
|
|
||||||
|
(3) Notification settings. Zulip gives you a great deal of control
|
||||||
|
over which messages trigger desktop notifications; you can configure
|
||||||
|
these extensively in the /#settings page (get there from the gear
|
||||||
|
menu). If you find the desktop notifications annoying, consider
|
||||||
|
changing the settings to only trigger desktop notifications when you
|
||||||
|
receive a PM or are @-mentioned.
|
||||||
|
|
||||||
|
(4) The mobile and desktop apps. Currently, the Zulip Desktop app
|
||||||
|
only supports talking to servers with a properly signed SSL
|
||||||
|
certificate, so you may find that you get a blank screen when you
|
||||||
|
connect to a Zulip server using a self-signed certificate.
|
||||||
|
|
||||||
|
The Zulip iOS and Android apps in their respective stores don't yet
|
||||||
|
support talking to non-zulip.com servers; the iOS app is waiting on
|
||||||
|
Apple's app store review, while the Android app is waiting on someone
|
||||||
|
to do the small project of adding a field to specify what Zulip server
|
||||||
|
to talk to.
|
||||||
|
|
||||||
|
These issues will likely all be addressed in the coming weeks; make
|
||||||
|
sure to join the zulip-announce@googlegroups.com list so that you can
|
||||||
|
receive the announcements when these become available.
|
||||||
|
|
||||||
|
(5) All the other features: Hotkeys, emoji, search filters,
|
||||||
|
@-mentions, etc. Zulip has lots of great features, make sure your
|
||||||
|
team knows they exist and how to use them effectively.
|
||||||
|
|
||||||
|
(6) Enjoy your Zulip installation! If you discover things that you
|
||||||
|
wish had been documented, please contribute documentation suggestions
|
||||||
|
either via a GitHub issue or pull request; we love even small
|
||||||
|
contributions, and we'd love to make the Zulip documentation cover
|
||||||
|
everything anyone might want to know about running Zulip in
|
||||||
|
production.
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
Maintaining Zulip in production:
|
||||||
|
|
||||||
|
* To upgrade to a new version, download the appropriate release
|
||||||
|
tarball from https://www.zulip.org, and then run as root
|
||||||
|
|
||||||
|
/home/zulip/deployments/current/scripts/upgrade-zulip <tarball>
|
||||||
|
|
||||||
|
The upgrade process will shut down the service, run `apt-get
|
||||||
|
upgrade` and any database migrations, and then bring the service
|
||||||
|
back up. This will result in some brief downtime for the service,
|
||||||
|
which should be under 30 seconds unless there is an expensive
|
||||||
|
transition involved. Unless you have tested the upgrade in advance,
|
||||||
|
we recommend doing upgrades at off hours.
|
||||||
|
|
||||||
|
You can create your own release tarballs from a copy of zulip.git
|
||||||
|
repository using `tools/build-release-tarball`.
|
||||||
|
|
||||||
|
* To update your settings, simply edit /etc/zulip/settings.py and then
|
||||||
|
run /home/zulip/deployments/current/scripts/restart-server to
|
||||||
|
restart the server
|
||||||
|
|
||||||
|
* You are responsible for running "apt-get upgrade" on your system on
|
||||||
|
a regular basis to ensure that it is up to date with the latest
|
||||||
|
security patches.
|
||||||
|
|
||||||
|
* To use the Zulip API with your Zulip server, you will need to use the
|
||||||
|
API endpoint of e.g. "https://zulip.yourdomain.net/api". Our Python
|
||||||
|
API example scripts support this via the
|
||||||
|
"--site=https://zulip.yourdomain.net" argument. The API bindings
|
||||||
|
support it via putting "site=https://zulip.yourdomain.net" in your
|
||||||
|
.zuliprc.
|
||||||
|
|
||||||
|
Every Zulip integration supports this sort of argument (or e.g. a
|
||||||
|
ZULIP_SITE variable in a zuliprc file or the environment), but this
|
||||||
|
is not yet documented for some of the integrations (the included
|
||||||
|
integration documentation on /integrations will properly document
|
||||||
|
how to do this for most integrations). Pull requests welcome to
|
||||||
|
document this for those integrations that don't discuss this!
|
||||||
|
|
||||||
|
* Similarly, you will need to instruct your users to specify the URL
|
||||||
|
for your Zulip server when using the Zulip desktop and mobile apps.
|
||||||
|
|
||||||
|
* As a measure to mitigate the impact of potential memory leaks in one
|
||||||
|
of the Zulip daemons, the service automatically restarts itself
|
||||||
|
every Sunday early morning. See /etc/cron.d/restart-zulip for the
|
||||||
|
precise configuration.
|
||||||
|
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
SSO Authentication:
|
||||||
|
|
||||||
|
Zulip supports integrating with a corporate Single-Sign-On solution.
|
||||||
|
There are a few ways to do it, but this section documents how to
|
||||||
|
configure Zulip to use an SSO solution that best supports Apache and
|
||||||
|
will set the REMOTE_USER variable:
|
||||||
|
|
||||||
|
(0) Check that /etc/zulip/settings.py has
|
||||||
|
"zproject.backends.ZulipRemoteUserBackend" as the only enabled value
|
||||||
|
in the "AUTHENTICATION_BACKENDS" list, and that "SSO_APPEND_DOMAIN" is
|
||||||
|
correct set depending on whether your SSO system uses email addresses
|
||||||
|
or just usernames in REMOTE_USER.
|
||||||
|
|
||||||
|
Make sure that you've restarted the Zulip server since making this
|
||||||
|
configuration change.
|
||||||
|
|
||||||
|
(1) Edit /etc/zulip/zulip.conf and change the puppet_classes line to read:
|
||||||
|
|
||||||
|
puppet_classes = zulip::enterprise, zulip::apache_sso
|
||||||
|
|
||||||
|
(2) As root, run
|
||||||
|
|
||||||
|
/home/zulip/deployments/current/scripts/zulip-puppet-apply
|
||||||
|
|
||||||
|
to install our SSO integration.
|
||||||
|
|
||||||
|
(3) To configure our SSO integration, edit
|
||||||
|
/etc/apache2/sites-available/zulip-sso.example and fill in the
|
||||||
|
configuration required for your SSO service to set REMOTE_USER and
|
||||||
|
place your completed configuration file at
|
||||||
|
|
||||||
|
/etc/apache2/sites-available/zulip-sso
|
||||||
|
|
||||||
|
(4) Run
|
||||||
|
|
||||||
|
a2ensite zulip-sso
|
||||||
|
|
||||||
|
To enable the Apache integration site.
|
||||||
|
|
||||||
|
Now you should be able to visit https://zulip.yourdomain.net/ and
|
||||||
|
login via the SSO solution.
|
||||||
264
THIRDPARTY
Normal file
264
THIRDPARTY
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||||
|
Upstream-Name: Zulip
|
||||||
|
Upstream-Contact: Zulip Development Discussion <zulip-devel@googlegroups.com>
|
||||||
|
Source: https://zulip.org/
|
||||||
|
Comment:
|
||||||
|
Unless otherwise noted, the Zulip software is distributed under the Apache
|
||||||
|
License, Version 2.0. The software includes some works released by third
|
||||||
|
parties under other free and open source licenses. Those works are
|
||||||
|
redistributed under the license terms under which the works were received.
|
||||||
|
.
|
||||||
|
While Dropbox has sought to provide complete and accurate licensing
|
||||||
|
information for each FOSS package, Dropbox does not represent or warrant
|
||||||
|
that the licensing information provided herein is correct or error-free.
|
||||||
|
Recipients of the Zulip software should investigate the identified FOSS
|
||||||
|
packages to confirm the accuracy of the licensing information provided.
|
||||||
|
Recipients are also encouraged to notify Dropbox of any inaccurate
|
||||||
|
information or errors found in these notices.
|
||||||
|
|
||||||
|
Files: *
|
||||||
|
Copyright: 2011-2015 Dropbox, Inc.
|
||||||
|
License: Apache-2
|
||||||
|
|
||||||
|
Files: api/*
|
||||||
|
Copyright: 2012-2014 Dropbox, Inc
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: api/integrations/perforce/git_p4.py
|
||||||
|
Copyright: 2007 Simon Hausmann <simon@lst.de>,
|
||||||
|
2007 Trolltech ASA
|
||||||
|
License: Expat
|
||||||
|
Comment: https://raw.github.com/git/git/34022ba/git-p4.py
|
||||||
|
|
||||||
|
Files: bots/jabber_mirror_backend.py
|
||||||
|
Copyright: 2013 Permabit, Inc., 2013-2014 Dropbox, Inc.
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: confirmation/*
|
||||||
|
Copyright: 2008, Jarek Zgoda <jarek.zgoda@gmail.com>
|
||||||
|
License: BSD-3-Clause
|
||||||
|
|
||||||
|
Files: node_modules/handlebars/*
|
||||||
|
Copyright: 2011 Yehuda Katz
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: puppet/apt/*
|
||||||
|
Copyright: 2011, Evolving Web Inc.
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: puppet/common/*
|
||||||
|
Copyright: 2007, David Schmitt
|
||||||
|
License: BSD-3-Clause
|
||||||
|
Comment: https://github.com/DavidS/puppet-common
|
||||||
|
Distribution includes a file `lib/puppet/parser/functions/ip_to_cron.rb` which
|
||||||
|
we removed due to unclear license
|
||||||
|
|
||||||
|
Files: puppet/stdlib/*
|
||||||
|
Copyright: 2011, Krzysztof Wilczynski
|
||||||
|
2011, Puppet Labs Inc
|
||||||
|
License: Apache-2.0
|
||||||
|
|
||||||
|
File: puppet/zulip_internal/files/mediawiki/Auth_remoteuser.php
|
||||||
|
Copyright: 2006 Otheus Shelling
|
||||||
|
2007 Rusty Burchfield
|
||||||
|
2009 James Kinsman
|
||||||
|
2010 Daniel Thomas
|
||||||
|
2010 Ian Ward Comfort
|
||||||
|
License: GPL-2.0
|
||||||
|
Comment: Not linked.
|
||||||
|
|
||||||
|
Files: puppet/zulip_internal/files/nagios_plugins/check_debian_packages
|
||||||
|
Copyright: 2005 Francesc Guasch
|
||||||
|
License: GPL-2.0
|
||||||
|
Comment: Not linked.
|
||||||
|
|
||||||
|
Files: puppet/zulip_internal/files/nagios_plugins/check_postgres.pl
|
||||||
|
Copyright: 2007-2015 Greg Sabino Mullane
|
||||||
|
License: BSD-2-Clause
|
||||||
|
|
||||||
|
Files: puppet/zulip_internal/files/nagios_plugins/check_website_response.sh
|
||||||
|
Copyright: 2011 Chris Freeman
|
||||||
|
License: GPL-2.0
|
||||||
|
|
||||||
|
Files: puppet/zulip_internal/files/trac/cgi-bin/
|
||||||
|
Copyright: 2003-2009 Edgewall Software
|
||||||
|
2003-2004 Jonas Borgström <jonas@edgewall.com>
|
||||||
|
License: BSD-3-Clause
|
||||||
|
|
||||||
|
Files: puppet/zulip_internal/files/pagerduty_nagios.pl
|
||||||
|
Copyright: 2011, PagerDuty, Inc.
|
||||||
|
License: BSD-3-Clause
|
||||||
|
|
||||||
|
Files: puppet/zulip_internal/files/zulip-ec2-configure-interfaces
|
||||||
|
Copyright: 2013, Dropbox, Inc.
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: static/audio/zulip.*
|
||||||
|
Copyright: 2011 Vidsyn
|
||||||
|
License: CC-0-1.0
|
||||||
|
|
||||||
|
Files: static/styles/thirdparty-fonts.css
|
||||||
|
Copyright: 2012-2013 Dave Gandy
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: static/third/fontawesome/*
|
||||||
|
Copyright: 2012-2013 Dave Gandy
|
||||||
|
License: SIL-OFL-1.1
|
||||||
|
|
||||||
|
Files: static/third/bootstrap/bootstrap-btn.css
|
||||||
|
Copyright: 2011-2014 Twitter, Inc
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: static/third/bootstrap/css/bootstrap-responsive.css static/third/bootstrap/css/bootstrap.css
|
||||||
|
Copyright: 2012 Twitter, Inc
|
||||||
|
License: Apache-2.0
|
||||||
|
Comment: The software has been modified.
|
||||||
|
|
||||||
|
Files: static/third/bootstrap/js/bootstrap.js
|
||||||
|
Copyright: 2012 Twitter, Inc
|
||||||
|
License: Apache-2.0
|
||||||
|
Comment: The software has been modified.
|
||||||
|
|
||||||
|
Files: static/third/bootstrap-notify/*
|
||||||
|
Copyright: 2013 Nijiko Yonskai
|
||||||
|
2012 Goodybag, Inc.
|
||||||
|
2012 Twitter, Inc
|
||||||
|
License: Apache-2.0
|
||||||
|
Comment: The software has been modified.
|
||||||
|
|
||||||
|
Files: static/third/gemoji/images/emoji/unicode/* tools/emoji_dump/*.ttf
|
||||||
|
Copyright: Google, Inc.
|
||||||
|
License: Apache-2.0
|
||||||
|
Comment: These are actually Noto Emoji, not gemoji.
|
||||||
|
|
||||||
|
Files: static/third/handlebars/handlebars.runtime.js
|
||||||
|
Copyright: 2011 Yehuda Katz
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: static/third/html5-formdata/formdata.js
|
||||||
|
Copyright: 2010 François de Metz
|
||||||
|
License: Expat
|
||||||
|
Comment: See https://github.com/francois2metz/html5-formdata
|
||||||
|
|
||||||
|
Files: src/zulip/static/third/jquery/*
|
||||||
|
Copyright: 2011, John Resig
|
||||||
|
2011, The Dojo Foundation
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: static/third/jquery-autosize/jquery.autosize.js
|
||||||
|
Copyright: 2013 Jack Moore
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: static/third/jquery-caret/*
|
||||||
|
Copyright: 2010 C.F., Wong
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: static/third/jquery-filedrop/jquery.filedrop.js
|
||||||
|
Copyright: Resopollution
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: static/third/jquery-form/jquery.form.js
|
||||||
|
Copyright: M. Alsup
|
||||||
|
License: Expat or GPL-2.0
|
||||||
|
|
||||||
|
Files: static/third/jquery-idle/jquery.idle.js
|
||||||
|
Copyright: 2011-2013 Henrique Boaventura
|
||||||
|
License: Expat
|
||||||
|
Comment: The software has been modified.
|
||||||
|
|
||||||
|
Files: static/third/jquery-mousewheel/jquery.mousewheel.js
|
||||||
|
Copyright: 2011 Brandon Aaron
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: static/third/jquery-perfect-scrollbar/*
|
||||||
|
Copyright: 2012 HyeonJe Jun
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: static/third/jquery-throttle-debounce/*
|
||||||
|
Copyright: 2010 "Cowboy" Ben Alman
|
||||||
|
License: Expat or GPL
|
||||||
|
|
||||||
|
Files: static/third/jquery-validate/*
|
||||||
|
Copyright: 2006 - 2011 Jörn Zaefferer
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: src/zulip/static/third/lazyload/*
|
||||||
|
Copyright: 2011 Ryan Grove
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: static/third/marked/*
|
||||||
|
Copyright: 2011-2013, Christopher Jeffrey
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: static/third/sockjs/sockjs-0.3.4.js
|
||||||
|
Copyright: 2011-2012 VMware, Inc.
|
||||||
|
2012 Douglas Crockford
|
||||||
|
License: Expat and public-domain
|
||||||
|
|
||||||
|
Files: static/third/sorttable/sorttable.js
|
||||||
|
Copyright: 2007 Stuart Langridge
|
||||||
|
License: X11
|
||||||
|
|
||||||
|
Files: static/third/sourcesans/*
|
||||||
|
Copyright: 2010, 2012, 2014 Adobe Systems Incorporated
|
||||||
|
License: SIL-OFL-1.1
|
||||||
|
|
||||||
|
Files: static/third/spectrum/*
|
||||||
|
Copyright: 2013 Brian Grinstead
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: static/third/spin/spin.js
|
||||||
|
Copyright: 2011-2013 Felix Gnass
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: static/third/underscore/underscore.js
|
||||||
|
Copyright: 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
||||||
|
License: Expat
|
||||||
|
Comment: https://github.com/jashkenas/underscore/blob/master/LICENSE
|
||||||
|
|
||||||
|
Files: static/third/winchan/*
|
||||||
|
Copyright: 2012 Lloyd Hilaiel
|
||||||
|
License: Expat
|
||||||
|
Comment: https://github.com/mozilla/winchan
|
||||||
|
|
||||||
|
Files: static/third/xdate/*
|
||||||
|
Copyright: 2010 C. F., Wong
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: static/third/zocial/*
|
||||||
|
Copyright: Sam Collins
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: tools/inject-messages/othello
|
||||||
|
Copyright: Shakespeare
|
||||||
|
License: public-domain
|
||||||
|
|
||||||
|
Files: tools/jslint/jslint.js
|
||||||
|
Copyright: 2002 Douglas Crockford
|
||||||
|
License: XXX-good-not-evil
|
||||||
|
|
||||||
|
Files: tools/python-proxy
|
||||||
|
Copyright: 2009 F.bio Domingues
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: tools/review
|
||||||
|
Copyright: 2010 Ksplice, Inc.
|
||||||
|
License: Apache-2.0
|
||||||
|
|
||||||
|
Files: zerver/lib/bugdown/codehilite.py zerver/lib/bugdown/fenced_code.py
|
||||||
|
Copyright: 2006-2008 Waylan Limberg
|
||||||
|
License: BSD-3-Clause
|
||||||
|
Comment: https://pypi.python.org/pypi/Markdown
|
||||||
|
|
||||||
|
Files: zerver/lib/ccache.py
|
||||||
|
Copyright: 2013 David Benjamin and Alan Huang
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: zerver/tests/frontend/casperjs/*
|
||||||
|
Copyright: 2011-2012 Nicolas Perriault
|
||||||
|
Joyent, Inc. and other Node contributors
|
||||||
|
License: Expat
|
||||||
|
|
||||||
|
Files: zerver/tests/frontend/casperjs/modules/vendors/*
|
||||||
|
Copyright: 2011, Jeremy Ashkenas
|
||||||
|
License: Expat
|
||||||
34
Vagrantfile
vendored
Normal file
34
Vagrantfile
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# -*- mode: ruby -*-
|
||||||
|
|
||||||
|
VAGRANTFILE_API_VERSION = "2"
|
||||||
|
|
||||||
|
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||||
|
|
||||||
|
# For LXC. VirtualBox hosts use a different box, described below.
|
||||||
|
config.vm.box = "fgrehm/trusty64-lxc"
|
||||||
|
|
||||||
|
# The Zulip development environment runs on 9991 on the guest.
|
||||||
|
config.vm.network "forwarded_port", guest: 9991, host: 9991, host_ip: "127.0.0.1"
|
||||||
|
|
||||||
|
config.vm.synced_folder ".", "/vagrant", disabled: true
|
||||||
|
config.vm.synced_folder ".", "/srv/zulip"
|
||||||
|
|
||||||
|
config.vm.provider "virtualbox" do |vb, override|
|
||||||
|
override.vm.box = "ubuntu/trusty64"
|
||||||
|
# 2GiB seemed reasonable here. The VM OOMs with only 1024MiB.
|
||||||
|
vb.memory = 2048
|
||||||
|
end
|
||||||
|
|
||||||
|
$provision_script = <<SCRIPT
|
||||||
|
set -x
|
||||||
|
set -e
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y python-pbs
|
||||||
|
python /srv/zulip/provision.py
|
||||||
|
SCRIPT
|
||||||
|
|
||||||
|
config.vm.provision "shell",
|
||||||
|
# We want provision.py to be run with the permissions of the vagrant user.
|
||||||
|
privileged: false,
|
||||||
|
inline: $provision_script
|
||||||
|
end
|
||||||
@@ -17,6 +17,10 @@ python manage.py client_activity
|
|||||||
python manage.py client_activity zulip.com
|
python manage.py client_activity zulip.com
|
||||||
python manage.py client_activity jesstess@zulip.com"""
|
python manage.py client_activity jesstess@zulip.com"""
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument('arg', metavar='<arg>', type=str, nargs='?', default=None,
|
||||||
|
help="realm or user to estimate client activity for")
|
||||||
|
|
||||||
def compute_activity(self, user_activity_objects):
|
def compute_activity(self, user_activity_objects):
|
||||||
# Report data from the past week.
|
# Report data from the past week.
|
||||||
#
|
#
|
||||||
@@ -49,21 +53,22 @@ python manage.py client_activity jesstess@zulip.com"""
|
|||||||
|
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
if len(args) == 0:
|
if options['arg'] is None:
|
||||||
# Report global activity.
|
# Report global activity.
|
||||||
self.compute_activity(UserActivity.objects.all())
|
self.compute_activity(UserActivity.objects.all())
|
||||||
elif len(args) == 1:
|
else:
|
||||||
|
arg = options['arg']
|
||||||
try:
|
try:
|
||||||
# Report activity for a user.
|
# Report activity for a user.
|
||||||
user_profile = get_user_profile_by_email(args[0])
|
user_profile = get_user_profile_by_email(arg)
|
||||||
self.compute_activity(UserActivity.objects.filter(
|
self.compute_activity(UserActivity.objects.filter(
|
||||||
user_profile=user_profile))
|
user_profile=user_profile))
|
||||||
except UserProfile.DoesNotExist:
|
except UserProfile.DoesNotExist:
|
||||||
try:
|
try:
|
||||||
# Report activity for a realm.
|
# Report activity for a realm.
|
||||||
realm = get_realm(args[0])
|
realm = get_realm(arg)
|
||||||
self.compute_activity(UserActivity.objects.filter(
|
self.compute_activity(UserActivity.objects.filter(
|
||||||
user_profile__realm=realm))
|
user_profile__realm=realm))
|
||||||
except Realm.DoesNotExist:
|
except Realm.DoesNotExist:
|
||||||
print "Unknown user or domain %s" % (args[0],)
|
print "Unknown user or domain %s" % (arg,)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ human_messages = Message.objects.filter(sending_client__name__in=HUMAN_CLIENT_LI
|
|||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = "Generate statistics on realm activity."
|
help = "Generate statistics on realm activity."
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument('realms', metavar='<realm>', type=str, nargs='*',
|
||||||
|
help="realm to generate statistics for")
|
||||||
|
|
||||||
def active_users(self, realm):
|
def active_users(self, realm):
|
||||||
# Has been active (on the website, for now) in the last 7 days.
|
# Has been active (on the website, for now) in the last 7 days.
|
||||||
activity_cutoff = datetime.datetime.now(tz=pytz.utc) - datetime.timedelta(days=7)
|
activity_cutoff = datetime.datetime.now(tz=pytz.utc) - datetime.timedelta(days=7)
|
||||||
@@ -64,9 +68,9 @@ class Command(BaseCommand):
|
|||||||
print "%.2f%% of" % (fraction * 100,), text
|
print "%.2f%% of" % (fraction * 100,), text
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
if args:
|
if options['realms']:
|
||||||
try:
|
try:
|
||||||
realms = [Realm.objects.get(domain=domain) for domain in args]
|
realms = [Realm.objects.get(domain=domain) for domain in options['realms']]
|
||||||
except Realm.DoesNotExist, e:
|
except Realm.DoesNotExist, e:
|
||||||
print e
|
print e
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|||||||
@@ -7,10 +7,14 @@ from zerver.models import Realm, Stream, Message, Subscription, Recipient
|
|||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = "Generate statistics on the streams for a realm."
|
help = "Generate statistics on the streams for a realm."
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument('realms', metavar='<realm>', type=str, nargs='*',
|
||||||
|
help="realm to generate statistics for")
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
if args:
|
if options['realms']:
|
||||||
try:
|
try:
|
||||||
realms = [Realm.objects.get(domain=domain) for domain in args]
|
realms = [Realm.objects.get(domain=domain) for domain in options['realms']]
|
||||||
except Realm.DoesNotExist, e:
|
except Realm.DoesNotExist, e:
|
||||||
print e
|
print e
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|||||||
@@ -9,15 +9,19 @@ from zerver.models import UserProfile, Realm, Stream, Message
|
|||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = "Generate statistics on user activity."
|
help = "Generate statistics on user activity."
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument('realms', metavar='<realm>', type=str, nargs='*',
|
||||||
|
help="realm to generate statistics for")
|
||||||
|
|
||||||
def messages_sent_by(self, user, week):
|
def messages_sent_by(self, user, week):
|
||||||
start = datetime.datetime.now(tz=pytz.utc) - datetime.timedelta(days=(week + 1)*7)
|
start = datetime.datetime.now(tz=pytz.utc) - datetime.timedelta(days=(week + 1)*7)
|
||||||
end = datetime.datetime.now(tz=pytz.utc) - datetime.timedelta(days=week*7)
|
end = datetime.datetime.now(tz=pytz.utc) - datetime.timedelta(days=week*7)
|
||||||
return Message.objects.filter(sender=user, pub_date__gt=start, pub_date__lte=end).count()
|
return Message.objects.filter(sender=user, pub_date__gt=start, pub_date__lte=end).count()
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
if args:
|
if options['realms']:
|
||||||
try:
|
try:
|
||||||
realms = [Realm.objects.get(domain=domain) for domain in args]
|
realms = [Realm.objects.get(domain=domain) for domain in options['realms']]
|
||||||
except Realm.DoesNotExist, e:
|
except Realm.DoesNotExist, e:
|
||||||
print e
|
print e
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|||||||
@@ -172,9 +172,7 @@ def realm_summary_table(realm_minutes):
|
|||||||
GROUP BY realm_id
|
GROUP BY realm_id
|
||||||
) at_risk_counts
|
) at_risk_counts
|
||||||
ON at_risk_counts.realm_id = realm.id
|
ON at_risk_counts.realm_id = realm.id
|
||||||
WHERE
|
WHERE EXISTS (
|
||||||
realm.domain not in ('customer4.invalid', 'wdaher.com')
|
|
||||||
AND EXISTS (
|
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM zerver_useractivity ua
|
FROM zerver_useractivity ua
|
||||||
JOIN zerver_userprofile up
|
JOIN zerver_userprofile up
|
||||||
@@ -226,11 +224,6 @@ def realm_summary_table(realm_minutes):
|
|||||||
|
|
||||||
# Count active sites
|
# Count active sites
|
||||||
def meets_goal(row):
|
def meets_goal(row):
|
||||||
# The wdaher.com realm doesn't count toward company goals for
|
|
||||||
# obvious reasons, and customer4.invalid is essentially a dup
|
|
||||||
# for users.customer4.invalid.
|
|
||||||
if row['domain'] in ['customer4.invalid', 'wdaher.com']:
|
|
||||||
return False
|
|
||||||
return row['active_user_count'] >= 5
|
return row['active_user_count'] >= 5
|
||||||
|
|
||||||
num_active_sites = len(filter(meets_goal, rows))
|
num_active_sites = len(filter(meets_goal, rows))
|
||||||
|
|||||||
@@ -30,15 +30,12 @@ file is as follows:
|
|||||||
[api]
|
[api]
|
||||||
key=<api key from the web interface>
|
key=<api key from the web interface>
|
||||||
email=<your email address>
|
email=<your email address>
|
||||||
|
site=<your Zulip server's URI>
|
||||||
If you are using Zulip Enterprise, you should also add
|
|
||||||
|
|
||||||
site=<your Zulip Enterprise server's URI>
|
|
||||||
|
|
||||||
Alternatively, you may explicitly use "--user" and "--api-key" in our
|
Alternatively, you may explicitly use "--user" and "--api-key" in our
|
||||||
examples, which is especially useful if you are running several bots
|
examples, which is especially useful if you are running several bots
|
||||||
which share a home directory. There is also a "--site" option for
|
which share a home directory. There is also a "--site" option for
|
||||||
setting the Zulip Enterprise server on the command line.
|
setting the Zulip server on the command line.
|
||||||
|
|
||||||
You can obtain your Zulip API key, create bots, and manage bots all
|
You can obtain your Zulip API key, create bots, and manage bots all
|
||||||
from your Zulip [settings page](https://zulip.com/#settings).
|
from your Zulip [settings page](https://zulip.com/#settings).
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ usage = """list-subscriptions --user=<bot's email address> --api-key=<bot's api
|
|||||||
|
|
||||||
Prints out a list of the user's subscriptions.
|
Prints out a list of the user's subscriptions.
|
||||||
|
|
||||||
Example: list-subscriptions --user=tabbott@zulip.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5
|
Example: list-subscriptions --user=username@example.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5
|
||||||
|
|
||||||
You can omit --user and --api-key arguments if you have a properly set up ~/.zuliprc
|
You can omit --user and --api-key arguments if you have a properly set up ~/.zuliprc
|
||||||
"""
|
"""
|
||||||
|
|||||||
51
api/examples/print-events
Executable file
51
api/examples/print-events
Executable file
@@ -0,0 +1,51 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright © 2012 Zulip, Inc.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import optparse
|
||||||
|
|
||||||
|
usage = """print-events --user=<bot's email address> --api-key=<bot's api key> [options]
|
||||||
|
|
||||||
|
Prints out certain events received by the indicated bot or user matching the filter below.
|
||||||
|
|
||||||
|
Example: print-events --user=username@example.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5
|
||||||
|
|
||||||
|
You can omit --user and --api-key arguments if you have a properly set up ~/.zuliprc
|
||||||
|
"""
|
||||||
|
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
|
||||||
|
import zulip
|
||||||
|
|
||||||
|
parser = optparse.OptionParser(usage=usage)
|
||||||
|
parser.add_option_group(zulip.generate_option_group(parser))
|
||||||
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
|
client = zulip.init_from_options(options)
|
||||||
|
|
||||||
|
def print_event(event):
|
||||||
|
print event
|
||||||
|
|
||||||
|
# This is a blocking call, and will continuously poll for new events
|
||||||
|
# Note also the filter here is messages to the stream Denmark; if you
|
||||||
|
# don't specify event_types it'll print all events.
|
||||||
|
client.call_on_each_event(print_event, event_types=["message"], narrow=[["stream", "Denmark"]])
|
||||||
@@ -29,7 +29,7 @@ usage = """print-messages --user=<bot's email address> --api-key=<bot's api key>
|
|||||||
|
|
||||||
Prints out each message received by the indicated bot or user.
|
Prints out each message received by the indicated bot or user.
|
||||||
|
|
||||||
Example: print-messages --user=tabbott@zulip.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5
|
Example: print-messages --user=username@example.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5
|
||||||
|
|
||||||
You can omit --user and --api-key arguments if you have a properly set up ~/.zuliprc
|
You can omit --user and --api-key arguments if you have a properly set up ~/.zuliprc
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ usage = """print-next-message --user=<bot's email address> --api-key=<bot's api
|
|||||||
|
|
||||||
Prints out the next message received by the user.
|
Prints out the next message received by the user.
|
||||||
|
|
||||||
Example: print-next-messages --user=tabbott@zulip.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5
|
Example: print-next-messages --user=username@example.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5
|
||||||
|
|
||||||
You can omit --user and --api-key arguments if you have a properly set up ~/.zuliprc
|
You can omit --user and --api-key arguments if you have a properly set up ~/.zuliprc
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ usage = """subscribe --user=<bot's email address> --api-key=<bot's api key> [opt
|
|||||||
|
|
||||||
Ensures the user is subscribed to the listed streams.
|
Ensures the user is subscribed to the listed streams.
|
||||||
|
|
||||||
Examples: subscribe --user=tabbott@zulip.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 --streams=foo
|
Examples: subscribe --user=username@example.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 --streams=foo
|
||||||
subscribe --user=tabbott@zulip.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 --streams='foo bar'
|
subscribe --user=username@example.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 --streams='foo bar'
|
||||||
|
|
||||||
You can omit --user and --api-key arguments if you have a properly set up ~/.zuliprc
|
You can omit --user and --api-key arguments if you have a properly set up ~/.zuliprc
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ usage = """unsubscribe --user=<bot's email address> --api-key=<bot's api key> [
|
|||||||
|
|
||||||
Ensures the user is not subscribed to the listed streams.
|
Ensures the user is not subscribed to the listed streams.
|
||||||
|
|
||||||
Examples: unsubscribe --user=tabbott@zulip.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 --streams=foo
|
Examples: unsubscribe --user=username@example.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 --streams=foo
|
||||||
unsubscribe --user=tabbott@zulip.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 --streams='foo bar'
|
unsubscribe --user=username@example.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 --streams='foo bar'
|
||||||
|
|
||||||
You can omit --user and --api-key arguments if you have a properly set up ~/.zuliprc
|
You can omit --user and --api-key arguments if you have a properly set up ~/.zuliprc
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ ZULIP_STREAM_NAME = "asana"
|
|||||||
### OPTIONAL CONFIGURATION ###
|
### OPTIONAL CONFIGURATION ###
|
||||||
|
|
||||||
# Set to None for logging to stdout when testing, and to a file for
|
# Set to None for logging to stdout when testing, and to a file for
|
||||||
# logging when deployed.
|
# logging in production.
|
||||||
#LOG_FILE = "/var/tmp/zulip_asana.log"
|
#LOG_FILE = "/var/tmp/zulip_asana.log"
|
||||||
LOG_FILE = None
|
LOG_FILE = None
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ RESUME_FILE = "/var/tmp/zulip_asana.state"
|
|||||||
# When initially started, how many hours of messages to include.
|
# When initially started, how many hours of messages to include.
|
||||||
ASANA_INITIAL_HISTORY_HOURS = 1
|
ASANA_INITIAL_HISTORY_HOURS = 1
|
||||||
|
|
||||||
# If you're using Zulip Enterprise, set this to your Zulip Enterprise server
|
# Set this to your Zulip API server URI
|
||||||
ZULIP_SITE = "https://api.zulip.com"
|
ZULIP_SITE = "https://api.zulip.com"
|
||||||
|
|
||||||
# If properly installed, the Zulip API should be in your import
|
# If properly installed, the Zulip API should be in your import
|
||||||
|
|||||||
19
api/integrations/asana/zulip_asana_mirror
Normal file → Executable file
19
api/integrations/asana/zulip_asana_mirror
Normal file → Executable file
@@ -22,11 +22,17 @@
|
|||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
# 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
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
# THE SOFTWARE.
|
# THE SOFTWARE.
|
||||||
|
#
|
||||||
|
# The "zulip_asana_mirror" script is run continuously, possibly on a work computer
|
||||||
|
# or preferably on a server.
|
||||||
|
#
|
||||||
|
# When restarted, it will attempt to pick up where it left off.
|
||||||
|
#
|
||||||
|
# python-dateutil is a dependency for this script.
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import dateutil.parser
|
|
||||||
import dateutil.tz
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
@@ -34,6 +40,15 @@ import time
|
|||||||
import urllib2
|
import urllib2
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
import dateutil.parser
|
||||||
|
import dateutil.tz
|
||||||
|
except ImportError, e:
|
||||||
|
print >>sys.stderr, e
|
||||||
|
print >>sys.stderr, "Please install the python-dateutil package."
|
||||||
|
exit(1)
|
||||||
|
|
||||||
sys.path.insert(0, os.path.dirname(__file__))
|
sys.path.insert(0, os.path.dirname(__file__))
|
||||||
import zulip_asana_config as config
|
import zulip_asana_config as config
|
||||||
VERSION = "0.9"
|
VERSION = "0.9"
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ ZULIP_STREAM_NAME = "basecamp"
|
|||||||
## path, but if not, set a custom path below
|
## path, but if not, set a custom path below
|
||||||
ZULIP_API_PATH = None
|
ZULIP_API_PATH = None
|
||||||
|
|
||||||
# If you're using Zulip Enterprise, set this to your Zulip Enterprise server
|
# Set this to your Zulip API server URI
|
||||||
ZULIP_SITE = "https://api.zulip.com"
|
ZULIP_SITE = "https://api.zulip.com"
|
||||||
|
|
||||||
# If you wish to log to a file rather than stdout/stderr,
|
# If you wish to log to a file rather than stdout/stderr,
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ client = zulip.Client(
|
|||||||
site=config.ZULIP_SITE,
|
site=config.ZULIP_SITE,
|
||||||
api_key=config.ZULIP_API_KEY,
|
api_key=config.ZULIP_API_KEY,
|
||||||
client="ZulipBasecamp/" + VERSION)
|
client="ZulipBasecamp/" + VERSION)
|
||||||
user_agent = "Basecamp To Zulip Mirroring script (support@zulip.com)"
|
user_agent = "Basecamp To Zulip Mirroring script (zulip-devel@googlegroups.com)"
|
||||||
htmlParser = HTMLParser()
|
htmlParser = HTMLParser()
|
||||||
|
|
||||||
# find some form of JSON loader/dumper, with a preference order for speed.
|
# find some form of JSON loader/dumper, with a preference order for speed.
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ ZULIP_TICKETS_STREAM_NAME = "tickets"
|
|||||||
# path, but if not, set a custom path below
|
# path, but if not, set a custom path below
|
||||||
ZULIP_API_PATH = None
|
ZULIP_API_PATH = None
|
||||||
|
|
||||||
# If you're using Zulip Enterprise, set this to your Zulip Enterprise server
|
# Set this to your Zulip API server URI
|
||||||
ZULIP_SITE = "https://api.zulip.com"
|
ZULIP_SITE = "https://api.zulip.com"
|
||||||
|
|
||||||
# If you wish to log to a file rather than stdout/stderr,
|
# If you wish to log to a file rather than stdout/stderr,
|
||||||
|
|||||||
@@ -22,12 +22,12 @@
|
|||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
# THE SOFTWARE.
|
# THE SOFTWARE.
|
||||||
#
|
#
|
||||||
# The "codebase-mirror.py" script is run continuously, possibly on a work computer
|
# The "zulip_codebase_mirror" script is run continuously, possibly on a work
|
||||||
# or preferably on a server.
|
# computer or preferably on a server.
|
||||||
#
|
#
|
||||||
# When restarted, it will attempt to pick up where it left off.
|
# When restarted, it will attempt to pick up where it left off.
|
||||||
#
|
#
|
||||||
# You may need to install the python-requests library, as well as python-dateutil
|
# python-dateutil is a dependency for this script.
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
import logging
|
import logging
|
||||||
@@ -37,7 +37,13 @@ import os
|
|||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
import dateutil.parser
|
|
||||||
|
try:
|
||||||
|
import dateutil.parser
|
||||||
|
except ImportError, e:
|
||||||
|
print >>sys.stderr, e
|
||||||
|
print >>sys.stderr, "Please install the python-dateutil package."
|
||||||
|
exit(1)
|
||||||
|
|
||||||
sys.path.insert(0, os.path.dirname(__file__))
|
sys.path.insert(0, os.path.dirname(__file__))
|
||||||
import zulip_codebase_config as config
|
import zulip_codebase_config as config
|
||||||
@@ -52,7 +58,7 @@ client = zulip.Client(
|
|||||||
site=config.ZULIP_SITE,
|
site=config.ZULIP_SITE,
|
||||||
api_key=config.ZULIP_API_KEY,
|
api_key=config.ZULIP_API_KEY,
|
||||||
client="ZulipCodebase/" + VERSION)
|
client="ZulipCodebase/" + VERSION)
|
||||||
user_agent = "Codebase To Zulip Mirroring script (support@zulip.com)"
|
user_agent = "Codebase To Zulip Mirroring script (zulip-devel@googlegroups.com)"
|
||||||
|
|
||||||
# find some form of JSON loader/dumper, with a preference order for speed.
|
# find some form of JSON loader/dumper, with a preference order for speed.
|
||||||
json_implementations = ['ujson', 'cjson', 'simplejson', 'json']
|
json_implementations = ['ujson', 'cjson', 'simplejson', 'json']
|
||||||
|
|||||||
@@ -61,5 +61,5 @@ def format_commit_message(author, subject, commit_id):
|
|||||||
## path, but if not, set a custom path below
|
## path, but if not, set a custom path below
|
||||||
ZULIP_API_PATH = None
|
ZULIP_API_PATH = None
|
||||||
|
|
||||||
# If you're using Zulip Enterprise, set this to your Zulip Enterprise server
|
# Set this to your Zulip server's API URI
|
||||||
ZULIP_SITE = "https://api.zulip.com"
|
ZULIP_SITE = "https://api.zulip.com"
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ def strip_tags(html):
|
|||||||
def compute_entry_hash(entry):
|
def compute_entry_hash(entry):
|
||||||
entry_time = entry.get("published", entry.get("updated"))
|
entry_time = entry.get("published", entry.get("updated"))
|
||||||
entry_id = entry.get("id", entry.get("link"))
|
entry_id = entry.get("id", entry.get("link"))
|
||||||
return hashlib.md5(entry_id + entry_time).hexdigest()
|
return hashlib.md5(entry_id + str(entry_time)).hexdigest()
|
||||||
|
|
||||||
def elide_subject(subject):
|
def elide_subject(subject):
|
||||||
MAX_TOPIC_LENGTH = 60
|
MAX_TOPIC_LENGTH = 60
|
||||||
@@ -184,7 +184,7 @@ for feed_url in feed_urls:
|
|||||||
entry_hash = compute_entry_hash(entry)
|
entry_hash = compute_entry_hash(entry)
|
||||||
# An entry has either been published or updated.
|
# An entry has either been published or updated.
|
||||||
entry_time = entry.get("published_parsed", entry.get("updated_parsed"))
|
entry_time = entry.get("published_parsed", entry.get("updated_parsed"))
|
||||||
if (time.time() - calendar.timegm(entry_time)) > OLDNESS_THRESHOLD * 60 * 60 * 24:
|
if entry_time is not None and (time.time() - calendar.timegm(entry_time)) > OLDNESS_THRESHOLD * 60 * 60 * 24:
|
||||||
# As a safeguard against misbehaving feeds, don't try to process
|
# As a safeguard against misbehaving feeds, don't try to process
|
||||||
# entries older than some threshold.
|
# entries older than some threshold.
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -53,5 +53,5 @@ def commit_notice_destination(path, commit):
|
|||||||
## path, but if not, set a custom path below
|
## path, but if not, set a custom path below
|
||||||
ZULIP_API_PATH = None
|
ZULIP_API_PATH = None
|
||||||
|
|
||||||
# If you're using Zulip Enterprise, set this to your Zulip Enterprise server
|
# Set this to your Zulip server's API URI
|
||||||
ZULIP_SITE = "https://api.zulip.com"
|
ZULIP_SITE = "https://api.zulip.com"
|
||||||
|
|||||||
@@ -47,5 +47,5 @@ TRAC_NOTIFY_FIELDS = ["description", "summary", "resolution", "comment", "owner"
|
|||||||
## path, but if not, set a custom path below
|
## path, but if not, set a custom path below
|
||||||
ZULIP_API_PATH = None
|
ZULIP_API_PATH = None
|
||||||
|
|
||||||
# If you're using Zulip Enterprise, set this to your Zulip Enterprise server
|
# Set this to your Zulip API server URI
|
||||||
ZULIP_SITE = "https://api.zulip.com"
|
ZULIP_SITE = "https://api.zulip.com"
|
||||||
|
|||||||
@@ -126,9 +126,9 @@ except ConfigParser.NoOptionError:
|
|||||||
user_id = options.twitter_id
|
user_id = options.twitter_id
|
||||||
|
|
||||||
client = zulip.Client(
|
client = zulip.Client(
|
||||||
email=options.email,
|
email=options.zulip_email,
|
||||||
api_key=options.api_key,
|
api_key=options.zulip_api_key,
|
||||||
site=options.site,
|
site=options.zulip_site,
|
||||||
client="ZulipTwitter/" + VERSION,
|
client="ZulipTwitter/" + VERSION,
|
||||||
verbose=True)
|
verbose=True)
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ package_info = dict(
|
|||||||
version=version(),
|
version=version(),
|
||||||
description='Bindings for the Zulip message API',
|
description='Bindings for the Zulip message API',
|
||||||
author='Zulip, Inc.',
|
author='Zulip, Inc.',
|
||||||
author_email='support@zulip.com',
|
author_email='zulip-devel@googlegroups.com',
|
||||||
classifiers=[
|
classifiers=[
|
||||||
'Development Status :: 3 - Alpha',
|
'Development Status :: 3 - Alpha',
|
||||||
'Environment :: Web Environment',
|
'Environment :: Web Environment',
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ import sys
|
|||||||
import os
|
import os
|
||||||
import optparse
|
import optparse
|
||||||
import platform
|
import platform
|
||||||
|
import urllib
|
||||||
|
import random
|
||||||
from distutils.version import LooseVersion
|
from distutils.version import LooseVersion
|
||||||
|
|
||||||
from ConfigParser import SafeConfigParser
|
from ConfigParser import SafeConfigParser
|
||||||
@@ -37,6 +39,8 @@ import logging
|
|||||||
|
|
||||||
__version__ = "0.2.4"
|
__version__ = "0.2.4"
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# Check that we have a recent enough version
|
# Check that we have a recent enough version
|
||||||
# Older versions don't provide the 'json' attribute on responses.
|
# Older versions don't provide the 'json' attribute on responses.
|
||||||
assert(LooseVersion(requests.__version__) >= LooseVersion('0.12.1'))
|
assert(LooseVersion(requests.__version__) >= LooseVersion('0.12.1'))
|
||||||
@@ -45,39 +49,91 @@ requests_json_is_function = callable(requests.Response.json)
|
|||||||
|
|
||||||
API_VERSTRING = "v1/"
|
API_VERSTRING = "v1/"
|
||||||
|
|
||||||
|
class CountingBackoff(object):
|
||||||
|
def __init__(self, maximum_retries=10, timeout_success_equivalent=None):
|
||||||
|
self.number_of_retries = 0
|
||||||
|
self.maximum_retries = maximum_retries
|
||||||
|
self.timeout_success_equivalent = timeout_success_equivalent
|
||||||
|
self.last_attempt_time = 0
|
||||||
|
|
||||||
|
def keep_going(self):
|
||||||
|
self._check_success_timeout()
|
||||||
|
return self.number_of_retries < self.maximum_retries
|
||||||
|
|
||||||
|
def succeed(self):
|
||||||
|
self.number_of_retries = 0
|
||||||
|
self.last_attempt_time = time.time()
|
||||||
|
|
||||||
|
def fail(self):
|
||||||
|
self._check_success_timeout()
|
||||||
|
self.number_of_retries = min(self.number_of_retries + 1,
|
||||||
|
self.maximum_retries)
|
||||||
|
self.last_attempt_time = time.time()
|
||||||
|
|
||||||
|
def _check_success_timeout(self):
|
||||||
|
if (self.timeout_success_equivalent is not None
|
||||||
|
and self.last_attempt_time != 0
|
||||||
|
and time.time() - self.last_attempt_time > self.timeout_success_equivalent):
|
||||||
|
self.number_of_retries = 0
|
||||||
|
|
||||||
|
class RandomExponentialBackoff(CountingBackoff):
|
||||||
|
def fail(self):
|
||||||
|
super(RandomExponentialBackoff, self).fail()
|
||||||
|
# Exponential growth with ratio sqrt(2); compute random delay
|
||||||
|
# between x and 2x where x is growing exponentially
|
||||||
|
delay_scale = int(2 ** (self.number_of_retries / 2.0 - 1)) + 1
|
||||||
|
delay = delay_scale + random.randint(1, delay_scale)
|
||||||
|
message = "Sleeping for %ss [max %s] before retrying." % (delay, delay_scale * 2)
|
||||||
|
try:
|
||||||
|
logger.warning(message)
|
||||||
|
except NameError:
|
||||||
|
print message
|
||||||
|
time.sleep(delay)
|
||||||
|
|
||||||
def _default_client():
|
def _default_client():
|
||||||
return "ZulipPython/" + __version__
|
return "ZulipPython/" + __version__
|
||||||
|
|
||||||
def generate_option_group(parser):
|
def generate_option_group(parser, prefix=''):
|
||||||
group = optparse.OptionGroup(parser, 'API configuration')
|
group = optparse.OptionGroup(parser, 'Zulip API configuration')
|
||||||
group.add_option('--site',
|
group.add_option('--%ssite' % (prefix,),
|
||||||
help="Zulip Enterprise server URI (if using Zulip Enterprise)",
|
dest="zulip_site",
|
||||||
|
help="Zulip server URI",
|
||||||
default=None)
|
default=None)
|
||||||
group.add_option('--api-key',
|
group.add_option('--%sapi-key' % (prefix,),
|
||||||
|
dest="zulip_api_key",
|
||||||
action='store')
|
action='store')
|
||||||
group.add_option('--user',
|
group.add_option('--%suser' % (prefix,),
|
||||||
dest='email',
|
dest='zulip_email',
|
||||||
help='Email address of the calling bot or user.')
|
help='Email address of the calling bot or user.')
|
||||||
group.add_option('--config-file',
|
group.add_option('--%sconfig-file' % (prefix,),
|
||||||
action='store',
|
action='store',
|
||||||
|
dest="zulip_config_file",
|
||||||
help='Location of an ini file containing the\nabove information. (default ~/.zuliprc)')
|
help='Location of an ini file containing the\nabove information. (default ~/.zuliprc)')
|
||||||
group.add_option('-v', '--verbose',
|
group.add_option('-v', '--verbose',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
help='Provide detailed output.')
|
help='Provide detailed output.')
|
||||||
group.add_option('--client',
|
group.add_option('--%sclient' % (prefix,),
|
||||||
action='store',
|
action='store',
|
||||||
default=None,
|
default=None,
|
||||||
|
dest="zulip_client",
|
||||||
help=optparse.SUPPRESS_HELP)
|
help=optparse.SUPPRESS_HELP)
|
||||||
return group
|
return group
|
||||||
|
|
||||||
def init_from_options(options, client=None):
|
def init_from_options(options, client=None):
|
||||||
if options.client is not None:
|
if options.zulip_client is not None:
|
||||||
client = options.client
|
client = options.zulip_client
|
||||||
elif client is None:
|
elif client is None:
|
||||||
client = _default_client()
|
client = _default_client()
|
||||||
return Client(email=options.email, api_key=options.api_key,
|
return Client(email=options.zulip_email, api_key=options.zulip_api_key,
|
||||||
config_file=options.config_file, verbose=options.verbose,
|
config_file=options.zulip_config_file, verbose=options.verbose,
|
||||||
site=options.site, client=client)
|
site=options.zulip_site, client=client)
|
||||||
|
|
||||||
|
def get_default_config_filename():
|
||||||
|
config_file = os.path.join(os.environ["HOME"], ".zuliprc")
|
||||||
|
if (not os.path.exists(config_file) and
|
||||||
|
os.path.exists(os.path.join(os.environ["HOME"], ".humbugrc"))):
|
||||||
|
raise RuntimeError("The Zulip API configuration file is now ~/.zuliprc; please run:\n\n mv ~/.humbugrc ~/.zuliprc\n")
|
||||||
|
return config_file
|
||||||
|
|
||||||
class Client(object):
|
class Client(object):
|
||||||
def __init__(self, email=None, api_key=None, config_file=None,
|
def __init__(self, email=None, api_key=None, config_file=None,
|
||||||
@@ -87,10 +143,7 @@ class Client(object):
|
|||||||
client = _default_client()
|
client = _default_client()
|
||||||
if None in (api_key, email):
|
if None in (api_key, email):
|
||||||
if config_file is None:
|
if config_file is None:
|
||||||
config_file = os.path.join(os.environ["HOME"], ".zuliprc")
|
config_file = get_default_config_filename()
|
||||||
if (not os.path.exists(config_file) and
|
|
||||||
os.path.exists(os.path.join(os.environ["HOME"], ".humbugrc"))):
|
|
||||||
raise RuntimeError("The Zulip API configuration file is now ~/.zuliprc; please run:\n\n mv ~/.humbugrc ~/.zuliprc\n")
|
|
||||||
if not os.path.exists(config_file):
|
if not os.path.exists(config_file):
|
||||||
raise RuntimeError("api_key or email not specified and %s does not exist"
|
raise RuntimeError("api_key or email not specified and %s does not exist"
|
||||||
% (config_file,))
|
% (config_file,))
|
||||||
@@ -123,8 +176,15 @@ class Client(object):
|
|||||||
self.client_name = client
|
self.client_name = client
|
||||||
|
|
||||||
def get_user_agent(self):
|
def get_user_agent(self):
|
||||||
vendor = platform.system()
|
vendor = ''
|
||||||
vendor_version = platform.release()
|
vendor_version = ''
|
||||||
|
try:
|
||||||
|
vendor = platform.system()
|
||||||
|
vendor_version = platform.release()
|
||||||
|
except IOError:
|
||||||
|
# If the calling process is handling SIGCHLD, platform.system() can
|
||||||
|
# fail with an IOError. See http://bugs.python.org/issue9127
|
||||||
|
pass
|
||||||
|
|
||||||
if vendor == "Linux":
|
if vendor == "Linux":
|
||||||
vendor, vendor_version, dummy = platform.linux_distribution()
|
vendor, vendor_version, dummy = platform.linux_distribution()
|
||||||
@@ -241,12 +301,16 @@ class Client(object):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _register(cls, name, url=None, make_request=(lambda request={}: request),
|
def _register(cls, name, url=None, make_request=(lambda request={}: request),
|
||||||
method="POST", **query_kwargs):
|
method="POST", computed_url=None, **query_kwargs):
|
||||||
if url is None:
|
if url is None:
|
||||||
url = name
|
url = name
|
||||||
def call(self, *args, **kwargs):
|
def call(self, *args, **kwargs):
|
||||||
request = make_request(*args, **kwargs)
|
request = make_request(*args, **kwargs)
|
||||||
return self.do_api_query(request, API_VERSTRING + url, method=method, **query_kwargs)
|
if computed_url is not None:
|
||||||
|
req_url = computed_url(request)
|
||||||
|
else:
|
||||||
|
req_url = url
|
||||||
|
return self.do_api_query(request, API_VERSTRING + req_url, method=method, **query_kwargs)
|
||||||
call.func_name = name
|
call.func_name = name
|
||||||
setattr(cls, name, call)
|
setattr(cls, name, call)
|
||||||
|
|
||||||
@@ -352,6 +416,7 @@ Client._register('update_message', method='PATCH', url='messages', make_request=
|
|||||||
Client._register('get_messages', method='GET', url='messages/latest', longpolling=True)
|
Client._register('get_messages', method='GET', url='messages/latest', longpolling=True)
|
||||||
Client._register('get_events', url='events', method='GET', longpolling=True, make_request=(lambda **kwargs: kwargs))
|
Client._register('get_events', url='events', method='GET', longpolling=True, make_request=(lambda **kwargs: kwargs))
|
||||||
Client._register('register', make_request=_mk_events)
|
Client._register('register', make_request=_mk_events)
|
||||||
|
Client._register('export', method='GET', url='export')
|
||||||
Client._register('deregister', url="events", method="DELETE", make_request=_mk_deregister)
|
Client._register('deregister', url="events", method="DELETE", make_request=_mk_deregister)
|
||||||
Client._register('get_profile', method='GET', url='users/me')
|
Client._register('get_profile', method='GET', url='users/me')
|
||||||
Client._register('get_streams', method='GET', url='streams', make_request=_kwargs_to_dict)
|
Client._register('get_streams', method='GET', url='streams', make_request=_kwargs_to_dict)
|
||||||
@@ -359,5 +424,8 @@ Client._register('get_members', method='GET', url='users')
|
|||||||
Client._register('list_subscriptions', method='GET', url='users/me/subscriptions')
|
Client._register('list_subscriptions', method='GET', url='users/me/subscriptions')
|
||||||
Client._register('add_subscriptions', url='users/me/subscriptions', make_request=_mk_subs)
|
Client._register('add_subscriptions', url='users/me/subscriptions', make_request=_mk_subs)
|
||||||
Client._register('remove_subscriptions', method='PATCH', url='users/me/subscriptions', make_request=_mk_rm_subs)
|
Client._register('remove_subscriptions', method='PATCH', url='users/me/subscriptions', make_request=_mk_rm_subs)
|
||||||
|
Client._register('get_subscribers', method='GET',
|
||||||
|
computed_url=lambda request: 'streams/%s/members' % (urllib.quote(request['stream'], safe=''),),
|
||||||
|
make_request=_kwargs_to_dict)
|
||||||
Client._register('render_message', method='GET', url='messages/render')
|
Client._register('render_message', method='GET', url='messages/render')
|
||||||
Client._register('create_user', method='POST', url='users')
|
Client._register('create_user', method='POST', url='users')
|
||||||
|
|||||||
202
assets/zulip-emoji/NOTICE
Normal file
202
assets/zulip-emoji/NOTICE
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
13
assets/zulip-emoji/README
Normal file
13
assets/zulip-emoji/README
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
This directory contains images adapted from the Noto project. For more detail
|
||||||
|
about Noto, please refer to:
|
||||||
|
|
||||||
|
https://code.google.com/p/noto/
|
||||||
|
|
||||||
|
These images were generated from the git repository at
|
||||||
|
<https://android.googlesource.com/platform/external/noto-fonts> as of
|
||||||
|
90372d894b5d9c9f2a111315d2eb3b8de1979ee4
|
||||||
|
|
||||||
|
and
|
||||||
|
|
||||||
|
<https://android.googlesource.com/platform/frameworks/base> at
|
||||||
|
07912f876c8639f811b06831465c14c4a3b17663.
|
||||||
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
@@ -11,5 +11,5 @@ ZULIP_DIR=/home/zulip/deployments/current
|
|||||||
STATE_DIR=/var/lib/nagios_state
|
STATE_DIR=/var/lib/nagios_state
|
||||||
STATE_FILE=$STATE_DIR/check-rabbitmq-consumers-$queue
|
STATE_FILE=$STATE_DIR/check-rabbitmq-consumers-$queue
|
||||||
|
|
||||||
$ZULIP_DIR/bots/check-rabbitmq-consumers --queue=$queue &> ${STATE_FILE}-tmp;
|
"$ZULIP_DIR/bots/check-rabbitmq-consumers" "--queue=$queue" &> "${STATE_FILE}-tmp";
|
||||||
mv ${STATE_FILE}-tmp $STATE_FILE
|
mv "${STATE_FILE}-tmp" "$STATE_FILE"
|
||||||
|
|||||||
@@ -6,8 +6,14 @@ import time
|
|||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
WARN_THRESHOLD = 10
|
WARN_THRESHOLD_DEFAULT = 10
|
||||||
CRIT_THRESHOLD = 50
|
WARN_THRESHOLD = {
|
||||||
|
'missedmessage_emails': 45,
|
||||||
|
}
|
||||||
|
CRIT_THRESHOLD_DEFAULT = 50
|
||||||
|
CRIT_THRESHOLD = {
|
||||||
|
'missedmessage_emails': 70,
|
||||||
|
}
|
||||||
|
|
||||||
states = {
|
states = {
|
||||||
0: "OK",
|
0: "OK",
|
||||||
@@ -33,10 +39,10 @@ for line in output.split("\n"):
|
|||||||
queue = m.group(1)
|
queue = m.group(1)
|
||||||
count = int(m.group(2))
|
count = int(m.group(2))
|
||||||
this_status = 0
|
this_status = 0
|
||||||
if count > CRIT_THRESHOLD:
|
if count > CRIT_THRESHOLD.get(queue, CRIT_THRESHOLD_DEFAULT):
|
||||||
this_status = 2
|
this_status = 2
|
||||||
warn_queues.append(queue)
|
warn_queues.append(queue)
|
||||||
elif count > WARN_THRESHOLD:
|
elif count > WARN_THRESHOLD.get(queue, WARN_THRESHOLD_DEFAULT):
|
||||||
this_status = max(status, 1)
|
this_status = max(status, 1)
|
||||||
warn_queues.append(queue)
|
warn_queues.append(queue)
|
||||||
|
|
||||||
@@ -50,7 +56,7 @@ now_struct = time.gmtime(now)
|
|||||||
# While we are sending digest emails, at 11am each weekday, the mail queues can
|
# While we are sending digest emails, at 11am each weekday, the mail queues can
|
||||||
# get backed up; don't alert on those.
|
# get backed up; don't alert on those.
|
||||||
if not set(warn_queues) - set(("missedmessage_emails", "digest_emails")) and \
|
if not set(warn_queues) - set(("missedmessage_emails", "digest_emails")) and \
|
||||||
now_struct.tm_hour == 16 and now_struct.tm_min < 15:
|
now_struct.tm_hour == 15 and now_struct.tm_min < 25:
|
||||||
status = 0
|
status = 0
|
||||||
print("%s|%s|%s|processing digests, not alerting on elevated mail queues" % (
|
print("%s|%s|%s|processing digests, not alerting on elevated mail queues" % (
|
||||||
now, status, states[status]))
|
now, status, states[status]))
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ parser.add_option_group(zulip.generate_option_group(parser))
|
|||||||
|
|
||||||
(options, args) = parser.parse_args()
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
if not (options.user and options.calendar):
|
if not (options.zulip_email and options.calendar):
|
||||||
parser.error('You must specify --user and --calendar')
|
parser.error('You must specify --user and --calendar')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -12,9 +12,11 @@ from irc.client import ip_numstr_to_quad, ip_quad_to_numstr
|
|||||||
import zulip
|
import zulip
|
||||||
import optparse
|
import optparse
|
||||||
|
|
||||||
|
IRC_DOMAIN = "irc.example.com"
|
||||||
|
|
||||||
def zulip_sender(sender_string):
|
def zulip_sender(sender_string):
|
||||||
nick = sender_string.split("!")[0]
|
nick = sender_string.split("!")[0]
|
||||||
return nick + "@irc.zulip.com"
|
return nick + "@" + IRC_DOMAIN
|
||||||
|
|
||||||
class IRCBot(irc.bot.SingleServerIRCBot):
|
class IRCBot(irc.bot.SingleServerIRCBot):
|
||||||
def __init__(self, channel, nickname, server, port=6667):
|
def __init__(self, channel, nickname, server, port=6667):
|
||||||
@@ -47,14 +49,14 @@ class IRCBot(irc.bot.SingleServerIRCBot):
|
|||||||
def on_privmsg(self, c, e):
|
def on_privmsg(self, c, e):
|
||||||
content = e.arguments[0]
|
content = e.arguments[0]
|
||||||
sender = zulip_sender(e.source)
|
sender = zulip_sender(e.source)
|
||||||
if sender.endswith("_zulip@irc.zulip.com"):
|
if sender.endswith("_zulip@" + IRC_DOMAIN):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Forward the PM to Zulip
|
# Forward the PM to Zulip
|
||||||
print zulip_client.send_message({
|
print zulip_client.send_message({
|
||||||
"sender": sender,
|
"sender": sender,
|
||||||
"type": "private",
|
"type": "private",
|
||||||
"to": "tabbott@zulip.com",
|
"to": "username@example.com",
|
||||||
"content": content,
|
"content": content,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -62,7 +64,7 @@ class IRCBot(irc.bot.SingleServerIRCBot):
|
|||||||
content = e.arguments[0]
|
content = e.arguments[0]
|
||||||
stream = e.target
|
stream = e.target
|
||||||
sender = zulip_sender(e.source)
|
sender = zulip_sender(e.source)
|
||||||
if sender.endswith("_zulip@irc.zulip.com"):
|
if sender.endswith("_zulip@" + IRC_DOMAIN):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Forward the stream message to Zulip
|
# Forward the stream message to Zulip
|
||||||
@@ -94,8 +96,8 @@ usage = """python irc-mirror.py --server=IRC_SERVER --channel=<CHANNEL> --nick-p
|
|||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
python irc-mirror.py --irc-server=127.0.0.1 --channel='#test' --nick-prefix=tabbott
|
python irc-mirror.py --irc-server=127.0.0.1 --channel='#test' --nick-prefix=username
|
||||||
--site=https://staging.zulip.com --user=irc-bot@zulip.com
|
--site=https://zulip.example.com --user=irc-bot@example.com
|
||||||
--api-key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
--api-key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
|
||||||
Note that "_zulip" will be automatically appended to the IRC nick provided
|
Note that "_zulip" will be automatically appended to the IRC nick provided
|
||||||
|
|||||||
59
bots/jabber_mirror.py
Executable file
59
bots/jabber_mirror.py
Executable file
@@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# Copyright (C) 2014 Zulip, Inc.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
import traceback
|
||||||
|
import signal
|
||||||
|
from zulip import RandomExponentialBackoff
|
||||||
|
|
||||||
|
def die(signal, frame):
|
||||||
|
# We actually want to exit, so run os._exit (so as not to be caught and restarted)
|
||||||
|
os._exit(1)
|
||||||
|
|
||||||
|
signal.signal(signal.SIGINT, die)
|
||||||
|
|
||||||
|
args = [os.path.join(os.path.dirname(sys.argv[0]), "jabber_mirror_backend.py")]
|
||||||
|
args.extend(sys.argv[1:])
|
||||||
|
|
||||||
|
backoff = RandomExponentialBackoff(timeout_success_equivalent=300)
|
||||||
|
while backoff.keep_going():
|
||||||
|
print "Starting Jabber mirroring bot"
|
||||||
|
try:
|
||||||
|
ret = subprocess.call(args)
|
||||||
|
except:
|
||||||
|
traceback.print_exc()
|
||||||
|
else:
|
||||||
|
if ret == 2:
|
||||||
|
# Don't try again on initial configuration errors
|
||||||
|
sys.exit(ret)
|
||||||
|
|
||||||
|
backoff.fail()
|
||||||
|
|
||||||
|
print ""
|
||||||
|
print ""
|
||||||
|
print "ERROR: The Jabber mirroring bot is unable to continue mirroring Jabber."
|
||||||
|
print "Please contact zulip-devel@googlegroups.com if you need assistance."
|
||||||
|
print ""
|
||||||
|
sys.exit(1)
|
||||||
445
bots/jabber_mirror_backend.py
Executable file
445
bots/jabber_mirror_backend.py
Executable file
@@ -0,0 +1,445 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
#
|
||||||
|
# Copyright (C) 2013 Permabit, Inc.
|
||||||
|
# Copyright (C) 2013--2014 Zulip, Inc.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
# The following is a table showing which kinds of messages are handled by the
|
||||||
|
# mirror in each mode:
|
||||||
|
#
|
||||||
|
# Message origin/type --> | Jabber | Zulip
|
||||||
|
# Mode/sender-, +-----+----+--------+----
|
||||||
|
# V | MUC | PM | stream | PM
|
||||||
|
# --------------+-------------+-----+----+--------+----
|
||||||
|
# | other sender| | x | |
|
||||||
|
# personal mode +-------------+-----+----+--------+----
|
||||||
|
# | self sender | | x | x | x
|
||||||
|
# ------------- +-------------+-----+----+--------+----
|
||||||
|
# | other sender| x | | |
|
||||||
|
# public mode +-------------+-----+----+--------+----
|
||||||
|
# | self sender | | | |
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import threading
|
||||||
|
import optparse
|
||||||
|
|
||||||
|
from sleekxmpp import ClientXMPP, InvalidJID, JID
|
||||||
|
from sleekxmpp.exceptions import IqError, IqTimeout
|
||||||
|
from ConfigParser import SafeConfigParser
|
||||||
|
import os, sys, zulip, getpass
|
||||||
|
import re
|
||||||
|
|
||||||
|
__version__ = "1.1"
|
||||||
|
|
||||||
|
def room_to_stream(room):
|
||||||
|
return room + "/xmpp"
|
||||||
|
|
||||||
|
def stream_to_room(stream):
|
||||||
|
return stream.lower().rpartition("/xmpp")[0]
|
||||||
|
|
||||||
|
def jid_to_zulip(jid):
|
||||||
|
suffix = ''
|
||||||
|
if not jid.username.endswith("-bot"):
|
||||||
|
suffix = options.zulip_email_suffix
|
||||||
|
return "%s%s@%s" % (jid.username, suffix, options.zulip_domain)
|
||||||
|
|
||||||
|
def zulip_to_jid(email, jabber_domain):
|
||||||
|
jid = JID(email, domain=jabber_domain)
|
||||||
|
if (options.zulip_email_suffix
|
||||||
|
and options.zulip_email_suffix in jid.username
|
||||||
|
and not jid.username.endswith("-bot")):
|
||||||
|
jid.username = jid.username.rpartition(options.zulip_email_suffix)[0]
|
||||||
|
return jid
|
||||||
|
|
||||||
|
class JabberToZulipBot(ClientXMPP):
|
||||||
|
def __init__(self, jid, password, rooms):
|
||||||
|
if jid.resource:
|
||||||
|
self.nick = jid.resource
|
||||||
|
else:
|
||||||
|
self.nick = jid.username
|
||||||
|
jid.resource = "zulip"
|
||||||
|
ClientXMPP.__init__(self, jid, password)
|
||||||
|
self.rooms = set()
|
||||||
|
self.rooms_to_join = rooms
|
||||||
|
self.add_event_handler("session_start", self.session_start)
|
||||||
|
self.add_event_handler("message", self.message)
|
||||||
|
self.zulip = None
|
||||||
|
self.use_ipv6 = False
|
||||||
|
|
||||||
|
self.register_plugin('xep_0045') # Jabber chatrooms
|
||||||
|
self.register_plugin('xep_0199') # XMPP Ping
|
||||||
|
|
||||||
|
def set_zulip_client(self, client):
|
||||||
|
self.zulip = client
|
||||||
|
|
||||||
|
def session_start(self, event):
|
||||||
|
self.get_roster()
|
||||||
|
self.send_presence()
|
||||||
|
for room in self.rooms_to_join:
|
||||||
|
self.join_muc(room)
|
||||||
|
|
||||||
|
def join_muc(self, room):
|
||||||
|
if room in self.rooms:
|
||||||
|
return
|
||||||
|
logging.debug("Joining " + room)
|
||||||
|
self.rooms.add(room)
|
||||||
|
muc_jid = JID(local=room, domain=options.conference_domain)
|
||||||
|
xep0045 = self.plugin['xep_0045']
|
||||||
|
try:
|
||||||
|
xep0045.joinMUC(muc_jid, self.nick, wait=True)
|
||||||
|
except InvalidJID:
|
||||||
|
logging.error("Could not join room: " + str(muc_jid))
|
||||||
|
return
|
||||||
|
|
||||||
|
# Configure the room. Really, we should only do this if the room is
|
||||||
|
# newly created.
|
||||||
|
form = None
|
||||||
|
try:
|
||||||
|
form = xep0045.getRoomConfig(muc_jid)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
if form:
|
||||||
|
xep0045.configureRoom(muc_jid, form)
|
||||||
|
else:
|
||||||
|
logging.error("Could not configure room: " + str(muc_jid))
|
||||||
|
|
||||||
|
def leave_muc(self, room):
|
||||||
|
if room not in self.rooms:
|
||||||
|
return
|
||||||
|
logging.debug("Leaving " + room)
|
||||||
|
self.rooms.remove(room)
|
||||||
|
muc_jid = JID(local=room, domain=options.conference_domain)
|
||||||
|
self.plugin['xep_0045'].leaveMUC(muc_jid, self.nick)
|
||||||
|
|
||||||
|
def message(self, msg):
|
||||||
|
try:
|
||||||
|
if msg["type"] == "groupchat":
|
||||||
|
return self.group(msg)
|
||||||
|
elif msg["type"] == "chat":
|
||||||
|
return self.private(msg)
|
||||||
|
else:
|
||||||
|
logging.warning("Got unexpected message type")
|
||||||
|
logging.warning(msg)
|
||||||
|
except Exception:
|
||||||
|
logging.exception("Error forwarding Jabber => Zulip")
|
||||||
|
|
||||||
|
def private(self, msg):
|
||||||
|
if options.mode == 'public' or msg['thread'] == u'\u1FFFE':
|
||||||
|
return
|
||||||
|
sender = jid_to_zulip(msg["from"])
|
||||||
|
recipient = jid_to_zulip(msg["to"])
|
||||||
|
|
||||||
|
zulip_message = dict(
|
||||||
|
sender = sender,
|
||||||
|
type = "private",
|
||||||
|
to = recipient,
|
||||||
|
content = msg["body"],
|
||||||
|
)
|
||||||
|
ret = self.zulip.client.send_message(zulip_message)
|
||||||
|
if ret.get("result") != "success":
|
||||||
|
logging.error(ret)
|
||||||
|
|
||||||
|
def group(self, msg):
|
||||||
|
if options.mode == 'personal' or msg["thread"] == u'\u1FFFE':
|
||||||
|
return
|
||||||
|
|
||||||
|
subject = msg["subject"]
|
||||||
|
if len(subject) == 0:
|
||||||
|
subject = "(no topic)"
|
||||||
|
stream = room_to_stream(msg['from'].local)
|
||||||
|
sender_nick = msg.get_mucnick()
|
||||||
|
if not sender_nick:
|
||||||
|
# Messages from the room itself have no nickname. We should not try
|
||||||
|
# to mirror these
|
||||||
|
return
|
||||||
|
jid = self.nickname_to_jid(msg.get_mucroom(), sender_nick)
|
||||||
|
sender = jid_to_zulip(jid)
|
||||||
|
zulip_message = dict(
|
||||||
|
forged = "yes",
|
||||||
|
sender = sender,
|
||||||
|
type = "stream",
|
||||||
|
subject = subject,
|
||||||
|
to = stream,
|
||||||
|
content = msg["body"],
|
||||||
|
)
|
||||||
|
ret = self.zulip.client.send_message(zulip_message)
|
||||||
|
if ret.get("result") != "success":
|
||||||
|
logging.error(ret)
|
||||||
|
|
||||||
|
def nickname_to_jid(self, room, nick):
|
||||||
|
jid = self.plugin['xep_0045'].getJidProperty(room, nick, "jid")
|
||||||
|
if (jid is None or jid == ''):
|
||||||
|
return JID(local=nick.replace(' ', ''), domain=self.boundjid.domain)
|
||||||
|
else:
|
||||||
|
return jid
|
||||||
|
|
||||||
|
class ZulipToJabberBot(object):
|
||||||
|
def __init__(self, zulip_client):
|
||||||
|
self.client = zulip_client
|
||||||
|
self.jabber = None
|
||||||
|
|
||||||
|
def set_jabber_client(self, client):
|
||||||
|
self.jabber = client
|
||||||
|
|
||||||
|
def process_event(self, event):
|
||||||
|
if event['type'] == 'message':
|
||||||
|
message = event["message"]
|
||||||
|
if message['sender_email'] != self.client.email:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
if message['type'] == 'stream':
|
||||||
|
self.stream_message(message)
|
||||||
|
elif message['type'] == 'private':
|
||||||
|
self.private_message(message)
|
||||||
|
except:
|
||||||
|
logging.exception("Exception forwarding Zulip => Jabber")
|
||||||
|
elif event['type'] == 'subscription':
|
||||||
|
self.process_subscription(event)
|
||||||
|
elif event['type'] == 'stream':
|
||||||
|
self.process_stream(event)
|
||||||
|
|
||||||
|
def stream_message(self, msg):
|
||||||
|
stream = msg['display_recipient']
|
||||||
|
if not stream.endswith("/xmpp"):
|
||||||
|
return
|
||||||
|
|
||||||
|
room = stream_to_room(stream)
|
||||||
|
jabber_recipient = JID(local=room, domain=options.conference_domain)
|
||||||
|
outgoing = self.jabber.make_message(
|
||||||
|
mto = jabber_recipient,
|
||||||
|
mbody = msg['content'],
|
||||||
|
mtype = 'groupchat')
|
||||||
|
outgoing['thread'] = u'\u1FFFE'
|
||||||
|
outgoing.send()
|
||||||
|
|
||||||
|
def private_message(self, msg):
|
||||||
|
for recipient in msg['display_recipient']:
|
||||||
|
if recipient["email"] == self.client.email:
|
||||||
|
continue
|
||||||
|
if not recipient["is_mirror_dummy"]:
|
||||||
|
continue
|
||||||
|
recip_email = recipient['email']
|
||||||
|
jabber_recipient = zulip_to_jid(recip_email, self.jabber.boundjid.domain)
|
||||||
|
outgoing = self.jabber.make_message(
|
||||||
|
mto = jabber_recipient,
|
||||||
|
mbody = msg['content'],
|
||||||
|
mtype = 'chat')
|
||||||
|
outgoing['thread'] = u'\u1FFFE'
|
||||||
|
outgoing.send()
|
||||||
|
|
||||||
|
def process_subscription(self, event):
|
||||||
|
if event['op'] == 'add':
|
||||||
|
streams = [s['name'].lower() for s in event['subscriptions']]
|
||||||
|
streams = [s for s in streams if s.endswith("/xmpp")]
|
||||||
|
for stream in streams:
|
||||||
|
self.jabber.join_muc(stream_to_room(stream))
|
||||||
|
if event['op'] == 'remove':
|
||||||
|
streams = [s['name'].lower() for s in event['subscriptions']]
|
||||||
|
streams = [s for s in streams if s.endswith("/xmpp")]
|
||||||
|
for stream in streams:
|
||||||
|
self.jabber.leave_muc(stream_to_room(stream))
|
||||||
|
|
||||||
|
def process_stream(self, event):
|
||||||
|
if event['op'] == 'occupy':
|
||||||
|
streams = [s['name'].lower() for s in event['streams']]
|
||||||
|
streams = [s for s in streams if s.endswith("/xmpp")]
|
||||||
|
for stream in streams:
|
||||||
|
self.jabber.join_muc(stream_to_room(stream))
|
||||||
|
if event['op'] == 'vacate':
|
||||||
|
streams = [s['name'].lower() for s in event['streams']]
|
||||||
|
streams = [s for s in streams if s.endswith("/xmpp")]
|
||||||
|
for stream in streams:
|
||||||
|
self.jabber.leave_muc(stream_to_room(stream))
|
||||||
|
|
||||||
|
def get_rooms(zulip):
|
||||||
|
def get_stream_infos(key, method):
|
||||||
|
ret = method()
|
||||||
|
if ret.get("result") != "success":
|
||||||
|
logging.error(ret)
|
||||||
|
sys.exit("Could not get initial list of Zulip %s" % (key,))
|
||||||
|
return ret[key]
|
||||||
|
|
||||||
|
if options.mode == 'public':
|
||||||
|
stream_infos = get_stream_infos("streams", zulip.client.get_streams)
|
||||||
|
else:
|
||||||
|
stream_infos = get_stream_infos("subscriptions", zulip.client.list_subscriptions)
|
||||||
|
|
||||||
|
rooms = []
|
||||||
|
for stream_info in stream_infos:
|
||||||
|
stream = stream_info['name']
|
||||||
|
if stream.endswith("/xmpp"):
|
||||||
|
rooms.append(stream_to_room(stream))
|
||||||
|
return rooms
|
||||||
|
|
||||||
|
def config_error(msg):
|
||||||
|
sys.stderr.write("%s\n" % (msg,))
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = optparse.OptionParser(epilog=
|
||||||
|
'''Most general and Jabber configuration options may also be specified in the
|
||||||
|
zulip configuration file under the jabber_mirror section (exceptions are noted
|
||||||
|
in their help sections). Keys have the same name as options with hyphens
|
||||||
|
replaced with underscores. Zulip configuration options go in the api section,
|
||||||
|
as normal.'''.replace("\n", " ")
|
||||||
|
)
|
||||||
|
parser.add_option('--mode',
|
||||||
|
default=None,
|
||||||
|
action='store',
|
||||||
|
help= \
|
||||||
|
'''Which mode to run in. Valid options are "personal" and "public". In
|
||||||
|
"personal" mode, the mirror uses an individual users' credentials and mirrors
|
||||||
|
all messages they send on Zulip to Jabber and all private Jabber messages to
|
||||||
|
Zulip. In "public" mode, the mirror uses the credentials for a dedicated mirror
|
||||||
|
user and mirrors messages sent to Jabber rooms to Zulip. Defaults to
|
||||||
|
"personal"'''.replace("\n", " "))
|
||||||
|
parser.add_option('--zulip-email-suffix',
|
||||||
|
default=None,
|
||||||
|
action='store',
|
||||||
|
help= \
|
||||||
|
'''Add the specified suffix to the local part of email addresses constructed
|
||||||
|
from JIDs and nicks before sending requests to the Zulip server, and remove the
|
||||||
|
suffix before sending requests to the Jabber server. For example, specifying
|
||||||
|
"+foo" will cause messages that are sent to the "bar" room by nickname "qux" to
|
||||||
|
be mirrored to the "bar/xmpp" stream in Zulip by user "qux+foo@example.com". This
|
||||||
|
option does not affect login credentials.'''.replace("\n", " "))
|
||||||
|
parser.add_option('-d', '--debug',
|
||||||
|
help='set logging to DEBUG. Can not be set via config file.',
|
||||||
|
action='store_const',
|
||||||
|
dest='log_level',
|
||||||
|
const=logging.DEBUG,
|
||||||
|
default=logging.INFO)
|
||||||
|
|
||||||
|
jabber_group = optparse.OptionGroup(parser, "Jabber configuration")
|
||||||
|
jabber_group.add_option('--jid',
|
||||||
|
default=None,
|
||||||
|
action='store',
|
||||||
|
help="Your Jabber JID. If a resource is specified, "
|
||||||
|
+ "it will be used as the nickname when joining MUCs. "
|
||||||
|
+ "Specifying the nickname is mostly useful if you want "
|
||||||
|
+ "to run the public mirror from a regular user instead of "
|
||||||
|
+ "from a dedicated account.")
|
||||||
|
jabber_group.add_option('--jabber-password',
|
||||||
|
default=None,
|
||||||
|
action='store',
|
||||||
|
help="Your Jabber password")
|
||||||
|
jabber_group.add_option('--conference-domain',
|
||||||
|
default=None,
|
||||||
|
action='store',
|
||||||
|
help="Your Jabber conference domain (E.g. conference.jabber.example.com). "
|
||||||
|
+ "If not specifed, \"conference.\" will be prepended to your JID's domain.")
|
||||||
|
jabber_group.add_option('--no-use-tls',
|
||||||
|
default=None,
|
||||||
|
action='store_true')
|
||||||
|
jabber_group.add_option('--jabber-server-address',
|
||||||
|
default=None,
|
||||||
|
action='store',
|
||||||
|
help="The hostname of your Jabber server. This is only needed if "
|
||||||
|
"your server is missing SRV records")
|
||||||
|
jabber_group.add_option('--jabber-server-port',
|
||||||
|
default='5222',
|
||||||
|
action='store',
|
||||||
|
help="The port of your Jabber server. This is only needed if "
|
||||||
|
"your server is missing SRV records")
|
||||||
|
|
||||||
|
parser.add_option_group(jabber_group)
|
||||||
|
parser.add_option_group(zulip.generate_option_group(parser, "zulip-"))
|
||||||
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
|
logging.basicConfig(level=options.log_level,
|
||||||
|
format='%(levelname)-8s %(message)s')
|
||||||
|
|
||||||
|
if options.zulip_config_file is None:
|
||||||
|
config_file = zulip.get_default_config_filename()
|
||||||
|
else:
|
||||||
|
config_file = options.zulip_config_file
|
||||||
|
|
||||||
|
config = SafeConfigParser()
|
||||||
|
try:
|
||||||
|
with file(config_file, 'r') as f:
|
||||||
|
config.readfp(f, config_file)
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
for option in ("jid", "jabber_password", "conference_domain", "mode", "zulip_email_suffix", "jabber_server_address", "jabber_server_port"):
|
||||||
|
if (getattr(options, option) is None
|
||||||
|
and config.has_option("jabber_mirror", option)):
|
||||||
|
setattr(options, option, config.get("jabber_mirror", option))
|
||||||
|
|
||||||
|
for option in ("no_use_tls",):
|
||||||
|
if getattr(options, option) is None:
|
||||||
|
if config.has_option("jabber_mirror", option):
|
||||||
|
setattr(options, option, config.getboolean("jabber_mirror", option))
|
||||||
|
else:
|
||||||
|
setattr(options, option, False)
|
||||||
|
|
||||||
|
if options.mode is None:
|
||||||
|
options.mode = "personal"
|
||||||
|
|
||||||
|
if options.zulip_email_suffix is None:
|
||||||
|
options.zulip_email_suffix = ''
|
||||||
|
|
||||||
|
if options.mode not in ('public', 'personal'):
|
||||||
|
config_error("Bad value for --mode: must be one of 'public' or 'personal'")
|
||||||
|
|
||||||
|
if None in (options.jid, options.jabber_password):
|
||||||
|
config_error("You must specify your Jabber JID and Jabber password either "
|
||||||
|
+ "in the Zulip configuration file or on the commandline")
|
||||||
|
|
||||||
|
zulip = ZulipToJabberBot(zulip.init_from_options(options, "JabberMirror/" + __version__))
|
||||||
|
# This won't work for open realms that don't have a consistent domain
|
||||||
|
options.zulip_domain = zulip.client.email.partition('@')[-1]
|
||||||
|
|
||||||
|
try:
|
||||||
|
jid = JID(options.jid)
|
||||||
|
except InvalidJID as e:
|
||||||
|
config_error("Bad JID: %s: %s" % (options.jid, e.message))
|
||||||
|
|
||||||
|
if options.conference_domain is None:
|
||||||
|
options.conference_domain = "conference.%s" % (jid.domain,)
|
||||||
|
|
||||||
|
xmpp = JabberToZulipBot(jid, options.jabber_password, get_rooms(zulip))
|
||||||
|
|
||||||
|
address = None
|
||||||
|
if options.jabber_server_address:
|
||||||
|
address = (options.jabber_server_address, options.jabber_server_port)
|
||||||
|
|
||||||
|
if not xmpp.connect(use_tls=not options.no_use_tls, address=address):
|
||||||
|
sys.exit("Unable to connect to Jabber server")
|
||||||
|
|
||||||
|
xmpp.set_zulip_client(zulip)
|
||||||
|
zulip.set_jabber_client(xmpp)
|
||||||
|
|
||||||
|
xmpp.process(block=False)
|
||||||
|
if options.mode == 'public':
|
||||||
|
event_types = ['stream']
|
||||||
|
else:
|
||||||
|
event_types = ['message', 'subscription']
|
||||||
|
|
||||||
|
try:
|
||||||
|
logging.info("Connecting to Zulip.")
|
||||||
|
zulip.client.call_on_each_event(zulip.process_event,
|
||||||
|
event_types=event_types)
|
||||||
|
except BaseException as e:
|
||||||
|
logging.exception("Exception in main loop")
|
||||||
|
xmpp.abort()
|
||||||
|
sys.exit(1)
|
||||||
@@ -28,7 +28,6 @@ import traceback
|
|||||||
import signal
|
import signal
|
||||||
|
|
||||||
from zephyr_mirror_backend import parse_args
|
from zephyr_mirror_backend import parse_args
|
||||||
from zephyr_mirror_backend import RandomExponentialBackoff
|
|
||||||
|
|
||||||
def die(signal, frame):
|
def die(signal, frame):
|
||||||
# We actually want to exit, so run os._exit (so as not to be caught and restarted)
|
# We actually want to exit, so run os._exit (so as not to be caught and restarted)
|
||||||
@@ -38,6 +37,9 @@ signal.signal(signal.SIGINT, die)
|
|||||||
|
|
||||||
(options, args) = parse_args()
|
(options, args) = parse_args()
|
||||||
|
|
||||||
|
sys.path[:0] = [os.path.join(options.root_path, 'api')]
|
||||||
|
from zulip import RandomExponentialBackoff
|
||||||
|
|
||||||
args = [os.path.join(options.root_path, "user_root", "zephyr_mirror_backend.py")]
|
args = [os.path.join(options.root_path, "user_root", "zephyr_mirror_backend.py")]
|
||||||
args.extend(sys.argv[1:])
|
args.extend(sys.argv[1:])
|
||||||
|
|
||||||
@@ -60,7 +62,7 @@ if options.forward_class_messages and not options.noshard:
|
|||||||
pass
|
pass
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
backoff = RandomExponentialBackoff()
|
backoff = RandomExponentialBackoff(timeout_success_equivalent=300)
|
||||||
while backoff.keep_going():
|
while backoff.keep_going():
|
||||||
print "Starting zephyr mirroring bot"
|
print "Starting zephyr mirroring bot"
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -37,39 +37,8 @@ import signal
|
|||||||
import logging
|
import logging
|
||||||
import hashlib
|
import hashlib
|
||||||
import tempfile
|
import tempfile
|
||||||
import random
|
|
||||||
import select
|
import select
|
||||||
|
|
||||||
class CountingBackoff(object):
|
|
||||||
def __init__(self, maximum_retries=10):
|
|
||||||
self.number_of_retries = 0
|
|
||||||
self.maximum_retries = maximum_retries
|
|
||||||
|
|
||||||
def keep_going(self):
|
|
||||||
return self.number_of_retries < self.maximum_retries
|
|
||||||
|
|
||||||
def succeed(self):
|
|
||||||
self.number_of_retries = 0
|
|
||||||
|
|
||||||
def fail(self):
|
|
||||||
self.number_of_retries = min(self.number_of_retries + 1,
|
|
||||||
self.maximum_retries)
|
|
||||||
|
|
||||||
class RandomExponentialBackoff(CountingBackoff):
|
|
||||||
def fail(self):
|
|
||||||
self.number_of_retries = min(self.number_of_retries + 1,
|
|
||||||
self.maximum_retries)
|
|
||||||
# Exponential growth with ratio sqrt(2); compute random delay
|
|
||||||
# between x and 2x where x is growing exponentially
|
|
||||||
delay_scale = int(2 ** (self.number_of_retries / 2.0 - 1)) + 1
|
|
||||||
delay = delay_scale + random.randint(1, delay_scale)
|
|
||||||
message = "Sleeping for %ss [max %s] before retrying." % (delay, delay_scale * 2)
|
|
||||||
try:
|
|
||||||
logger.warning(message)
|
|
||||||
except NameError:
|
|
||||||
print message
|
|
||||||
time.sleep(delay)
|
|
||||||
|
|
||||||
DEFAULT_SITE = "https://api.zulip.com"
|
DEFAULT_SITE = "https://api.zulip.com"
|
||||||
|
|
||||||
class States:
|
class States:
|
||||||
@@ -401,7 +370,7 @@ def process_notice(notice, log):
|
|||||||
if is_personal:
|
if is_personal:
|
||||||
if body.startswith("CC:"):
|
if body.startswith("CC:"):
|
||||||
is_huddle = True
|
is_huddle = True
|
||||||
# Map "CC: sipbtest espuser" => "starnine@mit.edu,espuser@mit.edu"
|
# Map "CC: user1 user2" => "user1@mit.edu, user2@mit.edu"
|
||||||
huddle_recipients = [to_zulip_username(x.strip()) for x in
|
huddle_recipients = [to_zulip_username(x.strip()) for x in
|
||||||
body.split("\n")[0][4:].split()]
|
body.split("\n")[0][4:].split()]
|
||||||
if notice.sender not in huddle_recipients:
|
if notice.sender not in huddle_recipients:
|
||||||
@@ -478,7 +447,7 @@ def quit_failed_initialization(message):
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def zephyr_init_autoretry():
|
def zephyr_init_autoretry():
|
||||||
backoff = RandomExponentialBackoff()
|
backoff = zulip.RandomExponentialBackoff()
|
||||||
while backoff.keep_going():
|
while backoff.keep_going():
|
||||||
try:
|
try:
|
||||||
# zephyr.init() tries to clear old subscriptions, and thus
|
# zephyr.init() tries to clear old subscriptions, and thus
|
||||||
@@ -493,7 +462,7 @@ def zephyr_init_autoretry():
|
|||||||
quit_failed_initialization("Could not initialize Zephyr library, quitting!")
|
quit_failed_initialization("Could not initialize Zephyr library, quitting!")
|
||||||
|
|
||||||
def zephyr_load_session_autoretry(session_path):
|
def zephyr_load_session_autoretry(session_path):
|
||||||
backoff = RandomExponentialBackoff()
|
backoff = zulip.RandomExponentialBackoff()
|
||||||
while backoff.keep_going():
|
while backoff.keep_going():
|
||||||
try:
|
try:
|
||||||
session = file(session_path, "r").read()
|
session = file(session_path, "r").read()
|
||||||
@@ -508,7 +477,7 @@ def zephyr_load_session_autoretry(session_path):
|
|||||||
quit_failed_initialization("Could not load saved Zephyr session, quitting!")
|
quit_failed_initialization("Could not load saved Zephyr session, quitting!")
|
||||||
|
|
||||||
def zephyr_subscribe_autoretry(sub):
|
def zephyr_subscribe_autoretry(sub):
|
||||||
backoff = RandomExponentialBackoff()
|
backoff = zulip.RandomExponentialBackoff()
|
||||||
while backoff.keep_going():
|
while backoff.keep_going():
|
||||||
try:
|
try:
|
||||||
zephyr.Subscriptions().add(sub)
|
zephyr.Subscriptions().add(sub)
|
||||||
@@ -629,7 +598,9 @@ Feedback button or at support@zulip.com."""
|
|||||||
wrapped_content = "\n".join("\n".join(wrapper.wrap(line))
|
wrapped_content = "\n".join("\n".join(wrapper.wrap(line))
|
||||||
for line in message["content"].replace("@", "@@").split("\n"))
|
for line in message["content"].replace("@", "@@").split("\n"))
|
||||||
|
|
||||||
zwrite_args = ["zwrite", "-n", "-s", message["sender_full_name"], "-F", "Zephyr error: See http://zephyr.1ts.org/wiki/df"]
|
zwrite_args = ["zwrite", "-n", "-s", message["sender_full_name"],
|
||||||
|
"-F", "Zephyr error: See http://zephyr.1ts.org/wiki/df",
|
||||||
|
"-x", "UTF-8"]
|
||||||
|
|
||||||
# Hack to make ctl's fake username setup work :)
|
# Hack to make ctl's fake username setup work :)
|
||||||
if message['type'] == "stream" and zulip_account_email == "ctl@mit.edu":
|
if message['type'] == "stream" and zulip_account_email == "ctl@mit.edu":
|
||||||
@@ -763,7 +734,7 @@ def maybe_forward_to_zephyr(message):
|
|||||||
logger.exception("Error forwarding message:")
|
logger.exception("Error forwarding message:")
|
||||||
|
|
||||||
def zulip_to_zephyr(options):
|
def zulip_to_zephyr(options):
|
||||||
# Sync messages from zephyr to zulip
|
# Sync messages from zulip to zephyr
|
||||||
logger.info("Starting syncing messages.")
|
logger.info("Starting syncing messages.")
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[program:zmirror-USERNAME]
|
[program:zmirror-USERNAME]
|
||||||
command=python /home/zulip/zulip/bots/zephyr_mirror_backend.py --root-path=/home/zulip/zulip/bots --user=USERNAME --log-path=/home/zulip/logs/mirror-log-%(program_name)s --use-sessions --session-path=/home/zulip/zephyr_sessions/%(program_name)s --api-key-file=/home/zulip/api-keys/%(program_name)s --ignore-expired-tickets --nagios-path=/home/zulip/mirror_status/%(program_name)s --nagios-class=zulip-mirror-nagios
|
command=python /home/zulip/zulip/bots/zephyr_mirror_backend.py --root-path=/home/zulip/zulip --user=USERNAME --log-path=/home/zulip/logs/mirror-log-%(program_name)s --use-sessions --session-path=/home/zulip/zephyr_sessions/%(program_name)s --api-key-file=/home/zulip/api-keys/%(program_name)s --ignore-expired-tickets --nagios-path=/home/zulip/mirror_status/%(program_name)s --nagios-class=zulip-mirror-nagios
|
||||||
priority=200 ; the relative start priority (default 999)
|
priority=200 ; the relative start priority (default 999)
|
||||||
autostart=true ; start at supervisord start (default: true)
|
autostart=true ; start at supervisord start (default: true)
|
||||||
autorestart=true ; whether/when to restart (default: unexpected)
|
autorestart=true ; whether/when to restart (default: unexpected)
|
||||||
|
|||||||
@@ -39,4 +39,4 @@ def format_commit_message(author, subject, commit_id):
|
|||||||
return '!avatar(%s) [%s](https://git.zulip.net/eng/zulip/commit/%s)\n' % (author, subject, commit_id)
|
return '!avatar(%s) [%s](https://git.zulip.net/eng/zulip/commit/%s)\n' % (author, subject, commit_id)
|
||||||
|
|
||||||
ZULIP_API_PATH = "/home/zulip/zulip/api"
|
ZULIP_API_PATH = "/home/zulip/zulip/api"
|
||||||
ZULIP_SITE = "https://staging.zulip.com"
|
ZULIP_SITE = "https://zulip.com"
|
||||||
|
|||||||
@@ -11,4 +11,4 @@ TRAC_BASE_TICKET_URL = "https://trac.zulip.net/ticket"
|
|||||||
|
|
||||||
TRAC_NOTIFY_FIELDS = ["description", "summary", "resolution", "comment", "owner"]
|
TRAC_NOTIFY_FIELDS = ["description", "summary", "resolution", "comment", "owner"]
|
||||||
ZULIP_API_PATH = "/home/zulip/zulip/api"
|
ZULIP_API_PATH = "/home/zulip/zulip/api"
|
||||||
ZULIP_SITE = "https://staging.zulip.com"
|
ZULIP_SITE = "https://zulip.com"
|
||||||
|
|||||||
@@ -4,4 +4,4 @@
|
|||||||
[api]
|
[api]
|
||||||
email = nagios-bot@zulip.com
|
email = nagios-bot@zulip.com
|
||||||
key = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
key = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
site = https://staging.zulip.com
|
site = https://zulip.com
|
||||||
|
|||||||
@@ -1,45 +1,29 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import datetime
|
from __future__ import unicode_literals
|
||||||
from south.db import db
|
|
||||||
from south.v2 import SchemaMigration
|
from django.db import models, migrations
|
||||||
from django.db import models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(SchemaMigration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
def forwards(self, orm):
|
dependencies = [
|
||||||
# Adding model 'Confirmation'
|
('contenttypes', '0001_initial'),
|
||||||
db.create_table('confirmation_confirmation', (
|
]
|
||||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
|
||||||
('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
|
|
||||||
('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
|
|
||||||
('date_sent', self.gf('django.db.models.fields.DateTimeField')()),
|
|
||||||
('confirmation_key', self.gf('django.db.models.fields.CharField')(max_length=40)),
|
|
||||||
))
|
|
||||||
db.send_create_signal('confirmation', ['Confirmation'])
|
|
||||||
|
|
||||||
|
operations = [
|
||||||
def backwards(self, orm):
|
migrations.CreateModel(
|
||||||
# Deleting model 'Confirmation'
|
name='Confirmation',
|
||||||
db.delete_table('confirmation_confirmation')
|
fields=[
|
||||||
|
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||||
|
('object_id', models.PositiveIntegerField()),
|
||||||
models = {
|
('date_sent', models.DateTimeField(verbose_name='sent')),
|
||||||
'confirmation.confirmation': {
|
('confirmation_key', models.CharField(max_length=40, verbose_name='activation key')),
|
||||||
'Meta': {'object_name': 'Confirmation'},
|
('content_type', models.ForeignKey(to='contenttypes.ContentType')),
|
||||||
'confirmation_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
|
],
|
||||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
options={
|
||||||
'date_sent': ('django.db.models.fields.DateTimeField', [], {}),
|
'verbose_name': 'confirmation email',
|
||||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
'verbose_name_plural': 'confirmation emails',
|
||||||
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {})
|
},
|
||||||
},
|
bases=(models.Model,),
|
||||||
'contenttypes.contenttype': {
|
),
|
||||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
]
|
||||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
|
||||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
|
||||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
|
||||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
complete_apps = ['confirmation']
|
|
||||||
|
|||||||
@@ -34,9 +34,10 @@ def generate_key():
|
|||||||
return generate_random_token(40)
|
return generate_random_token(40)
|
||||||
|
|
||||||
def generate_activation_url(key):
|
def generate_activation_url(key):
|
||||||
current_site = Site.objects.get_current()
|
return u'%s%s%s' % (settings.EXTERNAL_URI_SCHEME,
|
||||||
return u'https://%s%s' % (current_site.domain,
|
settings.EXTERNAL_HOST,
|
||||||
reverse('confirmation.views.confirm', kwargs={'confirmation_key': key}))
|
reverse('confirmation.views.confirm',
|
||||||
|
kwargs={'confirmation_key': key}))
|
||||||
|
|
||||||
|
|
||||||
class ConfirmationManager(models.Manager):
|
class ConfirmationManager(models.Manager):
|
||||||
@@ -48,7 +49,7 @@ class ConfirmationManager(models.Manager):
|
|||||||
except self.model.DoesNotExist:
|
except self.model.DoesNotExist:
|
||||||
return False
|
return False
|
||||||
obj = confirmation.content_object
|
obj = confirmation.content_object
|
||||||
status_field = get_status_field(obj._meta.app_label, obj._meta.module_name)
|
status_field = get_status_field(obj._meta.app_label, obj._meta.model_name)
|
||||||
setattr(obj, status_field, getattr(settings, 'STATUS_ACTIVE', 1))
|
setattr(obj, status_field, getattr(settings, 'STATUS_ACTIVE', 1))
|
||||||
obj.save()
|
obj.save()
|
||||||
return obj
|
return obj
|
||||||
@@ -74,7 +75,7 @@ class ConfirmationManager(models.Manager):
|
|||||||
if additional_context is not None:
|
if additional_context is not None:
|
||||||
context.update(additional_context)
|
context.update(additional_context)
|
||||||
templates = [
|
templates = [
|
||||||
'confirmation/%s_confirmation_email_subject.txt' % obj._meta.module_name,
|
'confirmation/%s_confirmation_email_subject.txt' % obj._meta.model_name,
|
||||||
'confirmation/confirmation_email_subject.txt',
|
'confirmation/confirmation_email_subject.txt',
|
||||||
]
|
]
|
||||||
if subject_template_path:
|
if subject_template_path:
|
||||||
@@ -83,7 +84,7 @@ class ConfirmationManager(models.Manager):
|
|||||||
template = loader.select_template(templates)
|
template = loader.select_template(templates)
|
||||||
subject = template.render(context).strip().replace(u'\n', u' ') # no newlines, please
|
subject = template.render(context).strip().replace(u'\n', u' ') # no newlines, please
|
||||||
templates = [
|
templates = [
|
||||||
'confirmation/%s_confirmation_email_body.txt' % obj._meta.module_name,
|
'confirmation/%s_confirmation_email_body.txt' % obj._meta.model_name,
|
||||||
'confirmation/confirmation_email_body.txt',
|
'confirmation/confirmation_email_body.txt',
|
||||||
]
|
]
|
||||||
if body_template_path:
|
if body_template_path:
|
||||||
|
|||||||
@@ -31,13 +31,13 @@ def confirm(request, confirmation_key):
|
|||||||
'key': confirmation_key,
|
'key': confirmation_key,
|
||||||
'full_name': request.GET.get("full_name", None),
|
'full_name': request.GET.get("full_name", None),
|
||||||
'support_email': settings.ZULIP_ADMINISTRATOR,
|
'support_email': settings.ZULIP_ADMINISTRATOR,
|
||||||
'enterprise': settings.ENTERPRISE
|
'voyager': settings.VOYAGER
|
||||||
}
|
}
|
||||||
templates = [
|
templates = [
|
||||||
'confirmation/confirm.html',
|
'confirmation/confirm.html',
|
||||||
]
|
]
|
||||||
if obj:
|
if obj:
|
||||||
# if we have an object, we can use specific template
|
# if we have an object, we can use specific template
|
||||||
templates.insert(0, 'confirmation/confirm_%s.html' % obj._meta.module_name)
|
templates.insert(0, 'confirmation/confirm_%s.html' % obj._meta.model_name)
|
||||||
return render_to_response(templates, ctx,
|
return render_to_response(templates, ctx,
|
||||||
context_instance=RequestContext(request))
|
context_instance=RequestContext(request))
|
||||||
|
|||||||
@@ -2,20 +2,8 @@ from django.conf.urls import patterns, url
|
|||||||
from django.views.generic import TemplateView, RedirectView
|
from django.views.generic import TemplateView, RedirectView
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
# Job postings
|
|
||||||
url(r'^jobs/$', TemplateView.as_view(template_name='corporate/jobs/index.html')),
|
|
||||||
url(r'^jobs/lead-designer/$', TemplateView.as_view(template_name='corporate/jobs/lead-designer.html')),
|
|
||||||
|
|
||||||
# Zephyr/MIT
|
# Zephyr/MIT
|
||||||
url(r'^zephyr/$', TemplateView.as_view(template_name='corporate/zephyr.html')),
|
url(r'^zephyr/$', TemplateView.as_view(template_name='corporate/zephyr.html')),
|
||||||
url(r'^mit/$', TemplateView.as_view(template_name='corporate/mit.html')),
|
url(r'^mit/$', TemplateView.as_view(template_name='corporate/mit.html')),
|
||||||
url(r'^zephyr-mirror/$', TemplateView.as_view(template_name='corporate/zephyr-mirror.html')),
|
url(r'^zephyr-mirror/$', TemplateView.as_view(template_name='corporate/zephyr-mirror.html')),
|
||||||
|
|
||||||
# Marketing
|
|
||||||
url(r'^compare/$', TemplateView.as_view(template_name='corporate/compare.html')),
|
|
||||||
# signup form
|
|
||||||
url(r'^signup/$', TemplateView.as_view(template_name='corporate/signup.html'),
|
|
||||||
name='signup'),
|
|
||||||
# TODO: The beta signup view should probably be moved to corporate.
|
|
||||||
url(r'^signup/sign-me-up$', 'zerver.views.beta_signup_submission', name='beta-signup-submission'),
|
|
||||||
)
|
)
|
||||||
|
|||||||
1
docs/.gitignore
vendored
Normal file
1
docs/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
_build
|
||||||
192
docs/Makefile
Normal file
192
docs/Makefile
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
# Makefile for Sphinx documentation
|
||||||
|
#
|
||||||
|
|
||||||
|
# You can set these variables from the command line.
|
||||||
|
SPHINXOPTS =
|
||||||
|
SPHINXBUILD = sphinx-build
|
||||||
|
PAPER =
|
||||||
|
BUILDDIR = _build
|
||||||
|
|
||||||
|
# User-friendly check for sphinx-build
|
||||||
|
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
|
||||||
|
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Internal variables.
|
||||||
|
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||||
|
PAPEROPT_letter = -D latex_paper_size=letter
|
||||||
|
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||||
|
# the i18n builder cannot share the environment and doctrees with the others
|
||||||
|
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||||
|
|
||||||
|
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo "Please use \`make <target>' where <target> is one of"
|
||||||
|
@echo " html to make standalone HTML files"
|
||||||
|
@echo " dirhtml to make HTML files named index.html in directories"
|
||||||
|
@echo " singlehtml to make a single large HTML file"
|
||||||
|
@echo " pickle to make pickle files"
|
||||||
|
@echo " json to make JSON files"
|
||||||
|
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||||
|
@echo " qthelp to make HTML files and a qthelp project"
|
||||||
|
@echo " applehelp to make an Apple Help Book"
|
||||||
|
@echo " devhelp to make HTML files and a Devhelp project"
|
||||||
|
@echo " epub to make an epub"
|
||||||
|
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||||
|
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||||
|
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
|
||||||
|
@echo " text to make text files"
|
||||||
|
@echo " man to make manual pages"
|
||||||
|
@echo " texinfo to make Texinfo files"
|
||||||
|
@echo " info to make Texinfo files and run them through makeinfo"
|
||||||
|
@echo " gettext to make PO message catalogs"
|
||||||
|
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||||
|
@echo " xml to make Docutils-native XML files"
|
||||||
|
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
|
||||||
|
@echo " linkcheck to check all external links for integrity"
|
||||||
|
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||||
|
@echo " coverage to run coverage check of the documentation (if enabled)"
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(BUILDDIR)/*
|
||||||
|
|
||||||
|
html:
|
||||||
|
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||||
|
|
||||||
|
dirhtml:
|
||||||
|
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||||
|
|
||||||
|
singlehtml:
|
||||||
|
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||||
|
|
||||||
|
pickle:
|
||||||
|
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can process the pickle files."
|
||||||
|
|
||||||
|
json:
|
||||||
|
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can process the JSON files."
|
||||||
|
|
||||||
|
htmlhelp:
|
||||||
|
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||||
|
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||||
|
|
||||||
|
qthelp:
|
||||||
|
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||||
|
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||||
|
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/zulip-contributor-docs.qhcp"
|
||||||
|
@echo "To view the help file:"
|
||||||
|
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/zulip-contributor-docs.qhc"
|
||||||
|
|
||||||
|
applehelp:
|
||||||
|
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
|
||||||
|
@echo "N.B. You won't be able to view it unless you put it in" \
|
||||||
|
"~/Library/Documentation/Help or install it in your application" \
|
||||||
|
"bundle."
|
||||||
|
|
||||||
|
devhelp:
|
||||||
|
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||||
|
@echo
|
||||||
|
@echo "Build finished."
|
||||||
|
@echo "To view the help file:"
|
||||||
|
@echo "# mkdir -p $$HOME/.local/share/devhelp/zulip-contributor-docs"
|
||||||
|
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/zulip-contributor-docs"
|
||||||
|
@echo "# devhelp"
|
||||||
|
|
||||||
|
epub:
|
||||||
|
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||||
|
|
||||||
|
latex:
|
||||||
|
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||||
|
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||||
|
"(use \`make latexpdf' here to do that automatically)."
|
||||||
|
|
||||||
|
latexpdf:
|
||||||
|
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||||
|
@echo "Running LaTeX files through pdflatex..."
|
||||||
|
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||||
|
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||||
|
|
||||||
|
latexpdfja:
|
||||||
|
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||||
|
@echo "Running LaTeX files through platex and dvipdfmx..."
|
||||||
|
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
|
||||||
|
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||||
|
|
||||||
|
text:
|
||||||
|
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||||
|
|
||||||
|
man:
|
||||||
|
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||||
|
|
||||||
|
texinfo:
|
||||||
|
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||||
|
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||||
|
"(use \`make info' here to do that automatically)."
|
||||||
|
|
||||||
|
info:
|
||||||
|
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||||
|
@echo "Running Texinfo files through makeinfo..."
|
||||||
|
make -C $(BUILDDIR)/texinfo info
|
||||||
|
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||||
|
|
||||||
|
gettext:
|
||||||
|
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||||
|
|
||||||
|
changes:
|
||||||
|
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||||
|
@echo
|
||||||
|
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||||
|
|
||||||
|
linkcheck:
|
||||||
|
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||||
|
@echo
|
||||||
|
@echo "Link check complete; look for any errors in the above output " \
|
||||||
|
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||||
|
|
||||||
|
doctest:
|
||||||
|
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||||
|
@echo "Testing of doctests in the sources finished, look at the " \
|
||||||
|
"results in $(BUILDDIR)/doctest/output.txt."
|
||||||
|
|
||||||
|
coverage:
|
||||||
|
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
|
||||||
|
@echo "Testing of coverage in the sources finished, look at the " \
|
||||||
|
"results in $(BUILDDIR)/coverage/python.txt."
|
||||||
|
|
||||||
|
xml:
|
||||||
|
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
|
||||||
|
|
||||||
|
pseudoxml:
|
||||||
|
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
|
||||||
23
docs/README.md
Normal file
23
docs/README.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
These docs are written in rST, and are included on the zulip.org website
|
||||||
|
as well as on each development installation. Many of these docs
|
||||||
|
have been ported from the internal docs of Zulip Inc.,
|
||||||
|
and may need to be updated for use in the open source project.
|
||||||
|
|
||||||
|
To generate HTML docs locally from rST:
|
||||||
|
|
||||||
|
* `pip install sphinx`
|
||||||
|
* In this directory, `make html`. Output appears in a `_build/html` subdirectory.
|
||||||
|
|
||||||
|
To create rST from MediaWiki input:
|
||||||
|
|
||||||
|
* Use `pandoc -r mediawiki -w rst` on MediaWiki source.
|
||||||
|
* Use unescape.py to remove any leftover HTML entities (often inside <pre>
|
||||||
|
tags and the like).
|
||||||
|
|
||||||
|
We can use pandoc to translate mediawiki into reStructuredText, but some things need fixing up:
|
||||||
|
|
||||||
|
* Add page titles.
|
||||||
|
* Review pages for formatting (especially inline code chunks) and content.
|
||||||
|
* Fix wiki links?
|
||||||
|
* Add pages to the table of contents (`index.rst`).
|
||||||
|
|
||||||
10
docs/_static/theme_overrides.css
vendored
Normal file
10
docs/_static/theme_overrides.css
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/* override table width restrictions */
|
||||||
|
.wy-table-responsive table td, .wy-table-responsive table th {
|
||||||
|
/* !important prevents the common CSS stylesheets from
|
||||||
|
overriding this as on RTD they are loaded after this stylesheet */
|
||||||
|
white-space: normal !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-table-responsive {
|
||||||
|
overflow: visible !important;
|
||||||
|
}
|
||||||
484
docs/code-style.rst
Normal file
484
docs/code-style.rst
Normal file
@@ -0,0 +1,484 @@
|
|||||||
|
==========================
|
||||||
|
Code style and conventions
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Be consistent!
|
||||||
|
==============
|
||||||
|
|
||||||
|
Look at the surrounding code, or a similar part of the project, and
|
||||||
|
try to do the same thing. If you think the other code has actively bad
|
||||||
|
style, fix it (in a separate commit).
|
||||||
|
|
||||||
|
When in doubt, send an email to zulip-devel@googlegroups.com with your
|
||||||
|
question.
|
||||||
|
|
||||||
|
Lint tools
|
||||||
|
==========
|
||||||
|
|
||||||
|
You can run them all at once with
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
./tools/lint-all
|
||||||
|
|
||||||
|
You can set this up as a local Git commit hook with
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
``tools/setup-git-repo``
|
||||||
|
|
||||||
|
The Vagrant setup process runs this for you.
|
||||||
|
|
||||||
|
``lint-all`` runs many lint checks in parallel, including
|
||||||
|
|
||||||
|
- Javascript (`JSLint <http://www.jslint.com/>`__)
|
||||||
|
|
||||||
|
``tools/jslint/check-all.js`` contains a pretty fine-grained set of
|
||||||
|
JSLint options, rule exceptions, and allowed global variables. If you
|
||||||
|
add a new global, you'll need to add it to the list.
|
||||||
|
|
||||||
|
- Python (`Pyflakes <http://pypi.python.org/pypi/pyflakes>`__)
|
||||||
|
- templates
|
||||||
|
- Puppet configuration
|
||||||
|
- custom checks (e.g. trailing whitespace and spaces-not-tabs)
|
||||||
|
|
||||||
|
Secrets
|
||||||
|
=======
|
||||||
|
|
||||||
|
Please don't put any passwords, secret access keys, etc. inline in the
|
||||||
|
code. Instead, use the ``get_secret`` function in
|
||||||
|
``zproject/settings.py`` to read secrets from ``/etc/zulip/secrets.conf``.
|
||||||
|
|
||||||
|
Dangerous constructs
|
||||||
|
====================
|
||||||
|
|
||||||
|
Misuse of database queries
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
Look out for Django code like this::
|
||||||
|
|
||||||
|
[Foo.objects.get(id=bar.x.id)
|
||||||
|
for bar in Bar.objects.filter(...)
|
||||||
|
if bar.baz < 7]
|
||||||
|
|
||||||
|
This will make one database query for each ``Bar``, which is slow in
|
||||||
|
production (but not in local testing!). Instead of a list comprehension,
|
||||||
|
write a single query using Django's `QuerySet
|
||||||
|
API <https://docs.djangoproject.com/en/dev/ref/models/querysets/>`__.
|
||||||
|
|
||||||
|
If you can't rewrite it as a single query, that's a sign that something
|
||||||
|
is wrong with the database schema. So don't defer this optimization when
|
||||||
|
performing schema changes, or else you may later find that it's
|
||||||
|
impossible.
|
||||||
|
|
||||||
|
UserProfile.objects.get() / Client.objects.get / etc.
|
||||||
|
-----------------------------------------------------
|
||||||
|
|
||||||
|
In our Django code, never do direct
|
||||||
|
``UserProfile.objects.get(email=foo)`` database queries. Instead always
|
||||||
|
use ``get_user_profile_by_{email,id}``. There are 3 reasons for this:
|
||||||
|
|
||||||
|
#. It's guaranteed to correctly do a case-inexact lookup
|
||||||
|
#. It fetches the user object from memcached, which is faster
|
||||||
|
#. It always fetches a UserProfile object which has been queried using
|
||||||
|
.selected\_related(), and thus will perform well when one later
|
||||||
|
accesses related models like the Realm.
|
||||||
|
|
||||||
|
Similarly we have ``get_client`` and ``get_stream`` functions to fetch
|
||||||
|
those commonly accessed objects via memcached.
|
||||||
|
|
||||||
|
Using Django model objects as keys in sets/dicts
|
||||||
|
------------------------------------------------
|
||||||
|
|
||||||
|
Don't use Django model objects as keys in sets/dictionaries -- you will
|
||||||
|
get unexpected behavior when dealing with objects obtained from
|
||||||
|
different database queries:
|
||||||
|
|
||||||
|
For example,
|
||||||
|
``UserProfile.objects.only("id").get(id=17) in set([UserProfile.objects.get(id=17)])``
|
||||||
|
is False
|
||||||
|
|
||||||
|
You should work with the IDs instead.
|
||||||
|
|
||||||
|
user\_profile.save()
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
You should always pass the update\_fields keyword argument to .save()
|
||||||
|
when modifying an existing Django model object. By default, .save() will
|
||||||
|
overwrite every value in the column, which results in lots of race
|
||||||
|
conditions where unrelated changes made by one thread can be
|
||||||
|
accidentally overwritten by another thread that fetched its UserProfile
|
||||||
|
object before the first thread wrote out its change.
|
||||||
|
|
||||||
|
Using raw saves to update important model objects
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
In most cases, we already have a function in zephyr/lib/actions.py with
|
||||||
|
a name like do\_activate\_user that will correctly handle lookups,
|
||||||
|
caching, and notifying running browsers via the event system about your
|
||||||
|
change. So please check whether such a function exists before writing
|
||||||
|
new code to modify a model object, since your new code has a good chance
|
||||||
|
of getting at least one of these things wrong.
|
||||||
|
|
||||||
|
``x.attr('zid')`` vs. ``rows.id(x)``
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
Our message row DOM elements have a custom attribute ``zid`` which
|
||||||
|
contains the numerical message ID. **Don't access this directly as**
|
||||||
|
``x.attr('zid')`` ! The result will be a string and comparisons (e.g.
|
||||||
|
with ``<=``) will give the wrong result, occasionally, just enough to
|
||||||
|
make a bug that's impossible to track down.
|
||||||
|
|
||||||
|
You should instead use the ``id`` function from the ``rows`` module, as
|
||||||
|
in ``rows.id(x)``. This returns a number. Even in cases where you do
|
||||||
|
want a string, use the ``id`` function, as it will simplify future code
|
||||||
|
changes. In most contexts in JavaScript where a string is needed, you
|
||||||
|
can pass a number without any explicit conversion.
|
||||||
|
|
||||||
|
Javascript var
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Always declare Javascript variables using ``var``::
|
||||||
|
|
||||||
|
var x = ...;
|
||||||
|
|
||||||
|
In a function, ``var`` is necessary or else ``x`` will be a global
|
||||||
|
variable. For variables declared at global scope, this has no effect,
|
||||||
|
but we do it for consistency.
|
||||||
|
|
||||||
|
Javascript has function scope only, not block scope. This means that a
|
||||||
|
``var`` declaration inside a ``for`` or ``if`` acts the same as a
|
||||||
|
``var`` declaration at the beginning of the surrounding ``function``. To
|
||||||
|
avoid confusion, declare all variables at the top of a function.
|
||||||
|
|
||||||
|
Javascript ``for (i in myArray)``
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
Don't use it:
|
||||||
|
`[1] <http://stackoverflow.com/questions/500504/javascript-for-in-with-arrays>`__,
|
||||||
|
`[2] <http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml#for-in_loop>`__,
|
||||||
|
`[3] <http://www.jslint.com/lint.html#forin>`__
|
||||||
|
|
||||||
|
jQuery global state
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Don't mess with jQuery global state once the app has loaded. Code like
|
||||||
|
this is very dangerous::
|
||||||
|
|
||||||
|
$.ajaxSetup({ async: false });
|
||||||
|
$.get(...);
|
||||||
|
$.ajaxSetup({ async: true });
|
||||||
|
|
||||||
|
jQuery and the browser are free to run other code while the request is
|
||||||
|
pending, which could perform other Ajax requests with the altered
|
||||||
|
settings.
|
||||||
|
|
||||||
|
Instead, switch to the more general |ajax|_ function, which can take options
|
||||||
|
like ``async``.
|
||||||
|
|
||||||
|
.. |ajax| replace:: ``$.ajax``
|
||||||
|
.. _ajax: http://api.jquery.com/jQuery.ajax
|
||||||
|
|
||||||
|
State and logs files
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Do not write state and logs files inside the current working directory
|
||||||
|
in the production environment. This will not how you expect, because the
|
||||||
|
current working directory for the app changes every time we do a deploy.
|
||||||
|
Instead, hardcode a path in settings.py -- see SERVER\_LOG\_PATH in
|
||||||
|
settings.py for an example.
|
||||||
|
|
||||||
|
JS array/object manipulation
|
||||||
|
============================
|
||||||
|
|
||||||
|
For generic functions that operate on arrays or JavaScript objects, you
|
||||||
|
should generally use `Underscore <http://underscorejs.org/>`__. We used
|
||||||
|
to use jQuery's utility functions, but the Underscore equivalents are
|
||||||
|
more consistent, better-behaved and offer more choices.
|
||||||
|
|
||||||
|
A quick conversion table::
|
||||||
|
|
||||||
|
$.each → _.each (parameters to the callback reversed)
|
||||||
|
$.inArray → _.indexOf (parameters reversed)
|
||||||
|
$.grep → _.filter
|
||||||
|
$.map → _.map
|
||||||
|
$.extend → _.extend
|
||||||
|
|
||||||
|
There's a subtle difference in the case of ``_.extend``; it will replace
|
||||||
|
attributes with undefined, whereas jQuery won't::
|
||||||
|
|
||||||
|
$.extend({foo: 2}, {foo: undefined}); // yields {foo: 2}, BUT...
|
||||||
|
_.extend({foo: 2}, {foo: undefined}); // yields {foo: undefined}!
|
||||||
|
|
||||||
|
Also, ``_.each`` does not let you break out of the iteration early by
|
||||||
|
returning false, the way jQuery's version does. If you're doing this,
|
||||||
|
you probably want ``_.find``, ``_.every``, or ``_.any``, rather than
|
||||||
|
'each'.
|
||||||
|
|
||||||
|
Some Underscore functions have multiple names. You should always use the
|
||||||
|
canonical name (given in large print in the Underscore documentation),
|
||||||
|
with the exception of ``_.any``, which we prefer over the less clear
|
||||||
|
'some'.
|
||||||
|
|
||||||
|
More arbitrary style things
|
||||||
|
===========================
|
||||||
|
|
||||||
|
General
|
||||||
|
-------
|
||||||
|
|
||||||
|
Indentation is four space characters for Python, JS, CSS, and shell
|
||||||
|
scripts. Indentation is two space characters for HTML templates.
|
||||||
|
|
||||||
|
We never use tabs anywhere in source code we write, but we have some
|
||||||
|
third-party files which contain tabs.
|
||||||
|
|
||||||
|
Keep third-party static files under the directory
|
||||||
|
``zephyr/static/third/``, with one subdirectory per third-party project.
|
||||||
|
|
||||||
|
We don't have an absolute hard limit on line length, but we should avoid
|
||||||
|
extremely long lines. A general guideline is: refactor stuff to get it
|
||||||
|
under 85 characters, unless that makes the code a lot uglier, in which
|
||||||
|
case it's fine to go up to 120 or so.
|
||||||
|
|
||||||
|
Whitespace guidelines:
|
||||||
|
|
||||||
|
- Put one space (or more for alignment) around binary arithmetic and
|
||||||
|
equality operators.
|
||||||
|
- Put one space around each part of the ternary operator.
|
||||||
|
- Put one space between keywords like ``if`` and ``while`` and their
|
||||||
|
associated open paren.
|
||||||
|
- Put one space between the closing paren for ``if`` and ``while``-like
|
||||||
|
constructs and the opening curly brace. Put the curly brace on the
|
||||||
|
same line unless doing otherwise improves readability.
|
||||||
|
- Put no space before or after the open paren for function calls and no
|
||||||
|
space before the close paren for function calls.
|
||||||
|
- For the comma operator and colon operator in languages where it is
|
||||||
|
used for inline dictionaries, put no space before it and at least one
|
||||||
|
space after. Only use more than one space for alignment.
|
||||||
|
|
||||||
|
Javascript
|
||||||
|
----------
|
||||||
|
|
||||||
|
Don't use ``==`` and ``!=`` because these operators perform type
|
||||||
|
coercions, which can mask bugs. Always use ``===`` and ``!==``.
|
||||||
|
|
||||||
|
End every statement with a semicolon.
|
||||||
|
|
||||||
|
``if`` statements with no braces are allowed, if the body is simple and
|
||||||
|
its extent is abundantly clear from context and formatting.
|
||||||
|
|
||||||
|
Anonymous functions should have spaces before and after the argument
|
||||||
|
list::
|
||||||
|
|
||||||
|
var x = function (foo, bar) { // ...
|
||||||
|
|
||||||
|
When calling a function with an anonymous function as an argument, use
|
||||||
|
this style::
|
||||||
|
|
||||||
|
$.get('foo', function (data) {
|
||||||
|
var x = ...;
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
|
||||||
|
The inner function body is indented one level from the outer function
|
||||||
|
call. The closing brace for the inner function and the closing
|
||||||
|
parenthesis for the outer call are together on the same line. This style
|
||||||
|
isn't necessarily appropriate for calls with multiple anonymous
|
||||||
|
functions or other arguments following them.
|
||||||
|
|
||||||
|
Use
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
$(function () { ...
|
||||||
|
|
||||||
|
rather than
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
$(document).ready(function () { ...
|
||||||
|
|
||||||
|
and combine adjacent on-ready functions, if they are logically related.
|
||||||
|
|
||||||
|
The best way to build complicated DOM elements is a Mustache template
|
||||||
|
like ``zephyr/static/templates/message.handlebars``. For simpler things
|
||||||
|
you can use jQuery DOM building APIs like so::
|
||||||
|
|
||||||
|
var new_tr = $('<tr />').attr('id', zephyr.id);
|
||||||
|
|
||||||
|
Passing a HTML string to jQuery is fine for simple hardcoded things::
|
||||||
|
|
||||||
|
foo.append('<p id="selected">foo</p>');
|
||||||
|
|
||||||
|
but avoid programmatically building complicated strings.
|
||||||
|
|
||||||
|
We used to favor attaching behaviors in templates like so::
|
||||||
|
|
||||||
|
<p onclick="select_zephyr({{id}})">
|
||||||
|
|
||||||
|
but there are some reasons to prefer attaching events using jQuery code:
|
||||||
|
|
||||||
|
- Potential huge performance gains by using delegated events where
|
||||||
|
possible
|
||||||
|
- When calling a function from an ``onclick`` attribute, ``this`` is
|
||||||
|
not bound to the element like you might think
|
||||||
|
- jQuery does event normalization
|
||||||
|
|
||||||
|
Either way, avoid complicated JavaScript code inside HTML attributes;
|
||||||
|
call a helper function instead.
|
||||||
|
|
||||||
|
HTML / CSS
|
||||||
|
----------
|
||||||
|
|
||||||
|
Don't use the ``style=`` attribute. Instead, define logical classes and
|
||||||
|
put your styles in ``zulip.css``.
|
||||||
|
|
||||||
|
Don't use the tag name in a selector unless you have to. In other words,
|
||||||
|
use ``.foo`` instead of ``span.foo``. We shouldn't have to care if the
|
||||||
|
tag type changes in the future.
|
||||||
|
|
||||||
|
Don't use inline event handlers (``onclick=``, etc. attributes).
|
||||||
|
Instead, attach a jQuery event handler
|
||||||
|
(``$('#foo').on('click', function () {...})``) when the DOM is ready
|
||||||
|
(inside a ``$(function () {...})`` block).
|
||||||
|
|
||||||
|
Use this format when you have the same block applying to multiple CSS
|
||||||
|
styles (separate lines for each selector)::
|
||||||
|
|
||||||
|
selector1,
|
||||||
|
selector2 {
|
||||||
|
};
|
||||||
|
|
||||||
|
Python
|
||||||
|
------
|
||||||
|
|
||||||
|
- Scripts should start with ``#!/usr/bin/env python`` and not
|
||||||
|
``#!/usr/bin/python``. See commit ``437d4aee`` for an explanation of
|
||||||
|
why. Don't put such a line on a Python file unless it's meaningful to
|
||||||
|
run it as a script. (Some libraries can also be run as scripts, e.g.
|
||||||
|
to run a test suite.)
|
||||||
|
- The first import in a file should be
|
||||||
|
``from __future__ import absolute_import``, per `PEP
|
||||||
|
328 <http://docs.python.org/2/whatsnew/2.5.html#pep-328-absolute-and-relative-imports>`__
|
||||||
|
- Put all imports together at the top of the file, absent a compelling
|
||||||
|
reason to do otherwise.
|
||||||
|
- Unpacking sequences doesn't require list brackets::
|
||||||
|
|
||||||
|
[x, y] = xs # unnecessary
|
||||||
|
x, y = xs # better
|
||||||
|
|
||||||
|
- For string formatting, use ``x % (y,)`` rather than ``x % y``, to
|
||||||
|
avoid ambiguity if ``y`` happens to be a tuple.
|
||||||
|
- When selecting by id, don't use ``foo.pk`` when you mean ``foo.id``.
|
||||||
|
E.g.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
recipient = Recipient(type_id=huddle.pk, type=Recipient.HUDDLE)
|
||||||
|
|
||||||
|
should be written as
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
recipient = Recipient(type_id=huddle.id, type=Recipient.HUDDLE)
|
||||||
|
|
||||||
|
in case we ever change the primary keys.
|
||||||
|
|
||||||
|
Version Control
|
||||||
|
===============
|
||||||
|
|
||||||
|
Commit Discipline
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
We follow the Git project's own commit discipline practice of "Each
|
||||||
|
commit is a minimal coherent idea".
|
||||||
|
|
||||||
|
Coherency requirements for any commit:
|
||||||
|
|
||||||
|
- It should pass tests (so test updates needed by a change should be in
|
||||||
|
the same commit as the original change, not a separate "fix the tests
|
||||||
|
that were broken by the last commit" commit).
|
||||||
|
- It should be safe to deploy individually, or comment in detail in the
|
||||||
|
commit message as to why it isn't (maybe with a [manual] tag). So
|
||||||
|
implementing a new API endpoint in one commit and then adding the
|
||||||
|
security checks in a future commit should be avoided -- the security
|
||||||
|
checks should be there from the beginning.
|
||||||
|
- Error handling should generally be included along with the code that
|
||||||
|
might trigger the error.
|
||||||
|
- TODO comments should be in the commit that introduces the
|
||||||
|
issue or functionality with further work required.
|
||||||
|
|
||||||
|
When you should be minimal:
|
||||||
|
|
||||||
|
- Significant refactorings should be done in a separate commit from
|
||||||
|
functional changes.
|
||||||
|
- Moving code from one file to another should be done in a separate
|
||||||
|
commits from functional changes or even refactoring within a file.
|
||||||
|
- 2 different refactorings should be done in different commits.
|
||||||
|
- 2 different features should be done in different commits.
|
||||||
|
- If you find yourself writing a commit message that reads like a list
|
||||||
|
of somewhat dissimilar things that you did, you probably should have
|
||||||
|
just done 2 commits.
|
||||||
|
|
||||||
|
When not to be overly minimal:
|
||||||
|
|
||||||
|
- For completely new features, you don't necessarily need to split out
|
||||||
|
new commits for each little subfeature of the new feature. E.g. if
|
||||||
|
you're writing a new tool from scratch, it's fine to have the initial
|
||||||
|
tool have plenty of options/features without doing separate commits
|
||||||
|
for each one. That said, reviewing a 2000-line giant blob of new
|
||||||
|
code isn't fun, so please be thoughtful about submitting things in
|
||||||
|
reviewable units.
|
||||||
|
- Don't bother to split back end commits from front end commits, even
|
||||||
|
though the backend can often be coherent on its own.
|
||||||
|
|
||||||
|
Other considerations:
|
||||||
|
|
||||||
|
- Overly fine commits are easily squashed, but not vice versa, so err
|
||||||
|
toward small commits, and the code reviewer can advise on squashing.
|
||||||
|
|
||||||
|
It can take some practice to get used to writing your commits this
|
||||||
|
way. For example, often you'll start adding a feature, and discover
|
||||||
|
you need to a refactoring partway through writing the feature. When
|
||||||
|
that happens, we recommend stashing your partial feature, do the
|
||||||
|
refactoring, commit it, and then finish implementing your feature.
|
||||||
|
|
||||||
|
Commit Messages
|
||||||
|
---------------
|
||||||
|
|
||||||
|
- The first line of commit messages should be written in the imperative
|
||||||
|
and be kept relatively short while concisely explaining what the
|
||||||
|
commit does. For example:
|
||||||
|
|
||||||
|
Bad::
|
||||||
|
|
||||||
|
bugfix
|
||||||
|
gather_subscriptions was broken
|
||||||
|
|
||||||
|
Good::
|
||||||
|
|
||||||
|
Prevent gather_subscriptions from throwing an exception when given bad input.
|
||||||
|
|
||||||
|
- Please use a complete sentence, ending with a period.
|
||||||
|
|
||||||
|
- The rest of the commit message should be written in full prose and
|
||||||
|
explain why and how the change was made. If the commit makes
|
||||||
|
performance improvements, you should generally include some rough
|
||||||
|
benchmarks showing that it actually improves the performance.
|
||||||
|
|
||||||
|
- In your commit message, you should describe any manual testing you
|
||||||
|
did in addition to running the automated tests, and any aspects of
|
||||||
|
the commit that you think are questionable and you'd like special
|
||||||
|
attention applied to.
|
||||||
|
|
||||||
|
Tests
|
||||||
|
-----
|
||||||
|
|
||||||
|
All significant new features should come with tests.
|
||||||
|
|
||||||
|
Third party code
|
||||||
|
----------------
|
||||||
|
|
||||||
|
When adding new third-party packages to our codebase, please include
|
||||||
|
"[third]" at the beginning of the commit message. You don't necessarily
|
||||||
|
need to do this when patching third-party code that's already in tree.
|
||||||
295
docs/conf.py
Normal file
295
docs/conf.py
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# zulip-contributor-docs documentation build configuration file, created by
|
||||||
|
# sphinx-quickstart on Mon Aug 17 16:24:04 2015.
|
||||||
|
#
|
||||||
|
# This file is execfile()d with the current directory set to its
|
||||||
|
# containing dir.
|
||||||
|
#
|
||||||
|
# Note that not all possible configuration values are present in this
|
||||||
|
# autogenerated file.
|
||||||
|
#
|
||||||
|
# All configuration values have a default; values that are commented out
|
||||||
|
# serve to show the default.
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import shlex
|
||||||
|
|
||||||
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
|
#sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
|
||||||
|
# -- General configuration ------------------------------------------------
|
||||||
|
|
||||||
|
# If your documentation needs a minimal Sphinx version, state it here.
|
||||||
|
#needs_sphinx = '1.0'
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
|
# ones.
|
||||||
|
extensions = []
|
||||||
|
|
||||||
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
templates_path = ['_templates']
|
||||||
|
|
||||||
|
# The suffix(es) of source filenames.
|
||||||
|
# You can specify multiple suffix as a list of string:
|
||||||
|
# source_suffix = ['.rst', '.md']
|
||||||
|
source_suffix = '.rst'
|
||||||
|
|
||||||
|
# The encoding of source files.
|
||||||
|
#source_encoding = 'utf-8-sig'
|
||||||
|
|
||||||
|
# The master toctree document.
|
||||||
|
master_doc = 'index'
|
||||||
|
|
||||||
|
# General information about the project.
|
||||||
|
project = u'Zulip'
|
||||||
|
copyright = u'2015, The Zulip Team'
|
||||||
|
author = u'The Zulip Team'
|
||||||
|
|
||||||
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
|
# |version| and |release|, also used in various other places throughout the
|
||||||
|
# built documents.
|
||||||
|
#
|
||||||
|
# The short X.Y version.
|
||||||
|
version = '0.1'
|
||||||
|
# The full version, including alpha/beta/rc tags.
|
||||||
|
release = '0.1'
|
||||||
|
|
||||||
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
|
# for a list of supported languages.
|
||||||
|
#
|
||||||
|
# This is also used if you do content translation via gettext catalogs.
|
||||||
|
# Usually you set "language" from the command line for these cases.
|
||||||
|
language = None
|
||||||
|
|
||||||
|
# There are two options for replacing |today|: either, you set today to some
|
||||||
|
# non-false value, then it is used:
|
||||||
|
#today = ''
|
||||||
|
# Else, today_fmt is used as the format for a strftime call.
|
||||||
|
#today_fmt = '%B %d, %Y'
|
||||||
|
|
||||||
|
# List of patterns, relative to source directory, that match files and
|
||||||
|
# directories to ignore when looking for source files.
|
||||||
|
exclude_patterns = ['_build']
|
||||||
|
|
||||||
|
# The reST default role (used for this markup: `text`) to use for all
|
||||||
|
# documents.
|
||||||
|
#default_role = None
|
||||||
|
|
||||||
|
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||||
|
#add_function_parentheses = True
|
||||||
|
|
||||||
|
# If true, the current module name will be prepended to all description
|
||||||
|
# unit titles (such as .. function::).
|
||||||
|
#add_module_names = True
|
||||||
|
|
||||||
|
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||||
|
# output. They are ignored by default.
|
||||||
|
#show_authors = False
|
||||||
|
|
||||||
|
# The name of the Pygments (syntax highlighting) style to use.
|
||||||
|
pygments_style = 'sphinx'
|
||||||
|
|
||||||
|
# A list of ignored prefixes for module index sorting.
|
||||||
|
#modindex_common_prefix = []
|
||||||
|
|
||||||
|
# If true, keep warnings as "system message" paragraphs in the built documents.
|
||||||
|
#keep_warnings = False
|
||||||
|
|
||||||
|
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||||
|
todo_include_todos = False
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output ----------------------------------------------
|
||||||
|
|
||||||
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
|
# a list of builtin themes.
|
||||||
|
|
||||||
|
# Read The Docs can't import sphinx_rtd_theme, so don't import it there.
|
||||||
|
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
|
||||||
|
|
||||||
|
if not on_rtd:
|
||||||
|
import sphinx_rtd_theme
|
||||||
|
html_theme = 'sphinx_rtd_theme'
|
||||||
|
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
||||||
|
|
||||||
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
|
# further. For a list of options available for each theme, see the
|
||||||
|
# documentation.
|
||||||
|
#html_theme_options = {}
|
||||||
|
|
||||||
|
# Add any paths that contain custom themes here, relative to this directory.
|
||||||
|
#html_theme_path = []
|
||||||
|
|
||||||
|
# The name for this set of Sphinx documents. If None, it defaults to
|
||||||
|
# "<project> v<release> documentation".
|
||||||
|
#html_title = None
|
||||||
|
|
||||||
|
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||||
|
#html_short_title = None
|
||||||
|
|
||||||
|
# The name of an image file (relative to this directory) to place at the top
|
||||||
|
# of the sidebar.
|
||||||
|
#html_logo = None
|
||||||
|
|
||||||
|
# The name of an image file (within the static path) to use as favicon of the
|
||||||
|
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||||
|
# pixels large.
|
||||||
|
#html_favicon = None
|
||||||
|
|
||||||
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
|
html_static_path = ['_static']
|
||||||
|
|
||||||
|
# Add any extra paths that contain custom files (such as robots.txt or
|
||||||
|
# .htaccess) here, relative to this directory. These files are copied
|
||||||
|
# directly to the root of the documentation.
|
||||||
|
#html_extra_path = []
|
||||||
|
|
||||||
|
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||||
|
# using the given strftime format.
|
||||||
|
#html_last_updated_fmt = '%b %d, %Y'
|
||||||
|
|
||||||
|
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||||
|
# typographically correct entities.
|
||||||
|
#html_use_smartypants = True
|
||||||
|
|
||||||
|
# Custom sidebar templates, maps document names to template names.
|
||||||
|
#html_sidebars = {}
|
||||||
|
|
||||||
|
# Additional templates that should be rendered to pages, maps page names to
|
||||||
|
# template names.
|
||||||
|
#html_additional_pages = {}
|
||||||
|
|
||||||
|
# If false, no module index is generated.
|
||||||
|
#html_domain_indices = True
|
||||||
|
|
||||||
|
# If false, no index is generated.
|
||||||
|
#html_use_index = True
|
||||||
|
|
||||||
|
# If true, the index is split into individual pages for each letter.
|
||||||
|
#html_split_index = False
|
||||||
|
|
||||||
|
# If true, links to the reST sources are added to the pages.
|
||||||
|
#html_show_sourcelink = True
|
||||||
|
|
||||||
|
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||||
|
#html_show_sphinx = True
|
||||||
|
|
||||||
|
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||||
|
#html_show_copyright = True
|
||||||
|
|
||||||
|
# If true, an OpenSearch description file will be output, and all pages will
|
||||||
|
# contain a <link> tag referring to it. The value of this option must be the
|
||||||
|
# base URL from which the finished HTML is served.
|
||||||
|
#html_use_opensearch = ''
|
||||||
|
|
||||||
|
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||||
|
#html_file_suffix = None
|
||||||
|
|
||||||
|
# Language to be used for generating the HTML full-text search index.
|
||||||
|
# Sphinx supports the following languages:
|
||||||
|
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
|
||||||
|
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
|
||||||
|
#html_search_language = 'en'
|
||||||
|
|
||||||
|
# A dictionary with options for the search language support, empty by default.
|
||||||
|
# Now only 'ja' uses this config value
|
||||||
|
#html_search_options = {'type': 'default'}
|
||||||
|
|
||||||
|
# The name of a javascript file (relative to the configuration directory) that
|
||||||
|
# implements a search results scorer. If empty, the default will be used.
|
||||||
|
#html_search_scorer = 'scorer.js'
|
||||||
|
|
||||||
|
# Output file base name for HTML help builder.
|
||||||
|
htmlhelp_basename = 'zulip-contributor-docsdoc'
|
||||||
|
|
||||||
|
def setup(app):
|
||||||
|
# overrides for wide tables in RTD theme
|
||||||
|
app.add_stylesheet('theme_overrides.css') # path relative to _static
|
||||||
|
|
||||||
|
# -- Options for LaTeX output ---------------------------------------------
|
||||||
|
|
||||||
|
latex_elements = {
|
||||||
|
# The paper size ('letterpaper' or 'a4paper').
|
||||||
|
#'papersize': 'letterpaper',
|
||||||
|
|
||||||
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
|
#'pointsize': '10pt',
|
||||||
|
|
||||||
|
# Additional stuff for the LaTeX preamble.
|
||||||
|
#'preamble': '',
|
||||||
|
|
||||||
|
# Latex figure (float) alignment
|
||||||
|
#'figure_align': 'htbp',
|
||||||
|
}
|
||||||
|
|
||||||
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
|
# (source start file, target name, title,
|
||||||
|
# author, documentclass [howto, manual, or own class]).
|
||||||
|
latex_documents = [
|
||||||
|
(master_doc, 'zulip-contributor-docs.tex', u'Zulip Documentation',
|
||||||
|
u'The Zulip Team', 'manual'),
|
||||||
|
]
|
||||||
|
|
||||||
|
# The name of an image file (relative to this directory) to place at the top of
|
||||||
|
# the title page.
|
||||||
|
#latex_logo = None
|
||||||
|
|
||||||
|
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||||
|
# not chapters.
|
||||||
|
#latex_use_parts = False
|
||||||
|
|
||||||
|
# If true, show page references after internal links.
|
||||||
|
#latex_show_pagerefs = False
|
||||||
|
|
||||||
|
# If true, show URL addresses after external links.
|
||||||
|
#latex_show_urls = False
|
||||||
|
|
||||||
|
# Documents to append as an appendix to all manuals.
|
||||||
|
#latex_appendices = []
|
||||||
|
|
||||||
|
# If false, no module index is generated.
|
||||||
|
#latex_domain_indices = True
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for manual page output ---------------------------------------
|
||||||
|
|
||||||
|
# One entry per manual page. List of tuples
|
||||||
|
# (source start file, name, description, authors, manual section).
|
||||||
|
man_pages = [
|
||||||
|
(master_doc, 'zulip-contributor-docs', u'Zulip Documentation',
|
||||||
|
[author], 1)
|
||||||
|
]
|
||||||
|
|
||||||
|
# If true, show URL addresses after external links.
|
||||||
|
#man_show_urls = False
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for Texinfo output -------------------------------------------
|
||||||
|
|
||||||
|
# Grouping the document tree into Texinfo files. List of tuples
|
||||||
|
# (source start file, target name, title, author,
|
||||||
|
# dir menu entry, description, category)
|
||||||
|
texinfo_documents = [
|
||||||
|
(master_doc, 'zulip-contributor-docs', u'Zulip Documentation',
|
||||||
|
author, 'zulip-contributor-docs', 'Documentation for contributing to Zulip.',
|
||||||
|
'Miscellaneous'),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Documents to append as an appendix to all manuals.
|
||||||
|
#texinfo_appendices = []
|
||||||
|
|
||||||
|
# If false, no module index is generated.
|
||||||
|
#texinfo_domain_indices = True
|
||||||
|
|
||||||
|
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||||
|
#texinfo_show_urls = 'footnote'
|
||||||
|
|
||||||
|
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||||
|
#texinfo_no_detailmenu = False
|
||||||
95
docs/directory-structure.rst
Normal file
95
docs/directory-structure.rst
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
===================
|
||||||
|
Directory structure
|
||||||
|
===================
|
||||||
|
|
||||||
|
This page documents the Zulip directory structure and how to decide where to
|
||||||
|
put a file.
|
||||||
|
|
||||||
|
Scripts
|
||||||
|
=======
|
||||||
|
|
||||||
|
+--------------------+-----------------------------------------------------------------------------------+
|
||||||
|
| ``scripts/`` | Scripts that production deployments might run manually (e.g. ``restart-server``) |
|
||||||
|
+--------------------+-----------------------------------------------------------------------------------+
|
||||||
|
| ``bin/`` | Scripts that are needed on production deployments but humans should never run |
|
||||||
|
+--------------------+-----------------------------------------------------------------------------------+
|
||||||
|
| ``scripts/setup/`` | Tools that production deployments will only run once, during installation |
|
||||||
|
+--------------------+-----------------------------------------------------------------------------------+
|
||||||
|
| ``tools/`` | Development tools |
|
||||||
|
+--------------------+-----------------------------------------------------------------------------------+
|
||||||
|
|
||||||
|
Bots
|
||||||
|
====
|
||||||
|
|
||||||
|
+------------------------+----------------------------------------------------------------------+
|
||||||
|
| ``api/integrations`` | Bots distributed as part of the Zulip API bundle. |
|
||||||
|
+------------------------+----------------------------------------------------------------------+
|
||||||
|
| ``bots/`` | Previously Zulip internal bots. These usually need a bit of work. |
|
||||||
|
+------------------------+----------------------------------------------------------------------+
|
||||||
|
|
||||||
|
Management commands
|
||||||
|
===================
|
||||||
|
|
||||||
|
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| ``zerver/management/commands/`` | Management commands one might run at a production deployment site (e.g. scripts to change a value or deactivate a user properly) |
|
||||||
|
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------+
|
||||||
|
|
||||||
|
Views
|
||||||
|
=====
|
||||||
|
|
||||||
|
+--------------------------------+-----------------------------------------+
|
||||||
|
| ``zerver/tornadoviews.py`` | Tornado views |
|
||||||
|
+--------------------------------+-----------------------------------------+
|
||||||
|
| ``zerver/views/webhooks.py`` | Webhook views |
|
||||||
|
+--------------------------------+-----------------------------------------+
|
||||||
|
| ``zerver/views/messages.py`` | message-related views |
|
||||||
|
+--------------------------------+-----------------------------------------+
|
||||||
|
| ``zerver/views/__init__.py`` | other Django views |
|
||||||
|
+--------------------------------+-----------------------------------------+
|
||||||
|
|
||||||
|
Static assets
|
||||||
|
=============
|
||||||
|
|
||||||
|
+---------------+---------------------------------------------------------------------------------------------------------------+
|
||||||
|
| ``assets/`` | For assets not to be served to the web (e.g. the system to generate our favicons) |
|
||||||
|
+---------------+---------------------------------------------------------------------------------------------------------------+
|
||||||
|
| ``static/`` | For things we do want to both serve to the web and distribute to production deployments (e.g. the webpages) |
|
||||||
|
+---------------+---------------------------------------------------------------------------------------------------------------+
|
||||||
|
|
||||||
|
Puppet
|
||||||
|
======
|
||||||
|
|
||||||
|
+--------------------+----------------------------------------------------------------------------------+
|
||||||
|
| ``puppet/zulip`` | For configuration for production deployments |
|
||||||
|
+--------------------+----------------------------------------------------------------------------------+
|
||||||
|
|
||||||
|
Templates
|
||||||
|
=========
|
||||||
|
|
||||||
|
+--------------------------+--------------------------------------------------------+
|
||||||
|
| ``templates/zerver`` | For templates related to zerver views |
|
||||||
|
+--------------------------+--------------------------------------------------------+
|
||||||
|
| ``static/templates`` | Handlebars templates for the frontend |
|
||||||
|
+--------------------------+--------------------------------------------------------+
|
||||||
|
|
||||||
|
Tests
|
||||||
|
=====
|
||||||
|
|
||||||
|
+------------------------+-----------------------------------+
|
||||||
|
| ``zerver/test*.py`` | Backend tests | |
|
||||||
|
+------------------------+-----------------------------------+
|
||||||
|
| ``zerver/tests/frontend/node`` | Node Frontend unit tests |
|
||||||
|
+------------------------+-----------------------------------+
|
||||||
|
| ``zerver/tests/frontend/tests`` | Casper frontend tests |
|
||||||
|
+------------------------+-----------------------------------+
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
=============
|
||||||
|
|
||||||
|
+-------------+-----------------------------------------------+
|
||||||
|
| ``docs/`` | Source for this documentation |
|
||||||
|
+-------------+-----------------------------------------------+
|
||||||
|
|
||||||
|
You can consult the repository's .gitattributes file to see exactly
|
||||||
|
which components are excluded from production releases (release
|
||||||
|
tarballs are generated using tools/build-release-tarball).
|
||||||
9
docs/html_unescape.py
Executable file
9
docs/html_unescape.py
Executable file
@@ -0,0 +1,9 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Remove HTML entity escaping left over from MediaWiki->rST conversion.
|
||||||
|
|
||||||
|
import html
|
||||||
|
import sys
|
||||||
|
|
||||||
|
for line in sys.stdin:
|
||||||
|
print(html.unescape(line), end='')
|
||||||
25
docs/index.rst
Normal file
25
docs/index.rst
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
.. zulip documentation master file, created by
|
||||||
|
sphinx-quickstart on Mon Aug 17 16:24:04 2015.
|
||||||
|
You can adapt this file completely to your liking, but it should at least
|
||||||
|
contain the root `toctree` directive.
|
||||||
|
|
||||||
|
Welcome to Zulip documentation!
|
||||||
|
===============================
|
||||||
|
|
||||||
|
Contents:
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
new-feature-tutorial
|
||||||
|
code-style
|
||||||
|
directory-structure
|
||||||
|
testing
|
||||||
|
|
||||||
|
Indices and tables
|
||||||
|
==================
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
* :ref:`modindex`
|
||||||
|
* :ref:`search`
|
||||||
|
|
||||||
85
docs/new-feature-tutorial.rst
Normal file
85
docs/new-feature-tutorial.rst
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
====================
|
||||||
|
New Feature Tutorial
|
||||||
|
====================
|
||||||
|
|
||||||
|
.. attention::
|
||||||
|
This tutorial is an unfinished work -- contributions welcome!
|
||||||
|
|
||||||
|
The changes needed to add a new feature will vary, of course. We give an
|
||||||
|
example here that illustrates some of the common steps needed. We describe
|
||||||
|
the process of adding a new setting for admins that restricts inviting new
|
||||||
|
users to admins only.
|
||||||
|
|
||||||
|
Backend Changes
|
||||||
|
===============
|
||||||
|
|
||||||
|
Adding a field to the database
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
The server accesses the underlying database in `zerver/models.py`. Add
|
||||||
|
a new field in the appropriate class, `realm_invite_by_admins_only`
|
||||||
|
in the `Realm` class in this case.
|
||||||
|
|
||||||
|
Once you do so, you need to create the migration and run it; the
|
||||||
|
process is documented at:
|
||||||
|
https://docs.djangoproject.com/en/1.8/topics/migrations/
|
||||||
|
|
||||||
|
Once you've run the migration, to test your changes, you'll want to
|
||||||
|
restart memcached on your development server (``/etc/init.d/memcached restart``) and
|
||||||
|
then restart ``run-dev.py`` to avoid interacting with cached objects.
|
||||||
|
|
||||||
|
Backend changes
|
||||||
|
---------------
|
||||||
|
|
||||||
|
You should add code in `zerver/lib/actions.py` to interact with the database,
|
||||||
|
that actually updates the relevant field. In this case, `do_set_realm_invite_by_admins_only`
|
||||||
|
is a function that actually updates the field in the database, and sends
|
||||||
|
an event announcing that this change has been made.
|
||||||
|
|
||||||
|
You then need update the `fetch_initial_state_data` and `apply_events` functions
|
||||||
|
in `zerver/lib/actions.py` to update the state based on the event you just created.
|
||||||
|
In this case, we add a line
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
state['realm_invite_by_admins_only'] = user_profile.realm.invite_by_admins_only`
|
||||||
|
|
||||||
|
to the `fetch_initial_state_data` function. The `apply_events` function
|
||||||
|
doesn't need to be updated since
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
elif event['type'] == 'realm':
|
||||||
|
field = 'realm_' + event['property']
|
||||||
|
state[field] = event['value']
|
||||||
|
|
||||||
|
already took care of our event.
|
||||||
|
|
||||||
|
Then update `zerver/views/__init__.py` to actually call your function.
|
||||||
|
In the dictionary which sets the javascript `page_params` dictionary,
|
||||||
|
add a value for your feature.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
realm_invite_by_admins_only = register_ret['realm_invite_by_admins_only']
|
||||||
|
|
||||||
|
Perhaps your new option controls some other backend rendering: in our case
|
||||||
|
we test for this option in the `home` method for adding a variable to the response.
|
||||||
|
The functions in this file control the generation of various pages served
|
||||||
|
(along with the Django templates).
|
||||||
|
Our new feature also shows up in the administration tab (as a checkbox),
|
||||||
|
so we need to update the `update_realm` function.
|
||||||
|
|
||||||
|
|
||||||
|
Finally, add tests for your backend changes; at the very least you
|
||||||
|
should add a test of your event data flowing through the system in
|
||||||
|
``test_events.py``.
|
||||||
|
|
||||||
|
|
||||||
|
Frontend changes
|
||||||
|
----------------
|
||||||
|
|
||||||
|
You need to change various things on the front end. In this case, the relevant files
|
||||||
|
are `static/js/server_events.js`, `static/js/admin.js`, `static/styles/zulip.css
|
||||||
|
and `static/templates/admin_tab.handlebars`.
|
||||||
|
|
||||||
1
docs/requirements.readthedocs.txt
Normal file
1
docs/requirements.readthedocs.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Empty requirements.txt to avoid readthedocs installing all our dependencies.
|
||||||
251
docs/testing.rst
Normal file
251
docs/testing.rst
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
=======
|
||||||
|
Testing
|
||||||
|
=======
|
||||||
|
|
||||||
|
Running tests
|
||||||
|
=============
|
||||||
|
|
||||||
|
To run everything, just use ``./tools/test-all``. This runs lint checks,
|
||||||
|
web frontend / whole-system blackbox tests, and backend Django tests.
|
||||||
|
|
||||||
|
If you want to run individual parts, see the various commands inside
|
||||||
|
that script.
|
||||||
|
|
||||||
|
Schema and initial data changes
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
If you change the database schema or change the initial test data, you
|
||||||
|
have have to regenerate the pristine test database by running
|
||||||
|
``tools/do-destroy-rebuild-test-database``.
|
||||||
|
|
||||||
|
Wiping the test databases
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
You should first try running: ``tools/do-destroy-rebuild-test-database``
|
||||||
|
|
||||||
|
If that fails you should try to do:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
sudo -u postgres psql
|
||||||
|
> DROP DATABASE zulip_test;
|
||||||
|
> DROP DATABASE zulip_test_template;
|
||||||
|
|
||||||
|
and then run ``tools/do-destroy-rebuild-test-database``
|
||||||
|
|
||||||
|
Recreating the postgres cluster
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
**This is irreversible, so do it with care, and never do this anywhere
|
||||||
|
in production.**
|
||||||
|
|
||||||
|
If your postgres cluster (collection of databases) gets totally trashed
|
||||||
|
permissions-wise, and you can't otherwise repair it, you can recreate
|
||||||
|
it. On Ubuntu:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
sudo pg_dropcluster --stop 9.1 main
|
||||||
|
sudo pg_createcluster --locale=en_US.utf8 --start 9.1 main
|
||||||
|
|
||||||
|
Backend Django tests
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
These live in ``zerver/tests.py`` and ``zerver/test_*.py``. Run them
|
||||||
|
with ``tools/test-backend``.
|
||||||
|
|
||||||
|
Web frontend black-box tests
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
These live in ``zerver/tests/frontend/tests/``. This is a "black box"
|
||||||
|
test; we load the frontend in a real (headless) browser, from a real dev
|
||||||
|
server, and simulate UI interactions like sending messages, narrowing,
|
||||||
|
etc.
|
||||||
|
|
||||||
|
Since this is interacting with a real dev server, it can catch backend
|
||||||
|
bugs as well.
|
||||||
|
|
||||||
|
You can run this with ``./zerver/tests/frontend/run``. You will need
|
||||||
|
`PhantomJS <http://phantomjs.org/>`__ 1.7.0 or later.
|
||||||
|
|
||||||
|
Debugging Casper.JS
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Casper.js (via PhantomJS) has support for remote debugging. However, it
|
||||||
|
is not perfect. Here are some steps for using it and gotchas you might
|
||||||
|
want to know.
|
||||||
|
|
||||||
|
To turn on remote debugging, pass ``--remote-debug`` to the
|
||||||
|
``./zerver/frontend/tests/run`` script. This will run the tests with
|
||||||
|
port ``7777`` open for remote debugging. You can now connect to
|
||||||
|
``localhost:7777`` in a Webkit browser. Somewhat recent versions of
|
||||||
|
Chrome or Safari might be required.
|
||||||
|
|
||||||
|
- When connecting to the remote debugger, you will see a list of pages,
|
||||||
|
probably 2. One page called ``about:blank`` is the headless page in
|
||||||
|
which the CasperJS test itself is actually running in. This is where
|
||||||
|
your test code is.
|
||||||
|
- The other page, probably ``localhost:9981``, is the Zulip page that
|
||||||
|
the test is testing---that is, the page running our app that our test
|
||||||
|
is exercising.
|
||||||
|
|
||||||
|
Since the tests are now running, you can open the ``about:blank`` page,
|
||||||
|
switch to the Scripts tab, and open the running ``0x-foo.js`` test. If
|
||||||
|
you set a breakpoint and it is hit, the inspector will pause and you can
|
||||||
|
do your normal JS debugging. You can also put breakpoints in the Zulip
|
||||||
|
webpage itself if you wish to inspect the state of the Zulip frontend.
|
||||||
|
|
||||||
|
Web frontend unit tests
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
As an alternative to the black-box whole-app testing, you can unit test
|
||||||
|
individual JavaScript files that use the module pattern. For example, to
|
||||||
|
test the ``foobar.js`` file, you would first add the following to the
|
||||||
|
bottom of ``foobar.js``:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
if (typeof module !== 'undefined') {
|
||||||
|
module.exports = foobar;
|
||||||
|
}
|
||||||
|
|
||||||
|
This makes ``foobar.js`` follow the CommonJS module pattern, so it can
|
||||||
|
be required in Node.js, which runs our tests.
|
||||||
|
|
||||||
|
Now create ``zerver/tests/frontend/node/foobar.js``. At the top, require
|
||||||
|
the `Node.js assert module <http://nodejs.org/api/assert.html>`__, and
|
||||||
|
the module you're testing, like so:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
var assert = require('assert');
|
||||||
|
var foobar = require('js/foobar.js');
|
||||||
|
|
||||||
|
(If the module you're testing depends on other modules, or modifies
|
||||||
|
global state, you need to also read `the next section`__.)
|
||||||
|
|
||||||
|
__ handling-dependencies_
|
||||||
|
|
||||||
|
Define and call some tests using the `assert
|
||||||
|
module <http://nodejs.org/api/assert.html>`__. Note that for "equal"
|
||||||
|
asserts, the *actual* value comes first, the *expected* value second.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
(function test_somefeature() {
|
||||||
|
assert.strictEqual(foobar.somefeature('baz'), 'quux');
|
||||||
|
assert.throws(foobar.somefeature('Invalid Input'));
|
||||||
|
}());
|
||||||
|
|
||||||
|
The test runner (index.js) automatically runs all .js files in the
|
||||||
|
zerver/tests/frontend/node directory.
|
||||||
|
|
||||||
|
.. _handling-dependencies:
|
||||||
|
|
||||||
|
Handling dependencies in tests
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The following scheme helps avoid tests leaking globals between each
|
||||||
|
other.
|
||||||
|
|
||||||
|
First, if you can avoid globals, do it, and the code that is directly
|
||||||
|
under test can simply be handled like this:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
var search = require('js/search_suggestion.js');
|
||||||
|
|
||||||
|
For deeper dependencies, you want to categorize each module as follows:
|
||||||
|
|
||||||
|
- Exercise the module's real code for deeper, more realistic testing?
|
||||||
|
- Stub out the module's interface for more control, speed, and
|
||||||
|
isolation?
|
||||||
|
- Do some combination of the above?
|
||||||
|
|
||||||
|
For all the modules where you want to run actual code, add a statement
|
||||||
|
like the following to the top of your test file:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
add_dependencies({
|
||||||
|
_: 'third/underscore/underscore.js',
|
||||||
|
util: 'js/util.js',
|
||||||
|
Dict: 'js/dict.js',
|
||||||
|
Handlebars: 'handlebars',
|
||||||
|
Filter: 'js/filter.js',
|
||||||
|
typeahead_helper: 'js/typeahead_helper.js',
|
||||||
|
stream_data: 'js/stream_data.js',
|
||||||
|
narrow: 'js/narrow.js'
|
||||||
|
});
|
||||||
|
|
||||||
|
For modules that you want to completely stub out, please use a pattern
|
||||||
|
like this:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
set_global('page_params', {
|
||||||
|
email: 'bob@zulip.com'
|
||||||
|
});
|
||||||
|
|
||||||
|
// then maybe further down
|
||||||
|
global.page_params.email = 'alice@zulip.com';
|
||||||
|
|
||||||
|
Finally, there's the hybrid situation, where you want to borrow some of
|
||||||
|
a module's real functionality but stub out other pieces. Obviously, this
|
||||||
|
is a pretty strong smell that the other module might be lacking in
|
||||||
|
cohesion, but that code might be outside your jurisdiction. The pattern
|
||||||
|
here is this:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
// Use real versions of parse/unparse
|
||||||
|
var narrow = require('js/narrow.js');
|
||||||
|
set_global('narrow', {
|
||||||
|
parse: narrow.parse,
|
||||||
|
unparse: narrow.unparse
|
||||||
|
});
|
||||||
|
|
||||||
|
// But later, I want to stub the stream without having to call super-expensive
|
||||||
|
// real code like narrow.activate().
|
||||||
|
global.narrow.stream = function () {
|
||||||
|
return 'office';
|
||||||
|
};
|
||||||
|
|
||||||
|
Coverage reports
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
You can automatically generate coverage reports for the JavaScript unit
|
||||||
|
tests. To do so, install istanbul:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
sudo npm install -g istanbul
|
||||||
|
|
||||||
|
And run test-js-with-node with the 'cover' parameter:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
tools/test-js-with-node cover
|
||||||
|
|
||||||
|
Then open ``coverage/lcov-report/js/index.html`` in your browser.
|
||||||
|
Modules we don't test *at all* aren't listed in the report, so this
|
||||||
|
tends to overstate how good our overall coverage is, but it's accurate
|
||||||
|
for individual files. You can also click a filename to see the specific
|
||||||
|
statements and branches not tested. 100% branch coverage isn't
|
||||||
|
necessarily possible, but getting to at least 80% branch coverage is a
|
||||||
|
good goal.
|
||||||
|
|
||||||
|
Manual testing (local app + web browser)
|
||||||
|
========================================
|
||||||
|
|
||||||
|
Setting up the manual testing database
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
./tools/do-destroy-rebuild-database
|
||||||
|
|
||||||
|
Will populate your local database with all the usual accounts plus some
|
||||||
|
test messages involving Shakespeare characters.
|
||||||
@@ -1 +0,0 @@
|
|||||||
../zproject/backends.py
|
|
||||||
177
provision.py
Normal file
177
provision.py
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import platform
|
||||||
|
|
||||||
|
try:
|
||||||
|
import sh
|
||||||
|
except ImportError:
|
||||||
|
import pbs as sh
|
||||||
|
|
||||||
|
SUPPORTED_PLATFORMS = {
|
||||||
|
"Ubuntu": [
|
||||||
|
"trusty",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
APT_DEPENDENCIES = {
|
||||||
|
"trusty": [
|
||||||
|
"closure-compiler",
|
||||||
|
"libffi-dev",
|
||||||
|
"memcached",
|
||||||
|
"rabbitmq-server",
|
||||||
|
"libldap2-dev",
|
||||||
|
"redis-server",
|
||||||
|
"postgresql-server-dev-all",
|
||||||
|
"libmemcached-dev",
|
||||||
|
"postgresql-9.3",
|
||||||
|
"python-dev",
|
||||||
|
"hunspell-en-us",
|
||||||
|
"nodejs",
|
||||||
|
"python-virtualenv",
|
||||||
|
"supervisor",
|
||||||
|
"git",
|
||||||
|
"npm",
|
||||||
|
"node-jquery",
|
||||||
|
"yui-compressor",
|
||||||
|
"puppet", # Used by lint-all
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# TODO: backport node-{cssstyle,htmlparser2,nwmatcher} to trusty,
|
||||||
|
# so we can eliminate npm (above) and this section.
|
||||||
|
NPM_DEPENDENCIES = {
|
||||||
|
"trusty": [
|
||||||
|
"cssstyle",
|
||||||
|
"htmlparser2",
|
||||||
|
"nwmatcher",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
VENV_PATH="/srv/zulip-venv"
|
||||||
|
ZULIP_PATH="/srv/zulip"
|
||||||
|
|
||||||
|
# TODO: Parse arguments properly
|
||||||
|
if "--travis" in sys.argv:
|
||||||
|
ZULIP_PATH="."
|
||||||
|
|
||||||
|
# tsearch-extras is an extension to postgres's built-in full-text search.
|
||||||
|
# TODO: use a real APT repository
|
||||||
|
TSEARCH_URL_BASE = "https://dl.dropboxusercontent.com/u/283158365/zuliposs/"
|
||||||
|
TSEARCH_PACKAGE_NAME = {
|
||||||
|
"trusty": "postgresql-9.3-tsearch-extras"
|
||||||
|
}
|
||||||
|
TSEARCH_VERSION = "0.1.2"
|
||||||
|
# TODO: this path is platform-specific!
|
||||||
|
TSEARCH_STOPWORDS_PATH = "/usr/share/postgresql/9.3/tsearch_data/"
|
||||||
|
REPO_STOPWORDS_PATH = os.path.join(
|
||||||
|
ZULIP_PATH,
|
||||||
|
"puppet",
|
||||||
|
"zulip",
|
||||||
|
"files",
|
||||||
|
"postgresql",
|
||||||
|
"zulip_english.stop",
|
||||||
|
)
|
||||||
|
|
||||||
|
LOUD = dict(_out=sys.stdout, _err=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
log = logging.getLogger("zulip-provisioner")
|
||||||
|
# TODO: support other architectures
|
||||||
|
if platform.architecture()[0] == '64bit':
|
||||||
|
arch = 'amd64'
|
||||||
|
else:
|
||||||
|
log.critical("Only amd64 is supported.")
|
||||||
|
|
||||||
|
vendor, version, codename = platform.dist()
|
||||||
|
|
||||||
|
if not (vendor in SUPPORTED_PLATFORMS and codename in SUPPORTED_PLATFORMS[vendor]):
|
||||||
|
log.critical("Unsupported platform: {} {}".format(vendor, codename))
|
||||||
|
|
||||||
|
with sh.sudo:
|
||||||
|
sh.apt_get.update(**LOUD)
|
||||||
|
|
||||||
|
sh.apt_get.install(*APT_DEPENDENCIES["trusty"], assume_yes=True, **LOUD)
|
||||||
|
|
||||||
|
temp_deb_path = sh.mktemp("package_XXXXXX.deb", tmpdir=True)
|
||||||
|
|
||||||
|
sh.wget(
|
||||||
|
"{}/{}_{}_{}.deb".format(
|
||||||
|
TSEARCH_URL_BASE,
|
||||||
|
TSEARCH_PACKAGE_NAME["trusty"],
|
||||||
|
TSEARCH_VERSION,
|
||||||
|
arch,
|
||||||
|
),
|
||||||
|
output_document=temp_deb_path,
|
||||||
|
**LOUD
|
||||||
|
)
|
||||||
|
|
||||||
|
with sh.sudo:
|
||||||
|
sh.dpkg("--install", temp_deb_path, **LOUD)
|
||||||
|
|
||||||
|
with sh.sudo:
|
||||||
|
PHANTOMJS_PATH = "/srv/phantomjs"
|
||||||
|
PHANTOMJS_TARBALL = os.path.join(PHANTOMJS_PATH, "phantomjs-1.9.8-linux-x86_64.tar.bz2")
|
||||||
|
sh.mkdir("-p", PHANTOMJS_PATH, **LOUD)
|
||||||
|
sh.wget("https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.8-linux-x86_64.tar.bz2",
|
||||||
|
output_document=PHANTOMJS_TARBALL, **LOUD)
|
||||||
|
sh.tar("xj", directory=PHANTOMJS_PATH, file=PHANTOMJS_TARBALL, **LOUD)
|
||||||
|
sh.ln("-sf", os.path.join(PHANTOMJS_PATH, "phantomjs-1.9.8-linux-x86_64", "bin", "phantomjs"),
|
||||||
|
"/usr/local/bin/phantomjs", **LOUD)
|
||||||
|
|
||||||
|
with sh.sudo:
|
||||||
|
sh.rm("-rf", VENV_PATH, **LOUD)
|
||||||
|
sh.mkdir("-p", VENV_PATH, **LOUD)
|
||||||
|
sh.chown("{}:{}".format(os.getuid(), os.getgid()), VENV_PATH, **LOUD)
|
||||||
|
|
||||||
|
sh.virtualenv(VENV_PATH, **LOUD)
|
||||||
|
|
||||||
|
# Add the ./tools and ./scripts/setup directories inside the repository root to
|
||||||
|
# the system path; we'll reference them later.
|
||||||
|
orig_path = os.environ["PATH"]
|
||||||
|
os.environ["PATH"] = os.pathsep.join((
|
||||||
|
os.path.join(ZULIP_PATH, "tools"),
|
||||||
|
os.path.join(ZULIP_PATH, "scripts", "setup"),
|
||||||
|
orig_path
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
# Put Python virtualenv activation in our .bash_profile.
|
||||||
|
with open(os.path.expanduser('~/.bash_profile'), 'w+') as bash_profile:
|
||||||
|
bash_profile.writelines([
|
||||||
|
"source .bashrc\n",
|
||||||
|
"source %s\n" % (os.path.join(VENV_PATH, "bin", "activate"),),
|
||||||
|
])
|
||||||
|
|
||||||
|
# Switch current Python context to the virtualenv.
|
||||||
|
activate_this = os.path.join(VENV_PATH, "bin", "activate_this.py")
|
||||||
|
execfile(activate_this, dict(__file__=activate_this))
|
||||||
|
|
||||||
|
sh.pip.install(requirement=os.path.join(ZULIP_PATH, "requirements.txt"), **LOUD)
|
||||||
|
|
||||||
|
with sh.sudo:
|
||||||
|
sh.cp(REPO_STOPWORDS_PATH, TSEARCH_STOPWORDS_PATH, **LOUD)
|
||||||
|
|
||||||
|
# Add additional node packages for test-js-with-node.
|
||||||
|
with sh.sudo:
|
||||||
|
sh.npm.install(*NPM_DEPENDENCIES["trusty"], g=True, prefix="/usr", **LOUD)
|
||||||
|
|
||||||
|
# Management commands expect to be run from the root of the project.
|
||||||
|
os.chdir(ZULIP_PATH)
|
||||||
|
|
||||||
|
os.system("tools/download-zxcvbn")
|
||||||
|
os.system("tools/emoji_dump/build_emoji")
|
||||||
|
os.system("generate_secrets.py -d")
|
||||||
|
if "--travis" in sys.argv:
|
||||||
|
os.system("sudo service rabbitmq-server restart")
|
||||||
|
os.system("sudo service redis-server restart")
|
||||||
|
os.system("sudo service memcached restart")
|
||||||
|
sh.configure_rabbitmq(**LOUD)
|
||||||
|
sh.postgres_init_db(**LOUD)
|
||||||
|
sh.do_destroy_rebuild_database(**LOUD)
|
||||||
|
sh.postgres_init_test_db(**LOUD)
|
||||||
|
sh.do_destroy_rebuild_test_database(**LOUD)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
@@ -32,8 +32,8 @@ Listen 127.0.0.1:8888
|
|||||||
# You shouldn't need to edit anything below this line.
|
# You shouldn't need to edit anything below this line.
|
||||||
|
|
||||||
SSLEngine On
|
SSLEngine On
|
||||||
SSLCertificateFile /etc/ssl/certs/zulip-enterprise.combined-chain.crt
|
SSLCertificateFile /etc/ssl/certs/zulip.combined-chain.crt
|
||||||
SSLCertificateKeyFile /etc/ssl/private/zulip-enterprise.key
|
SSLCertificateKeyFile /etc/ssl/private/zulip.key
|
||||||
|
|
||||||
WSGIScriptAlias / /home/zulip/deployments/current/zproject/wsgi.py
|
WSGIScriptAlias / /home/zulip/deployments/current/zproject/wsgi.py
|
||||||
WSGIDaemonProcess zulip threads=5 user=zulip python-path=/home/zulip/deployments/current/
|
WSGIDaemonProcess zulip threads=5 user=zulip python-path=/home/zulip/deployments/current/
|
||||||
|
|||||||
@@ -54,5 +54,7 @@
|
|||||||
#@student - maxlogins 4
|
#@student - maxlogins 4
|
||||||
zulip soft nofile 40000
|
zulip soft nofile 40000
|
||||||
zulip hard nofile 50000
|
zulip hard nofile 50000
|
||||||
|
root soft nofile 40000
|
||||||
|
root hard nofile 50000
|
||||||
|
|
||||||
# End of file
|
# End of file
|
||||||
|
|||||||
@@ -36,6 +36,10 @@ http {
|
|||||||
default upgrade;
|
default upgrade;
|
||||||
'' close;
|
'' close;
|
||||||
}
|
}
|
||||||
|
# These are the official ciphers as of 2014-10-14
|
||||||
|
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||||
|
ssl_ciphers EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:EECDH+RC4:RSA+RC4:!MD5;
|
||||||
|
|
||||||
|
|
||||||
include /etc/nginx/conf.d/*.conf;
|
include /etc/nginx/conf.d/*.conf;
|
||||||
include /etc/nginx/sites-enabled/*;
|
include /etc/nginx/sites-enabled/*;
|
||||||
|
|||||||
@@ -9,10 +9,8 @@ server {
|
|||||||
listen 443;
|
listen 443;
|
||||||
|
|
||||||
ssl on;
|
ssl on;
|
||||||
ssl_certificate /etc/ssl/certs/zulip-enterprise.combined-chain.crt;
|
ssl_certificate /etc/ssl/certs/zulip.combined-chain.crt;
|
||||||
ssl_certificate_key /etc/ssl/private/zulip-enterprise.key;
|
ssl_certificate_key /etc/ssl/private/zulip.key;
|
||||||
|
|
||||||
add_header X-Frame-Options DENY;
|
|
||||||
|
|
||||||
location /user_uploads {
|
location /user_uploads {
|
||||||
add_header X-Content-Type-Options nosniff;
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
|||||||
@@ -14,13 +14,36 @@ location /static/ {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Send longpoll requests to Tornado
|
# Send longpoll requests to Tornado
|
||||||
location ~ /json/get_events|/json/events|/api/v1/events {
|
location ~ /json/get_events|/json/events {
|
||||||
proxy_pass http://tornado;
|
proxy_pass http://tornado;
|
||||||
include /etc/nginx/zulip-include/proxy_longpolling;
|
include /etc/nginx/zulip-include/proxy_longpolling;
|
||||||
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Send longpoll requests to Tornado
|
||||||
|
location /api/v1/events {
|
||||||
|
|
||||||
|
add_header Access-Control-Allow-Origin *;
|
||||||
|
add_header Access-Control-Allow-Headers Authorization;
|
||||||
|
add_header Access-Control-Allow-Methods 'GET, POST';
|
||||||
|
|
||||||
|
if ($request_method = 'OPTIONS') {
|
||||||
|
add_header Access-Control-Allow-Origin *;
|
||||||
|
add_header Access-Control-Allow-Headers Authorization;
|
||||||
|
add_header Access-Control-Allow-Methods 'GET, POST';
|
||||||
|
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||||
|
add_header 'Content-Length' 0;
|
||||||
|
return 204;
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy_pass http://tornado;
|
||||||
|
include /etc/nginx/zulip-include/proxy_longpolling;
|
||||||
|
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# Send sockjs requests to Tornado
|
# Send sockjs requests to Tornado
|
||||||
location /sockjs {
|
location /sockjs {
|
||||||
proxy_pass http://tornado;
|
proxy_pass http://tornado;
|
||||||
@@ -38,4 +61,19 @@ location / {
|
|||||||
fastcgi_next_upstream off;
|
fastcgi_next_upstream off;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location /api/ {
|
||||||
|
add_header Access-Control-Allow-Origin *;
|
||||||
|
add_header Access-Control-Allow-Headers Authorization;
|
||||||
|
add_header Access-Control-Allow-Methods 'GET, POST';
|
||||||
|
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_pass django;
|
||||||
|
fastcgi_split_path_info ^()(.*)$;
|
||||||
|
# Second number set to `getconf PAGESIZE`
|
||||||
|
fastcgi_buffers 1024 4k;
|
||||||
|
fastcgi_max_temp_file_size 0;
|
||||||
|
fastcgi_next_upstream off;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
include /etc/nginx/zulip-include/app.d/*.conf;
|
include /etc/nginx/zulip-include/app.d/*.conf;
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
/.*\+.*@.*/ zulip@localhost
|
/.*\+.*@.*/ zulip@localhost
|
||||||
|
/^mm.*/ zulip@localhost
|
||||||
|
|||||||
@@ -38,15 +38,15 @@
|
|||||||
# The default values of these variables are driven from the -D command-line
|
# The default values of these variables are driven from the -D command-line
|
||||||
# option or PGDATA environment variable, represented here as ConfigDir.
|
# option or PGDATA environment variable, represented here as ConfigDir.
|
||||||
|
|
||||||
data_directory = '/var/lib/postgresql/9.1/main' # use data in another directory
|
data_directory = '/var/lib/postgresql/9.3/main' # use data in another directory
|
||||||
# (change requires restart)
|
# (change requires restart)
|
||||||
hba_file = '/etc/postgresql/9.1/main/pg_hba.conf' # host-based authentication file
|
hba_file = '/etc/postgresql/9.3/main/pg_hba.conf' # host-based authentication file
|
||||||
# (change requires restart)
|
# (change requires restart)
|
||||||
ident_file = '/etc/postgresql/9.1/main/pg_ident.conf' # ident configuration file
|
ident_file = '/etc/postgresql/9.3/main/pg_ident.conf' # ident configuration file
|
||||||
# (change requires restart)
|
# (change requires restart)
|
||||||
|
|
||||||
# If external_pid_file is not explicitly set, no extra PID file is written.
|
# If external_pid_file is not explicitly set, no extra PID file is written.
|
||||||
external_pid_file = '/var/run/postgresql/9.1-main.pid' # write an extra PID file
|
external_pid_file = '/var/run/postgresql/9.3-main.pid' # write an extra PID file
|
||||||
# (change requires restart)
|
# (change requires restart)
|
||||||
|
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ port = 5432 # (change requires restart)
|
|||||||
# Note: Increasing max_connections costs ~400 bytes of shared memory per
|
# Note: Increasing max_connections costs ~400 bytes of shared memory per
|
||||||
# connection slot, plus lock space (see max_locks_per_transaction).
|
# connection slot, plus lock space (see max_locks_per_transaction).
|
||||||
#superuser_reserved_connections = 3 # (change requires restart)
|
#superuser_reserved_connections = 3 # (change requires restart)
|
||||||
unix_socket_directory = '/var/run/postgresql' # (change requires restart)
|
unix_socket_directories = '/var/run/postgresql' # (change requires restart)
|
||||||
#unix_socket_group = '' # (change requires restart)
|
#unix_socket_group = '' # (change requires restart)
|
||||||
#unix_socket_permissions = 0777 # begin with 0 to use octal notation
|
#unix_socket_permissions = 0777 # begin with 0 to use octal notation
|
||||||
# (change requires restart)
|
# (change requires restart)
|
||||||
@@ -77,7 +77,7 @@ unix_socket_directory = '/var/run/postgresql' # (change requires restart)
|
|||||||
# - Security and Authentication -
|
# - Security and Authentication -
|
||||||
|
|
||||||
#authentication_timeout = 1min # 1s-600s
|
#authentication_timeout = 1min # 1s-600s
|
||||||
ssl = true # (change requires restart)
|
#ssl = true # (change requires restart)
|
||||||
#ssl_ciphers = 'ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH' # allowed SSL ciphers
|
#ssl_ciphers = 'ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH' # allowed SSL ciphers
|
||||||
# (change requires restart)
|
# (change requires restart)
|
||||||
#ssl_renegotiation_limit = 512MB # amount of data between renegotiations
|
#ssl_renegotiation_limit = 512MB # amount of data between renegotiations
|
||||||
@@ -106,7 +106,7 @@ ssl = true # (change requires restart)
|
|||||||
|
|
||||||
# - Memory -
|
# - Memory -
|
||||||
|
|
||||||
# shared_buffers = 24MB # min 128kB
|
shared_buffers = 128MB # min 128kB
|
||||||
# (change requires restart)
|
# (change requires restart)
|
||||||
#temp_buffers = 8MB # min 800kB
|
#temp_buffers = 8MB # min 800kB
|
||||||
#max_prepared_transactions = 0 # zero disables the feature
|
#max_prepared_transactions = 0 # zero disables the feature
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/env python
|
||||||
import psycopg2
|
import psycopg2
|
||||||
import psycopg2.extensions
|
import psycopg2.extensions
|
||||||
import select
|
import select
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
[main]
|
|
||||||
server = puppet.zulip.com
|
|
||||||
environment = production
|
|
||||||
confdir = /etc/puppet
|
|
||||||
logdir=/var/log/puppet
|
|
||||||
vardir=/var/lib/puppet
|
|
||||||
ssldir=/var/lib/puppet/ssl
|
|
||||||
rundir=/var/run/puppet
|
|
||||||
factpath=$vardir/lib/facter
|
|
||||||
templatedir=$confdir/templates
|
|
||||||
prerun_command=/etc/puppet/etckeeper-commit-pre
|
|
||||||
postrun_command=/etc/puppet/etckeeper-commit-post
|
|
||||||
modulepath = /root/zulip/puppet:/etc/puppet/modules:/usr/share/puppet/modules
|
|
||||||
|
|
||||||
[master]
|
|
||||||
environment = production
|
|
||||||
manifest = $confdir/environments/$environment/manifests/site.pp
|
|
||||||
modulepath = $confdir/environments/$environment/modules
|
|
||||||
[agent]
|
|
||||||
report = true
|
|
||||||
show_diff = true
|
|
||||||
environment = production
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# Redis configuration file example
|
# Redis configuration file example
|
||||||
|
|
||||||
# Note on units: when memory size is needed, it is possible to specifiy
|
# Note on units: when memory size is needed, it is possible to specify
|
||||||
# it in the usual form of 1k 5GB 4M and so forth:
|
# it in the usual form of 1k 5GB 4M and so forth:
|
||||||
#
|
#
|
||||||
# 1k => 1000 bytes
|
# 1k => 1000 bytes
|
||||||
@@ -12,6 +12,26 @@
|
|||||||
#
|
#
|
||||||
# units are case insensitive so 1GB 1Gb 1gB are all the same.
|
# units are case insensitive so 1GB 1Gb 1gB are all the same.
|
||||||
|
|
||||||
|
################################## INCLUDES ###################################
|
||||||
|
|
||||||
|
# Include one or more other config files here. This is useful if you
|
||||||
|
# have a standard template that goes to all Redis server but also need
|
||||||
|
# to customize a few per-server settings. Include files can include
|
||||||
|
# other files, so use this wisely.
|
||||||
|
#
|
||||||
|
# Notice option "include" won't be rewritten by command "CONFIG REWRITE"
|
||||||
|
# from admin or Redis Sentinel. Since Redis always uses the last processed
|
||||||
|
# line as value of a configuration directive, you'd better put includes
|
||||||
|
# at the beginning of this file to avoid overwriting config change at runtime.
|
||||||
|
#
|
||||||
|
# If instead you are interested in using includes to override configuration
|
||||||
|
# options, it is better to use include as the last line.
|
||||||
|
#
|
||||||
|
# include /path/to/local.conf
|
||||||
|
# include /path/to/other.conf
|
||||||
|
|
||||||
|
################################ GENERAL #####################################
|
||||||
|
|
||||||
# By default Redis does not run as a daemon. Use 'yes' if you need it.
|
# By default Redis does not run as a daemon. Use 'yes' if you need it.
|
||||||
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
|
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
|
||||||
daemonize yes
|
daemonize yes
|
||||||
@@ -24,9 +44,14 @@ pidfile /var/run/redis/redis-server.pid
|
|||||||
# If port 0 is specified Redis will not listen on a TCP socket.
|
# If port 0 is specified Redis will not listen on a TCP socket.
|
||||||
port 6379
|
port 6379
|
||||||
|
|
||||||
# If you want you can bind a single interface, if the bind option is not
|
# By default Redis listens for connections from all the network interfaces
|
||||||
# specified all the interfaces will listen for incoming connections.
|
# available on the server. It is possible to listen to just one or multiple
|
||||||
|
# interfaces using the "bind" configuration directive, followed by one or
|
||||||
|
# more IP addresses.
|
||||||
#
|
#
|
||||||
|
# Examples:
|
||||||
|
#
|
||||||
|
# bind 192.168.1.100 10.0.0.1
|
||||||
bind 127.0.0.1
|
bind 127.0.0.1
|
||||||
|
|
||||||
# Specify the path for the unix socket that will be used to listen for
|
# Specify the path for the unix socket that will be used to listen for
|
||||||
@@ -39,15 +64,31 @@ bind 127.0.0.1
|
|||||||
# Close the connection after a client is idle for N seconds (0 to disable)
|
# Close the connection after a client is idle for N seconds (0 to disable)
|
||||||
timeout 0
|
timeout 0
|
||||||
|
|
||||||
# Set server verbosity to 'debug'
|
# TCP keepalive.
|
||||||
# it can be one of:
|
#
|
||||||
|
# If non-zero, use SO_KEEPALIVE to send TCP ACKs to clients in absence
|
||||||
|
# of communication. This is useful for two reasons:
|
||||||
|
#
|
||||||
|
# 1) Detect dead peers.
|
||||||
|
# 2) Take the connection alive from the point of view of network
|
||||||
|
# equipment in the middle.
|
||||||
|
#
|
||||||
|
# On Linux, the specified value (in seconds) is the period used to send ACKs.
|
||||||
|
# Note that to close the connection the double of the time is needed.
|
||||||
|
# On other kernels the period depends on the kernel configuration.
|
||||||
|
#
|
||||||
|
# A reasonable value for this option is 60 seconds.
|
||||||
|
tcp-keepalive 0
|
||||||
|
|
||||||
|
# Specify the server verbosity level.
|
||||||
|
# This can be one of:
|
||||||
# debug (a lot of information, useful for development/testing)
|
# debug (a lot of information, useful for development/testing)
|
||||||
# verbose (many rarely useful info, but not a mess like the debug level)
|
# verbose (many rarely useful info, but not a mess like the debug level)
|
||||||
# notice (moderately verbose, what you want in production probably)
|
# notice (moderately verbose, what you want in production probably)
|
||||||
# warning (only very important / critical messages are logged)
|
# warning (only very important / critical messages are logged)
|
||||||
loglevel notice
|
loglevel notice
|
||||||
|
|
||||||
# Specify the log file name. Also 'stdout' can be used to force
|
# Specify the log file name. Also the empty string can be used to force
|
||||||
# Redis to log on the standard output. Note that if you use standard
|
# Redis to log on the standard output. Note that if you use standard
|
||||||
# output for logging but daemonize, logs will be sent to /dev/null
|
# output for logging but daemonize, logs will be sent to /dev/null
|
||||||
logfile /var/log/redis/redis-server.log
|
logfile /var/log/redis/redis-server.log
|
||||||
@@ -59,7 +100,7 @@ logfile /var/log/redis/redis-server.log
|
|||||||
# Specify the syslog identity.
|
# Specify the syslog identity.
|
||||||
# syslog-ident redis
|
# syslog-ident redis
|
||||||
|
|
||||||
# Specify the syslog facility. Must be USER or between LOCAL0-LOCAL7.
|
# Specify the syslog facility. Must be USER or between LOCAL0-LOCAL7.
|
||||||
# syslog-facility local0
|
# syslog-facility local0
|
||||||
|
|
||||||
# Set the number of databases. The default database is DB 0, you can select
|
# Set the number of databases. The default database is DB 0, you can select
|
||||||
@@ -67,7 +108,7 @@ logfile /var/log/redis/redis-server.log
|
|||||||
# dbid is a number between 0 and 'databases'-1
|
# dbid is a number between 0 and 'databases'-1
|
||||||
databases 16
|
databases 16
|
||||||
|
|
||||||
################################ SNAPSHOTTING #################################
|
################################ SNAPSHOTTING ################################
|
||||||
#
|
#
|
||||||
# Save the DB on disk:
|
# Save the DB on disk:
|
||||||
#
|
#
|
||||||
@@ -82,10 +123,31 @@ databases 16
|
|||||||
# after 60 sec if at least 10000 keys changed
|
# after 60 sec if at least 10000 keys changed
|
||||||
#
|
#
|
||||||
# Note: you can disable saving at all commenting all the "save" lines.
|
# Note: you can disable saving at all commenting all the "save" lines.
|
||||||
|
#
|
||||||
|
# It is also possible to remove all the previously configured save
|
||||||
|
# points by adding a save directive with a single empty string argument
|
||||||
|
# like in the following example:
|
||||||
|
#
|
||||||
|
# save ""
|
||||||
|
|
||||||
# save 900 1
|
save 900 1
|
||||||
# save 300 10
|
save 300 10
|
||||||
# save 60 10000
|
save 60 10000
|
||||||
|
|
||||||
|
# By default Redis will stop accepting writes if RDB snapshots are enabled
|
||||||
|
# (at least one save point) and the latest background save failed.
|
||||||
|
# This will make the user aware (in a hard way) that data is not persisting
|
||||||
|
# on disk properly, otherwise chances are that no one will notice and some
|
||||||
|
# disaster will happen.
|
||||||
|
#
|
||||||
|
# If the background saving process will start working again Redis will
|
||||||
|
# automatically allow writes again.
|
||||||
|
#
|
||||||
|
# However if you have setup your proper monitoring of the Redis server
|
||||||
|
# and persistence, you may want to disable this feature so that Redis will
|
||||||
|
# continue to work as usual even if there are problems with disk,
|
||||||
|
# permissions, and so forth.
|
||||||
|
stop-writes-on-bgsave-error yes
|
||||||
|
|
||||||
# Compress string objects using LZF when dump .rdb databases?
|
# Compress string objects using LZF when dump .rdb databases?
|
||||||
# For default that's set to 'yes' as it's almost always a win.
|
# For default that's set to 'yes' as it's almost always a win.
|
||||||
@@ -93,6 +155,15 @@ databases 16
|
|||||||
# the dataset will likely be bigger if you have compressible values or keys.
|
# the dataset will likely be bigger if you have compressible values or keys.
|
||||||
rdbcompression yes
|
rdbcompression yes
|
||||||
|
|
||||||
|
# Since version 5 of RDB a CRC64 checksum is placed at the end of the file.
|
||||||
|
# This makes the format more resistant to corruption but there is a performance
|
||||||
|
# hit to pay (around 10%) when saving and loading RDB files, so you can disable it
|
||||||
|
# for maximum performances.
|
||||||
|
#
|
||||||
|
# RDB files created with checksum disabled have a checksum of zero that will
|
||||||
|
# tell the loading code to skip the check.
|
||||||
|
rdbchecksum yes
|
||||||
|
|
||||||
# The filename where to dump the DB
|
# The filename where to dump the DB
|
||||||
dbfilename dump.rdb
|
dbfilename dump.rdb
|
||||||
|
|
||||||
@@ -101,7 +172,7 @@ dbfilename dump.rdb
|
|||||||
# The DB will be written inside this directory, with the filename specified
|
# The DB will be written inside this directory, with the filename specified
|
||||||
# above using the 'dbfilename' configuration directive.
|
# above using the 'dbfilename' configuration directive.
|
||||||
#
|
#
|
||||||
# Also the Append Only File will be created inside this directory.
|
# The Append Only File will also be created inside this directory.
|
||||||
#
|
#
|
||||||
# Note that you must specify a directory here, not a file name.
|
# Note that you must specify a directory here, not a file name.
|
||||||
dir /var/lib/redis
|
dir /var/lib/redis
|
||||||
@@ -122,27 +193,46 @@ dir /var/lib/redis
|
|||||||
#
|
#
|
||||||
# masterauth <master-password>
|
# masterauth <master-password>
|
||||||
|
|
||||||
# When a slave lost the connection with the master, or when the replication
|
# When a slave loses its connection with the master, or when the replication
|
||||||
# is still in progress, the slave can act in two different ways:
|
# is still in progress, the slave can act in two different ways:
|
||||||
#
|
#
|
||||||
# 1) if slave-serve-stale-data is set to 'yes' (the default) the slave will
|
# 1) if slave-serve-stale-data is set to 'yes' (the default) the slave will
|
||||||
# still reply to client requests, possibly with out of data data, or the
|
# still reply to client requests, possibly with out of date data, or the
|
||||||
# data set may just be empty if this is the first synchronization.
|
# data set may just be empty if this is the first synchronization.
|
||||||
#
|
#
|
||||||
# 2) if slave-serve-stale data is set to 'no' the slave will reply with
|
# 2) if slave-serve-stale-data is set to 'no' the slave will reply with
|
||||||
# an error "SYNC with master in progress" to all the kind of commands
|
# an error "SYNC with master in progress" to all the kind of commands
|
||||||
# but to INFO and SLAVEOF.
|
# but to INFO and SLAVEOF.
|
||||||
#
|
#
|
||||||
slave-serve-stale-data yes
|
slave-serve-stale-data yes
|
||||||
|
|
||||||
|
# You can configure a slave instance to accept writes or not. Writing against
|
||||||
|
# a slave instance may be useful to store some ephemeral data (because data
|
||||||
|
# written on a slave will be easily deleted after resync with the master) but
|
||||||
|
# may also cause problems if clients are writing to it because of a
|
||||||
|
# misconfiguration.
|
||||||
|
#
|
||||||
|
# Since Redis 2.6 by default slaves are read-only.
|
||||||
|
#
|
||||||
|
# Note: read only slaves are not designed to be exposed to untrusted clients
|
||||||
|
# on the internet. It's just a protection layer against misuse of the instance.
|
||||||
|
# Still a read only slave exports by default all the administrative commands
|
||||||
|
# such as CONFIG, DEBUG, and so forth. To a limited extent you can improve
|
||||||
|
# security of read only slaves using 'rename-command' to shadow all the
|
||||||
|
# administrative / dangerous commands.
|
||||||
|
slave-read-only yes
|
||||||
|
|
||||||
# Slaves send PINGs to server in a predefined interval. It's possible to change
|
# Slaves send PINGs to server in a predefined interval. It's possible to change
|
||||||
# this interval with the repl_ping_slave_period option. The default value is 10
|
# this interval with the repl_ping_slave_period option. The default value is 10
|
||||||
# seconds.
|
# seconds.
|
||||||
#
|
#
|
||||||
# repl-ping-slave-period 10
|
# repl-ping-slave-period 10
|
||||||
|
|
||||||
# The following option sets a timeout for both Bulk transfer I/O timeout and
|
# The following option sets the replication timeout for:
|
||||||
# master data or ping response timeout. The default value is 60 seconds.
|
#
|
||||||
|
# 1) Bulk transfer I/O during SYNC, from the point of view of slave.
|
||||||
|
# 2) Master timeout from the point of view of slaves (data, pings).
|
||||||
|
# 3) Slave timeout from the point of view of masters (REPLCONF ACK pings).
|
||||||
#
|
#
|
||||||
# It is important to make sure that this value is greater than the value
|
# It is important to make sure that this value is greater than the value
|
||||||
# specified for repl-ping-slave-period otherwise a timeout will be detected
|
# specified for repl-ping-slave-period otherwise a timeout will be detected
|
||||||
@@ -150,6 +240,80 @@ slave-serve-stale-data yes
|
|||||||
#
|
#
|
||||||
# repl-timeout 60
|
# repl-timeout 60
|
||||||
|
|
||||||
|
# Disable TCP_NODELAY on the slave socket after SYNC?
|
||||||
|
#
|
||||||
|
# If you select "yes" Redis will use a smaller number of TCP packets and
|
||||||
|
# less bandwidth to send data to slaves. But this can add a delay for
|
||||||
|
# the data to appear on the slave side, up to 40 milliseconds with
|
||||||
|
# Linux kernels using a default configuration.
|
||||||
|
#
|
||||||
|
# If you select "no" the delay for data to appear on the slave side will
|
||||||
|
# be reduced but more bandwidth will be used for replication.
|
||||||
|
#
|
||||||
|
# By default we optimize for low latency, but in very high traffic conditions
|
||||||
|
# or when the master and slaves are many hops away, turning this to "yes" may
|
||||||
|
# be a good idea.
|
||||||
|
repl-disable-tcp-nodelay no
|
||||||
|
|
||||||
|
# Set the replication backlog size. The backlog is a buffer that accumulates
|
||||||
|
# slave data when slaves are disconnected for some time, so that when a slave
|
||||||
|
# wants to reconnect again, often a full resync is not needed, but a partial
|
||||||
|
# resync is enough, just passing the portion of data the slave missed while
|
||||||
|
# disconnected.
|
||||||
|
#
|
||||||
|
# The biggest the replication backlog, the longer the time the slave can be
|
||||||
|
# disconnected and later be able to perform a partial resynchronization.
|
||||||
|
#
|
||||||
|
# The backlog is only allocated once there is at least a slave connected.
|
||||||
|
#
|
||||||
|
# repl-backlog-size 1mb
|
||||||
|
|
||||||
|
# After a master has no longer connected slaves for some time, the backlog
|
||||||
|
# will be freed. The following option configures the amount of seconds that
|
||||||
|
# need to elapse, starting from the time the last slave disconnected, for
|
||||||
|
# the backlog buffer to be freed.
|
||||||
|
#
|
||||||
|
# A value of 0 means to never release the backlog.
|
||||||
|
#
|
||||||
|
# repl-backlog-ttl 3600
|
||||||
|
|
||||||
|
# The slave priority is an integer number published by Redis in the INFO output.
|
||||||
|
# It is used by Redis Sentinel in order to select a slave to promote into a
|
||||||
|
# master if the master is no longer working correctly.
|
||||||
|
#
|
||||||
|
# A slave with a low priority number is considered better for promotion, so
|
||||||
|
# for instance if there are three slaves with priority 10, 100, 25 Sentinel will
|
||||||
|
# pick the one with priority 10, that is the lowest.
|
||||||
|
#
|
||||||
|
# However a special priority of 0 marks the slave as not able to perform the
|
||||||
|
# role of master, so a slave with priority of 0 will never be selected by
|
||||||
|
# Redis Sentinel for promotion.
|
||||||
|
#
|
||||||
|
# By default the priority is 100.
|
||||||
|
slave-priority 100
|
||||||
|
|
||||||
|
# It is possible for a master to stop accepting writes if there are less than
|
||||||
|
# N slaves connected, having a lag less or equal than M seconds.
|
||||||
|
#
|
||||||
|
# The N slaves need to be in "online" state.
|
||||||
|
#
|
||||||
|
# The lag in seconds, that must be <= the specified value, is calculated from
|
||||||
|
# the last ping received from the slave, that is usually sent every second.
|
||||||
|
#
|
||||||
|
# This option does not GUARANTEES that N replicas will accept the write, but
|
||||||
|
# will limit the window of exposure for lost writes in case not enough slaves
|
||||||
|
# are available, to the specified number of seconds.
|
||||||
|
#
|
||||||
|
# For example to require at least 3 slaves with a lag <= 10 seconds use:
|
||||||
|
#
|
||||||
|
# min-slaves-to-write 3
|
||||||
|
# min-slaves-max-lag 10
|
||||||
|
#
|
||||||
|
# Setting one or the other to 0 disables the feature.
|
||||||
|
#
|
||||||
|
# By default min-slaves-to-write is set to 0 (feature disabled) and
|
||||||
|
# min-slaves-max-lag is set to 10.
|
||||||
|
|
||||||
################################## SECURITY ###################################
|
################################## SECURITY ###################################
|
||||||
|
|
||||||
# Require clients to issue AUTH <PASSWORD> before processing any other
|
# Require clients to issue AUTH <PASSWORD> before processing any other
|
||||||
@@ -167,33 +331,39 @@ slave-serve-stale-data yes
|
|||||||
|
|
||||||
# Command renaming.
|
# Command renaming.
|
||||||
#
|
#
|
||||||
# It is possilbe to change the name of dangerous commands in a shared
|
# It is possible to change the name of dangerous commands in a shared
|
||||||
# environment. For instance the CONFIG command may be renamed into something
|
# environment. For instance the CONFIG command may be renamed into something
|
||||||
# of hard to guess so that it will be still available for internal-use
|
# hard to guess so that it will still be available for internal-use tools
|
||||||
# tools but not available for general clients.
|
# but not available for general clients.
|
||||||
#
|
#
|
||||||
# Example:
|
# Example:
|
||||||
#
|
#
|
||||||
# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
|
# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
|
||||||
#
|
#
|
||||||
# It is also possilbe to completely kill a command renaming it into
|
# It is also possible to completely kill a command by renaming it into
|
||||||
# an empty string:
|
# an empty string:
|
||||||
#
|
#
|
||||||
# rename-command CONFIG ""
|
# rename-command CONFIG ""
|
||||||
|
#
|
||||||
|
# Please note that changing the name of commands that are logged into the
|
||||||
|
# AOF file or transmitted to slaves may cause problems.
|
||||||
|
|
||||||
################################### LIMITS ####################################
|
################################### LIMITS ####################################
|
||||||
|
|
||||||
# Set the max number of connected clients at the same time. By default there
|
# Set the max number of connected clients at the same time. By default
|
||||||
# is no limit, and it's up to the number of file descriptors the Redis process
|
# this limit is set to 10000 clients, however if the Redis server is not
|
||||||
# is able to open. The special value '0' means no limits.
|
# able to configure the process file limit to allow for the specified limit
|
||||||
|
# the max number of allowed clients is set to the current file limit
|
||||||
|
# minus 32 (as Redis reserves a few file descriptors for internal uses).
|
||||||
|
#
|
||||||
# Once the limit is reached Redis will close all the new connections sending
|
# Once the limit is reached Redis will close all the new connections sending
|
||||||
# an error 'max number of clients reached'.
|
# an error 'max number of clients reached'.
|
||||||
#
|
#
|
||||||
# maxclients 128
|
# maxclients 10000
|
||||||
|
|
||||||
# Don't use more memory than the specified amount of bytes.
|
# Don't use more memory than the specified amount of bytes.
|
||||||
# When the memory limit is reached Redis will try to remove keys
|
# When the memory limit is reached Redis will try to remove keys
|
||||||
# accordingly to the eviction policy selected (see maxmemmory-policy).
|
# according to the eviction policy selected (see maxmemory-policy).
|
||||||
#
|
#
|
||||||
# If Redis can't remove keys according to the policy, or if the policy is
|
# If Redis can't remove keys according to the policy, or if the policy is
|
||||||
# set to 'noeviction', Redis will start to reply with errors to commands
|
# set to 'noeviction', Redis will start to reply with errors to commands
|
||||||
@@ -201,7 +371,7 @@ slave-serve-stale-data yes
|
|||||||
# to reply to read-only commands like GET.
|
# to reply to read-only commands like GET.
|
||||||
#
|
#
|
||||||
# This option is usually useful when using Redis as an LRU cache, or to set
|
# This option is usually useful when using Redis as an LRU cache, or to set
|
||||||
# an hard memory limit for an instance (using the 'noeviction' policy).
|
# a hard memory limit for an instance (using the 'noeviction' policy).
|
||||||
#
|
#
|
||||||
# WARNING: If you have slaves attached to an instance with maxmemory on,
|
# WARNING: If you have slaves attached to an instance with maxmemory on,
|
||||||
# the size of the output buffers needed to feed the slaves are subtracted
|
# the size of the output buffers needed to feed the slaves are subtracted
|
||||||
@@ -217,16 +387,16 @@ slave-serve-stale-data yes
|
|||||||
# maxmemory <bytes>
|
# maxmemory <bytes>
|
||||||
|
|
||||||
# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory
|
# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory
|
||||||
# is reached? You can select among five behavior:
|
# is reached. You can select among five behaviors:
|
||||||
#
|
#
|
||||||
# volatile-lru -> remove the key with an expire set using an LRU algorithm
|
# volatile-lru -> remove the key with an expire set using an LRU algorithm
|
||||||
# allkeys-lru -> remove any key accordingly to the LRU algorithm
|
# allkeys-lru -> remove any key accordingly to the LRU algorithm
|
||||||
# volatile-random -> remove a random key with an expire set
|
# volatile-random -> remove a random key with an expire set
|
||||||
# allkeys->random -> remove a random key, any key
|
# allkeys-random -> remove a random key, any key
|
||||||
# volatile-ttl -> remove the key with the nearest expire time (minor TTL)
|
# volatile-ttl -> remove the key with the nearest expire time (minor TTL)
|
||||||
# noeviction -> don't expire at all, just return an error on write operations
|
# noeviction -> don't expire at all, just return an error on write operations
|
||||||
#
|
#
|
||||||
# Note: with all the kind of policies, Redis will return an error on write
|
# Note: with any of the above policies, Redis will return an error on write
|
||||||
# operations, when there are not suitable keys for eviction.
|
# operations, when there are not suitable keys for eviction.
|
||||||
#
|
#
|
||||||
# At the date of writing this commands are: set setnx setex append
|
# At the date of writing this commands are: set setnx setex append
|
||||||
@@ -249,26 +419,29 @@ slave-serve-stale-data yes
|
|||||||
|
|
||||||
############################## APPEND ONLY MODE ###############################
|
############################## APPEND ONLY MODE ###############################
|
||||||
|
|
||||||
# By default Redis asynchronously dumps the dataset on disk. If you can live
|
# By default Redis asynchronously dumps the dataset on disk. This mode is
|
||||||
# with the idea that the latest records will be lost if something like a crash
|
# good enough in many applications, but an issue with the Redis process or
|
||||||
# happens this is the preferred way to run Redis. If instead you care a lot
|
# a power outage may result into a few minutes of writes lost (depending on
|
||||||
# about your data and don't want to that a single record can get lost you should
|
# the configured save points).
|
||||||
# enable the append only mode: when this mode is enabled Redis will append
|
|
||||||
# every write operation received in the file appendonly.aof. This file will
|
|
||||||
# be read on startup in order to rebuild the full dataset in memory.
|
|
||||||
#
|
#
|
||||||
# Note that you can have both the async dumps and the append only file if you
|
# The Append Only File is an alternative persistence mode that provides
|
||||||
# like (you have to comment the "save" statements above to disable the dumps).
|
# much better durability. For instance using the default data fsync policy
|
||||||
# Still if append only mode is enabled Redis will load the data from the
|
# (see later in the config file) Redis can lose just one second of writes in a
|
||||||
# log file at startup ignoring the dump.rdb file.
|
# dramatic event like a server power outage, or a single write if something
|
||||||
|
# wrong with the Redis process itself happens, but the operating system is
|
||||||
|
# still running correctly.
|
||||||
#
|
#
|
||||||
# IMPORTANT: Check the BGREWRITEAOF to check how to rewrite the append
|
# AOF and RDB persistence can be enabled at the same time without problems.
|
||||||
# log file in background when it gets too big.
|
# If the AOF is enabled on startup Redis will load the AOF, that is the file
|
||||||
|
# with the better durability guarantees.
|
||||||
|
#
|
||||||
|
# Please check http://redis.io/topics/persistence for more information.
|
||||||
|
|
||||||
appendonly no
|
appendonly no
|
||||||
|
|
||||||
# The name of the append only file (default: "appendonly.aof")
|
# The name of the append only file (default: "appendonly.aof")
|
||||||
# appendfilename appendonly.aof
|
|
||||||
|
appendfilename "appendonly.aof"
|
||||||
|
|
||||||
# The fsync() call tells the Operating System to actually write data on disk
|
# The fsync() call tells the Operating System to actually write data on disk
|
||||||
# instead to wait for more data in the output buffer. Some OS will really flush
|
# instead to wait for more data in the output buffer. Some OS will really flush
|
||||||
@@ -278,16 +451,19 @@ appendonly no
|
|||||||
#
|
#
|
||||||
# no: don't fsync, just let the OS flush the data when it wants. Faster.
|
# no: don't fsync, just let the OS flush the data when it wants. Faster.
|
||||||
# always: fsync after every write to the append only log . Slow, Safest.
|
# always: fsync after every write to the append only log . Slow, Safest.
|
||||||
# everysec: fsync only if one second passed since the last fsync. Compromise.
|
# everysec: fsync only one time every second. Compromise.
|
||||||
#
|
#
|
||||||
# The default is "everysec" that's usually the right compromise between
|
# The default is "everysec", as that's usually the right compromise between
|
||||||
# speed and data safety. It's up to you to understand if you can relax this to
|
# speed and data safety. It's up to you to understand if you can relax this to
|
||||||
# "no" that will will let the operating system flush the output buffer when
|
# "no" that will let the operating system flush the output buffer when
|
||||||
# it wants, for better performances (but if you can live with the idea of
|
# it wants, for better performances (but if you can live with the idea of
|
||||||
# some data loss consider the default persistence mode that's snapshotting),
|
# some data loss consider the default persistence mode that's snapshotting),
|
||||||
# or on the contrary, use "always" that's very slow but a bit safer than
|
# or on the contrary, use "always" that's very slow but a bit safer than
|
||||||
# everysec.
|
# everysec.
|
||||||
#
|
#
|
||||||
|
# More details please check the following article:
|
||||||
|
# http://antirez.com/post/redis-persistence-demystified.html
|
||||||
|
#
|
||||||
# If unsure, use "everysec".
|
# If unsure, use "everysec".
|
||||||
|
|
||||||
# appendfsync always
|
# appendfsync always
|
||||||
@@ -305,21 +481,22 @@ appendfsync everysec
|
|||||||
# that will prevent fsync() from being called in the main process while a
|
# that will prevent fsync() from being called in the main process while a
|
||||||
# BGSAVE or BGREWRITEAOF is in progress.
|
# BGSAVE or BGREWRITEAOF is in progress.
|
||||||
#
|
#
|
||||||
# This means that while another child is saving the durability of Redis is
|
# This means that while another child is saving, the durability of Redis is
|
||||||
# the same as "appendfsync none", that in pratical terms means that it is
|
# the same as "appendfsync none". In practical terms, this means that it is
|
||||||
# possible to lost up to 30 seconds of log in the worst scenario (with the
|
# possible to lose up to 30 seconds of log in the worst scenario (with the
|
||||||
# default Linux settings).
|
# default Linux settings).
|
||||||
#
|
#
|
||||||
# If you have latency problems turn this to "yes". Otherwise leave it as
|
# If you have latency problems turn this to "yes". Otherwise leave it as
|
||||||
# "no" that is the safest pick from the point of view of durability.
|
# "no" that is the safest pick from the point of view of durability.
|
||||||
|
|
||||||
no-appendfsync-on-rewrite no
|
no-appendfsync-on-rewrite no
|
||||||
|
|
||||||
# Automatic rewrite of the append only file.
|
# Automatic rewrite of the append only file.
|
||||||
# Redis is able to automatically rewrite the log file implicitly calling
|
# Redis is able to automatically rewrite the log file implicitly calling
|
||||||
# BGREWRITEAOF when the AOF log size will growth by the specified percentage.
|
# BGREWRITEAOF when the AOF log size grows by the specified percentage.
|
||||||
#
|
#
|
||||||
# This is how it works: Redis remembers the size of the AOF file after the
|
# This is how it works: Redis remembers the size of the AOF file after the
|
||||||
# latest rewrite (or if no rewrite happened since the restart, the size of
|
# latest rewrite (if no rewrite has happened since the restart, the size of
|
||||||
# the AOF at startup is used).
|
# the AOF at startup is used).
|
||||||
#
|
#
|
||||||
# This base size is compared to the current size. If the current size is
|
# This base size is compared to the current size. If the current size is
|
||||||
@@ -328,12 +505,30 @@ no-appendfsync-on-rewrite no
|
|||||||
# is useful to avoid rewriting the AOF file even if the percentage increase
|
# is useful to avoid rewriting the AOF file even if the percentage increase
|
||||||
# is reached but it is still pretty small.
|
# is reached but it is still pretty small.
|
||||||
#
|
#
|
||||||
# Specify a precentage of zero in order to disable the automatic AOF
|
# Specify a percentage of zero in order to disable the automatic AOF
|
||||||
# rewrite feature.
|
# rewrite feature.
|
||||||
|
|
||||||
auto-aof-rewrite-percentage 100
|
auto-aof-rewrite-percentage 100
|
||||||
auto-aof-rewrite-min-size 64mb
|
auto-aof-rewrite-min-size 64mb
|
||||||
|
|
||||||
|
################################ LUA SCRIPTING ###############################
|
||||||
|
|
||||||
|
# Max execution time of a Lua script in milliseconds.
|
||||||
|
#
|
||||||
|
# If the maximum execution time is reached Redis will log that a script is
|
||||||
|
# still in execution after the maximum allowed time and will start to
|
||||||
|
# reply to queries with an error.
|
||||||
|
#
|
||||||
|
# When a long running script exceed the maximum execution time only the
|
||||||
|
# SCRIPT KILL and SHUTDOWN NOSAVE commands are available. The first can be
|
||||||
|
# used to stop a script that did not yet called write commands. The second
|
||||||
|
# is the only way to shut down the server in the case a write commands was
|
||||||
|
# already issue by the script but the user don't want to wait for the natural
|
||||||
|
# termination of the script.
|
||||||
|
#
|
||||||
|
# Set it to 0 or a negative value for unlimited execution without warnings.
|
||||||
|
lua-time-limit 5000
|
||||||
|
|
||||||
################################## SLOW LOG ###################################
|
################################## SLOW LOG ###################################
|
||||||
|
|
||||||
# The Redis Slow Log is a system to log queries that exceeded a specified
|
# The Redis Slow Log is a system to log queries that exceeded a specified
|
||||||
@@ -358,88 +553,59 @@ slowlog-log-slower-than 10000
|
|||||||
# You can reclaim memory used by the slow log with SLOWLOG RESET.
|
# You can reclaim memory used by the slow log with SLOWLOG RESET.
|
||||||
slowlog-max-len 128
|
slowlog-max-len 128
|
||||||
|
|
||||||
################################ VIRTUAL MEMORY ###############################
|
############################# Event notification ##############################
|
||||||
|
|
||||||
### WARNING! Virtual Memory is deprecated in Redis 2.4
|
# Redis can notify Pub/Sub clients about events happening in the key space.
|
||||||
### The use of Virtual Memory is strongly discouraged.
|
# This feature is documented at http://redis.io/topics/keyspace-events
|
||||||
|
|
||||||
# Virtual Memory allows Redis to work with datasets bigger than the actual
|
|
||||||
# amount of RAM needed to hold the whole dataset in memory.
|
|
||||||
# In order to do so very used keys are taken in memory while the other keys
|
|
||||||
# are swapped into a swap file, similarly to what operating systems do
|
|
||||||
# with memory pages.
|
|
||||||
#
|
#
|
||||||
# To enable VM just set 'vm-enabled' to yes, and set the following three
|
# For instance if keyspace events notification is enabled, and a client
|
||||||
# VM parameters accordingly to your needs.
|
# performs a DEL operation on key "foo" stored in the Database 0, two
|
||||||
|
# messages will be published via Pub/Sub:
|
||||||
vm-enabled no
|
|
||||||
# vm-enabled yes
|
|
||||||
|
|
||||||
# This is the path of the Redis swap file. As you can guess, swap files
|
|
||||||
# can't be shared by different Redis instances, so make sure to use a swap
|
|
||||||
# file for every redis process you are running. Redis will complain if the
|
|
||||||
# swap file is already in use.
|
|
||||||
#
|
#
|
||||||
# The best kind of storage for the Redis swap file (that's accessed at random)
|
# PUBLISH __keyspace@0__:foo del
|
||||||
# is a Solid State Disk (SSD).
|
# PUBLISH __keyevent@0__:del foo
|
||||||
#
|
#
|
||||||
# *** WARNING *** if you are using a shared hosting the default of putting
|
# It is possible to select the events that Redis will notify among a set
|
||||||
# the swap file under /tmp is not secure. Create a dir with access granted
|
# of classes. Every class is identified by a single character:
|
||||||
# only to Redis user and configure Redis to create the swap file there.
|
|
||||||
vm-swap-file /var/lib/redis/redis.swap
|
|
||||||
|
|
||||||
# vm-max-memory configures the VM to use at max the specified amount of
|
|
||||||
# RAM. Everything that deos not fit will be swapped on disk *if* possible, that
|
|
||||||
# is, if there is still enough contiguous space in the swap file.
|
|
||||||
#
|
#
|
||||||
# With vm-max-memory 0 the system will swap everything it can. Not a good
|
# K Keyspace events, published with __keyspace@<db>__ prefix.
|
||||||
# default, just specify the max amount of RAM you can in bytes, but it's
|
# E Keyevent events, published with __keyevent@<db>__ prefix.
|
||||||
# better to leave some margin. For instance specify an amount of RAM
|
# g Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ...
|
||||||
# that's more or less between 60 and 80% of your free RAM.
|
# $ String commands
|
||||||
vm-max-memory 0
|
# l List commands
|
||||||
|
# s Set commands
|
||||||
# Redis swap files is split into pages. An object can be saved using multiple
|
# h Hash commands
|
||||||
# contiguous pages, but pages can't be shared between different objects.
|
# z Sorted set commands
|
||||||
# So if your page is too big, small objects swapped out on disk will waste
|
# x Expired events (events generated every time a key expires)
|
||||||
# a lot of space. If you page is too small, there is less space in the swap
|
# e Evicted events (events generated when a key is evicted for maxmemory)
|
||||||
# file (assuming you configured the same number of total swap file pages).
|
# A Alias for g$lshzxe, so that the "AKE" string means all the events.
|
||||||
#
|
#
|
||||||
# If you use a lot of small objects, use a page size of 64 or 32 bytes.
|
# The "notify-keyspace-events" takes as argument a string that is composed
|
||||||
# If you use a lot of big objects, use a bigger page size.
|
# by zero or multiple characters. The empty string means that notifications
|
||||||
# If unsure, use the default :)
|
# are disabled at all.
|
||||||
vm-page-size 32
|
|
||||||
|
|
||||||
# Number of total memory pages in the swap file.
|
|
||||||
# Given that the page table (a bitmap of free/used pages) is taken in memory,
|
|
||||||
# every 8 pages on disk will consume 1 byte of RAM.
|
|
||||||
#
|
#
|
||||||
# The total swap size is vm-page-size * vm-pages
|
# Example: to enable list and generic events, from the point of view of the
|
||||||
|
# event name, use:
|
||||||
#
|
#
|
||||||
# With the default of 32-bytes memory pages and 134217728 pages Redis will
|
# notify-keyspace-events Elg
|
||||||
# use a 4 GB swap file, that will use 16 MB of RAM for the page table.
|
|
||||||
#
|
#
|
||||||
# It's better to use the smallest acceptable value for your application,
|
# Example 2: to get the stream of the expired keys subscribing to channel
|
||||||
# but the default is large in order to work in most conditions.
|
# name __keyevent@0__:expired use:
|
||||||
vm-pages 134217728
|
|
||||||
|
|
||||||
# Max number of VM I/O threads running at the same time.
|
|
||||||
# This threads are used to read/write data from/to swap file, since they
|
|
||||||
# also encode and decode objects from disk to memory or the reverse, a bigger
|
|
||||||
# number of threads can help with big objects even if they can't help with
|
|
||||||
# I/O itself as the physical device may not be able to couple with many
|
|
||||||
# reads/writes operations at the same time.
|
|
||||||
#
|
#
|
||||||
# The special value of 0 turn off threaded I/O and enables the blocking
|
# notify-keyspace-events Ex
|
||||||
# Virtual Memory implementation.
|
#
|
||||||
vm-max-threads 4
|
# By default all notifications are disabled because most users don't need
|
||||||
|
# this feature and the feature has some overhead. Note that if you don't
|
||||||
|
# specify at least one of K or E, no events will be delivered.
|
||||||
|
notify-keyspace-events ""
|
||||||
|
|
||||||
############################### ADVANCED CONFIG ###############################
|
############################### ADVANCED CONFIG ###############################
|
||||||
# Hashes are encoded in a special way (much more memory efficient) when they
|
|
||||||
# have at max a given numer of elements, and the biggest element does not
|
# Hashes are encoded using a memory efficient data structure when they have a
|
||||||
# exceed a given threshold. You can configure this limits with the following
|
# small number of entries, and the biggest entry does not exceed a given
|
||||||
# configuration directives.
|
# threshold. These thresholds can be configured using the following directives.
|
||||||
hash-max-zipmap-entries 512
|
hash-max-ziplist-entries 512
|
||||||
hash-max-zipmap-value 64
|
hash-max-ziplist-value 64
|
||||||
|
|
||||||
# Similarly to hashes, small lists are also encoded in a special way in order
|
# Similarly to hashes, small lists are also encoded in a special way in order
|
||||||
# to save a lot of space. The special representation is only used when
|
# to save a lot of space. The special representation is only used when
|
||||||
@@ -462,9 +628,9 @@ zset-max-ziplist-value 64
|
|||||||
|
|
||||||
# Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in
|
# Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in
|
||||||
# order to help rehashing the main Redis hash table (the one mapping top-level
|
# order to help rehashing the main Redis hash table (the one mapping top-level
|
||||||
# keys to values). The hash table implementation redis uses (see dict.c)
|
# keys to values). The hash table implementation Redis uses (see dict.c)
|
||||||
# performs a lazy rehashing: the more operation you run into an hash table
|
# performs a lazy rehashing: the more operation you run into a hash table
|
||||||
# that is rhashing, the more rehashing "steps" are performed, so if the
|
# that is rehashing, the more rehashing "steps" are performed, so if the
|
||||||
# server is idle the rehashing is never complete and some more memory is used
|
# server is idle the rehashing is never complete and some more memory is used
|
||||||
# by the hash table.
|
# by the hash table.
|
||||||
#
|
#
|
||||||
@@ -480,12 +646,65 @@ zset-max-ziplist-value 64
|
|||||||
# want to free memory asap when possible.
|
# want to free memory asap when possible.
|
||||||
activerehashing yes
|
activerehashing yes
|
||||||
|
|
||||||
################################## INCLUDES ###################################
|
# The client output buffer limits can be used to force disconnection of clients
|
||||||
|
# that are not reading data from the server fast enough for some reason (a
|
||||||
# Include one or more other config files here. This is useful if you
|
# common reason is that a Pub/Sub client can't consume messages as fast as the
|
||||||
# have a standard template that goes to all redis server but also need
|
# publisher can produce them).
|
||||||
# to customize a few per-server settings. Include files can include
|
|
||||||
# other files, so use this wisely.
|
|
||||||
#
|
#
|
||||||
# include /path/to/local.conf
|
# The limit can be set differently for the three different classes of clients:
|
||||||
# include /path/to/other.conf
|
#
|
||||||
|
# normal -> normal clients
|
||||||
|
# slave -> slave clients and MONITOR clients
|
||||||
|
# pubsub -> clients subscribed to at least one pubsub channel or pattern
|
||||||
|
#
|
||||||
|
# The syntax of every client-output-buffer-limit directive is the following:
|
||||||
|
#
|
||||||
|
# client-output-buffer-limit <class> <hard limit> <soft limit> <soft seconds>
|
||||||
|
#
|
||||||
|
# A client is immediately disconnected once the hard limit is reached, or if
|
||||||
|
# the soft limit is reached and remains reached for the specified number of
|
||||||
|
# seconds (continuously).
|
||||||
|
# So for instance if the hard limit is 32 megabytes and the soft limit is
|
||||||
|
# 16 megabytes / 10 seconds, the client will get disconnected immediately
|
||||||
|
# if the size of the output buffers reach 32 megabytes, but will also get
|
||||||
|
# disconnected if the client reaches 16 megabytes and continuously overcomes
|
||||||
|
# the limit for 10 seconds.
|
||||||
|
#
|
||||||
|
# By default normal clients are not limited because they don't receive data
|
||||||
|
# without asking (in a push way), but just after a request, so only
|
||||||
|
# asynchronous clients may create a scenario where data is requested faster
|
||||||
|
# than it can read.
|
||||||
|
#
|
||||||
|
# Instead there is a default limit for pubsub and slave clients, since
|
||||||
|
# subscribers and slaves receive data in a push fashion.
|
||||||
|
#
|
||||||
|
# Both the hard or the soft limit can be disabled by setting them to zero.
|
||||||
|
client-output-buffer-limit normal 0 0 0
|
||||||
|
client-output-buffer-limit slave 256mb 64mb 60
|
||||||
|
client-output-buffer-limit pubsub 32mb 8mb 60
|
||||||
|
|
||||||
|
# Redis calls an internal function to perform many background tasks, like
|
||||||
|
# closing connections of clients in timeout, purging expired keys that are
|
||||||
|
# never requested, and so forth.
|
||||||
|
#
|
||||||
|
# Not all tasks are performed with the same frequency, but Redis checks for
|
||||||
|
# tasks to perform accordingly to the specified "hz" value.
|
||||||
|
#
|
||||||
|
# By default "hz" is set to 10. Raising the value will use more CPU when
|
||||||
|
# Redis is idle, but at the same time will make Redis more responsive when
|
||||||
|
# there are many keys expiring at the same time, and timeouts may be
|
||||||
|
# handled with more precision.
|
||||||
|
#
|
||||||
|
# The range is between 1 and 500, however a value over 100 is usually not
|
||||||
|
# a good idea. Most users should use the default of 10 and raise this up to
|
||||||
|
# 100 only in environments where very low latency is required.
|
||||||
|
hz 10
|
||||||
|
|
||||||
|
# When a child rewrites the AOF file, if the following option is enabled
|
||||||
|
# the file will be fsync-ed every 32 MB of data generated. This is useful
|
||||||
|
# in order to commit the file to the disk more incrementally and avoid
|
||||||
|
# big latency spikes.
|
||||||
|
aof-rewrite-incremental-fsync yes
|
||||||
|
|
||||||
|
# Zulip-specific configuration: disable saving to disk.
|
||||||
|
save ""
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
|
|||||||
user=zulip ; setuid to this UNIX account to run the program
|
user=zulip ; setuid to this UNIX account to run the program
|
||||||
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
||||||
stdout_logfile=/var/log/zulip/django.log ; stdout log path, NONE for none; default AUTO
|
stdout_logfile=/var/log/zulip/django.log ; stdout log path, NONE for none; default AUTO
|
||||||
;stdout_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB)
|
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
|
||||||
;stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
|
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
|
||||||
;stdout_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
|
;stdout_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
|
||||||
;stdout_events_enabled=false ; emit events on stdout writes (default false)
|
;stdout_events_enabled=false ; emit events on stdout writes (default false)
|
||||||
;stderr_logfile=/var/log/zulip/app.err ; stderr log path, NONE for none; default AUTO
|
;stderr_logfile=/var/log/zulip/app.err ; stderr log path, NONE for none; default AUTO
|
||||||
@@ -52,6 +52,8 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
|
|||||||
user=zulip ; setuid to this UNIX account to run the program
|
user=zulip ; setuid to this UNIX account to run the program
|
||||||
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
||||||
stdout_logfile=/var/log/zulip/tornado.log ; stdout log path, NONE for none; default AUTO
|
stdout_logfile=/var/log/zulip/tornado.log ; stdout log path, NONE for none; default AUTO
|
||||||
|
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
|
||||||
|
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
|
||||||
directory=/home/zulip/deployments/current/
|
directory=/home/zulip/deployments/current/
|
||||||
|
|
||||||
[program:zulip-events-user-activity]
|
[program:zulip-events-user-activity]
|
||||||
@@ -64,6 +66,8 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
|
|||||||
user=zulip ; setuid to this UNIX account to run the program
|
user=zulip ; setuid to this UNIX account to run the program
|
||||||
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
||||||
stdout_logfile=/var/log/zulip/events-user-activity.log ; stdout log path, NONE for none; default AUTO
|
stdout_logfile=/var/log/zulip/events-user-activity.log ; stdout log path, NONE for none; default AUTO
|
||||||
|
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
|
||||||
|
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
|
||||||
directory=/home/zulip/deployments/current/
|
directory=/home/zulip/deployments/current/
|
||||||
|
|
||||||
[program:zulip-events-user-activity-interval]
|
[program:zulip-events-user-activity-interval]
|
||||||
@@ -76,6 +80,8 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
|
|||||||
user=zulip ; setuid to this UNIX account to run the program
|
user=zulip ; setuid to this UNIX account to run the program
|
||||||
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
||||||
stdout_logfile=/var/log/zulip/events-user-activity-interval.log ; stdout log path, NONE for none; default AUTO
|
stdout_logfile=/var/log/zulip/events-user-activity-interval.log ; stdout log path, NONE for none; default AUTO
|
||||||
|
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
|
||||||
|
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
|
||||||
directory=/home/zulip/deployments/current/
|
directory=/home/zulip/deployments/current/
|
||||||
|
|
||||||
[program:zulip-events-user-presence]
|
[program:zulip-events-user-presence]
|
||||||
@@ -88,6 +94,8 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
|
|||||||
user=zulip ; setuid to this UNIX account to run the program
|
user=zulip ; setuid to this UNIX account to run the program
|
||||||
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
||||||
stdout_logfile=/var/log/zulip/events-user-presence.log ; stdout log path, NONE for none; default AUTO
|
stdout_logfile=/var/log/zulip/events-user-presence.log ; stdout log path, NONE for none; default AUTO
|
||||||
|
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
|
||||||
|
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
|
||||||
directory=/home/zulip/deployments/current/
|
directory=/home/zulip/deployments/current/
|
||||||
|
|
||||||
[program:zulip-events-signups]
|
[program:zulip-events-signups]
|
||||||
@@ -100,6 +108,8 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
|
|||||||
user=zulip ; setuid to this UNIX account to run the program
|
user=zulip ; setuid to this UNIX account to run the program
|
||||||
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
||||||
stdout_logfile=/var/log/zulip/events-signups.log ; stdout log path, NONE for none; default AUTO
|
stdout_logfile=/var/log/zulip/events-signups.log ; stdout log path, NONE for none; default AUTO
|
||||||
|
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
|
||||||
|
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
|
||||||
directory=/home/zulip/deployments/current/
|
directory=/home/zulip/deployments/current/
|
||||||
|
|
||||||
[program:zulip-events-confirmation-emails]
|
[program:zulip-events-confirmation-emails]
|
||||||
@@ -112,6 +122,8 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
|
|||||||
user=zulip ; setuid to this UNIX account to run the program
|
user=zulip ; setuid to this UNIX account to run the program
|
||||||
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
||||||
stdout_logfile=/var/log/zulip/events-confirmation-emails.log ; stdout log path, NONE for none; default AUTO
|
stdout_logfile=/var/log/zulip/events-confirmation-emails.log ; stdout log path, NONE for none; default AUTO
|
||||||
|
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
|
||||||
|
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
|
||||||
directory=/home/zulip/deployments/current/
|
directory=/home/zulip/deployments/current/
|
||||||
|
|
||||||
[program:zulip-events-missedmessage_reminders]
|
[program:zulip-events-missedmessage_reminders]
|
||||||
@@ -124,6 +136,8 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
|
|||||||
user=zulip ; setuid to this UNIX account to run the program
|
user=zulip ; setuid to this UNIX account to run the program
|
||||||
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
||||||
stdout_logfile=/var/log/zulip/events-missedmessage_reminders.log ; stdout log path, NONE for none; default AUTO
|
stdout_logfile=/var/log/zulip/events-missedmessage_reminders.log ; stdout log path, NONE for none; default AUTO
|
||||||
|
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
|
||||||
|
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
|
||||||
directory=/home/zulip/deployments/current/
|
directory=/home/zulip/deployments/current/
|
||||||
|
|
||||||
[program:zulip-events-missedmessage_mobile_notifications]
|
[program:zulip-events-missedmessage_mobile_notifications]
|
||||||
@@ -136,6 +150,8 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
|
|||||||
user=zulip ; setuid to this UNIX account to run the program
|
user=zulip ; setuid to this UNIX account to run the program
|
||||||
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
||||||
stdout_logfile=/var/log/zulip/events-missedmessage_mobile_notifications.log ; stdout log path, NONE for none; default AUTO
|
stdout_logfile=/var/log/zulip/events-missedmessage_mobile_notifications.log ; stdout log path, NONE for none; default AUTO
|
||||||
|
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
|
||||||
|
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
|
||||||
directory=/home/zulip/deployments/current/
|
directory=/home/zulip/deployments/current/
|
||||||
|
|
||||||
[program:zulip-events-slowqueries]
|
[program:zulip-events-slowqueries]
|
||||||
@@ -148,6 +164,8 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
|
|||||||
user=zulip ; setuid to this UNIX account to run the program
|
user=zulip ; setuid to this UNIX account to run the program
|
||||||
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
||||||
stdout_logfile=/var/log/zulip/events-slow_queries.log ; stdout log path, NONE for none; default AUTO
|
stdout_logfile=/var/log/zulip/events-slow_queries.log ; stdout log path, NONE for none; default AUTO
|
||||||
|
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
|
||||||
|
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
|
||||||
directory=/home/zulip/deployments/current/
|
directory=/home/zulip/deployments/current/
|
||||||
|
|
||||||
[program:zulip-events-message_sender]
|
[program:zulip-events-message_sender]
|
||||||
@@ -161,6 +179,8 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
|
|||||||
user=zulip ; setuid to this UNIX account to run the program
|
user=zulip ; setuid to this UNIX account to run the program
|
||||||
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
||||||
stdout_logfile=/var/log/zulip/events-message_sender.log ; stdout log path, NONE for none; default AUTO
|
stdout_logfile=/var/log/zulip/events-message_sender.log ; stdout log path, NONE for none; default AUTO
|
||||||
|
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
|
||||||
|
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
|
||||||
directory=/home/zulip/deployments/current/
|
directory=/home/zulip/deployments/current/
|
||||||
numprocs=5
|
numprocs=5
|
||||||
|
|
||||||
@@ -174,6 +194,8 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
|
|||||||
user=zulip ; setuid to this UNIX account to run the program
|
user=zulip ; setuid to this UNIX account to run the program
|
||||||
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
||||||
stdout_logfile=/var/log/zulip/events-feedback_messages.log ; stdout log path, NONE for none; default AUTO
|
stdout_logfile=/var/log/zulip/events-feedback_messages.log ; stdout log path, NONE for none; default AUTO
|
||||||
|
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
|
||||||
|
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
|
||||||
directory=/home/zulip/deployments/current/
|
directory=/home/zulip/deployments/current/
|
||||||
|
|
||||||
[program:zulip-events-error_reports]
|
[program:zulip-events-error_reports]
|
||||||
@@ -186,6 +208,8 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
|
|||||||
user=zulip ; setuid to this UNIX account to run the program
|
user=zulip ; setuid to this UNIX account to run the program
|
||||||
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
||||||
stdout_logfile=/var/log/zulip/events-error_reports.log ; stdout log path, NONE for none; default AUTO
|
stdout_logfile=/var/log/zulip/events-error_reports.log ; stdout log path, NONE for none; default AUTO
|
||||||
|
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
|
||||||
|
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
|
||||||
directory=/home/zulip/deployments/current/
|
directory=/home/zulip/deployments/current/
|
||||||
|
|
||||||
[program:zulip-events-digest_emails]
|
[program:zulip-events-digest_emails]
|
||||||
@@ -198,6 +222,8 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
|
|||||||
user=zulip ; setuid to this UNIX account to run the program
|
user=zulip ; setuid to this UNIX account to run the program
|
||||||
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
||||||
stdout_logfile=/var/log/zulip/events-digest_emails.log ; stdout log path, NONE for none; default AUTO
|
stdout_logfile=/var/log/zulip/events-digest_emails.log ; stdout log path, NONE for none; default AUTO
|
||||||
|
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
|
||||||
|
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
|
||||||
directory=/home/zulip/deployments/current/
|
directory=/home/zulip/deployments/current/
|
||||||
|
|
||||||
[program:zulip-events-email_mirror]
|
[program:zulip-events-email_mirror]
|
||||||
@@ -210,6 +236,8 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
|
|||||||
user=zulip ; setuid to this UNIX account to run the program
|
user=zulip ; setuid to this UNIX account to run the program
|
||||||
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
||||||
stdout_logfile=/var/log/zulip/events-email_mirror.log ; stdout log path, NONE for none; default AUTO
|
stdout_logfile=/var/log/zulip/events-email_mirror.log ; stdout log path, NONE for none; default AUTO
|
||||||
|
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
|
||||||
|
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
|
||||||
directory=/home/zulip/deployments/current/
|
directory=/home/zulip/deployments/current/
|
||||||
|
|
||||||
[program:zulip-deliver-enqueued-emails]
|
[program:zulip-deliver-enqueued-emails]
|
||||||
@@ -222,6 +250,8 @@ stopwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
|
|||||||
user=zulip ; setuid to this UNIX account to run the program
|
user=zulip ; setuid to this UNIX account to run the program
|
||||||
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
||||||
stdout_logfile=/var/log/zulip/events-deliver_enqueued_emails.log ; stdout log path, NONE for none; default AUTO
|
stdout_logfile=/var/log/zulip/events-deliver_enqueued_emails.log ; stdout log path, NONE for none; default AUTO
|
||||||
|
stdout_logfile_maxbytes=1GB ; max # logfile bytes b4 rotation (default 50MB)
|
||||||
|
stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
|
||||||
directory=/home/zulip/deployments/current/
|
directory=/home/zulip/deployments/current/
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ class zulip::app_frontend {
|
|||||||
# Django dependencies
|
# Django dependencies
|
||||||
"python-django",
|
"python-django",
|
||||||
"python-django-guardian",
|
"python-django-guardian",
|
||||||
"python-django-auth-openid",
|
|
||||||
"python-django-south",
|
|
||||||
"python-django-pipeline",
|
"python-django-pipeline",
|
||||||
"python-django-bitfield",
|
"python-django-bitfield",
|
||||||
# Needed for mock objects in decorators
|
# Needed for mock objects in decorators
|
||||||
@@ -28,7 +26,7 @@ class zulip::app_frontend {
|
|||||||
# Used for Hesiod lookups, etc.
|
# Used for Hesiod lookups, etc.
|
||||||
"python-dns",
|
"python-dns",
|
||||||
# Needed to access our database
|
# Needed to access our database
|
||||||
"postgresql-client-9.1",
|
"postgresql-client-9.3",
|
||||||
"python-psycopg2",
|
"python-psycopg2",
|
||||||
# Needed for building complex DB queries
|
# Needed for building complex DB queries
|
||||||
"python-sqlalchemy",
|
"python-sqlalchemy",
|
||||||
@@ -49,7 +47,6 @@ class zulip::app_frontend {
|
|||||||
# Needed for S3 file uploads
|
# Needed for S3 file uploads
|
||||||
"python-boto",
|
"python-boto",
|
||||||
# Needed to send email
|
# Needed to send email
|
||||||
"python-postmonkey",
|
|
||||||
"python-mandrill",
|
"python-mandrill",
|
||||||
# Needed to generate diffs for edits
|
# Needed to generate diffs for edits
|
||||||
"python-diff-match-patch",
|
"python-diff-match-patch",
|
||||||
@@ -59,10 +56,12 @@ class zulip::app_frontend {
|
|||||||
"python-gcm-client",
|
"python-gcm-client",
|
||||||
# Needed for avatar image resizing
|
# Needed for avatar image resizing
|
||||||
"python-imaging",
|
"python-imaging",
|
||||||
# Needed for LDAP support
|
# Needed for LDAP support
|
||||||
"python-django-auth-ldap",
|
"python-django-auth-ldap",
|
||||||
# Needed for Google Apps mobile auth
|
# Needed for Google Apps mobile auth
|
||||||
"python-googleapi",
|
"python-googleapi",
|
||||||
|
# Needed for JWT-based auth
|
||||||
|
"python-pyjwt",
|
||||||
]
|
]
|
||||||
define safepackage ( $ensure = present ) {
|
define safepackage ( $ensure = present ) {
|
||||||
if !defined(Package[$title]) {
|
if !defined(Package[$title]) {
|
||||||
|
|||||||
@@ -22,13 +22,12 @@ class zulip::base {
|
|||||||
|
|
||||||
group { 'zulip':
|
group { 'zulip':
|
||||||
ensure => present,
|
ensure => present,
|
||||||
gid => '1000',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
user { 'zulip':
|
user { 'zulip':
|
||||||
ensure => present,
|
ensure => present,
|
||||||
uid => '1000',
|
|
||||||
gid => '1000',
|
|
||||||
require => Group['zulip'],
|
require => Group['zulip'],
|
||||||
|
gid => 'zulip',
|
||||||
shell => '/bin/bash',
|
shell => '/bin/bash',
|
||||||
home => '/home/zulip',
|
home => '/home/zulip',
|
||||||
managehome => true,
|
managehome => true,
|
||||||
@@ -41,14 +40,6 @@ class zulip::base {
|
|||||||
group => 'zulip',
|
group => 'zulip',
|
||||||
}
|
}
|
||||||
|
|
||||||
file { '/etc/puppet/puppet.conf':
|
|
||||||
ensure => file,
|
|
||||||
mode => 640,
|
|
||||||
owner => "root",
|
|
||||||
group => "root",
|
|
||||||
source => 'puppet:///modules/zulip/puppet.conf',
|
|
||||||
}
|
|
||||||
|
|
||||||
file { '/etc/security/limits.conf':
|
file { '/etc/security/limits.conf':
|
||||||
ensure => file,
|
ensure => file,
|
||||||
mode => 640,
|
mode => 640,
|
||||||
@@ -57,6 +48,13 @@ class zulip::base {
|
|||||||
source => 'puppet:///modules/zulip/limits.conf',
|
source => 'puppet:///modules/zulip/limits.conf',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# This directory is written to by cron jobs for reading by Nagios
|
||||||
|
file { '/var/lib/nagios_state/':
|
||||||
|
ensure => directory,
|
||||||
|
group => 'zulip',
|
||||||
|
mode => 774,
|
||||||
|
}
|
||||||
|
|
||||||
file { '/var/log/zulip':
|
file { '/var/log/zulip':
|
||||||
ensure => 'directory',
|
ensure => 'directory',
|
||||||
owner => 'zulip',
|
owner => 'zulip',
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class zulip::postfix_localmail {
|
|||||||
mode => 0644,
|
mode => 0644,
|
||||||
owner => root,
|
owner => root,
|
||||||
group => root,
|
group => root,
|
||||||
content => "@${fqdn}",
|
content => "${fqdn}",
|
||||||
}
|
}
|
||||||
|
|
||||||
file {'/etc/postfix/main.cf':
|
file {'/etc/postfix/main.cf':
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ class zulip::postgres_appdb {
|
|||||||
$appdb_packages = [# Needed to run process_fts_updates
|
$appdb_packages = [# Needed to run process_fts_updates
|
||||||
"python-psycopg2",
|
"python-psycopg2",
|
||||||
# Needed for our full text search system
|
# Needed for our full text search system
|
||||||
"postgresql-9.1-tsearch-extras",
|
"postgresql-9.3-tsearch-extras",
|
||||||
]
|
]
|
||||||
define safepackage ( $ensure = present ) {
|
define safepackage ( $ensure = present ) {
|
||||||
if !defined(Package[$title]) {
|
if !defined(Package[$title]) {
|
||||||
@@ -37,16 +37,16 @@ class zulip::postgres_appdb {
|
|||||||
notify => Service[supervisor],
|
notify => Service[supervisor],
|
||||||
}
|
}
|
||||||
|
|
||||||
file { '/usr/share/postgresql/9.1/tsearch_data/en_us.dict':
|
file { '/usr/share/postgresql/9.3/tsearch_data/en_us.dict':
|
||||||
ensure => 'link',
|
ensure => 'link',
|
||||||
target => '/var/cache/postgresql/dicts/en_us.dict',
|
target => '/var/cache/postgresql/dicts/en_us.dict',
|
||||||
}
|
}
|
||||||
file { '/usr/share/postgresql/9.1/tsearch_data/en_us.affix':
|
file { '/usr/share/postgresql/9.3/tsearch_data/en_us.affix':
|
||||||
ensure => 'link',
|
ensure => 'link',
|
||||||
target => '/var/cache/postgresql/dicts/en_us.affix',
|
target => '/var/cache/postgresql/dicts/en_us.affix',
|
||||||
}
|
}
|
||||||
file { "/usr/share/postgresql/9.1/tsearch_data/zulip_english.stop":
|
file { "/usr/share/postgresql/9.3/tsearch_data/zulip_english.stop":
|
||||||
require => Package["postgresql-9.1"],
|
require => Package["postgresql-9.3"],
|
||||||
ensure => file,
|
ensure => file,
|
||||||
owner => "root",
|
owner => "root",
|
||||||
group => "root",
|
group => "root",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
class zulip::postgres_common {
|
class zulip::postgres_common {
|
||||||
$postgres_packages = [# The database itself
|
$postgres_packages = [# The database itself
|
||||||
"postgresql-9.1",
|
"postgresql-9.3",
|
||||||
# tools for database setup
|
# tools for database setup
|
||||||
"pgtune",
|
"pgtune",
|
||||||
# tools for database monitoring
|
# tools for database monitoring
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
class zulip::rabbit {
|
class zulip::rabbit {
|
||||||
$rabbit_packages = [# Needed to run rabbitmq
|
$rabbit_packages = [# Needed to run rabbitmq
|
||||||
|
"erlang-base",
|
||||||
"rabbitmq-server",
|
"rabbitmq-server",
|
||||||
]
|
]
|
||||||
package { $rabbit_packages: ensure => "installed" }
|
package { $rabbit_packages: ensure => "installed" }
|
||||||
@@ -39,5 +40,21 @@ class zulip::rabbit {
|
|||||||
source => "puppet:///modules/zulip/rabbitmq/rabbitmq.config",
|
source => "puppet:///modules/zulip/rabbitmq/rabbitmq.config",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# epmd doesn't have an init script. This won't leak epmd processes
|
||||||
|
# because epmd checks if one is already running and exits if so.
|
||||||
|
#
|
||||||
|
# TODO: Ideally we'd still check if it's already running to keep the
|
||||||
|
# puppet log for what is being changed clean
|
||||||
|
exec { "epmd":
|
||||||
|
command => "epmd -daemon",
|
||||||
|
require => Package[erlang-base],
|
||||||
|
path => "/usr/bin/:/bin/",
|
||||||
|
}
|
||||||
|
|
||||||
|
service { "rabbitmq-server":
|
||||||
|
ensure => running,
|
||||||
|
require => Exec["epmd"],
|
||||||
|
}
|
||||||
|
|
||||||
# TODO: Should also call exactly once "configure-rabbitmq"
|
# TODO: Should also call exactly once "configure-rabbitmq"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
class zulip::enterprise {
|
class zulip::voyager {
|
||||||
include zulip::base
|
include zulip::base
|
||||||
include zulip::app_frontend
|
include zulip::app_frontend
|
||||||
include zulip::postgres_appdb
|
include zulip::postgres_appdb
|
||||||
include zulip::redis
|
include zulip::redis
|
||||||
|
|
||||||
apt::source {'zulip':
|
apt::source {'zulip':
|
||||||
location => 'http://apt.zulip.com/enterprise',
|
location => 'http://ppa.launchpad.net/tabbott/zulip/ubuntu',
|
||||||
release => 'precise',
|
release => 'trusty',
|
||||||
repos => 'v1',
|
repos => 'main',
|
||||||
key => 'E5FB045CA79AA8FC25FDE9F3B4F81D07A529EF65',
|
key => '84C2BE60E50E336456E4749CE84240474E26AE47',
|
||||||
key_source => 'https://zulip.com/dist/keys/enterprise.asc',
|
key_source => 'https://zulip.com/dist/keys/zulip.asc',
|
||||||
pin => '995',
|
pin => '995',
|
||||||
include_src => true,
|
include_src => true,
|
||||||
}
|
}
|
||||||
@@ -44,8 +44,8 @@ class zulip::enterprise {
|
|||||||
source => "puppet:///modules/zulip/cron.d/restart-zulip",
|
source => "puppet:///modules/zulip/cron.d/restart-zulip",
|
||||||
}
|
}
|
||||||
|
|
||||||
file { '/etc/postgresql/9.1/main/postgresql.conf.template':
|
file { '/etc/postgresql/9.3/main/postgresql.conf.template':
|
||||||
require => Package["postgresql-9.1"],
|
require => Package["postgresql-9.3"],
|
||||||
ensure => file,
|
ensure => file,
|
||||||
owner => "postgres",
|
owner => "postgres",
|
||||||
group => "postgres",
|
group => "postgres",
|
||||||
@@ -82,12 +82,12 @@ vm.dirty_background_ratio = 5
|
|||||||
exec { 'pgtune':
|
exec { 'pgtune':
|
||||||
require => Package["pgtune"],
|
require => Package["pgtune"],
|
||||||
# Let Postgres use half the memory on the machine
|
# Let Postgres use half the memory on the machine
|
||||||
command => "pgtune -T Web -M $half_memory -i /etc/postgresql/9.1/main/postgresql.conf.template -o /etc/postgresql/9.1/main/postgresql.conf",
|
command => "pgtune -T Web -M $half_memory -i /etc/postgresql/9.3/main/postgresql.conf.template -o /etc/postgresql/9.3/main/postgresql.conf",
|
||||||
refreshonly => true,
|
refreshonly => true,
|
||||||
subscribe => File['/etc/postgresql/9.1/main/postgresql.conf.template']
|
subscribe => File['/etc/postgresql/9.3/main/postgresql.conf.template']
|
||||||
}
|
}
|
||||||
|
|
||||||
exec { 'pg_ctlcluster 9.1 main restart':
|
exec { 'pg_ctlcluster 9.3 main restart':
|
||||||
require => Exec["sysctl_p"],
|
require => Exec["sysctl_p"],
|
||||||
refreshonly => true,
|
refreshonly => true,
|
||||||
subscribe => [ Exec['pgtune'], File['/etc/sysctl.d/40-postgresql.conf'] ]
|
subscribe => [ Exec['pgtune'], File['/etc/sysctl.d/40-postgresql.conf'] ]
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# This file is managed by puppet; local changes will be overridden.
|
# This file is managed by puppet; local changes will be overridden.
|
||||||
|
|
||||||
smtpd_banner = $myhostname ESMTP $mail_name (Zulip Enterprise)
|
smtpd_banner = $myhostname ESMTP $mail_name (Zulip Voyager)
|
||||||
biff = no
|
biff = no
|
||||||
|
|
||||||
# appending .domain is the MUA's job.
|
# appending .domain is the MUA's job.
|
||||||
|
|||||||
@@ -1,83 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIE+zCCA+OgAwIBAgIQDJOL1Hip5tpyq5kwwV/lQzANBgkqhkiG9w0BAQUFADBz
|
|
||||||
MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD
|
|
||||||
VQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEZMBcGA1UE
|
|
||||||
AxMQUG9zaXRpdmVTU0wgQ0EgMjAeFw0xMzA3MTIwMDAwMDBaFw0xNDA3MTIyMzU5
|
|
||||||
NTlaMFExITAfBgNVBAsTGERvbWFpbiBDb250cm9sIFZhbGlkYXRlZDEUMBIGA1UE
|
|
||||||
CxMLUG9zaXRpdmVTU0wxFjAUBgNVBAMTDWFwaS56dWxpcC5jb20wggEiMA0GCSqG
|
|
||||||
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+GsCaNbs6bR4CB0MJ2NARH0JMoXsCVHHC
|
|
||||||
fT149arpZoAf9s4cmUgqe/qXl7jeh1Hb5UtARhchNMR/poFX9Dd73qTVfDEvtASW
|
|
||||||
ezpsEAB3KJQiISjUyL8xxRAggYf5AXtJ2QzaHoQ3sQk65lVuarB4aQwFB+SsbdtU
|
|
||||||
dDTHAgnJ3p8Vz4cFjus2n/EW+td5c74V7Y6nAj/ww8ygRRdAvfGmHa84ZHEu+xCI
|
|
||||||
5cnX0704hJETDfv1ELg257Rmg5pbwHfThSGs5KWv7AQqpLg+wNRD/s5LO1o6zB1z
|
|
||||||
Toidcq8HaD2/hS3oAQUibySRjieTHE1JU1ueqjfn0grrCpoSjgrDAgMBAAGjggGr
|
|
||||||
MIIBpzAfBgNVHSMEGDAWgBSZ5EBfaxRePgXZ3dNjVPxiuPcArDAdBgNVHQ4EFgQU
|
|
||||||
py+lc7gytud0YnB4ddplmEgkEeIwDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQC
|
|
||||||
MAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMFAGA1UdIARJMEcwOwYL
|
|
||||||
KwYBBAGyMQECAgcwLDAqBggrBgEFBQcCARYeaHR0cDovL3d3dy5wb3NpdGl2ZXNz
|
|
||||||
bC5jb20vQ1BTMAgGBmeBDAECATA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vY3Js
|
|
||||||
LmNvbW9kb2NhLmNvbS9Qb3NpdGl2ZVNTTENBMi5jcmwwbAYIKwYBBQUHAQEEYDBe
|
|
||||||
MDYGCCsGAQUFBzAChipodHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9Qb3NpdGl2ZVNT
|
|
||||||
TENBMi5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTAr
|
|
||||||
BgNVHREEJDAigg1hcGkuenVsaXAuY29tghF3d3cuYXBpLnp1bGlwLmNvbTANBgkq
|
|
||||||
hkiG9w0BAQUFAAOCAQEAQKpkB8eRq5K2KBMVFolxSqix4qWo/uPiOQU6kbjkJNdK
|
|
||||||
P1Wg+p1R1KsLTLDEZmqTnfIBluez/RqfEoPdh+cF2e0GP55Y2ogno+89oaW4ijUr
|
|
||||||
IgTor/b1ZVv+yQIi/u27hLpq/h5E5ZM6HpmQ5YcA4z3MY7VoXNxYY5iO34YzuD0n
|
|
||||||
emoDuM1JJuGTzPkxE/dUzRU7GUmi5cXQgdGQ9lvutI/DuyZsDJV54TW2882cpW82
|
|
||||||
5x4a77Esvx7VlqBC5KxN/NPN/ZwIs5vl4F1+/sf2Tr7oMDkZ4Tc944mkj5MAbhhm
|
|
||||||
JZV4K+MlPPP7VSWOr+y+lMHAAqk7nhBi8MPP4XOo0A==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIE5TCCA82gAwIBAgIQB28SRoFFnCjVSNaXxA4AGzANBgkqhkiG9w0BAQUFADBv
|
|
||||||
MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk
|
|
||||||
ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF
|
|
||||||
eHRlcm5hbCBDQSBSb290MB4XDTEyMDIxNjAwMDAwMFoXDTIwMDUzMDEwNDgzOFow
|
|
||||||
czELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
|
||||||
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxGTAXBgNV
|
|
||||||
BAMTEFBvc2l0aXZlU1NMIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
|
||||||
AoIBAQDo6jnjIqaqucQA0OeqZztDB71Pkuu8vgGjQK3g70QotdA6voBUF4V6a4Rs
|
|
||||||
NjbloyTi/igBkLzX3Q+5K05IdwVpr95XMLHo+xoD9jxbUx6hAUlocnPWMytDqTcy
|
|
||||||
Ug+uJ1YxMGCtyb1zLDnukNh1sCUhYHsqfwL9goUfdE+SNHNcHQCgsMDqmOK+ARRY
|
|
||||||
FygiinddUCXNmmym5QzlqyjDsiCJ8AckHpXCLsDl6ez2PRIHSD3SwyNWQezT3zVL
|
|
||||||
yOf2hgVSEEOajBd8i6q8eODwRTusgFX+KJPhChFo9FJXb/5IC1tdGmpnc5mCtJ5D
|
|
||||||
YD7HWyoSbhruyzmuwzWdqLxdsC/DAgMBAAGjggF3MIIBczAfBgNVHSMEGDAWgBSt
|
|
||||||
vZh6NLQm9/rEJlTvA73gJMtUGjAdBgNVHQ4EFgQUmeRAX2sUXj4F2d3TY1T8Yrj3
|
|
||||||
AKwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwEQYDVR0gBAow
|
|
||||||
CDAGBgRVHSAAMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0
|
|
||||||
LmNvbS9BZGRUcnVzdEV4dGVybmFsQ0FSb290LmNybDCBswYIKwYBBQUHAQEEgaYw
|
|
||||||
gaMwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9BZGRUcnVz
|
|
||||||
dEV4dGVybmFsQ0FSb290LnA3YzA5BggrBgEFBQcwAoYtaHR0cDovL2NydC51c2Vy
|
|
||||||
dHJ1c3QuY29tL0FkZFRydXN0VVROU0dDQ0EuY3J0MCUGCCsGAQUFBzABhhlodHRw
|
|
||||||
Oi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBBQUAA4IBAQCcNuNOrvGK
|
|
||||||
u2yXjI9LZ9Cf2ISqnyFfNaFbxCtjDei8d12nxDf9Sy2e6B1pocCEzNFti/OBy59L
|
|
||||||
dLBJKjHoN0DrH9mXoxoR1Sanbg+61b4s/bSRZNy+OxlQDXqV8wQTqbtHD4tc0azC
|
|
||||||
e3chUN1bq+70ptjUSlNrTa24yOfmUlhNQ0zCoiNPDsAgOa/fT0JbHtMJ9BgJWSrZ
|
|
||||||
6EoYvzL7+i1ki4fKWyvouAt+vhcSxwOCKa9Yr4WEXT0K3yNRw82vEL+AaXeRCk/l
|
|
||||||
uuGtm87fM04wO+mPZn+C+mv626PAcwDj1hKvTfIPWhRRH224hoFiB85ccsJP81cq
|
|
||||||
cdnUl4XmGFO3
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
|
|
||||||
MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
|
|
||||||
IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
|
|
||||||
MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
|
|
||||||
FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
|
|
||||||
bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
|
|
||||||
dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
|
|
||||||
H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
|
|
||||||
uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
|
|
||||||
mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
|
|
||||||
a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
|
|
||||||
E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
|
|
||||||
WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
|
|
||||||
VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
|
|
||||||
Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
|
|
||||||
cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
|
|
||||||
IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
|
|
||||||
AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
|
|
||||||
YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
|
|
||||||
6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
|
|
||||||
Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
|
|
||||||
c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
|
|
||||||
mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIE+zCCA+OgAwIBAgIQDJOL1Hip5tpyq5kwwV/lQzANBgkqhkiG9w0BAQUFADBz
|
|
||||||
MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD
|
|
||||||
VQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEZMBcGA1UE
|
|
||||||
AxMQUG9zaXRpdmVTU0wgQ0EgMjAeFw0xMzA3MTIwMDAwMDBaFw0xNDA3MTIyMzU5
|
|
||||||
NTlaMFExITAfBgNVBAsTGERvbWFpbiBDb250cm9sIFZhbGlkYXRlZDEUMBIGA1UE
|
|
||||||
CxMLUG9zaXRpdmVTU0wxFjAUBgNVBAMTDWFwaS56dWxpcC5jb20wggEiMA0GCSqG
|
|
||||||
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+GsCaNbs6bR4CB0MJ2NARH0JMoXsCVHHC
|
|
||||||
fT149arpZoAf9s4cmUgqe/qXl7jeh1Hb5UtARhchNMR/poFX9Dd73qTVfDEvtASW
|
|
||||||
ezpsEAB3KJQiISjUyL8xxRAggYf5AXtJ2QzaHoQ3sQk65lVuarB4aQwFB+SsbdtU
|
|
||||||
dDTHAgnJ3p8Vz4cFjus2n/EW+td5c74V7Y6nAj/ww8ygRRdAvfGmHa84ZHEu+xCI
|
|
||||||
5cnX0704hJETDfv1ELg257Rmg5pbwHfThSGs5KWv7AQqpLg+wNRD/s5LO1o6zB1z
|
|
||||||
Toidcq8HaD2/hS3oAQUibySRjieTHE1JU1ueqjfn0grrCpoSjgrDAgMBAAGjggGr
|
|
||||||
MIIBpzAfBgNVHSMEGDAWgBSZ5EBfaxRePgXZ3dNjVPxiuPcArDAdBgNVHQ4EFgQU
|
|
||||||
py+lc7gytud0YnB4ddplmEgkEeIwDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQC
|
|
||||||
MAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMFAGA1UdIARJMEcwOwYL
|
|
||||||
KwYBBAGyMQECAgcwLDAqBggrBgEFBQcCARYeaHR0cDovL3d3dy5wb3NpdGl2ZXNz
|
|
||||||
bC5jb20vQ1BTMAgGBmeBDAECATA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vY3Js
|
|
||||||
LmNvbW9kb2NhLmNvbS9Qb3NpdGl2ZVNTTENBMi5jcmwwbAYIKwYBBQUHAQEEYDBe
|
|
||||||
MDYGCCsGAQUFBzAChipodHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9Qb3NpdGl2ZVNT
|
|
||||||
TENBMi5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTAr
|
|
||||||
BgNVHREEJDAigg1hcGkuenVsaXAuY29tghF3d3cuYXBpLnp1bGlwLmNvbTANBgkq
|
|
||||||
hkiG9w0BAQUFAAOCAQEAQKpkB8eRq5K2KBMVFolxSqix4qWo/uPiOQU6kbjkJNdK
|
|
||||||
P1Wg+p1R1KsLTLDEZmqTnfIBluez/RqfEoPdh+cF2e0GP55Y2ogno+89oaW4ijUr
|
|
||||||
IgTor/b1ZVv+yQIi/u27hLpq/h5E5ZM6HpmQ5YcA4z3MY7VoXNxYY5iO34YzuD0n
|
|
||||||
emoDuM1JJuGTzPkxE/dUzRU7GUmi5cXQgdGQ9lvutI/DuyZsDJV54TW2882cpW82
|
|
||||||
5x4a77Esvx7VlqBC5KxN/NPN/ZwIs5vl4F1+/sf2Tr7oMDkZ4Tc944mkj5MAbhhm
|
|
||||||
JZV4K+MlPPP7VSWOr+y+lMHAAqk7nhBi8MPP4XOo0A==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFSzCCBDOgAwIBAgIQC9+c6kd+aB3quGVISZS4fzANBgkqhkiG9w0BAQsFADBw
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
|
||||||
|
dXJhbmNlIFNlcnZlciBDQTAeFw0xNTAyMDYwMDAwMDBaFw0xNzAyMDkxMjAwMDBa
|
||||||
|
MG4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
|
||||||
|
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxGzAZBgNVBAMTEmNo
|
||||||
|
YXQuZHJvcGJveGVyLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||||
|
AO8HnnyDj64aGeEoFewFuASlpw8YzBnbF9E1A4CFdevwXCfHhDUXUZd3nGwHTlUc
|
||||||
|
Yq/Yn6iDc0S08ZTM5OJmeeNxsZojHK6CaZjKEiRkerRVwq7AWEPvJWdVlmRjDXMX
|
||||||
|
rpGlL44L9voeKDr4ueq9uP85QIffbtF7wRFjxHH5ULPxcVFGeFsShaaWkK1YdVl0
|
||||||
|
C0KarUBxX6Dz0J5KB9Am2qGz7fEGmMeYmLjUQEohvD+NLnSHIH1gCCrnMDyp7SX4
|
||||||
|
iVlSwJBfZJB71uTB2+9CX3k+jgMA6l+KrjyUoFTJmxGkcwyEqKoCoJG2mL81L0fZ
|
||||||
|
Yx55K1kJh6qBXAg4JIwMD7UCAwEAAaOCAeEwggHdMB8GA1UdIwQYMBaAFFFo/5Cv
|
||||||
|
Agd1PMzZZWRiohK4WXI7MB0GA1UdDgQWBBQgWnzJolAbDp9oilo3SuR3LPcSIDAd
|
||||||
|
BgNVHREEFjAUghJjaGF0LmRyb3Bib3hlci5uZXQwDgYDVR0PAQH/BAQDAgWgMB0G
|
||||||
|
A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5o
|
||||||
|
dHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzMuY3JsMDSg
|
||||||
|
MqAwhi5odHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzMu
|
||||||
|
Y3JsMEIGA1UdIAQ7MDkwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBz
|
||||||
|
Oi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgYMGCCsGAQUFBwEBBHcwdTAkBggrBgEF
|
||||||
|
BQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tME0GCCsGAQUFBzAChkFodHRw
|
||||||
|
Oi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEySGlnaEFzc3VyYW5j
|
||||||
|
ZVNlcnZlckNBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQCa
|
||||||
|
dUkIIbDl2iEmWE//z9jPgFboPzkzDR+03cBuvBRkqQ8SD/+pfB/TiZQerKS+xcy7
|
||||||
|
NB/0kvBnMqGsknXYL9w2rGFv0R/sDHDCiwtxh+1mwS9r+AvmCRkA3T7mcSO3O9lI
|
||||||
|
dIbrIhPJHvmyac7rCAvmW1i4KTbCSaBOLLmSnXjLpa6E3zrv4Xn2k8u6eOCLNgqV
|
||||||
|
89qswf/pYZcvHKgyFZ9PdhwXxV9MO1c9U/GCWOZWXextAtmAvbxJDkc2JqT2mS1D
|
||||||
|
8GvkaMudfm1o/dYvv9F0tgsh4UGpWnvlp8IXZil2Ik4m2yfc37MoNgpNa0ytEJUp
|
||||||
|
tFDLVilooSEBYckHRdm+
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||||
|
ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL
|
||||||
|
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
|
||||||
|
LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy
|
||||||
|
YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2
|
||||||
|
4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC
|
||||||
|
Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1
|
||||||
|
itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn
|
||||||
|
4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X
|
||||||
|
sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft
|
||||||
|
bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA
|
||||||
|
MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
|
||||||
|
NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
|
||||||
|
dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t
|
||||||
|
L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG
|
||||||
|
BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ
|
||||||
|
UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D
|
||||||
|
aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd
|
||||||
|
aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH
|
||||||
|
E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly
|
||||||
|
/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu
|
||||||
|
xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF
|
||||||
|
0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae
|
||||||
|
cPUeybQ=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFQTCCBCmgAwIBAgIQAiBxGEAt+S6rlqaxlh4i9TANBgkqhkiG9w0BAQsFADBw
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
|
||||||
|
dXJhbmNlIFNlcnZlciBDQTAeFw0xNDA0MTYwMDAwMDBaFw0xNjA0MjAxMjAwMDBa
|
||||||
|
MGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
|
||||||
|
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxFjAUBgNVBAMTDWdp
|
||||||
|
dC56dWxpcC5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgo7bC
|
||||||
|
QDUprWNwBgGI1uytomGzO141oZQq0TY4VI/EXiAQ1gClyJ6NgEBPD+RVK4/82JIW
|
||||||
|
RLkztIaM3uyO6JXOBzDifehI32l2Tqj0ZtvipOzE/IJyucAXvVocHCtseKpCcUB0
|
||||||
|
pSXhie2RH9y0cTRZHMY7OW5N3+SE+W4W57eo0QCHzhKetcD0AOdIx1rDltuyPHCr
|
||||||
|
xybH4LIYTMsE71Nx7RZI3KJvlWUNQtvY0bF9Xy/2Ag47mLf1vlpWkvWRNTWd6t5v
|
||||||
|
7zcNAbohYAaeGrUrhFbTojIjzd31BioZPY5N4XJYDQCtlk+g3EhsarPRAsJ3+C/e
|
||||||
|
HJC3JVYxEtScUlULAgMBAAGjggHcMIIB2DAfBgNVHSMEGDAWgBRRaP+QrwIHdTzM
|
||||||
|
2WVkYqISuFlyOzAdBgNVHQ4EFgQU/AFjeJNjGOJat2Ng5D/djicf7lIwGAYDVR0R
|
||||||
|
BBEwD4INZ2l0Lnp1bGlwLm5ldDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYI
|
||||||
|
KwYBBQUHAwEGCCsGAQUFBwMCMHUGA1UdHwRuMGwwNKAyoDCGLmh0dHA6Ly9jcmwz
|
||||||
|
LmRpZ2ljZXJ0LmNvbS9zaGEyLWhhLXNlcnZlci1nMi5jcmwwNKAyoDCGLmh0dHA6
|
||||||
|
Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWhhLXNlcnZlci1nMi5jcmwwQgYDVR0g
|
||||||
|
BDswOTA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGln
|
||||||
|
aWNlcnQuY29tL0NQUzCBgwYIKwYBBQUHAQEEdzB1MCQGCCsGAQUFBzABhhhodHRw
|
||||||
|
Oi8vb2NzcC5kaWdpY2VydC5jb20wTQYIKwYBBQUHMAKGQWh0dHA6Ly9jYWNlcnRz
|
||||||
|
LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJIaWdoQXNzdXJhbmNlU2VydmVyQ0Eu
|
||||||
|
Y3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBAJUD9412uJCVG5lZ
|
||||||
|
AYWKQ101Mx5+IcbiNhFpyXiPhmPDHD+qAZUCoFbdcPA9U9AOwcI55+Z6hZ7bcYhB
|
||||||
|
KOSMEf60hwQbN1CdvR6oV25DZ6QbBF8R6PLMEym/T4auVj98wA1J1kgVS33SRoWt
|
||||||
|
PWa4eVXxJL/977CMJNoYh5hjmxivXq7swIrn+xA4D79euFPZdzqov6+oKtzRQNY5
|
||||||
|
qATfF4GD4Sj6qZqIetuIv42BcUGd+s0VH6GMDvKlcDA51q7N8WVoGrsIRHmOV2qF
|
||||||
|
fNSpzreV9YDFOv0KUJCThdJiwdJVNS/ZgE1fNvyhCNcbISBkfkSR8rROu5LY0xDB
|
||||||
|
51QMgbM=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
N CERTIFICATE-----
|
||||||
|
MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||||
|
ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL
|
||||||
|
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
|
||||||
|
LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy
|
||||||
|
YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2
|
||||||
|
4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC
|
||||||
|
Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1
|
||||||
|
itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn
|
||||||
|
4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X
|
||||||
|
sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft
|
||||||
|
bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA
|
||||||
|
MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
|
||||||
|
NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
|
||||||
|
dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t
|
||||||
|
L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG
|
||||||
|
BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ
|
||||||
|
UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D
|
||||||
|
aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd
|
||||||
|
aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH
|
||||||
|
E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly
|
||||||
|
/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu
|
||||||
|
xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF
|
||||||
|
0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae
|
||||||
|
cPUeybQ=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
31
puppet/zulip_internal/files/certs/git.zulip.net.crt
Normal file
31
puppet/zulip_internal/files/certs/git.zulip.net.crt
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFQTCCBCmgAwIBAgIQAiBxGEAt+S6rlqaxlh4i9TANBgkqhkiG9w0BAQsFADBw
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
|
||||||
|
dXJhbmNlIFNlcnZlciBDQTAeFw0xNDA0MTYwMDAwMDBaFw0xNjA0MjAxMjAwMDBa
|
||||||
|
MGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
|
||||||
|
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxFjAUBgNVBAMTDWdp
|
||||||
|
dC56dWxpcC5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgo7bC
|
||||||
|
QDUprWNwBgGI1uytomGzO141oZQq0TY4VI/EXiAQ1gClyJ6NgEBPD+RVK4/82JIW
|
||||||
|
RLkztIaM3uyO6JXOBzDifehI32l2Tqj0ZtvipOzE/IJyucAXvVocHCtseKpCcUB0
|
||||||
|
pSXhie2RH9y0cTRZHMY7OW5N3+SE+W4W57eo0QCHzhKetcD0AOdIx1rDltuyPHCr
|
||||||
|
xybH4LIYTMsE71Nx7RZI3KJvlWUNQtvY0bF9Xy/2Ag47mLf1vlpWkvWRNTWd6t5v
|
||||||
|
7zcNAbohYAaeGrUrhFbTojIjzd31BioZPY5N4XJYDQCtlk+g3EhsarPRAsJ3+C/e
|
||||||
|
HJC3JVYxEtScUlULAgMBAAGjggHcMIIB2DAfBgNVHSMEGDAWgBRRaP+QrwIHdTzM
|
||||||
|
2WVkYqISuFlyOzAdBgNVHQ4EFgQU/AFjeJNjGOJat2Ng5D/djicf7lIwGAYDVR0R
|
||||||
|
BBEwD4INZ2l0Lnp1bGlwLm5ldDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYI
|
||||||
|
KwYBBQUHAwEGCCsGAQUFBwMCMHUGA1UdHwRuMGwwNKAyoDCGLmh0dHA6Ly9jcmwz
|
||||||
|
LmRpZ2ljZXJ0LmNvbS9zaGEyLWhhLXNlcnZlci1nMi5jcmwwNKAyoDCGLmh0dHA6
|
||||||
|
Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWhhLXNlcnZlci1nMi5jcmwwQgYDVR0g
|
||||||
|
BDswOTA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGln
|
||||||
|
aWNlcnQuY29tL0NQUzCBgwYIKwYBBQUHAQEEdzB1MCQGCCsGAQUFBzABhhhodHRw
|
||||||
|
Oi8vb2NzcC5kaWdpY2VydC5jb20wTQYIKwYBBQUHMAKGQWh0dHA6Ly9jYWNlcnRz
|
||||||
|
LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJIaWdoQXNzdXJhbmNlU2VydmVyQ0Eu
|
||||||
|
Y3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBAJUD9412uJCVG5lZ
|
||||||
|
AYWKQ101Mx5+IcbiNhFpyXiPhmPDHD+qAZUCoFbdcPA9U9AOwcI55+Z6hZ7bcYhB
|
||||||
|
KOSMEf60hwQbN1CdvR6oV25DZ6QbBF8R6PLMEym/T4auVj98wA1J1kgVS33SRoWt
|
||||||
|
PWa4eVXxJL/977CMJNoYh5hjmxivXq7swIrn+xA4D79euFPZdzqov6+oKtzRQNY5
|
||||||
|
qATfF4GD4Sj6qZqIetuIv42BcUGd+s0VH6GMDvKlcDA51q7N8WVoGrsIRHmOV2qF
|
||||||
|
fNSpzreV9YDFOv0KUJCThdJiwdJVNS/ZgE1fNvyhCNcbISBkfkSR8rROu5LY0xDB
|
||||||
|
51QMgbM=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFRTCCBC2gAwIBAgIQDDxR9Pi3OvaLaxM1QQINATANBgkqhkiG9w0BAQsFADBw
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
|
||||||
|
dXJhbmNlIFNlcnZlciBDQTAeFw0xNDA0MTYwMDAwMDBaFw0xNjA0MjAxMjAwMDBa
|
||||||
|
MGsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
|
||||||
|
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxGDAWBgNVBAMTD211
|
||||||
|
bmluLnp1bGlwLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMmH
|
||||||
|
EH72mRFJapF9jJAHZs1dDxka0DD6vEzIlUPylq009VZguROUm1/2/37vtOaZdoRP
|
||||||
|
zJ+LNq1Aeam3JdVuNd2EA4Rl0UbZM1P+yMggfffMzLczQRTumSCaOPq5SMqnS0az
|
||||||
|
2UITCxknaQmW8g4nbLElChbW7GYFIYxSizfz5yTqV25mqMN1IIDpRJghGU6154Pk
|
||||||
|
VSPWvynzWmDAW9UJDBT9dqJp3TAFKNzQGad1ERkkPr2XXd71KjjLFfqKiVCAK4oq
|
||||||
|
r281CQEHh7uUPVq0zrwLvtCPaMx7Zq+0a82/ABnA2wEDiptSXZ6K/2LF/otGzXsy
|
||||||
|
udTRD/0hTBQ0R5Y9DscCAwEAAaOCAd4wggHaMB8GA1UdIwQYMBaAFFFo/5CvAgd1
|
||||||
|
PMzZZWRiohK4WXI7MB0GA1UdDgQWBBRsJooKV4ptTkrJjKsAJ7CwyvzzqTAaBgNV
|
||||||
|
HREEEzARgg9tdW5pbi56dWxpcC5uZXQwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW
|
||||||
|
MBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5odHRwOi8v
|
||||||
|
Y3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzIuY3JsMDSgMqAwhi5o
|
||||||
|
dHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzIuY3JsMEIG
|
||||||
|
A1UdIAQ7MDkwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3
|
||||||
|
LmRpZ2ljZXJ0LmNvbS9DUFMwgYMGCCsGAQUFBwEBBHcwdTAkBggrBgEFBQcwAYYY
|
||||||
|
aHR0cDovL29jc3AuZGlnaWNlcnQuY29tME0GCCsGAQUFBzAChkFodHRwOi8vY2Fj
|
||||||
|
ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEySGlnaEFzc3VyYW5jZVNlcnZl
|
||||||
|
ckNBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQAjA309Hd9C
|
||||||
|
lrPzMKjJTXP6G9PUH3YpkUVdRitV5lrNZwfQL5SomehxL9KG58Obvzuae0SJMWfE
|
||||||
|
ODP6jkPywbv0n4RKaQEQwB80CZj4nKqrnsJGToSVWE+Wso/E6tBF3NjFqZzVNok2
|
||||||
|
+ql6rElmI9H0n7be6x78p4TGqzEEbnS56hlppWXYQXPWi40vJSQCo8/YIy62L6wj
|
||||||
|
Ulaqdx+sqxE7qR/AwhWlsFpcKP2XRN91fzPtKj/mlGyyYk6r1gnhoqvSlQqqucKs
|
||||||
|
UJ60uG8I4hfwbGIJyuCX3ipvhl9RpH+UL4MQCPD8sKxQfnn7T5iEQylWubCsU3K5
|
||||||
|
ORxuyUfWjLpo
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||||
|
ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL
|
||||||
|
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
|
||||||
|
LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy
|
||||||
|
YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2
|
||||||
|
4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC
|
||||||
|
Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1
|
||||||
|
itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn
|
||||||
|
4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X
|
||||||
|
sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft
|
||||||
|
bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA
|
||||||
|
MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
|
||||||
|
NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
|
||||||
|
dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t
|
||||||
|
L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG
|
||||||
|
BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ
|
||||||
|
UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D
|
||||||
|
aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd
|
||||||
|
aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH
|
||||||
|
E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly
|
||||||
|
/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu
|
||||||
|
xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF
|
||||||
|
0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae
|
||||||
|
cPUeybQ=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
31
puppet/zulip_internal/files/certs/munin.zulip.net.crt
Normal file
31
puppet/zulip_internal/files/certs/munin.zulip.net.crt
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFRTCCBC2gAwIBAgIQDDxR9Pi3OvaLaxM1QQINATANBgkqhkiG9w0BAQsFADBw
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
|
||||||
|
dXJhbmNlIFNlcnZlciBDQTAeFw0xNDA0MTYwMDAwMDBaFw0xNjA0MjAxMjAwMDBa
|
||||||
|
MGsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
|
||||||
|
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxGDAWBgNVBAMTD211
|
||||||
|
bmluLnp1bGlwLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMmH
|
||||||
|
EH72mRFJapF9jJAHZs1dDxka0DD6vEzIlUPylq009VZguROUm1/2/37vtOaZdoRP
|
||||||
|
zJ+LNq1Aeam3JdVuNd2EA4Rl0UbZM1P+yMggfffMzLczQRTumSCaOPq5SMqnS0az
|
||||||
|
2UITCxknaQmW8g4nbLElChbW7GYFIYxSizfz5yTqV25mqMN1IIDpRJghGU6154Pk
|
||||||
|
VSPWvynzWmDAW9UJDBT9dqJp3TAFKNzQGad1ERkkPr2XXd71KjjLFfqKiVCAK4oq
|
||||||
|
r281CQEHh7uUPVq0zrwLvtCPaMx7Zq+0a82/ABnA2wEDiptSXZ6K/2LF/otGzXsy
|
||||||
|
udTRD/0hTBQ0R5Y9DscCAwEAAaOCAd4wggHaMB8GA1UdIwQYMBaAFFFo/5CvAgd1
|
||||||
|
PMzZZWRiohK4WXI7MB0GA1UdDgQWBBRsJooKV4ptTkrJjKsAJ7CwyvzzqTAaBgNV
|
||||||
|
HREEEzARgg9tdW5pbi56dWxpcC5uZXQwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW
|
||||||
|
MBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5odHRwOi8v
|
||||||
|
Y3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzIuY3JsMDSgMqAwhi5o
|
||||||
|
dHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzIuY3JsMEIG
|
||||||
|
A1UdIAQ7MDkwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3
|
||||||
|
LmRpZ2ljZXJ0LmNvbS9DUFMwgYMGCCsGAQUFBwEBBHcwdTAkBggrBgEFBQcwAYYY
|
||||||
|
aHR0cDovL29jc3AuZGlnaWNlcnQuY29tME0GCCsGAQUFBzAChkFodHRwOi8vY2Fj
|
||||||
|
ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEySGlnaEFzc3VyYW5jZVNlcnZl
|
||||||
|
ckNBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQAjA309Hd9C
|
||||||
|
lrPzMKjJTXP6G9PUH3YpkUVdRitV5lrNZwfQL5SomehxL9KG58Obvzuae0SJMWfE
|
||||||
|
ODP6jkPywbv0n4RKaQEQwB80CZj4nKqrnsJGToSVWE+Wso/E6tBF3NjFqZzVNok2
|
||||||
|
+ql6rElmI9H0n7be6x78p4TGqzEEbnS56hlppWXYQXPWi40vJSQCo8/YIy62L6wj
|
||||||
|
Ulaqdx+sqxE7qR/AwhWlsFpcKP2XRN91fzPtKj/mlGyyYk6r1gnhoqvSlQqqucKs
|
||||||
|
UJ60uG8I4hfwbGIJyuCX3ipvhl9RpH+UL4MQCPD8sKxQfnn7T5iEQylWubCsU3K5
|
||||||
|
ORxuyUfWjLpo
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFRzCCBC+gAwIBAgIQCwfY+SvxDTFK0KY29dqHWjANBgkqhkiG9w0BAQsFADBw
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
|
||||||
|
dXJhbmNlIFNlcnZlciBDQTAeFw0xNDA0MTYwMDAwMDBaFw0xNjA0MjAxMjAwMDBa
|
||||||
|
MGwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
|
||||||
|
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxGTAXBgNVBAMTEG5h
|
||||||
|
Z2lvcy56dWxpcC5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCy
|
||||||
|
J6F6KjG/Y1vf3oj947a+otyc/BFH81K9AsZUrL46kXoCkdr6SJqJDKYLn/adv+OI
|
||||||
|
GTDo8LpbISE2FkviRFgUEIAkHcxdF4UMv1fpby2VcYleFigD2Fn+LkWcCpqk9uRL
|
||||||
|
VhAgbZdXLLw0LtTMp0kESO+DsjpfbwjNP+POZBLN96PoOToiUmNJKwhLucckmo/K
|
||||||
|
QrEfwRdDxJfD12NYCl8ZEOFfQEinWmstvschCM1LOeZTBDBHFXOvi1xhPu8utpHJ
|
||||||
|
xdibN0vWn17Cole0Blris3sT34KA/FRswCJ4jTxtL58WIE19YLiLDoP3kDNuNjZc
|
||||||
|
uhXk/sgqrGqam5GQfUOhAgMBAAGjggHfMIIB2zAfBgNVHSMEGDAWgBRRaP+QrwIH
|
||||||
|
dTzM2WVkYqISuFlyOzAdBgNVHQ4EFgQUGk12Sw4Clj8YyjOggnJ7LXTXRoAwGwYD
|
||||||
|
VR0RBBQwEoIQbmFnaW9zLnp1bGlwLm5ldDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0l
|
||||||
|
BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHUGA1UdHwRuMGwwNKAyoDCGLmh0dHA6
|
||||||
|
Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9zaGEyLWhhLXNlcnZlci1nMi5jcmwwNKAyoDCG
|
||||||
|
Lmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWhhLXNlcnZlci1nMi5jcmww
|
||||||
|
QgYDVR0gBDswOTA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93
|
||||||
|
d3cuZGlnaWNlcnQuY29tL0NQUzCBgwYIKwYBBQUHAQEEdzB1MCQGCCsGAQUFBzAB
|
||||||
|
hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wTQYIKwYBBQUHMAKGQWh0dHA6Ly9j
|
||||||
|
YWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJIaWdoQXNzdXJhbmNlU2Vy
|
||||||
|
dmVyQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBACsGRuZG
|
||||||
|
SVqbo/VtJJCOLSS4+IeyaPWqvH0e7Nlt4NPrgZVoI+JBPhwEnfbtGPX4epIu+gRF
|
||||||
|
1Zazk0E9nGUh5AUatruz0wq/FCj4eg+koV1XJLwlJde/s2IgEilG15wBWhH02uJo
|
||||||
|
oM+wScbr4rPxwgB4Dytz/HAYIXzMyPdYr0/zFGBpCtHIDd5E1mFyCn+0tCh0TRBm
|
||||||
|
YleHUA6A7CXq9iKNknIpJw/BDOYLtNz91qCBL4U3sB9kfJ4HEF9jC8/HhlW6IH1r
|
||||||
|
B5zjnj4D0FDyJSzBF44HUbzCxp7t/rEnQTASSdQaMcm9T7rqw8doJ8umnDLLeqp5
|
||||||
|
2IeiKC3ePDOsopE=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||||
|
ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL
|
||||||
|
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
|
||||||
|
LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy
|
||||||
|
YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2
|
||||||
|
4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC
|
||||||
|
Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1
|
||||||
|
itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn
|
||||||
|
4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X
|
||||||
|
sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft
|
||||||
|
bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA
|
||||||
|
MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
|
||||||
|
NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
|
||||||
|
dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t
|
||||||
|
L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG
|
||||||
|
BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ
|
||||||
|
UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D
|
||||||
|
aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd
|
||||||
|
aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH
|
||||||
|
E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly
|
||||||
|
/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu
|
||||||
|
xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF
|
||||||
|
0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae
|
||||||
|
cPUeybQ=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -1,36 +1,31 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
MIIGVDCCBTygAwIBAgIDC9I3MA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
|
MIIFRzCCBC+gAwIBAgIQCwfY+SvxDTFK0KY29dqHWjANBgkqhkiG9w0BAQsFADBw
|
||||||
TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg
|
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
|
||||||
MSBQcmltYXJ5IEludGVybWVkaWF0ZSBTZXJ2ZXIgQ0EwHhcNMTMwOTA0MTcxMDI4
|
dXJhbmNlIFNlcnZlciBDQTAeFw0xNDA0MTYwMDAwMDBaFw0xNjA0MjAxMjAwMDBa
|
||||||
WhcNMTQwOTA1MTA1ODI3WjBoMRkwFwYDVQQNExBncWdkOTFoVlNLUUw4d2k2MQsw
|
MGwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
|
||||||
CQYDVQQGEwJVUzEZMBcGA1UEAxMQbmFnaW9zLnp1bGlwLm5ldDEjMCEGCSqGSIb3
|
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxGTAXBgNVBAMTEG5h
|
||||||
DQEJARYUaG9zdG1hc3RlckB6dWxpcC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
|
Z2lvcy56dWxpcC5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCy
|
||||||
DwAwggEKAoIBAQC3r6IfMWzcOZzQUlY3AU5P89WsWt0JLjCPFhxCLplVfR9a0VZk
|
J6F6KjG/Y1vf3oj947a+otyc/BFH81K9AsZUrL46kXoCkdr6SJqJDKYLn/adv+OI
|
||||||
2e7xiOuldoXSkwuzXPATQHPlmsbJdN9g86agj9VLhfiIr7rZV3Fx4IUJqaAE62eB
|
GTDo8LpbISE2FkviRFgUEIAkHcxdF4UMv1fpby2VcYleFigD2Fn+LkWcCpqk9uRL
|
||||||
rMdPYfP5EjB3zMSuJYFldqsLFfHvucBqGvM2b9F7iuDFHaeQk9xETeKx5fADUdI7
|
VhAgbZdXLLw0LtTMp0kESO+DsjpfbwjNP+POZBLN96PoOToiUmNJKwhLucckmo/K
|
||||||
FqLyL3mWmfm8vS9mNLOdkxN93D6R6zvIwUUvDya9wYl5b1D3IAL1ADaMsAGqbihW
|
QrEfwRdDxJfD12NYCl8ZEOFfQEinWmstvschCM1LOeZTBDBHFXOvi1xhPu8utpHJ
|
||||||
N5Prdv2d+v4S/OiA+x9fM26WRVr4oFfSNsVQzHOVEwuuazXx8IgN2NgjcAMmbJBz
|
xdibN0vWn17Cole0Blris3sT34KA/FRswCJ4jTxtL58WIE19YLiLDoP3kDNuNjZc
|
||||||
dWzjy1XOek07vEKo5D7Quh4IxuQXF2GFbExxAgMBAAGjggLgMIIC3DAJBgNVHRME
|
uhXk/sgqrGqam5GQfUOhAgMBAAGjggHfMIIB2zAfBgNVHSMEGDAWgBRRaP+QrwIH
|
||||||
AjAAMAsGA1UdDwQEAwIDqDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQU
|
dTzM2WVkYqISuFlyOzAdBgNVHQ4EFgQUGk12Sw4Clj8YyjOggnJ7LXTXRoAwGwYD
|
||||||
ydhvTxMKSA0pXcaM0rZaN3IxCRswHwYDVR0jBBgwFoAU60I00Jiwq5/0G2sI98xk
|
VR0RBBQwEoIQbmFnaW9zLnp1bGlwLm5ldDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0l
|
||||||
Lu8OLEUwJgYDVR0RBB8wHYIQbmFnaW9zLnp1bGlwLm5ldIIJenVsaXAubmV0MIIB
|
BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHUGA1UdHwRuMGwwNKAyoDCGLmh0dHA6
|
||||||
VgYDVR0gBIIBTTCCAUkwCAYGZ4EMAQIBMIIBOwYLKwYBBAGBtTcBAgMwggEqMC4G
|
Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9zaGEyLWhhLXNlcnZlci1nMi5jcmwwNKAyoDCG
|
||||||
CCsGAQUFBwIBFiJodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kucGRmMIH3
|
Lmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWhhLXNlcnZlci1nMi5jcmww
|
||||||
BggrBgEFBQcCAjCB6jAnFiBTdGFydENvbSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
|
QgYDVR0gBDswOTA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93
|
||||||
eTADAgEBGoG+VGhpcyBjZXJ0aWZpY2F0ZSB3YXMgaXNzdWVkIGFjY29yZGluZyB0
|
d3cuZGlnaWNlcnQuY29tL0NQUzCBgwYIKwYBBQUHAQEEdzB1MCQGCCsGAQUFBzAB
|
||||||
byB0aGUgQ2xhc3MgMSBWYWxpZGF0aW9uIHJlcXVpcmVtZW50cyBvZiB0aGUgU3Rh
|
hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wTQYIKwYBBQUHMAKGQWh0dHA6Ly9j
|
||||||
cnRDb20gQ0EgcG9saWN5LCByZWxpYW5jZSBvbmx5IGZvciB0aGUgaW50ZW5kZWQg
|
YWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJIaWdoQXNzdXJhbmNlU2Vy
|
||||||
cHVycG9zZSBpbiBjb21wbGlhbmNlIG9mIHRoZSByZWx5aW5nIHBhcnR5IG9ibGln
|
dmVyQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBACsGRuZG
|
||||||
YXRpb25zLjA1BgNVHR8ELjAsMCqgKKAmhiRodHRwOi8vY3JsLnN0YXJ0c3NsLmNv
|
SVqbo/VtJJCOLSS4+IeyaPWqvH0e7Nlt4NPrgZVoI+JBPhwEnfbtGPX4epIu+gRF
|
||||||
bS9jcnQxLWNybC5jcmwwgY4GCCsGAQUFBwEBBIGBMH8wOQYIKwYBBQUHMAGGLWh0
|
1Zazk0E9nGUh5AUatruz0wq/FCj4eg+koV1XJLwlJde/s2IgEilG15wBWhH02uJo
|
||||||
dHA6Ly9vY3NwLnN0YXJ0c3NsLmNvbS9zdWIvY2xhc3MxL3NlcnZlci9jYTBCBggr
|
oM+wScbr4rPxwgB4Dytz/HAYIXzMyPdYr0/zFGBpCtHIDd5E1mFyCn+0tCh0TRBm
|
||||||
BgEFBQcwAoY2aHR0cDovL2FpYS5zdGFydHNzbC5jb20vY2VydHMvc3ViLmNsYXNz
|
YleHUA6A7CXq9iKNknIpJw/BDOYLtNz91qCBL4U3sB9kfJ4HEF9jC8/HhlW6IH1r
|
||||||
MS5zZXJ2ZXIuY2EuY3J0MCMGA1UdEgQcMBqGGGh0dHA6Ly93d3cuc3RhcnRzc2wu
|
B5zjnj4D0FDyJSzBF44HUbzCxp7t/rEnQTASSdQaMcm9T7rqw8doJ8umnDLLeqp5
|
||||||
Y29tLzANBgkqhkiG9w0BAQUFAAOCAQEAIT+IkU07y1M1LNVr6CMjqz3voIYkQPNX
|
2IeiKC3ePDOsopE=
|
||||||
SssClaGMfyi3QSPVhniMUZJWiHvPLdLsDP1fbI4lRGAuIjHv6kAwGD1ZLrMTCTMl
|
|
||||||
pHD0Jnlf5rtWFzklWAt/dDslauaC7eYgMFx1fHja1vJu9QXUaTXas6GGxKfNYma9
|
|
||||||
OQgjxnEKjTciyyxnAA+i5d4I/eaJHeX79+PpyCULknDjrfBF1wAPakq9WJx+yzlt
|
|
||||||
pz9+3Ggdfhhecaixb/StyXYT8tXnQy+aTnLZqh7mmPWGd01oD5AFMwyCRr5nzepj
|
|
||||||
6R8DkHRe/3LFg4YDUpY8WORLTSAeQHVA3inGymsPlVJdmVSq///HdA==
|
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|||||||
@@ -1,116 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIGVjCCBT6gAwIBAgIDCxnMMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
|
|
||||||
TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0
|
|
||||||
YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg
|
|
||||||
MSBQcmltYXJ5IEludGVybWVkaWF0ZSBTZXJ2ZXIgQ0EwHhcNMTMwNzEyMTUwMjQ1
|
|
||||||
WhcNMTQwNzEyMjI0NDM0WjBpMRkwFwYDVQQNExBXODl0UjVjVkIyNTZ4ZzFwMQsw
|
|
||||||
CQYDVQQGEwJVUzEaMBgGA1UEAxMRc3RhZ2luZy56dWxpcC5jb20xIzAhBgkqhkiG
|
|
||||||
9w0BCQEWFGhvc3RtYXN0ZXJAenVsaXAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
|
||||||
AQ8AMIIBCgKCAQEA+omI0rp0LrwoxQ3vFPQDgqyOeHfoLLpSSqCLRZv+oH9aPscg
|
|
||||||
oTb2ua1VJjPGjBSKw7tsBitCLF9BEsDXZc0eQa6gqFzTEwC4n7xdqr9t0qxrF7ht
|
|
||||||
Uy9AJZZ0GuWkzk+qSMgl+/iRXv9PzCU/UnGNxI1AqiJUCRXcItriFbb5+mgOQlS8
|
|
||||||
EYYGnNR5mtU29UQadNiDzp73QgkCGfUxTBvJOcLntZRVAI9ElEcN4y2wfLcBhKJT
|
|
||||||
EE134j6JmY4Z7/UtyJa3gas3CM4Z2ttx5pEqT+qten7+/TdpkTj4R1BvYvPSRzDZ
|
|
||||||
TisDb0xa67CZ7bNf/Tyl9UeXRqAUix38TPuJ8QIDAQABo4IC4TCCAt0wCQYDVR0T
|
|
||||||
BAIwADALBgNVHQ8EBAMCA6gwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYE
|
|
||||||
FHQVTfN38Y2YZmpjAHBIp/aLDSOyMB8GA1UdIwQYMBaAFOtCNNCYsKuf9BtrCPfM
|
|
||||||
ZC7vDixFMCcGA1UdEQQgMB6CEXN0YWdpbmcuenVsaXAuY29tggl6dWxpcC5jb20w
|
|
||||||
ggFWBgNVHSAEggFNMIIBSTAIBgZngQwBAgEwggE7BgsrBgEEAYG1NwECAzCCASow
|
|
||||||
LgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYw
|
|
||||||
gfcGCCsGAQUFBwICMIHqMCcWIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9y
|
|
||||||
aXR5MAMCAQEagb5UaGlzIGNlcnRpZmljYXRlIHdhcyBpc3N1ZWQgYWNjb3JkaW5n
|
|
||||||
IHRvIHRoZSBDbGFzcyAxIFZhbGlkYXRpb24gcmVxdWlyZW1lbnRzIG9mIHRoZSBT
|
|
||||||
dGFydENvbSBDQSBwb2xpY3ksIHJlbGlhbmNlIG9ubHkgZm9yIHRoZSBpbnRlbmRl
|
|
||||||
ZCBwdXJwb3NlIGluIGNvbXBsaWFuY2Ugb2YgdGhlIHJlbHlpbmcgcGFydHkgb2Js
|
|
||||||
aWdhdGlvbnMuMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9jcmwuc3RhcnRzc2wu
|
|
||||||
Y29tL2NydDEtY3JsLmNybDCBjgYIKwYBBQUHAQEEgYEwfzA5BggrBgEFBQcwAYYt
|
|
||||||
aHR0cDovL29jc3Auc3RhcnRzc2wuY29tL3N1Yi9jbGFzczEvc2VydmVyL2NhMEIG
|
|
||||||
CCsGAQUFBzAChjZodHRwOi8vYWlhLnN0YXJ0c3NsLmNvbS9jZXJ0cy9zdWIuY2xh
|
|
||||||
c3MxLnNlcnZlci5jYS5jcnQwIwYDVR0SBBwwGoYYaHR0cDovL3d3dy5zdGFydHNz
|
|
||||||
bC5jb20vMA0GCSqGSIb3DQEBBQUAA4IBAQCTTSbioYG8QJfK6Yfc3ijdS2oOh8AI
|
|
||||||
Gf3IN1TpmWAM8ijhDsDX0E8/Us6PHCwsg+yLuHI+92/MtHHSMnfew5HenTol6hNY
|
|
||||||
CDPnaHd1UtDfp6/yp8U0iQMWIjxecL46IAyjdD9tX43dLhL5fziQYEJ2rjFHtK8J
|
|
||||||
FBRg9QZI536BJ4aPfcFWwWtaYqWB7Nib1n86SKCPl0Tn1HfFJ+j0vkh0EwoJ3y3z
|
|
||||||
8VbJNwI0DxYMUDN2burWvEzUfAtNh2c7vuHhY6q96kNTMmbed/1DPUWWVyXKYtVc
|
|
||||||
FC9Q+3yQ3JqCJ1XoV3OxiYzdQnNn8WQGsEx1pxD9D6mHYnffeOUlHqhB
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIGNDCCBBygAwIBAgIBGDANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
|
|
||||||
MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
|
|
||||||
Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
|
|
||||||
dGlvbiBBdXRob3JpdHkwHhcNMDcxMDI0MjA1NDE3WhcNMTcxMDI0MjA1NDE3WjCB
|
|
||||||
jDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsT
|
|
||||||
IlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxODA2BgNVBAMTL1N0
|
|
||||||
YXJ0Q29tIENsYXNzIDEgUHJpbWFyeSBJbnRlcm1lZGlhdGUgU2VydmVyIENBMIIB
|
|
||||||
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtonGrO8JUngHrJJj0PREGBiE
|
|
||||||
gFYfka7hh/oyULTTRwbw5gdfcA4Q9x3AzhA2NIVaD5Ksg8asWFI/ujjo/OenJOJA
|
|
||||||
pgh2wJJuniptTT9uYSAK21ne0n1jsz5G/vohURjXzTCm7QduO3CHtPn66+6CPAVv
|
|
||||||
kvek3AowHpNz/gfK11+AnSJYUq4G2ouHI2mw5CrY6oPSvfNx23BaKA+vWjhwRRI/
|
|
||||||
ME3NO68X5Q/LoKldSKqxYVDLNM08XMML6BDAjJvwAwNi/rJsPnIO7hxDKslIDlc5
|
|
||||||
xDEhyBDBLIf+VJVSH1I8MRKbf+fAoKVZ1eKPPvDVqOHXcDGpxLPPr21TLwb0pwID
|
|
||||||
AQABo4IBrTCCAakwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
|
|
||||||
VR0OBBYEFOtCNNCYsKuf9BtrCPfMZC7vDixFMB8GA1UdIwQYMBaAFE4L7xqkQFul
|
|
||||||
F2mHMMo0aEPQQa7yMGYGCCsGAQUFBwEBBFowWDAnBggrBgEFBQcwAYYbaHR0cDov
|
|
||||||
L29jc3Auc3RhcnRzc2wuY29tL2NhMC0GCCsGAQUFBzAChiFodHRwOi8vd3d3LnN0
|
|
||||||
YXJ0c3NsLmNvbS9zZnNjYS5jcnQwWwYDVR0fBFQwUjAnoCWgI4YhaHR0cDovL3d3
|
|
||||||
dy5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMCegJaAjhiFodHRwOi8vY3JsLnN0YXJ0
|
|
||||||
c3NsLmNvbS9zZnNjYS5jcmwwgYAGA1UdIAR5MHcwdQYLKwYBBAGBtTcBAgEwZjAu
|
|
||||||
BggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9saWN5LnBkZjA0
|
|
||||||
BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFydHNzbC5jb20vaW50ZXJtZWRpYXRl
|
|
||||||
LnBkZjANBgkqhkiG9w0BAQUFAAOCAgEAIQlJPqWIbuALi0jaMU2P91ZXouHTYlfp
|
|
||||||
tVbzhUV1O+VQHwSL5qBaPucAroXQ+/8gA2TLrQLhxpFy+KNN1t7ozD+hiqLjfDen
|
|
||||||
xk+PNdb01m4Ge90h2c9W/8swIkn+iQTzheWq8ecf6HWQTd35RvdCNPdFWAwRDYSw
|
|
||||||
xtpdPvkBnufh2lWVvnQce/xNFE+sflVHfXv0pQ1JHpXo9xLBzP92piVH0PN1Nb6X
|
|
||||||
t1gW66pceG/sUzCv6gRNzKkC4/C2BBL2MLERPZBOVmTX3DxDX3M570uvh+v2/miI
|
|
||||||
RHLq0gfGabDBoYvvF0nXYbFFSF87ICHpW7LM9NfpMfULFWE7epTj69m8f5SuauNi
|
|
||||||
YpaoZHy4h/OZMn6SolK+u/hlz8nyMPyLwcKmltdfieFcNID1j0cHL7SRv7Gifl9L
|
|
||||||
WtBbnySGBVFaaQNlQ0lxxeBvlDRr9hvYqbBMflPrj0jfyjO1SPo2ShpTpjMM0InN
|
|
||||||
SRXNiTE8kMBy12VLUjWKRhFEuT2OKGWmPnmeXAhEKa2wNREuIU640ucQPl2Eg7PD
|
|
||||||
wuTSxv0JS3QJ3fGz0xk+gA2iCxnwOOfFwq/iI9th4p1cbiCJSS4jarJiwUW0n6+L
|
|
||||||
p/EiO/h94pDQehn7Skzj0n1fSoMD7SfWI55rjbRZotnvbIIp3XUZPD9MEI3vu3Un
|
|
||||||
0q6Dp6jOW6c=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
|
|
||||||
MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
|
|
||||||
Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
|
|
||||||
dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9
|
|
||||||
MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
|
|
||||||
U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
|
|
||||||
cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
|
|
||||||
A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
|
|
||||||
pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
|
|
||||||
OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
|
|
||||||
Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
|
|
||||||
Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
|
|
||||||
HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
|
|
||||||
Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
|
|
||||||
+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
|
|
||||||
Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
|
|
||||||
Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
|
|
||||||
26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
|
|
||||||
AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
|
|
||||||
FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j
|
|
||||||
ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js
|
|
||||||
LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM
|
|
||||||
BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0
|
|
||||||
Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy
|
|
||||||
dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh
|
|
||||||
cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh
|
|
||||||
YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg
|
|
||||||
dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp
|
|
||||||
bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ
|
|
||||||
YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT
|
|
||||||
TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ
|
|
||||||
9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8
|
|
||||||
jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW
|
|
||||||
FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz
|
|
||||||
ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1
|
|
||||||
ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L
|
|
||||||
EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu
|
|
||||||
L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
|
|
||||||
yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC
|
|
||||||
O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V
|
|
||||||
um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
|
|
||||||
NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIGVjCCBT6gAwIBAgIDCxnMMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
|
|
||||||
TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0
|
|
||||||
YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg
|
|
||||||
MSBQcmltYXJ5IEludGVybWVkaWF0ZSBTZXJ2ZXIgQ0EwHhcNMTMwNzEyMTUwMjQ1
|
|
||||||
WhcNMTQwNzEyMjI0NDM0WjBpMRkwFwYDVQQNExBXODl0UjVjVkIyNTZ4ZzFwMQsw
|
|
||||||
CQYDVQQGEwJVUzEaMBgGA1UEAxMRc3RhZ2luZy56dWxpcC5jb20xIzAhBgkqhkiG
|
|
||||||
9w0BCQEWFGhvc3RtYXN0ZXJAenVsaXAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
|
||||||
AQ8AMIIBCgKCAQEA+omI0rp0LrwoxQ3vFPQDgqyOeHfoLLpSSqCLRZv+oH9aPscg
|
|
||||||
oTb2ua1VJjPGjBSKw7tsBitCLF9BEsDXZc0eQa6gqFzTEwC4n7xdqr9t0qxrF7ht
|
|
||||||
Uy9AJZZ0GuWkzk+qSMgl+/iRXv9PzCU/UnGNxI1AqiJUCRXcItriFbb5+mgOQlS8
|
|
||||||
EYYGnNR5mtU29UQadNiDzp73QgkCGfUxTBvJOcLntZRVAI9ElEcN4y2wfLcBhKJT
|
|
||||||
EE134j6JmY4Z7/UtyJa3gas3CM4Z2ttx5pEqT+qten7+/TdpkTj4R1BvYvPSRzDZ
|
|
||||||
TisDb0xa67CZ7bNf/Tyl9UeXRqAUix38TPuJ8QIDAQABo4IC4TCCAt0wCQYDVR0T
|
|
||||||
BAIwADALBgNVHQ8EBAMCA6gwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYE
|
|
||||||
FHQVTfN38Y2YZmpjAHBIp/aLDSOyMB8GA1UdIwQYMBaAFOtCNNCYsKuf9BtrCPfM
|
|
||||||
ZC7vDixFMCcGA1UdEQQgMB6CEXN0YWdpbmcuenVsaXAuY29tggl6dWxpcC5jb20w
|
|
||||||
ggFWBgNVHSAEggFNMIIBSTAIBgZngQwBAgEwggE7BgsrBgEEAYG1NwECAzCCASow
|
|
||||||
LgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYw
|
|
||||||
gfcGCCsGAQUFBwICMIHqMCcWIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9y
|
|
||||||
aXR5MAMCAQEagb5UaGlzIGNlcnRpZmljYXRlIHdhcyBpc3N1ZWQgYWNjb3JkaW5n
|
|
||||||
IHRvIHRoZSBDbGFzcyAxIFZhbGlkYXRpb24gcmVxdWlyZW1lbnRzIG9mIHRoZSBT
|
|
||||||
dGFydENvbSBDQSBwb2xpY3ksIHJlbGlhbmNlIG9ubHkgZm9yIHRoZSBpbnRlbmRl
|
|
||||||
ZCBwdXJwb3NlIGluIGNvbXBsaWFuY2Ugb2YgdGhlIHJlbHlpbmcgcGFydHkgb2Js
|
|
||||||
aWdhdGlvbnMuMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9jcmwuc3RhcnRzc2wu
|
|
||||||
Y29tL2NydDEtY3JsLmNybDCBjgYIKwYBBQUHAQEEgYEwfzA5BggrBgEFBQcwAYYt
|
|
||||||
aHR0cDovL29jc3Auc3RhcnRzc2wuY29tL3N1Yi9jbGFzczEvc2VydmVyL2NhMEIG
|
|
||||||
CCsGAQUFBzAChjZodHRwOi8vYWlhLnN0YXJ0c3NsLmNvbS9jZXJ0cy9zdWIuY2xh
|
|
||||||
c3MxLnNlcnZlci5jYS5jcnQwIwYDVR0SBBwwGoYYaHR0cDovL3d3dy5zdGFydHNz
|
|
||||||
bC5jb20vMA0GCSqGSIb3DQEBBQUAA4IBAQCTTSbioYG8QJfK6Yfc3ijdS2oOh8AI
|
|
||||||
Gf3IN1TpmWAM8ijhDsDX0E8/Us6PHCwsg+yLuHI+92/MtHHSMnfew5HenTol6hNY
|
|
||||||
CDPnaHd1UtDfp6/yp8U0iQMWIjxecL46IAyjdD9tX43dLhL5fziQYEJ2rjFHtK8J
|
|
||||||
FBRg9QZI536BJ4aPfcFWwWtaYqWB7Nib1n86SKCPl0Tn1HfFJ+j0vkh0EwoJ3y3z
|
|
||||||
8VbJNwI0DxYMUDN2burWvEzUfAtNh2c7vuHhY6q96kNTMmbed/1DPUWWVyXKYtVc
|
|
||||||
FC9Q+3yQ3JqCJ1XoV3OxiYzdQnNn8WQGsEx1pxD9D6mHYnffeOUlHqhB
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFRTCCBC2gAwIBAgIQCeu0vyc0EdwhoPpohoWSuzANBgkqhkiG9w0BAQsFADBw
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
|
||||||
|
dXJhbmNlIFNlcnZlciBDQTAeFw0xNDA0MTYwMDAwMDBaFw0xNjA0MjAxMjAwMDBa
|
||||||
|
MGsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
|
||||||
|
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxGDAWBgNVBAMTD3N0
|
||||||
|
YXRzLnp1bGlwLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANPQ
|
||||||
|
XZXfNdVW7N6CSzpM74dtLMAawINFfYuk1VFUqzC5L5uP7ZUwvhYVKVlJrnd5afGp
|
||||||
|
XARqaYhddvJxbDihO3vgCopkHdcRikRrJgwSvLUtCeX8kLUyHTX6XXmn52CspX+r
|
||||||
|
s2OYecGna+dnscWyL3K1UlVISJ2lyKGZU6t72Fyt7XYIFzVd/VruK6jfWsbZOpZ6
|
||||||
|
HZgKzcYP1CTrsAg5LvW4dqNaEJya9+JdyRWJ9zgDSWV+XzsJtbY3hg8IrCNLB/ck
|
||||||
|
F7wElqQg/tJNELgUyQmrIhyxqgHu0Nsg56Ug2KhIby4QaBzgBy7U+oTRgM8SYVCN
|
||||||
|
iFM74FG1/DA08pERaBkCAwEAAaOCAd4wggHaMB8GA1UdIwQYMBaAFFFo/5CvAgd1
|
||||||
|
PMzZZWRiohK4WXI7MB0GA1UdDgQWBBQRkQ0SirqkXztkBjr55UekEAqdljAaBgNV
|
||||||
|
HREEEzARgg9zdGF0cy56dWxpcC5uZXQwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW
|
||||||
|
MBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5odHRwOi8v
|
||||||
|
Y3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzIuY3JsMDSgMqAwhi5o
|
||||||
|
dHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzIuY3JsMEIG
|
||||||
|
A1UdIAQ7MDkwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3
|
||||||
|
LmRpZ2ljZXJ0LmNvbS9DUFMwgYMGCCsGAQUFBwEBBHcwdTAkBggrBgEFBQcwAYYY
|
||||||
|
aHR0cDovL29jc3AuZGlnaWNlcnQuY29tME0GCCsGAQUFBzAChkFodHRwOi8vY2Fj
|
||||||
|
ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEySGlnaEFzc3VyYW5jZVNlcnZl
|
||||||
|
ckNBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQArykRu8hdK
|
||||||
|
9tFLzDUcApS9xGuOSjJgGOPRW8symfNq4pU8dPp+gXtZ2BlxLeKn2bLR4XeLlvCj
|
||||||
|
LZRZaMVfrGyaEV9WzkyTVG64l7zjKNHqdN/AY/YAp6HcxXDNJs1eFUOB45yHLfkH
|
||||||
|
pG0gx9dnCR+rRyDpOVODNLP6/JIq79xluk6Eb4VaSlHrxnDoDb18Yolx3OlYnwNF
|
||||||
|
cceJrPJEL1AX7NqBRav7dSfR4DsyYzT+GKXx/mZe/igMn2pUjE5Idf5aw9citsU3
|
||||||
|
SaltVJZ3Kp4KBx1xHF06HUA3eb50vghOeGmMVYAWQIZeYHRDcbAhrFW0W7SnJwFc
|
||||||
|
ZQHYMrD1uDAQ
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||||
|
ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL
|
||||||
|
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
|
||||||
|
LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy
|
||||||
|
YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2
|
||||||
|
4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC
|
||||||
|
Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1
|
||||||
|
itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn
|
||||||
|
4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X
|
||||||
|
sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft
|
||||||
|
bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA
|
||||||
|
MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
|
||||||
|
NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
|
||||||
|
dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t
|
||||||
|
L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG
|
||||||
|
BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ
|
||||||
|
UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D
|
||||||
|
aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd
|
||||||
|
aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH
|
||||||
|
E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly
|
||||||
|
/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu
|
||||||
|
xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF
|
||||||
|
0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae
|
||||||
|
cPUeybQ=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
31
puppet/zulip_internal/files/certs/stats.zulip.net.crt
Normal file
31
puppet/zulip_internal/files/certs/stats.zulip.net.crt
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFRTCCBC2gAwIBAgIQCeu0vyc0EdwhoPpohoWSuzANBgkqhkiG9w0BAQsFADBw
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
|
||||||
|
dXJhbmNlIFNlcnZlciBDQTAeFw0xNDA0MTYwMDAwMDBaFw0xNjA0MjAxMjAwMDBa
|
||||||
|
MGsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
|
||||||
|
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxGDAWBgNVBAMTD3N0
|
||||||
|
YXRzLnp1bGlwLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANPQ
|
||||||
|
XZXfNdVW7N6CSzpM74dtLMAawINFfYuk1VFUqzC5L5uP7ZUwvhYVKVlJrnd5afGp
|
||||||
|
XARqaYhddvJxbDihO3vgCopkHdcRikRrJgwSvLUtCeX8kLUyHTX6XXmn52CspX+r
|
||||||
|
s2OYecGna+dnscWyL3K1UlVISJ2lyKGZU6t72Fyt7XYIFzVd/VruK6jfWsbZOpZ6
|
||||||
|
HZgKzcYP1CTrsAg5LvW4dqNaEJya9+JdyRWJ9zgDSWV+XzsJtbY3hg8IrCNLB/ck
|
||||||
|
F7wElqQg/tJNELgUyQmrIhyxqgHu0Nsg56Ug2KhIby4QaBzgBy7U+oTRgM8SYVCN
|
||||||
|
iFM74FG1/DA08pERaBkCAwEAAaOCAd4wggHaMB8GA1UdIwQYMBaAFFFo/5CvAgd1
|
||||||
|
PMzZZWRiohK4WXI7MB0GA1UdDgQWBBQRkQ0SirqkXztkBjr55UekEAqdljAaBgNV
|
||||||
|
HREEEzARgg9zdGF0cy56dWxpcC5uZXQwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW
|
||||||
|
MBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5odHRwOi8v
|
||||||
|
Y3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzIuY3JsMDSgMqAwhi5o
|
||||||
|
dHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzIuY3JsMEIG
|
||||||
|
A1UdIAQ7MDkwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3
|
||||||
|
LmRpZ2ljZXJ0LmNvbS9DUFMwgYMGCCsGAQUFBwEBBHcwdTAkBggrBgEFBQcwAYYY
|
||||||
|
aHR0cDovL29jc3AuZGlnaWNlcnQuY29tME0GCCsGAQUFBzAChkFodHRwOi8vY2Fj
|
||||||
|
ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEySGlnaEFzc3VyYW5jZVNlcnZl
|
||||||
|
ckNBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQArykRu8hdK
|
||||||
|
9tFLzDUcApS9xGuOSjJgGOPRW8symfNq4pU8dPp+gXtZ2BlxLeKn2bLR4XeLlvCj
|
||||||
|
LZRZaMVfrGyaEV9WzkyTVG64l7zjKNHqdN/AY/YAp6HcxXDNJs1eFUOB45yHLfkH
|
||||||
|
pG0gx9dnCR+rRyDpOVODNLP6/JIq79xluk6Eb4VaSlHrxnDoDb18Yolx3OlYnwNF
|
||||||
|
cceJrPJEL1AX7NqBRav7dSfR4DsyYzT+GKXx/mZe/igMn2pUjE5Idf5aw9citsU3
|
||||||
|
SaltVJZ3Kp4KBx1xHF06HUA3eb50vghOeGmMVYAWQIZeYHRDcbAhrFW0W7SnJwFc
|
||||||
|
ZQHYMrD1uDAQ
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIGeDCCBWCgAwIBAgIDCzx7MA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
|
|
||||||
TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0
|
|
||||||
YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg
|
|
||||||
MSBQcmltYXJ5IEludGVybWVkaWF0ZSBTZXJ2ZXIgQ0EwHhcNMTMwNzI3MjA0OTI2
|
|
||||||
WhcNMTQwNzI4MjAyMjU4WjCBizEZMBcGA1UEDRMQZXJIOUp3Y3NxcFB3T1pQdTEL
|
|
||||||
MAkGA1UEBhMCVVMxGTAXBgNVBAMTEHN0YXRzMS56dWxpcC5uZXQxRjBEBgkqhkiG
|
|
||||||
9w0BCQEWNzE5YmI4ZDJjYjkwNzRjZGRhODY0OWQzNDFkZDhlY2Q1LnByb3RlY3RA
|
|
||||||
d2hvaXNndWFyZC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDn
|
|
||||||
/nUFbsm89+Npxgq+B2jRqGvOnCPQ6QRgWj6ZQdZGuyOJ9JquSVc9YGgG/MGSa5hv
|
|
||||||
vzPxhC3NI0hH1nHypJtXbQS+UkI2tRSKdW89LVLcMJi2epqwlisBpobNIuMIQbsA
|
|
||||||
6HXY6qFI1r3WyRUZ3YggL4j35FEOW7pwx81fBFOgZaFu7b1PSjWyy1G0IrPalVaI
|
|
||||||
USsHu/pX1RxoTkcPlqG40pjVaQKHruJIaAQBBrW1r/QpDgan6PwiOSWrTJe/+WHU
|
|
||||||
xqlKO4WmPV70HRTZOFfMBQzO3PdR6a4RntjVbvvMycmCn6B0DKjDdnlP0iKAnlii
|
|
||||||
Lxiv/QO0MNkeX2l/l0H7AgMBAAGjggLgMIIC3DAJBgNVHRMEAjAAMAsGA1UdDwQE
|
|
||||||
AwIDqDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUPZ5uzgMNpTBQ5DBA
|
|
||||||
kipoNphC4uYwHwYDVR0jBBgwFoAU60I00Jiwq5/0G2sI98xkLu8OLEUwJgYDVR0R
|
|
||||||
BB8wHYIQc3RhdHMxLnp1bGlwLm5ldIIJenVsaXAubmV0MIIBVgYDVR0gBIIBTTCC
|
|
||||||
AUkwCAYGZ4EMAQIBMIIBOwYLKwYBBAGBtTcBAgMwggEqMC4GCCsGAQUFBwIBFiJo
|
|
||||||
dHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kucGRmMIH3BggrBgEFBQcCAjCB
|
|
||||||
6jAnFiBTdGFydENvbSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTADAgEBGoG+VGhp
|
|
||||||
cyBjZXJ0aWZpY2F0ZSB3YXMgaXNzdWVkIGFjY29yZGluZyB0byB0aGUgQ2xhc3Mg
|
|
||||||
MSBWYWxpZGF0aW9uIHJlcXVpcmVtZW50cyBvZiB0aGUgU3RhcnRDb20gQ0EgcG9s
|
|
||||||
aWN5LCByZWxpYW5jZSBvbmx5IGZvciB0aGUgaW50ZW5kZWQgcHVycG9zZSBpbiBj
|
|
||||||
b21wbGlhbmNlIG9mIHRoZSByZWx5aW5nIHBhcnR5IG9ibGlnYXRpb25zLjA1BgNV
|
|
||||||
HR8ELjAsMCqgKKAmhiRodHRwOi8vY3JsLnN0YXJ0c3NsLmNvbS9jcnQxLWNybC5j
|
|
||||||
cmwwgY4GCCsGAQUFBwEBBIGBMH8wOQYIKwYBBQUHMAGGLWh0dHA6Ly9vY3NwLnN0
|
|
||||||
YXJ0c3NsLmNvbS9zdWIvY2xhc3MxL3NlcnZlci9jYTBCBggrBgEFBQcwAoY2aHR0
|
|
||||||
cDovL2FpYS5zdGFydHNzbC5jb20vY2VydHMvc3ViLmNsYXNzMS5zZXJ2ZXIuY2Eu
|
|
||||||
Y3J0MCMGA1UdEgQcMBqGGGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tLzANBgkqhkiG
|
|
||||||
9w0BAQUFAAOCAQEApEbVfCf5LBHi7wFwtfraYMuf8TTZ6B41mBmN3wnavc2STtOd
|
|
||||||
+G9J3+oJeI6pwuNAHeY08EQZqAj8ijUnXPueeIziWISzFIaCQC8svHruxgR0nPUk
|
|
||||||
vSas89B74EhQ3gFpoEwnyi8rq59xVjluLkLmA93PGIk8c/02Z5NsW05k508kZwsm
|
|
||||||
Y1qtD1vAbhHQaTTzyc+8VK7SNtzIkjaIRcyEwE+J63q5uTisMIoJFnZJiUN2vQqg
|
|
||||||
I6sFnSNahB5WxEKsX5PF3tC7XLH6d5NmRL7kEaHS7U5QHUPLAPZEsYTcBHreAzEl
|
|
||||||
cBHkBWDioqskhYGkrBBE5RFWCtzUmVo86mxHYA==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFQzCCBCugAwIBAgIQD9VdZebVvG9+AG9yMOzijTANBgkqhkiG9w0BAQsFADBw
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz
|
||||||
|
dXJhbmNlIFNlcnZlciBDQTAeFw0xNDA0MTYwMDAwMDBaFw0xNjA0MjAxMjAwMDBa
|
||||||
|
MGoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T
|
||||||
|
YW4gRnJhbmNpc2NvMRUwEwYDVQQKEwxEcm9wYm94LCBJbmMxFzAVBgNVBAMTDnRy
|
||||||
|
YWMuenVsaXAubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzdeK
|
||||||
|
urQ+rI5ICqWM5KIcPrEprv281Vf9yuQRInk9mz7WdoscuPEIfCrnVj+wXG9L4Pco
|
||||||
|
u+BIDRCZ5/a0yfimS8U23zcieDNtZP4/HKpgwIkk4NkIZ/6u2muWzMe6AEjePKsd
|
||||||
|
EImJzcuTGoXJIY+z3I1HlzPUwLMSk4dHXPho4c/TJcJvNBp/MPbWCAvAKNq1Ehwj
|
||||||
|
GqtQjSYeUq1JJlF+jRZl8UvJANIObvMFuxGllw9H5IUCBIzRNpXxARpd4Fnz1Au0
|
||||||
|
m7bhBmNYIzXqQWqBZfU/qng118YjOYC+ZrcJqG1j1Rk0lrXhnq36LfC1OrefwjsZ
|
||||||
|
p6ly/U5F8oVvC8wlxQIDAQABo4IB3TCCAdkwHwYDVR0jBBgwFoAUUWj/kK8CB3U8
|
||||||
|
zNllZGKiErhZcjswHQYDVR0OBBYEFMi87D8ybP+KnZR3Lg788zRzn2CiMBkGA1Ud
|
||||||
|
EQQSMBCCDnRyYWMuenVsaXAubmV0MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAU
|
||||||
|
BggrBgEFBQcDAQYIKwYBBQUHAwIwdQYDVR0fBG4wbDA0oDKgMIYuaHR0cDovL2Ny
|
||||||
|
bDMuZGlnaWNlcnQuY29tL3NoYTItaGEtc2VydmVyLWcyLmNybDA0oDKgMIYuaHR0
|
||||||
|
cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItaGEtc2VydmVyLWcyLmNybDBCBgNV
|
||||||
|
HSAEOzA5MDcGCWCGSAGG/WwBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5k
|
||||||
|
aWdpY2VydC5jb20vQ1BTMIGDBggrBgEFBQcBAQR3MHUwJAYIKwYBBQUHMAGGGGh0
|
||||||
|
dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBNBggrBgEFBQcwAoZBaHR0cDovL2NhY2Vy
|
||||||
|
dHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkhpZ2hBc3N1cmFuY2VTZXJ2ZXJD
|
||||||
|
QS5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAQEK5QSNBYXCR
|
||||||
|
VVWJtJYU3ftiA1vlzkUvSBBC3McgLk+xPyLJEZspKJ6SEqenbNLi05heT2i7DNi4
|
||||||
|
ePJA9sQHBPUUYralS2be0CXym5Kj8+J9DRUXG829VLUs3ZLEwzCPTJC0gJ5Qm9r0
|
||||||
|
DMOgce059q62pgSxqHGq9PRnYLfsImanr1fWxonrA+tSxr+ACA77617uShRFtEe7
|
||||||
|
w7W9kaHG/rxNX4NyaA1dTPKJ/+R70k1UJWyiwnpW1aKzdwF1sN4FZx0PW3YW5Fww
|
||||||
|
JFO5LluyysXF/ccndhPBphF+KE0H7PdWUjQsQWq2qd6nLt1ZWmJaJsRK+YmbxSzE
|
||||||
|
ijy7IvLskw==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs
|
||||||
|
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||||
|
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||||
|
ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL
|
||||||
|
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
|
||||||
|
LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy
|
||||||
|
YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2
|
||||||
|
4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC
|
||||||
|
Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1
|
||||||
|
itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn
|
||||||
|
4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X
|
||||||
|
sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft
|
||||||
|
bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA
|
||||||
|
MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
|
||||||
|
NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
|
||||||
|
dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t
|
||||||
|
L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG
|
||||||
|
BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ
|
||||||
|
UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D
|
||||||
|
aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd
|
||||||
|
aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH
|
||||||
|
E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly
|
||||||
|
/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu
|
||||||
|
xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF
|
||||||
|
0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae
|
||||||
|
cPUeybQ=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user